Description
Melissa Hartsock opened SPR-13747 and commented
The URL content negotiation "format" parameter values are case sensitive and only lowercase values are accepted. URL query parameter format=json returns the appropriate json response but format=JSON results in a HttpMediaTypeNotAcceptableException and returns:
406 - The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
The same happens with xml vs XML or any other format value that is not lowercase.
The value of the format parameter should be case insensitive especially because the type and subtype of MediaType parameters should always be case-insensitive.
Cause:
Configuration:
ContentNegotiationConfigurer is configured with favorParameter = true and the following media type mappings are provided:
mediaType("json", MediaType.APPLICATION_JSON)
mediaType("xml", MediaType.APPLICATION_XML)
or
mediaType("JSON", MediaType.APPLICATION_JSON)
mediaType("XML", MediaType.APPLICATION_XML)
Result:
When the MappingMediaTypeFileExtensionResolver is constructed, it is passed a map containing the media type key to MediaType mappings defined above. In the constructor of MappingMediaTypeFileExtensionResolver, the key is converted to lowercase and the mapping of key to MediaType is added to the ConcurrentMap<String, MediaType> mediaTypes using the lowercase version of the key.
However, when retrieving the MediaType from a key in the lookupMediaType method, no conversion to lowercase is performed so any value for the URL "format" parameter other than the lowercase version will not return the proper MediaType result.
On May 1st, 2014, a change was made to ParameterContentNegotiationStrategy to handle cases where the content negotiation format URL parameter does not result in a match for a MediaType. If no match is found, a HttpMediaTypeNotAcceptableException is thrown resulting in the 406 response above. Prior to this commit, a null was returned instead of throwing an exception so this issue was hidden and appeared to function correctly.
Setting ignoreUnknownPathExtensions = true on the ContentNegotiationConfigurer will result in the same handling as prior to the May 1st, 2014 commit but it does not solve the real issue.
Solution:
Simply add a line to the lookupMediaType method to first convert the extension (media type key) to lowercase prior to attempting to retrieve it from the media type map:
protected MediaType lookupMediaType(String extension) {
extension = extension.toLowerCase(Locale.ENGLISH);
return this.mediaTypes.get(extension);
}
Affects: 4.1.8, 4.2.1, 4.2.2, 4.2.3
Backported to: 4.1.9