Fix Content negotiation incorrect when Accept header uses type parameters

pull/6/head
Shiyang Wang 2017-08-14 16:24:30 +08:00
parent 2c9ffc0e88
commit 66c2ec32f2
2 changed files with 36 additions and 4 deletions

View File

@ -273,6 +273,13 @@ func acceptMediaTypeOptions(params map[string]string, accepts *AcceptedMediaType
return options, true 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 // NegotiateMediaTypeOptions returns the most appropriate content type given the accept header and
// a list of alternatives along with the accepted media type parameters. // a list of alternatives along with the accepted media type parameters.
func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endpoint EndpointRestrictions) (MediaTypeOptions, bool) { func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endpoint EndpointRestrictions) (MediaTypeOptions, bool) {
@ -282,6 +289,7 @@ func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endp
}, true }, true
} }
var candidates candidateMediaTypeSlice
clauses := goautoneg.ParseAccept(header) clauses := goautoneg.ParseAccept(header)
for _, clause := range clauses { for _, clause := range clauses {
for i := range accepted { for i := range accepted {
@ -290,12 +298,17 @@ func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endp
case clause.Type == accepts.Type && clause.SubType == accepts.SubType, case clause.Type == accepts.Type && clause.SubType == accepts.SubType,
clause.Type == accepts.Type && clause.SubType == "*", clause.Type == accepts.Type && clause.SubType == "*",
clause.Type == "*" && clause.SubType == "*": clause.Type == "*" && clause.SubType == "*":
// TODO: should we prefer the first type with no unrecognized options? Do we need to ignore unrecognized candidates = append(candidates, candidateMediaType{accepted: accepts, clauses: clause})
// parameters.
return acceptMediaTypeOptions(clause.Params, accepts, endpoint)
} }
} }
} }
for _, v := range candidates {
if retVal, ret := acceptMediaTypeOptions(v.clauses.Params, v.accepted, endpoint); ret {
return retVal, true
}
}
return MediaTypeOptions{}, false return MediaTypeOptions{}, false
} }

View File

@ -181,7 +181,26 @@ func TestNegotiate(t *testing.T) {
serializer: fakeCodec, serializer: fakeCodec,
params: map[string]string{"pretty": "1"}, 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 // "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) // negotiation (the server, in error, has specified an invalid media type)
{ {