diff --git a/pkg/util/webhook/webhook.go b/pkg/util/webhook/webhook.go index b03640ae8..8552e91eb 100644 --- a/pkg/util/webhook/webhook.go +++ b/pkg/util/webhook/webhook.go @@ -83,6 +83,7 @@ func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFact clientConfig := rest.CopyConfig(config) codec := codecFactory.LegacyCodec(groupVersions...) + clientConfig.ContentType = runtime.ContentTypeJSON clientConfig.ContentConfig.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec}) clientConfig.Wrap(x509metrics.NewDeprecatedCertificateRoundTripperWrapperConstructor( diff --git a/pkg/util/webhook/webhook_test.go b/pkg/util/webhook/webhook_test.go index 068c6821e..dba0e3ed6 100644 --- a/pkg/util/webhook/webhook_test.go +++ b/pkg/util/webhook/webhook_test.go @@ -23,6 +23,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "net" "net/http" "net/http/httptest" @@ -33,11 +34,15 @@ import ( "strings" "testing" "time" + "unicode/utf8" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/wait" + exampleinstall "k8s.io/apiserver/pkg/apis/example/install" + examplev1 "k8s.io/apiserver/pkg/apis/example/v1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" v1 "k8s.io/client-go/tools/clientcmd/api/v1" @@ -927,3 +932,57 @@ func getSingleCounterValueFromRegistry(t *testing.T, r metrics.Gatherer, name st return -1 } + +func TestRESTConfigContentType(t *testing.T) { + server, err := newTestServer(clientCert, clientKey, caCert, func(w http.ResponseWriter, r *http.Request) { + if got := r.Header.Get("Content-Type"); got != runtime.ContentTypeJSON { + t.Errorf("expected request content-type: want %q got %q", runtime.ContentTypeJSON, got) + } + body, err := io.ReadAll(r.Body) + if err != nil { + t.Errorf("failed to read request body: %v", err) + return + } + if err := json.Unmarshal(body, new(any)); err != nil { + switch { + case len(body) == 0: + t.Log("empty request body") + case utf8.Valid(body): + t.Logf("request body: %s", string(body)) + default: + t.Logf("request body: 0x%x", body) + } + t.Errorf("failed to unmarshal request body as json: %v", err) + } + }) + if err != nil { + t.Errorf("failed to create server: %v", err) + return + } + defer server.Close() + + config := &rest.Config{ + ContentConfig: rest.ContentConfig{ + ContentType: "foo/bar", + }, + Host: server.URL, + TLSClientConfig: rest.TLSClientConfig{ + CAData: caCert, + CertData: clientCert, + KeyData: clientKey, + }, + } + + scheme := runtime.NewScheme() + exampleinstall.Install(scheme) + codecs := serializer.NewCodecFactory(scheme) + groupVersions := []schema.GroupVersion{examplev1.SchemeGroupVersion} + wh, err := NewGenericWebhook(scheme, codecs, config, groupVersions, retryBackoff) + if err != nil { + t.Fatalf("failed to create the webhook: %v", err) + } + + if err := wh.RestClient.Post().Body(&examplev1.Pod{}).Do(context.TODO()).Error(); err != nil { + t.Fatalf("failed to complete request: %v", err) + } +}