diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go index 8f8a50fe3e7..7f4225a5b93 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go @@ -273,6 +273,13 @@ func acceptMediaTypeOptions(params map[string]string, accepts *AcceptedMediaType return options, true } +type candidateMediaType struct { + accepted *AcceptedMediaType + clauses goautoneg.Accept +} + +type candidateMediaTypeSlice []candidateMediaType + // NegotiateMediaTypeOptions returns the most appropriate content type given the accept header and // a list of alternatives along with the accepted media type parameters. func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endpoint EndpointRestrictions) (MediaTypeOptions, bool) { @@ -282,6 +289,7 @@ func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endp }, true } + var candidates candidateMediaTypeSlice clauses := goautoneg.ParseAccept(header) for _, clause := range clauses { for i := range accepted { @@ -290,12 +298,17 @@ func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endp case clause.Type == accepts.Type && clause.SubType == accepts.SubType, clause.Type == accepts.Type && clause.SubType == "*", clause.Type == "*" && clause.SubType == "*": - // TODO: should we prefer the first type with no unrecognized options? Do we need to ignore unrecognized - // parameters. - return acceptMediaTypeOptions(clause.Params, accepts, endpoint) + candidates = append(candidates, candidateMediaType{accepted: accepts, clauses: clause}) } } } + + for _, v := range candidates { + if retVal, ret := acceptMediaTypeOptions(v.clauses.Params, v.accepted, endpoint); ret { + return retVal, true + } + } + return MediaTypeOptions{}, false } diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go index 8a747ff73dc..1d11d0a3048 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go @@ -181,7 +181,26 @@ func TestNegotiate(t *testing.T) { serializer: fakeCodec, params: map[string]string{"pretty": "1"}, }, - + { + req: &http.Request{ + Header: http.Header{ + "Accept": []string{"application/json;as=BOGUS;v=v1alpha1;g=meta.k8s.io, application/json"}, + }, + }, + contentType: "application/json", + ns: &fakeNegotiater{serializer: fakeCodec, types: []string{"application/json"}}, + serializer: fakeCodec, + }, + { + req: &http.Request{ + Header: http.Header{ + "Accept": []string{"application/BOGUS, application/json"}, + }, + }, + contentType: "application/json", + ns: &fakeNegotiater{serializer: fakeCodec, types: []string{"application/json"}}, + serializer: fakeCodec, + }, // "application" is not a valid media type, so the server will reject the response during // negotiation (the server, in error, has specified an invalid media type) {