Skip to content

Protobuf data corruption when CloudEvent is serialized/deserialized several times #523

Description

@mishap4

Any time serialize is called the payload is packed into Any, even it was already Any:

UT:

    @Test
    public void testMultipleSerializationDeserialization() throws InvalidProtocolBufferException {
        EventFormat serializer = new ProtobufFormat();

        Status status = Status.newBuilder().setCode(Code.UNKNOWN_VALUE).build();
        CloudEvent event1 = buildCloudEvent("id123", "test", "http:/test", status);
        CloudEventData data1 = event1.getData();
        assertTrue(data1 instanceof ProtoCloudEventData);
        Message message1 = ((ProtoCloudEventData) data1).getMessage();
        //assertTrue(message1 instanceof Any); // Not Any???
        assertTrue(message1 instanceof Status);
        assertEquals(status, message1);

        byte[] raw1 = serializer.serialize(event1);
        System.out.println("  event1: " + event1);
        System.out.println("    raw1: " + Arrays.toString(raw1));
        System.out.println("   size1: " + raw1.length);
        System.out.println("payload1: " + message1);

        CloudEvent event2 = serializer.deserialize(raw1);
        CloudEventData data2 = event2.getData();
        assertTrue(data2 instanceof ProtoCloudEventData);
        Message message2 = ((ProtoCloudEventData) data2).getMessage();
        assertTrue(message2 instanceof Any);
        assertEquals(status, ((Any) message2).unpack(Status.class));
        byte[] raw2 = serializer.serialize(event2);
        System.out.println("  event2: " + event2);
        System.out.println("    raw2: " + Arrays.toString(raw2));
        System.out.println("   size2: " + raw2.length);
        System.out.println("payload2: " + message2);
        //assertEquals(event1, event2);
        assertArrayEquals(raw1, raw2);

        CloudEvent event3 = serializer.deserialize(raw2);
        CloudEventData data3 = event3.getData();
        assertTrue(data3 instanceof ProtoCloudEventData);
        Message message3 = ((ProtoCloudEventData) data3).getMessage();
        assertTrue(message3 instanceof Any);
        assertEquals(status, (((Any) message3).unpack(Any.class).unpack(Status.class)));
        byte[] raw3 = serializer.serialize(event3);
        System.out.println("  event3: " + event3);
        System.out.println("    raw3: " + Arrays.toString(raw3));
        System.out.println("   size3: " + raw3.length);
        System.out.println("payload3: " + message3);
        //assertEquals(event1, event3);
        //assertEquals(event2, event3);
        assertArrayEquals(raw1, raw3);
        assertArrayEquals(raw2, raw3);
    }

    static CloudEvent buildCloudEvent(String id, String type, String source, Message message) {
        return CloudEventBuilder.v1()
                .withId(id)
                .withType(type)
                .withSource(URI.create(source))
                .withData(ProtoCloudEventData.wrap(message))
                .build();
    }
  event1: CloudEvent{id='id123', source=http:/test, type='test', data=io.cloudevents.protobuf.ProtoDataWrapper@6da29a93, extensions={}}
    raw1: [10, 5, 105, 100, 49, 50, 51, 18, 10, 104, 116, 116, 112, 58, 47, 116, 101, 115, 116, 26, 3, 49, 46, 48, 34, 4, 116, 101, 115, 116, 66, 43, 10, 37, 116, 121, 112, 101, 46, 103, 111, 111, 103, 108, 101, 97, 112, 105, 115, 46, 99, 111, 109, 47, 103, 111, 111, 103, 108, 101, 46, 114, 112, 99, 46, 83, 116, 97, 116, 117, 115, 18, 2, 8, 2]
   size1: 75
payload1: code: 2

  event2: CloudEvent{id='id123', source=http:/test, type='test', data=io.cloudevents.protobuf.ProtoDeserializer$ProtoAccessor@1ba03bde, extensions={}}
    raw2: [10, 5, 105, 100, 49, 50, 51, 18, 10, 104, 116, 116, 112, 58, 47, 116, 101, 115, 116, 26, 3, 49, 46, 48, 34, 4, 116, 101, 115, 116, 66, 86, 10, 39, 116, 121, 112, 101, 46, 103, 111, 111, 103, 108, 101, 97, 112, 105, 115, 46, 99, 111, 109, 47, 103, 111, 111, 103, 108, 101, 46, 112, 114, 111, 116, 111, 98, 117, 102, 46, 65, 110, 121, 18, 43, 10, 37, 116, 121, 112, 101, 46, 103, 111, 111, 103, 108, 101, 97, 112, 105, 115, 46, 99, 111, 109, 47, 103, 111, 111, 103, 108, 101, 46, 114, 112, 99, 46, 83, 116, 97, 116, 117, 115, 18, 2, 8, 2]
   size2: 118
payload2: type_url: "type.googleapis.com/google.rpc.Status"
value: "\b\002"

I believe ProtoSerializer.java should check that:

    public CloudEvent end(CloudEventData data) throws CloudEventRWException {
        if (data != null) {
            String dataContentType = null;
            Map<String, CloudEventAttributeValue> attributesMap = this.protoBuilder.getAttributesMap();
            CloudEventAttributeValue attrVal = (CloudEventAttributeValue)attributesMap.get("datacontenttype");
            if (attrVal != null && attrVal.hasCeString()) {
                dataContentType = attrVal.getCeString();
            }

            ProtoCloudEventData protoData;
            **if (data instanceof ProtoCloudEventData) {
                protoData = (ProtoCloudEventData)data;
                Message message = protoData.getMessage();
                if (message != null) {
                    if (message instanceof Any) {
                        this.protoBuilder.setProtoData((Any) message);
                    } else {
                        this.protoBuilder.setProtoData(Any.pack(message));
                    }
                }**
              ....

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions