diff --git a/spring-web/src/main/java/org/springframework/web/accept/AbstractMappingContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/AbstractMappingContentNegotiationStrategy.java index a85e4b19b67..1133b060f58 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/AbstractMappingContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/AbstractMappingContentNegotiationStrategy.java @@ -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. @@ -22,6 +22,7 @@ import java.util.Map; import org.springframework.http.MediaType; import org.springframework.util.StringUtils; +import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; /** @@ -34,6 +35,7 @@ import org.springframework.web.context.request.NativeWebRequest; public abstract class AbstractMappingContentNegotiationStrategy extends MappingMediaTypeFileExtensionResolver implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver { + /** * Create an instance with the given extension-to-MediaType lookup. * @throws IllegalArgumentException if a media type string cannot be parsed @@ -42,8 +44,9 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM super(mediaTypes); } + @Override - public List resolveMediaTypes(NativeWebRequest webRequest) { + public List resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException { String key = getMediaTypeKey(webRequest); if (StringUtils.hasText(key)) { MediaType mediaType = lookupMediaType(key); @@ -76,7 +79,7 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM * Invoked when no matching media type is found in the lookup map. * Sub-classes can take further steps to determine the media type. */ - protected MediaType handleNoMatch(NativeWebRequest request, String mappingKey) { + protected MediaType handleNoMatch(NativeWebRequest request, String key) throws HttpMediaTypeNotAcceptableException { return null; } diff --git a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java index 23fc2c40178..689f55ae8c9 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 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. @@ -55,6 +55,8 @@ public class ContentNegotiationManagerFactoryBean private Map mediaTypes = new HashMap(); + private boolean ignoreUnknownPathExtensions = true; + private Boolean useJaf; private String parameterName = "format"; @@ -116,6 +118,17 @@ public class ContentNegotiationManagerFactoryBean } } + /** + * Whether to ignore requests that have a file extension that does not match + * any mapped media types. Setting this to {@code false} will result in a + * {@code HttpMediaTypeNotAcceptableException} when there is no match. + * + *

By default this is set to {@code true}. + */ + public void setIgnoreUnknownPathExtensions(boolean ignoreUnknownPathExtensions) { + this.ignoreUnknownPathExtensions = ignoreUnknownPathExtensions; + } + /** * Indicate whether to use the Java Activation Framework as a fallback option * to map from file extensions to media types. This is used only when @@ -191,6 +204,7 @@ public class ContentNegotiationManagerFactoryBean } else { strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes); } + strategy.setIgnoreUnknownExtensions(this.ignoreUnknownPathExtensions); if (this.useJaf != null) { strategy.setUseJaf(this.useJaf); } 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 71e670d0fd6..3fee1520815 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 @@ -16,6 +16,7 @@ package org.springframework.web.accept; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -59,6 +60,7 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten } } + /** * Find the file extensions mapped to the given MediaType. * @return 0 or more extensions, never {@code null} @@ -74,6 +76,10 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten return Collections.unmodifiableList(this.allFileExtensions); } + protected List getAllMediaTypes() { + return new ArrayList(this.mediaTypes.values()); + } + /** * Return the MediaType mapped to the given extension. * @return a MediaType for the key or {@code null} diff --git a/spring-web/src/main/java/org/springframework/web/accept/ParameterContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/ParameterContentNegotiationStrategy.java index c5fe9f1b4f7..4e95128bdbf 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ParameterContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ParameterContentNegotiationStrategy.java @@ -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. @@ -22,6 +22,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.http.MediaType; import org.springframework.util.Assert; +import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; /** @@ -68,4 +69,8 @@ public class ParameterContentNegotiationStrategy extends AbstractMappingContentN } } + @Override + protected MediaType handleNoMatch(NativeWebRequest request, String key) throws HttpMediaTypeNotAcceptableException { + throw new HttpMediaTypeNotAcceptableException(getAllMediaTypes()); + } } diff --git a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java index c3c24fe85b8..8324bcf3948 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java @@ -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. @@ -32,6 +32,7 @@ import org.springframework.core.io.Resource; import org.springframework.http.MediaType; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; +import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.WebUtils; @@ -65,6 +66,8 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont private boolean useJaf = JAF_PRESENT; + private boolean ignoreUnknownExtensions = true; + /** * Create an instance with the given extension-to-MediaType lookup. @@ -82,14 +85,30 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont super(null); } + /** - * Indicate whether to use the Java Activation Framework to map from file extensions to media types. - *

Default is {@code true}, i.e. the Java Activation Framework is used (if available). + * Indicate whether to use the Java Activation Framework to map from file + * extensions to media types. + * + *

Default is {@code true}, i.e. the Java Activation Framework is used + * (if available). */ public void setUseJaf(boolean useJaf) { this.useJaf = useJaf; } + /** + * Whether to ignore requests that have a file extension that does not match + * any mapped media types. Setting this to {@code false} will result in a + * {@code HttpMediaTypeNotAcceptableException}. + * + *

By default this is set to {@code true}. + */ + public void setIgnoreUnknownExtensions(boolean ignoreUnknownExtensions) { + this.ignoreUnknownExtensions = ignoreUnknownExtensions; + } + + @Override protected String getMediaTypeKey(NativeWebRequest webRequest) { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); @@ -108,13 +127,18 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont } @Override - protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) { + protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) + throws HttpMediaTypeNotAcceptableException { + if (this.useJaf) { MediaType jafMediaType = JafMediaTypeFactory.getMediaType("file." + extension); if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) { return jafMediaType; } } + if (!this.ignoreUnknownExtensions) { + throw new HttpMediaTypeNotAcceptableException(getAllMediaTypes()); + } return null; } diff --git a/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java index 4e8ad8a317a..86aa5ad75bd 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java @@ -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. @@ -22,6 +22,7 @@ import javax.servlet.ServletContext; import org.springframework.http.MediaType; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; /** @@ -64,7 +65,9 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio * and if that doesn't help, delegate to the parent implementation. */ @Override - protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) { + protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) + throws HttpMediaTypeNotAcceptableException { + MediaType mediaType = null; if (this.servletContext != null) { String mimeType = this.servletContext.getMimeType("file." + extension); diff --git a/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java b/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java index f7924b840ed..7a61577f00e 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java @@ -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.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.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 mediaTypes = new HashMap(); + Map 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 mediaTypes = new HashMap(); + Map 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.emptyList(), manager.resolveMediaTypes(this.webRequest)); } @Test diff --git a/spring-web/src/test/java/org/springframework/web/accept/MappingContentNegotiationStrategyTests.java b/spring-web/src/test/java/org/springframework/web/accept/MappingContentNegotiationStrategyTests.java index f4b9f25bc9d..f6a72363676 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/MappingContentNegotiationStrategyTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/MappingContentNegotiationStrategyTests.java @@ -35,7 +35,7 @@ import org.springframework.web.context.request.NativeWebRequest; public class MappingContentNegotiationStrategyTests { @Test - public void resolveMediaTypes() { + public void resolveMediaTypes() throws Exception { Map 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 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 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 mapping = null; TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("xml", mapping); 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 b00b7c5d0af..ad7680d251f 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-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. diff --git a/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java b/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java index b814c5926e3..effb8357d0b 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java @@ -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() { + public void resolveMediaTypesFromMapping() throws Exception { + this.servletRequest.setRequestURI("test.html"); - PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); + PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); List mediaTypes = strategy.resolveMediaTypes(this.webRequest); assertEquals(Arrays.asList(new MediaType("text", "html")), mediaTypes); - strategy = new PathExtensionContentNegotiationStrategy(Collections.singletonMap("HTML", MediaType.APPLICATION_XHTML_XML)); + Map 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() { + public void resolveMediaTypesFromJaf() throws Exception { + this.servletRequest.setRequestURI("test.xls"); - PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); + PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); List 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 mediaTypes = strategy.resolveMediaTypes(this.webRequest); - assertEquals(Collections.emptyList(), mediaTypes); + assertEquals(Collections.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() { + public void getMediaTypeFilenameWithEncodedURI() throws Exception { + this.servletRequest.setRequestURI("/quo%20vadis%3f.html"); - PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); + PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); List 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 mediaTypes = strategy.resolveMediaTypes(this.webRequest); + + assertEquals(Collections.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); + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java index 7073e7122a3..880681ea6e3 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java @@ -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. @@ -94,6 +94,18 @@ public class ContentNegotiationConfigurer { return this; } + /** + * Whether to ignore requests that have a file extension that does not match + * any mapped media types. Setting this to {@code false} will result in a + * {@code HttpMediaTypeNotAcceptableException} when there is no match. + * + *

By default this is set to {@code true}. + */ + public ContentNegotiationConfigurer ignoreUnknownPathExtensions(boolean ignore) { + this.factoryBean.setIgnoreUnknownPathExtensions(ignore); + return this; + } + /** * Indicate whether to use the Java Activation Framework as a fallback option * to map from file extensions to media types. This is used only when