From c957b595183e56c8b2921be6bdc66949ff6dd779 Mon Sep 17 00:00:00 2001
From: Ben Luddy <bluddy@redhat.com>
Date: Fri, 25 Oct 2024 11:50:01 -0400
Subject: [PATCH] Wire client feature gates affecting RESTClient content
 config.

Kubernetes-commit: 67b9dc1f3e23529804345deea76d36d07dff59b1
---
 rest/client.go  | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 rest/request.go |  3 +++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/rest/client.go b/rest/client.go
index c864d1ec7..b98d02764 100644
--- a/rest/client.go
+++ b/rest/client.go
@@ -17,6 +17,8 @@ limitations under the License.
 package rest
 
 import (
+	"fmt"
+	"mime"
 	"net/http"
 	"net/url"
 	"os"
@@ -24,9 +26,11 @@ import (
 	"strings"
 	"time"
 
+	"github.com/munnerz/goautoneg"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/types"
+	clientfeatures "k8s.io/client-go/features"
 	"k8s.io/client-go/util/flowcontrol"
 )
 
@@ -115,7 +119,7 @@ func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientConte
 	return &RESTClient{
 		base:             &base,
 		versionedAPIPath: versionedAPIPath,
-		content:          config,
+		content:          scrubCBORContentConfigIfDisabled(config),
 		createBackoffMgr: readExpBackoffConfig,
 		rateLimiter:      rateLimiter,
 
@@ -123,6 +127,45 @@ func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientConte
 	}, nil
 }
 
+func scrubCBORContentConfigIfDisabled(content ClientContentConfig) ClientContentConfig {
+	if clientfeatures.TestOnlyFeatureGates.Enabled(clientfeatures.TestOnlyClientAllowsCBOR) {
+		return content
+	}
+
+	if mediatype, _, err := mime.ParseMediaType(content.ContentType); err == nil && mediatype == "application/cbor" {
+		content.ContentType = "application/json"
+	}
+
+	clauses := goautoneg.ParseAccept(content.AcceptContentTypes)
+	scrubbed := false
+	for i, clause := range clauses {
+		if clause.Type == "application" && clause.SubType == "cbor" {
+			scrubbed = true
+			clauses[i].SubType = "json"
+		}
+	}
+	if !scrubbed {
+		// No application/cbor in AcceptContentTypes, nothing more to do.
+		return content
+	}
+
+	parts := make([]string, 0, len(clauses))
+	for _, clause := range clauses {
+		// ParseAccept does not store the parameter "q" in Params.
+		params := clause.Params
+		if clause.Q < 1 { // omit q=1, it's the default
+			if params == nil {
+				params = make(map[string]string, 1)
+			}
+			params["q"] = strconv.FormatFloat(clause.Q, 'g', 3, 32)
+		}
+		parts = append(parts, mime.FormatMediaType(fmt.Sprintf("%s/%s", clause.Type, clause.SubType), params))
+	}
+	content.AcceptContentTypes = strings.Join(parts, ",")
+
+	return content
+}
+
 // GetRateLimiter returns rate limiter for a given client, or nil if it's called on a nil client
 func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
 	if c == nil {
diff --git a/rest/request.go b/rest/request.go
index 2f325ecd6..765b897d8 100644
--- a/rest/request.go
+++ b/rest/request.go
@@ -160,6 +160,9 @@ func NewRequest(c *RESTClient) *Request {
 	contentTypeNotSet := len(contentConfig.ContentType) == 0
 	if contentTypeNotSet {
 		contentConfig.ContentType = "application/json"
+		if clientfeatures.TestOnlyFeatureGates.Enabled(clientfeatures.TestOnlyClientAllowsCBOR) && clientfeatures.TestOnlyFeatureGates.Enabled(clientfeatures.TestOnlyClientPrefersCBOR) {
+			contentConfig.ContentType = "application/cbor"
+		}
 	}
 
 	r := &Request{