Add CBOR serializer option to disable JSON transcoding of raw types.

This commit is contained in:
Ben Luddy 2024-10-16 17:42:06 -04:00
parent db1239d354
commit d638d64572
No known key found for this signature in database
GPG Key ID: A6551E73A5974C30
2 changed files with 48 additions and 4 deletions

View File

@ -68,17 +68,30 @@ type Serializer interface {
var _ Serializer = &serializer{}
type options struct {
strict bool
strict bool
transcode bool
}
type Option func(*options)
// Strict configures a serializer to return a strict decoding error when it encounters map keys that
// do not correspond to a field in the target object of a decode operation. This option is disabled
// by default.
func Strict(s bool) Option {
return func(opts *options) {
opts.strict = s
}
}
// Transcode configures a serializer to transcode the "raw" bytes of a decoded runtime.RawExtension
// or metav1.FieldsV1 object to JSON. This is enabled by default to support existing programs that
// depend on the assumption that objects of either type contain valid JSON.
func Transcode(s bool) Option {
return func(opts *options) {
opts.transcode = s
}
}
type serializer struct {
metaFactory metaFactory
creater runtime.ObjectCreater
@ -88,6 +101,8 @@ type serializer struct {
func (serializer) private() {}
// NewSerializer creates and returns a serializer configured with the provided options. The default
// options are equivalent to explicitly passing Strict(false) and Transcode(true).
func NewSerializer(creater runtime.ObjectCreater, typer runtime.ObjectTyper, options ...Option) Serializer {
return newSerializer(&defaultMetaFactory{}, creater, typer, options...)
}
@ -98,6 +113,7 @@ func newSerializer(metaFactory metaFactory, creater runtime.ObjectCreater, typer
creater: creater,
typer: typer,
}
s.options.transcode = true
for _, o := range options {
o(&s.options)
}
@ -337,9 +353,10 @@ func (s *serializer) Decode(data []byte, gvk *schema.GroupVersionKind, into runt
return nil, actual, err
}
// TODO: Make possible to disable this behavior.
if err := transcodeRawTypes(obj); err != nil {
return nil, actual, err
if s.options.transcode {
if err := transcodeRawTypes(obj); err != nil {
return nil, actual, err
}
}
return obj, actual, strict

View File

@ -345,6 +345,33 @@ func TestDecode(t *testing.T) {
}
},
},
{
name: "raw types not transcoded",
options: []Option{Transcode(false)},
data: []byte{0xa4, 0x41, 'f', 0xa1, 0x41, 'a', 0x01, 0x42, 'f', 'p', 0xa1, 0x41, 'z', 0x02, 0x41, 'r', 0xa1, 0x41, 'b', 0x03, 0x42, 'r', 'p', 0xa1, 0x41, 'y', 0x04},
gvk: &schema.GroupVersionKind{},
metaFactory: stubMetaFactory{gvk: &schema.GroupVersionKind{}},
typer: stubTyper{gvks: []schema.GroupVersionKind{{Group: "x", Version: "y", Kind: "z"}}},
into: &structWithRawFields{},
expectedObj: &structWithRawFields{
FieldsV1: metav1.FieldsV1{Raw: []byte{0xa1, 0x41, 'a', 0x01}},
FieldsV1Pointer: &metav1.FieldsV1{Raw: []byte{0xa1, 0x41, 'z', 0x02}},
// RawExtension's UnmarshalCBOR ensures the self-described CBOR tag
// is present in the result so that there is never any ambiguity in
// distinguishing CBOR from JSON or Protobuf. It is unnecessary for
// FieldsV1 to do the same because the initial byte is always
// sufficient to distinguish a valid JSON-encoded FieldsV1 from a
// valid CBOR-encoded FieldsV1.
RawExtension: runtime.RawExtension{Raw: []byte{0xd9, 0xd9, 0xf7, 0xa1, 0x41, 'b', 0x03}},
RawExtensionPointer: &runtime.RawExtension{Raw: []byte{0xd9, 0xd9, 0xf7, 0xa1, 0x41, 'y', 0x04}},
},
expectedGVK: &schema.GroupVersionKind{Group: "x", Version: "y", Kind: "z"},
assertOnError: func(t *testing.T, err error) {
if err != nil {
t.Errorf("expected nil error, got: %v", err)
}
},
},
{
name: "object with embedded typemeta and objectmeta",
data: []byte("\xa2\x48metadata\xa1\x44name\x43foo\x44spec\xa0"), // {"metadata": {"name": "foo"}}