From b9845e7cb53171b1da46014e1bbcb418b5a4222d Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Wed, 13 Jul 2016 16:38:30 -0400 Subject: [PATCH] Don't double encode protobuf runtime.Unknown When using runtime.Object and runtime.RawExtension, passing runtime.Unknown to protobuf serializer should result in the raw message being serialized (since all normal protobuf objects are runtime.Unknown). Also, avoid setting a content-type when decoding a protobuf object except when the content appears to be proto. --- pkg/runtime/serializer/protobuf/protobuf.go | 33 +++++++++++++------ .../serializer/protobuf/protobuf_test.go | 8 ++--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/pkg/runtime/serializer/protobuf/protobuf.go b/pkg/runtime/serializer/protobuf/protobuf.go index b9eb9e5db86..a21df48a05d 100644 --- a/pkg/runtime/serializer/protobuf/protobuf.go +++ b/pkg/runtime/serializer/protobuf/protobuf.go @@ -124,7 +124,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil { *intoUnknown = unk - if len(intoUnknown.ContentType) == 0 { + if ok, _ := s.RecognizesData(bytes.NewBuffer(unk.Raw)); ok { intoUnknown.ContentType = s.contentType } return intoUnknown, &actual, nil @@ -167,17 +167,30 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi // Encode serializes the provided object to the given writer. func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error { - var unk runtime.Unknown - kind := obj.GetObjectKind().GroupVersionKind() - unk = runtime.Unknown{ - TypeMeta: runtime.TypeMeta{ - Kind: kind.Kind, - APIVersion: kind.GroupVersion().String(), - }, - } - prefixSize := uint64(len(s.prefix)) + var unk runtime.Unknown + switch t := obj.(type) { + case *runtime.Unknown: + estimatedSize := prefixSize + uint64(t.Size()) + data := make([]byte, estimatedSize) + i, err := t.MarshalTo(data[prefixSize:]) + if err != nil { + return err + } + copy(data, s.prefix) + _, err = w.Write(data[:prefixSize+uint64(i)]) + return err + default: + kind := obj.GetObjectKind().GroupVersionKind() + unk = runtime.Unknown{ + TypeMeta: runtime.TypeMeta{ + Kind: kind.Kind, + APIVersion: kind.GroupVersion().String(), + }, + } + } + switch t := obj.(type) { case bufferedMarshaller: // this path performs a single allocation during write but requires the caller to implement diff --git a/pkg/runtime/serializer/protobuf/protobuf_test.go b/pkg/runtime/serializer/protobuf/protobuf_test.go index 54c92bf42a0..77a291da8ec 100644 --- a/pkg/runtime/serializer/protobuf/protobuf_test.go +++ b/pkg/runtime/serializer/protobuf/protobuf_test.go @@ -205,7 +205,7 @@ func TestDecode(t *testing.T) { 0x0a, 0x15, 0x0a, 0x0d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // apiversion 0x12, 0x04, 0x74, 0x65, 0x73, 0x74, // kind - 0x12, 0x03, 0x01, 0x02, 0x03, // data + 0x12, 0x07, 0x6b, 0x38, 0x73, 0x00, 0x01, 0x02, 0x03, // data 0x1a, 0x00, // content-type 0x22, 0x00, // content-encoding } @@ -227,8 +227,7 @@ func TestDecode(t *testing.T) { }, { obj: &runtime.Unknown{ - ContentType: "application/protobuf", - Raw: []byte{}, + Raw: []byte{}, }, data: wire1, }, @@ -238,8 +237,9 @@ func TestDecode(t *testing.T) { APIVersion: "other/version", Kind: "test", }, + // content type is set because the prefix matches the content ContentType: "application/protobuf", - Raw: []byte{0x01, 0x02, 0x03}, + Raw: []byte{0x6b, 0x38, 0x73, 0x00, 0x01, 0x02, 0x03}, }, data: wire2, },