Update ContentNegotiationManager for unknown path exts
This change refines the logic of "mapping" content negotiation strategies with regards to how to handle cases where no mapping is found. The request parameter strategy now treats request parameter values that do not match any mapped media type as 406 errors. The path extension strategy provides a new flag called "ignoreUnknownExtensions" (true by default) that when set to false also results in a 406. The same flag is also exposed through the ContentNegotiationManagerFactoryBean and the MVC Java config. Issue: SPR-10170
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -26,6 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
@@ -41,6 +42,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
|
||||
private MockHttpServletRequest servletRequest;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.servletRequest = new MockHttpServletRequest();
|
||||
@@ -50,6 +52,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
this.factoryBean.setServletContext(this.servletRequest.getServletContext());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void defaultSettings() throws Exception {
|
||||
this.factoryBean.afterPropertiesSet();
|
||||
@@ -60,11 +63,16 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
assertEquals("Should be able to resolve file extensions by default",
|
||||
Arrays.asList(MediaType.IMAGE_GIF), manager.resolveMediaTypes(this.webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/flower?format=gif");
|
||||
this.servletRequest.addParameter("format", "gif");
|
||||
this.servletRequest.setRequestURI("/flower.xyz");
|
||||
|
||||
assertEquals("Should ignore unknown extensions by default",
|
||||
Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.setParameter("format", "gif");
|
||||
|
||||
assertEquals("Should not resolve request parameters by default",
|
||||
Collections.emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.addHeader("Accept", MediaType.IMAGE_GIF_VALUE);
|
||||
@@ -75,7 +83,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
public void addMediaTypes() throws Exception {
|
||||
Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
|
||||
Map<String, MediaType> mediaTypes = new HashMap<>();
|
||||
mediaTypes.put("json", MediaType.APPLICATION_JSON);
|
||||
this.factoryBean.addMediaTypes(mediaTypes);
|
||||
|
||||
@@ -86,11 +94,26 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest));
|
||||
}
|
||||
|
||||
// SPR-10170
|
||||
|
||||
@Test(expected = HttpMediaTypeNotAcceptableException.class)
|
||||
public void favorPathExtensionWithUnknownMediaType() throws Exception {
|
||||
this.factoryBean.setFavorPathExtension(true);
|
||||
this.factoryBean.setIgnoreUnknownPathExtensions(false);
|
||||
this.factoryBean.afterPropertiesSet();
|
||||
ContentNegotiationManager manager = this.factoryBean.getObject();
|
||||
|
||||
this.servletRequest.setRequestURI("/flower.xyz");
|
||||
this.servletRequest.addParameter("format", "json");
|
||||
|
||||
manager.resolveMediaTypes(this.webRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void favorParameter() throws Exception {
|
||||
this.factoryBean.setFavorParameter(true);
|
||||
|
||||
Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
|
||||
Map<String, MediaType> mediaTypes = new HashMap<>();
|
||||
mediaTypes.put("json", MediaType.APPLICATION_JSON);
|
||||
this.factoryBean.addMediaTypes(mediaTypes);
|
||||
|
||||
@@ -103,6 +126,20 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest));
|
||||
}
|
||||
|
||||
// SPR-10170
|
||||
|
||||
@Test(expected = HttpMediaTypeNotAcceptableException.class)
|
||||
public void favorParameterWithUnknownMediaType() throws HttpMediaTypeNotAcceptableException {
|
||||
this.factoryBean.setFavorParameter(true);
|
||||
this.factoryBean.afterPropertiesSet();
|
||||
ContentNegotiationManager manager = this.factoryBean.getObject();
|
||||
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.setParameter("format", "xyz");
|
||||
|
||||
manager.resolveMediaTypes(this.webRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreAcceptHeader() throws Exception {
|
||||
this.factoryBean.setIgnoreAcceptHeader(true);
|
||||
@@ -112,7 +149,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.addHeader("Accept", MediaType.IMAGE_GIF_VALUE);
|
||||
|
||||
assertEquals(Collections.emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
assertEquals(Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
public class MappingContentNegotiationStrategyTests {
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypes() {
|
||||
public void resolveMediaTypes() throws Exception {
|
||||
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("json", mapping);
|
||||
|
||||
@@ -46,7 +46,7 @@ public class MappingContentNegotiationStrategyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesNoMatch() {
|
||||
public void resolveMediaTypesNoMatch() throws Exception {
|
||||
Map<String, MediaType> mapping = null;
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("blah", mapping);
|
||||
|
||||
@@ -56,7 +56,7 @@ public class MappingContentNegotiationStrategyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesNoKey() {
|
||||
public void resolveMediaTypesNoKey() throws Exception {
|
||||
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy(null, mapping);
|
||||
|
||||
@@ -66,7 +66,7 @@ public class MappingContentNegotiationStrategyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesHandleNoMatch() {
|
||||
public void resolveMediaTypesHandleNoMatch() throws Exception {
|
||||
Map<String, MediaType> mapping = null;
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("xml", mapping);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
@@ -28,6 +29,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
@@ -43,32 +45,37 @@ public class PathExtensionContentNegotiationStrategyTests {
|
||||
|
||||
private MockHttpServletRequest servletRequest;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.servletRequest = new MockHttpServletRequest();
|
||||
this.webRequest = new ServletWebRequest(servletRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesFromMapping() {
|
||||
this.servletRequest.setRequestURI("test.html");
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesFromMapping() throws Exception {
|
||||
|
||||
this.servletRequest.setRequestURI("test.html");
|
||||
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
|
||||
|
||||
assertEquals(Arrays.asList(new MediaType("text", "html")), mediaTypes);
|
||||
|
||||
strategy = new PathExtensionContentNegotiationStrategy(Collections.singletonMap("HTML", MediaType.APPLICATION_XHTML_XML));
|
||||
Map<String, MediaType> mapping = Collections.singletonMap("HTML", MediaType.APPLICATION_XHTML_XML);
|
||||
strategy = new PathExtensionContentNegotiationStrategy(mapping);
|
||||
mediaTypes = strategy.resolveMediaTypes(this.webRequest);
|
||||
|
||||
assertEquals(Arrays.asList(new MediaType("application", "xhtml+xml")), mediaTypes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesFromJaf() {
|
||||
this.servletRequest.setRequestURI("test.xls");
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
public void resolveMediaTypesFromJaf() throws Exception {
|
||||
|
||||
this.servletRequest.setRequestURI("test.xls");
|
||||
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
|
||||
|
||||
assertEquals(Arrays.asList(new MediaType("application", "vnd.ms-excel")), mediaTypes);
|
||||
@@ -77,45 +84,67 @@ public class PathExtensionContentNegotiationStrategyTests {
|
||||
// SPR-10334
|
||||
|
||||
@Test
|
||||
public void getMediaTypeFromFilenameNoJaf() {
|
||||
public void getMediaTypeFromFilenameNoJaf() throws Exception {
|
||||
|
||||
this.servletRequest.setRequestURI("test.json");
|
||||
|
||||
ServletContext servletContext = this.servletRequest.getServletContext();
|
||||
PathExtensionContentNegotiationStrategy strategy =
|
||||
new ServletPathExtensionContentNegotiationStrategy(servletContext);
|
||||
ServletContext servletCxt = this.servletRequest.getServletContext();
|
||||
PathExtensionContentNegotiationStrategy strategy = new ServletPathExtensionContentNegotiationStrategy(servletCxt);
|
||||
strategy.setUseJaf(false);
|
||||
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
|
||||
|
||||
assertEquals(Collections.emptyList(), mediaTypes);
|
||||
assertEquals(Collections.<MediaType>emptyList(), mediaTypes);
|
||||
}
|
||||
|
||||
// SPR-8678
|
||||
|
||||
@Test
|
||||
public void getMediaTypeFilenameWithContextPath() {
|
||||
this.servletRequest.setContextPath("/project-1.0.0.M3");
|
||||
this.servletRequest.setRequestURI("/project-1.0.0.M3/");
|
||||
public void getMediaTypeFilenameWithContextPath() throws Exception {
|
||||
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
|
||||
this.servletRequest.setContextPath("/project-1.0.0.M3");
|
||||
this.servletRequest.setRequestURI("/project-1.0.0.M3/");
|
||||
assertTrue("Context path should be excluded", strategy.resolveMediaTypes(webRequest).isEmpty());
|
||||
|
||||
this.servletRequest.setRequestURI("/project-1.0.0.M3");
|
||||
|
||||
assertTrue("Context path should be excluded", strategy.resolveMediaTypes(webRequest).isEmpty());
|
||||
}
|
||||
|
||||
// SPR-9390
|
||||
|
||||
@Test
|
||||
public void getMediaTypeFilenameWithEncodedURI() {
|
||||
this.servletRequest.setRequestURI("/quo%20vadis%3f.html");
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
public void getMediaTypeFilenameWithEncodedURI() throws Exception {
|
||||
|
||||
this.servletRequest.setRequestURI("/quo%20vadis%3f.html");
|
||||
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
List<MediaType> result = strategy.resolveMediaTypes(webRequest);
|
||||
|
||||
assertEquals("Invalid content type", Collections.singletonList(new MediaType("text", "html")), result);
|
||||
}
|
||||
|
||||
// SPR-10170
|
||||
|
||||
@Test
|
||||
public void resolveMediaTypesIgnoreUnknownExtension() throws Exception {
|
||||
|
||||
this.servletRequest.setRequestURI("test.xyz");
|
||||
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
|
||||
|
||||
assertEquals(Collections.<MediaType>emptyList(), mediaTypes);
|
||||
}
|
||||
|
||||
@Test(expected = HttpMediaTypeNotAcceptableException.class)
|
||||
public void resolveMediaTypesDoNotIgnoreUnknownExtension() throws Exception {
|
||||
|
||||
this.servletRequest.setRequestURI("test.xyz");
|
||||
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
strategy.setIgnoreUnknownExtensions(false);
|
||||
strategy.resolveMediaTypes(this.webRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user