From 10c2fdb7f4cf6f43d04242ca27f0669beadcf43d Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Fri, 1 Nov 2024 13:14:06 -0400 Subject: [PATCH] Use application/cbor-seq media type in streaming CBOR responses. The media type application/cbor describes exactly one encoded item. As a new (to Kubernetes) format with no existing clients, streaming/watch responses will use the application/cbor-seq media type. CBOR watch responses conform to the specification of CBOR Sequences and are encoded as the concatenation of zero or more items with no additional framing. Kubernetes-commit: 504f14998e920ca8837b3310094b3da11c62a070 --- rest/client.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/rest/client.go b/rest/client.go index 9bcb99c5..393a4166 100644 --- a/rest/client.go +++ b/rest/client.go @@ -129,6 +129,7 @@ func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientConte func scrubCBORContentConfigIfDisabled(content ClientContentConfig) ClientContentConfig { if clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsAllowCBOR) { + content.Negotiator = clientNegotiatorWithCBORSequenceStreamDecoder{content.Negotiator} return content } @@ -294,3 +295,38 @@ func (p *requestClientContentConfigProvider) UnsupportedMediaType(requestContent p.sawUnsupportedMediaTypeForCBOR.Store(true) } } + +// clientNegotiatorWithCBORSequenceStreamDecoder is a ClientNegotiator that delegates to another +// ClientNegotiator to select the appropriate Encoder or Decoder for a given media type. As a +// special case, it will resolve "application/cbor-seq" (a CBOR Sequence, the concatenation of zero +// or more CBOR data items) as an alias for "application/cbor" (exactly one CBOR data item) when +// selecting a stream decoder. +type clientNegotiatorWithCBORSequenceStreamDecoder struct { + negotiator runtime.ClientNegotiator +} + +func (n clientNegotiatorWithCBORSequenceStreamDecoder) Encoder(contentType string, params map[string]string) (runtime.Encoder, error) { + return n.negotiator.Encoder(contentType, params) +} + +func (n clientNegotiatorWithCBORSequenceStreamDecoder) Decoder(contentType string, params map[string]string) (runtime.Decoder, error) { + return n.negotiator.Decoder(contentType, params) +} + +func (n clientNegotiatorWithCBORSequenceStreamDecoder) StreamDecoder(contentType string, params map[string]string) (runtime.Decoder, runtime.Serializer, runtime.Framer, error) { + if !clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsAllowCBOR) { + return n.negotiator.StreamDecoder(contentType, params) + } + + switch contentType { + case runtime.ContentTypeCBORSequence: + return n.negotiator.StreamDecoder(runtime.ContentTypeCBOR, params) + case runtime.ContentTypeCBOR: + // This media type is only appropriate for exactly one data item, not the zero or + // more events of a watch stream. + return nil, nil, nil, runtime.NegotiateError{ContentType: contentType, Stream: true} + default: + return n.negotiator.StreamDecoder(contentType, params) + } + +}