Skip to content

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

@mishap4

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));
                    }
                }**
              ....

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