From b077b4dddb25370053e3d517f7683dce73e42aa9 Mon Sep 17 00:00:00 2001 From: mhartsock Melissa Hartsock Date: Tue, 1 Dec 2015 12:36:50 -0500 Subject: [PATCH] Fix media type lookup case sensitivity Fixed a bug where the URL content negotiation "format" parameter values were case sensitive and only lowercase values were accepted. For example, URL query parameter format=json returned the appropriate JSON response but format=JSON resulted in a HttpMediaTypeNotAcceptableException and returned: 406 - The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers. When the MappingMediaTypeFileExtensionResolver is constructed, it is passed a map containing the media type key to MediaType mappings defined in the ContentNegotiationConfigurer. In the constructor of MappingMediaTypeFileExtensionResolver, the keys are converted to lowercase and the mappings of keys to MediaTypes are added to the ConcurrentMap mediaTypes using the lowercase version of the keys. 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. To make the media type lookup case insensitive, added a line to the lookupMediaType method in MediaTypeFileExtensionResolver to first convert the extension (media type key) to lowercase prior to attempting to retrieve it from the mediaTypes map. Issue: SPR-13747 --- .../MappingMediaTypeFileExtensionResolver.java | 1 + ...ppingMediaTypeFileExtensionResolverTests.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolver.java b/spring-web/src/main/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolver.java index 59125b5ea0..e223451d50 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolver.java +++ b/spring-web/src/main/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolver.java @@ -99,6 +99,7 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten * @return a MediaType for the key or {@code null} */ protected MediaType lookupMediaType(String extension) { + extension = extension.toLowerCase(Locale.ENGLISH); return this.mediaTypes.get(extension); } diff --git a/spring-web/src/test/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolverTests.java b/spring-web/src/test/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolverTests.java index 4ea3772843..a46c06a288 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,4 +51,18 @@ public class MappingMediaTypeFileExtensionResolverTests { assertTrue(extensions.isEmpty()); } + /** + * Unit test for SPR-13747 - ensures that reverse lookup of media type from media + * type key is case-insensitive. + * + * @author Melissa Hartsock + */ + @Test + public void lookupMediaTypeCaseInsensitive() { + Map mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON); + MappingMediaTypeFileExtensionResolver resolver = new MappingMediaTypeFileExtensionResolver(mapping); + MediaType mediaType = resolver.lookupMediaType("JSON"); + + assertEquals(mediaType, MediaType.APPLICATION_JSON); + } }