Browse Source

Merge pull request #1356 from poutsma/SPR-14908

pull/1360/merge
Rossen Stoyanchev 9 years ago
parent
commit
1be2d8343d
  1. 46
      spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java
  2. 16
      spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java
  3. 13
      spring-test/src/test/java/org/springframework/test/web/servlet/samples/context/WebAppResourceTests.java
  4. 104
      spring-web/src/main/java/org/springframework/http/MediaTypeFactory.java
  5. 17
      spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java
  6. 31
      spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java
  7. 7
      spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java
  8. 29
      spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java
  9. 31
      spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java
  10. 8
      spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java
  11. 1855
      spring-web/src/main/resources/org/springframework/http/mime.types
  12. 35
      spring-web/src/test/java/org/springframework/http/MediaTypeFactoryTests.java
  13. 45
      spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java
  14. 22
      spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java
  15. 27
      spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java
  16. 30
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java
  17. 30
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java
  18. 20
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/CompositeContentTypeResolverBuilderTests.java
  19. 18
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolverTests.java
  20. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java
  21. 5
      spring-webflux/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java
  22. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
  23. 4
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java
  24. 20
      spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java
  25. 12
      spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
  26. 1
      spring-webmvc/src/test/resources/org/springframework/web/servlet/resource/test/foo.bar

46
spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java

@ -29,7 +29,6 @@ import java.util.LinkedHashMap; @@ -29,7 +29,6 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.activation.FileTypeMap;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
@ -47,9 +46,12 @@ import org.apache.commons.logging.LogFactory; @@ -47,9 +46,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;
/**
@ -136,6 +138,8 @@ public class MockServletContext implements ServletContext { @@ -136,6 +138,8 @@ public class MockServletContext implements ServletContext {
private String responseCharacterEncoding;
private final Map<String, MediaType> mimeTypes = new LinkedHashMap<>();
/**
* Create a new {@code MockServletContext}, using no base path and a
@ -256,29 +260,27 @@ public class MockServletContext implements ServletContext { @@ -256,29 +260,27 @@ public class MockServletContext implements ServletContext {
return this.effectiveMinorVersion;
}
/**
* This method uses the default
* {@link javax.activation.FileTypeMap#getDefaultFileTypeMap() FileTypeMap}
* from the Java Activation Framework to resolve MIME types.
* <p>The Java Activation Framework returns {@code "application/octet-stream"}
* if the MIME type is unknown (i.e., it never returns {@code null}). Thus, in
* order to honor the {@link ServletContext#getMimeType(String)} contract,
* this method returns {@code null} if the MIME type is
* {@code "application/octet-stream"}.
* <p>{@code MockServletContext} does not provide a direct mechanism for
* setting a custom MIME type; however, if the default {@code FileTypeMap}
* is an instance of {@code javax.activation.MimetypesFileTypeMap}, a custom
* MIME type named {@code text/enigma} can be registered for a custom
* {@code .puzzle} file extension in the following manner:
* <pre style="code">
* MimetypesFileTypeMap mimetypesFileTypeMap = (MimetypesFileTypeMap) FileTypeMap.getDefaultFileTypeMap();
* mimetypesFileTypeMap.addMimeTypes("text/enigma puzzle");
* </pre>
*/
@Override
public String getMimeType(String filePath) {
String mimeType = FileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
return ("application/octet-stream".equals(mimeType) ? null : mimeType);
String extension = StringUtils.getFilenameExtension(filePath);
MediaType result;
if (this.mimeTypes.containsKey(extension)) {
result = this.mimeTypes.get(extension);
}
else {
result = MediaTypeFactory.getMediaType(filePath);
}
return result != null ? result.toString() : null;
}
/**
* Adds a mime type mapping for use by {@link #getMimeType(String)}.
* @param fileExtension a file extension, such as {@code txt}, {@code gif}
* @param mimeType the mime type
*/
public void addMimeType(String fileExtension, MediaType mimeType) {
Assert.notNull(fileExtension, "'fileExtension' must not be null");
this.mimeTypes.put(fileExtension, mimeType);
}
@Override

16
spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java

@ -18,16 +18,19 @@ package org.springframework.mock.web; @@ -18,16 +18,19 @@ package org.springframework.mock.web;
import java.util.Map;
import java.util.Set;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletRegistration;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.springframework.http.MediaType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Juergen Hoeller
@ -87,10 +90,7 @@ public class MockServletContextTests { @@ -87,10 +90,7 @@ public class MockServletContextTests {
*/
@Test
public void getMimeTypeWithCustomConfiguredType() {
FileTypeMap defaultFileTypeMap = FileTypeMap.getDefaultFileTypeMap();
assertThat(defaultFileTypeMap, instanceOf(MimetypesFileTypeMap.class));
MimetypesFileTypeMap mimetypesFileTypeMap = (MimetypesFileTypeMap) defaultFileTypeMap;
mimetypesFileTypeMap.addMimeTypes("text/enigma enigma");
sc.addMimeType("enigma", new MediaType("text", "enigma"));
assertEquals("text/enigma", sc.getMimeType("filename.enigma"));
}

13
spring-test/src/test/java/org/springframework/test/web/servlet/samples/context/WebAppResourceTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2002-2017 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.
@ -30,9 +30,12 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; @@ -30,9 +30,12 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests dependent on access to resources under the web application root directory.
@ -70,7 +73,7 @@ public class WebAppResourceTests { @@ -70,7 +73,7 @@ public class WebAppResourceTests {
@Test
public void resourceRequest() throws Exception {
this.mockMvc.perform(get("/resources/Spring.js"))
.andExpect(content().contentType("text/javascript"))
.andExpect(content().contentType("application/javascript"))
.andExpect(content().string(containsString("Spring={};")));
}

104
spring-web/src/main/java/org/springframework/http/MediaTypeFactory.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -16,62 +16,88 @@ @@ -16,62 +16,88 @@
package org.springframework.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
/**
* A factory delegate for resolving {@link MediaType} objects
* from {@link Resource} handles or filenames.
*
* <p>This implementation is based on the Java Activation Framework,
* sharing the MIME type definitions with Spring's JavaMail support.
* However, JAF is an implementation detail and not leaking out.
*
* @author Juergen Hoeller
* @author Arjen Poutsma
* @since 5.0
*/
public class MediaTypeFactory {
private static final FileTypeMap fileTypeMap;
private static final String MIME_TYPES_FILE_NAME = "/org/springframework/http/mime.types";
private static final MultiValueMap<String, MediaType> fileExtensionToMediaTypes;
static {
fileTypeMap = loadFileTypeMapFromContextSupportModule();
fileExtensionToMediaTypes = parseMimeTypes();
}
/**
* Parse the {@code mime.types} file found in the resources. Format is:
* <code>
* # comments begin with a '#'<br>
* # the format is &lt;mime type> &lt;space separated file extensions><br>
* # for example:<br>
* text/plain txt text<br>
* # this would map file.txt and file.text to<br>
* # the mime type "text/plain"<br>
* </code>
* @return a multi-value map, mapping media types to file extensions.
*/
private static MultiValueMap<String, MediaType> parseMimeTypes() {
InputStream is = null;
try {
is = MediaTypeFactory.class.getResourceAsStream(MIME_TYPES_FILE_NAME);
BufferedReader reader =
new BufferedReader(new InputStreamReader(is, StandardCharsets.US_ASCII));
private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
// See if we can find the extended mime.types from the context-support module...
Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");
if (mappingLocation.exists()) {
InputStream inputStream = null;
try {
inputStream = mappingLocation.getInputStream();
return new MimetypesFileTypeMap(inputStream);
}
catch (IOException ex) {
// ignore
MultiValueMap<String, MediaType> result = new LinkedMultiValueMap<>();
String line;
while ((line = reader.readLine()) != null) {
if (line.isEmpty() || line.charAt(0) == '#') {
continue;
}
String[] tokens = StringUtils.tokenizeToStringArray(line, " \t\n\r\f");
MediaType mediaType = MediaType.parseMediaType(tokens[0]);
for (int i = 1; i < tokens.length; i++) {
String fileExtension = tokens[i].toLowerCase(Locale.ENGLISH);
result.add(fileExtension, mediaType);
}
}
finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException ex) {
// ignore
}
return result;
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + MIME_TYPES_FILE_NAME + "'", ex);
}
finally {
if (is != null) {
try {
is.close();
}
catch (IOException ignore) {
}
}
}
return FileTypeMap.getDefaultFileTypeMap();
}
/**
* Determine a media type for the given resource, if possible.
* @param resource the resource to introspect
@ -88,8 +114,20 @@ public class MediaTypeFactory { @@ -88,8 +114,20 @@ public class MediaTypeFactory {
* @return the corresponding media type, or {@code null} if none found
*/
public static MediaType getMediaType(String filename) {
String mediaType = fileTypeMap.getContentType(filename);
return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);
List<MediaType> mediaTypes = getMediaTypes(filename);
return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null);
}
/**
* Determine the media types for the given file name, if possible.
* @param filename the file name plus extension
* @return the corresponding media types, or an empty list if none found
*/
public static List<MediaType> getMediaTypes(String filename) {
return Optional.ofNullable(StringUtils.getFilenameExtension(filename))
.map(s -> s.toLowerCase(Locale.ENGLISH))
.map(fileExtensionToMediaTypes::get)
.orElse(Collections.emptyList());
}
}

17
spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java

@ -27,16 +27,14 @@ import org.springframework.http.HttpInputMessage; @@ -27,16 +27,14 @@ import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StreamUtils;
/**
* Implementation of {@link HttpMessageConverter} that can read/write {@link Resource Resources}
* and supports byte range requests.
*
* <p>By default, this converter can read all media types. The Java Activation Framework (JAF) -
* if available - is used to determine the {@code Content-Type} of written resources.
* If JAF is not available, {@code application/octet-stream} is used.
* <p>By default, this converter can read all media types. The {@link MediaTypeFactory} is used
* to determine the {@code Content-Type} of written resources.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
@ -45,9 +43,6 @@ import org.springframework.util.StreamUtils; @@ -45,9 +43,6 @@ import org.springframework.util.StreamUtils;
*/
public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<Resource> {
private static final boolean jafPresent = ClassUtils.isPresent(
"javax.activation.FileTypeMap", ResourceHttpMessageConverter.class.getClassLoader());
private final boolean supportsReadStreaming;
@ -107,12 +102,8 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R @@ -107,12 +102,8 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
@Override
protected MediaType getDefaultContentType(Resource resource) {
if (jafPresent) {
return MediaTypeFactory.getMediaType(resource);
}
else {
return MediaType.APPLICATION_OCTET_STREAM;
}
MediaType mediaType = MediaTypeFactory.getMediaType(resource);
return mediaType != null ? mediaType : MediaType.APPLICATION_OCTET_STREAM;
}
@Override

31
spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java

@ -24,6 +24,7 @@ import java.lang.reflect.Type; @@ -24,6 +24,7 @@ import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourceRegion;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
@ -31,7 +32,6 @@ import org.springframework.http.HttpOutputMessage; @@ -31,7 +32,6 @@ import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StreamUtils;
@ -44,9 +44,6 @@ import org.springframework.util.StreamUtils; @@ -44,9 +44,6 @@ import org.springframework.util.StreamUtils;
*/
public class ResourceRegionHttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
private static final boolean jafPresent = ClassUtils.isPresent(
"javax.activation.FileTypeMap", ResourceHttpMessageConverter.class.getClassLoader());
public ResourceRegionHttpMessageConverter() {
super(MediaType.ALL);
}
@ -80,18 +77,24 @@ public class ResourceRegionHttpMessageConverter extends AbstractGenericHttpMessa @@ -80,18 +77,24 @@ public class ResourceRegionHttpMessageConverter extends AbstractGenericHttpMessa
@Override
@SuppressWarnings("unchecked")
protected MediaType getDefaultContentType(Object object) {
if (jafPresent) {
if(object instanceof ResourceRegion) {
return MediaTypeFactory.getMediaType(((ResourceRegion) object).getResource());
}
else {
Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
if(regions.size() > 0) {
return MediaTypeFactory.getMediaType(regions.iterator().next().getResource());
}
Resource resource = null;
if (object instanceof ResourceRegion) {
resource = ((ResourceRegion) object).getResource();
}
else {
Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
if (regions.size() > 0) {
resource = regions.iterator().next().getResource();
}
}
return MediaType.APPLICATION_OCTET_STREAM;
MediaType result = null;
if (resource != null) {
result = MediaTypeFactory.getMediaType(resource);
}
if (result == null) {
return MediaType.APPLICATION_OCTET_STREAM;
}
return result;
}
@Override

7
spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java

@ -143,10 +143,9 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me @@ -143,10 +143,9 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
* <p>At startup this method returns extensions explicitly registered with
* either {@link PathExtensionContentNegotiationStrategy} or
* {@link ParameterContentNegotiationStrategy}. At runtime if there is a
* "path extension" strategy and its
* {@link PathExtensionContentNegotiationStrategy#setUseJaf(boolean)
* useJaf} property is set to "true", the list of extensions may
* increase as file extensions are resolved via JAF and cached.
* "path extension" strategy, the list of extensions may
* increase as file extensions are resolved via
* {@link org.springframework.http.MediaTypeFactory} and cached.
*/
@Override
public List<String> getAllFileExtensions() {

29
spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -28,6 +28,7 @@ import javax.servlet.ServletContext; @@ -28,6 +28,7 @@ import javax.servlet.ServletContext;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.ServletContextAware;
@ -81,8 +82,7 @@ import org.springframework.web.context.ServletContextAware; @@ -81,8 +82,7 @@ import org.springframework.web.context.ServletContextAware;
* "application/json".
*
* <p>The path extension strategy will also use {@link ServletContext#getMimeType}
* and the Java Activation framework (JAF), if available, to resolve a path
* extension to a MediaType. You may {@link #setUseJaf suppress} the use of JAF.
* and {@link MediaTypeFactory} to resolve a path extension to a MediaType.
*
* @author Rossen Stoyanchev
* @since 3.2
@ -100,8 +100,6 @@ public class ContentNegotiationManagerFactoryBean @@ -100,8 +100,6 @@ public class ContentNegotiationManagerFactoryBean
private boolean ignoreUnknownPathExtensions = true;
private Boolean useJaf;
private String parameterName = "format";
private ContentNegotiationStrategy defaultNegotiationStrategy;
@ -130,8 +128,8 @@ public class ContentNegotiationManagerFactoryBean @@ -130,8 +128,8 @@ public class ContentNegotiationManagerFactoryBean
* (see Spring Framework reference documentation for more details on RFD
* attack protection).
* <p>The path extension strategy will also try to use
* {@link ServletContext#getMimeType} and JAF (if present) to resolve path
* extensions. To change this behavior see the {@link #useJaf} property.
* {@link ServletContext#getMimeType} and
* {@link org.springframework.http.MediaTypeFactory} to resolve path extensions.
* @param mediaTypes media type mappings
* @see #addMediaType(String, MediaType)
* @see #addMediaTypes(Map)
@ -177,18 +175,10 @@ public class ContentNegotiationManagerFactoryBean @@ -177,18 +175,10 @@ public class ContentNegotiationManagerFactoryBean
}
/**
* When {@link #setFavorPathExtension favorPathExtension} is set, this
* property determines whether to allow use of JAF (Java Activation Framework)
* to resolve a path extension to a specific MediaType.
* <p>By default this is not set in which case
* {@code PathExtensionContentNegotiationStrategy} will use JAF if available.
* @deprecated as 5.0, in favor of {@link MediaTypeFactory}, which has no JAF dependency.
*/
@Deprecated
public void setUseJaf(boolean useJaf) {
this.useJaf = useJaf;
}
private boolean isUseJafTurnedOff() {
return (this.useJaf != null && !this.useJaf);
}
/**
@ -254,7 +244,7 @@ public class ContentNegotiationManagerFactoryBean @@ -254,7 +244,7 @@ public class ContentNegotiationManagerFactoryBean
if (this.favorPathExtension) {
PathExtensionContentNegotiationStrategy strategy;
if (this.servletContext != null && !isUseJafTurnedOff()) {
if (this.servletContext != null) {
strategy = new ServletPathExtensionContentNegotiationStrategy(
this.servletContext, this.mediaTypes);
}
@ -262,9 +252,6 @@ public class ContentNegotiationManagerFactoryBean @@ -262,9 +252,6 @@ public class ContentNegotiationManagerFactoryBean
strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes);
}
strategy.setIgnoreUnknownExtensions(this.ignoreUnknownPathExtensions);
if (this.useJaf != null) {
strategy.setUseJaf(this.useJaf);
}
strategies.add(strategy);
}

31
spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java

@ -27,7 +27,6 @@ import org.springframework.core.io.Resource; @@ -27,7 +27,6 @@ import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
@ -39,26 +38,18 @@ import org.springframework.web.util.UrlPathHelper; @@ -39,26 +38,18 @@ import org.springframework.web.util.UrlPathHelper;
* request path to a key to be used to look up a media type.
*
* <p>If the file extension is not found in the explicit registrations provided
* to the constructor, the Java Activation Framework (JAF) is used as a fallback
* to the constructor, the {@link MediaTypeFactory} is used as a fallback
* mechanism.
*
* <p>The presence of the JAF is detected and enabled automatically but the
* {@link #setUseJaf(boolean)} property may be set to false.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class PathExtensionContentNegotiationStrategy extends AbstractMappingContentNegotiationStrategy {
private static final boolean JAF_PRESENT = ClassUtils.isPresent("javax.activation.FileTypeMap",
PathExtensionContentNegotiationStrategy.class.getClassLoader());
private static final Log logger = LogFactory.getLog(PathExtensionContentNegotiationStrategy.class);
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private boolean useJaf = true;
private boolean ignoreUnknownExtensions = true;
@ -89,11 +80,10 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont @@ -89,11 +80,10 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
}
/**
* Whether to use the Java Activation Framework to look up file extensions.
* <p>By default this is set to "true" but depends on JAF being present.
* @deprecated as 5.0, in favor of {@link MediaTypeFactory}, which has no JAF dependency.
*/
@Deprecated
public void setUseJaf(boolean useJaf) {
this.useJaf = useJaf;
}
/**
@ -122,11 +112,9 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont @@ -122,11 +112,9 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension)
throws HttpMediaTypeNotAcceptableException {
if (this.useJaf && JAF_PRESENT) {
MediaType mediaType = MediaTypeFactory.getMediaType("file." + extension);
if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
return mediaType;
}
MediaType mediaType = MediaTypeFactory.getMediaType("file." + extension);
if (mediaType != null) {
return mediaType;
}
if (this.ignoreUnknownExtensions) {
return null;
@ -138,7 +126,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont @@ -138,7 +126,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
* A public method exposing the knowledge of the path extension strategy to
* resolve file extensions to a {@link MediaType} in this case for a given
* {@link Resource}. The method first looks up any explicitly registered
* file extensions first and then falls back on JAF if available.
* file extensions first and then falls back on {@link MediaTypeFactory} if available.
* @param resource the resource to look up
* @return the MediaType for the extension, or {@code null} if none found
* @since 4.3
@ -151,12 +139,9 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont @@ -151,12 +139,9 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
if (extension != null) {
mediaType = lookupMediaType(extension);
}
if (mediaType == null && JAF_PRESENT) {
if (mediaType == null) {
mediaType = MediaTypeFactory.getMediaType(filename);
}
if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
mediaType = null;
}
return mediaType;
}

8
spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -52,7 +52,8 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio @@ -52,7 +52,8 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio
/**
* Create an instance without any mappings to start with. Mappings may be
* added later when extensions are resolved through
* {@link ServletContext#getMimeType(String)} or via JAF.
* {@link ServletContext#getMimeType(String)} or via
* {@link org.springframework.http.MediaTypeFactory}.
*/
public ServletPathExtensionContentNegotiationStrategy(ServletContext context) {
this(context, null);
@ -61,7 +62,8 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio @@ -61,7 +62,8 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio
/**
* Resolve file extension via {@link ServletContext#getMimeType(String)}
* and also delegate to base class for a potential JAF lookup.
* and also delegate to base class for a potential
* {@link org.springframework.http.MediaTypeFactory} lookup.
*/
@Override
protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension)

1855
spring-web/src/main/resources/org/springframework/http/mime.types

File diff suppressed because it is too large Load Diff

35
spring-web/src/test/java/org/springframework/http/MediaTypeFactoryTests.java

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* @author Arjen Poutsma
*/
public class MediaTypeFactoryTests {
@Test
public void getMediaType() {
assertEquals(MediaType.APPLICATION_XML, MediaTypeFactory.getMediaType("file.xml"));
assertEquals(MediaType.parseMediaType("application/javascript"), MediaTypeFactory.getMediaType("file.js"));
assertEquals(MediaType.parseMediaType("text/css"), MediaTypeFactory.getMediaType("file.css"));
}
}

45
spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java

@ -29,7 +29,6 @@ import java.util.LinkedHashMap; @@ -29,7 +29,6 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.activation.FileTypeMap;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
@ -47,9 +46,12 @@ import org.apache.commons.logging.LogFactory; @@ -47,9 +46,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;
/**
@ -136,6 +138,7 @@ public class MockServletContext implements ServletContext { @@ -136,6 +138,7 @@ public class MockServletContext implements ServletContext {
private String responseCharacterEncoding;
private final Map<String, MediaType> mimeTypes = new LinkedHashMap<>();
/**
* Create a new {@code MockServletContext}, using no base path and a
@ -256,29 +259,27 @@ public class MockServletContext implements ServletContext { @@ -256,29 +259,27 @@ public class MockServletContext implements ServletContext {
return this.effectiveMinorVersion;
}
/**
* This method uses the default
* {@link javax.activation.FileTypeMap#getDefaultFileTypeMap() FileTypeMap}
* from the Java Activation Framework to resolve MIME types.
* <p>The Java Activation Framework returns {@code "application/octet-stream"}
* if the MIME type is unknown (i.e., it never returns {@code null}). Thus, in
* order to honor the {@link ServletContext#getMimeType(String)} contract,
* this method returns {@code null} if the MIME type is
* {@code "application/octet-stream"}.
* <p>{@code MockServletContext} does not provide a direct mechanism for
* setting a custom MIME type; however, if the default {@code FileTypeMap}
* is an instance of {@code javax.activation.MimetypesFileTypeMap}, a custom
* MIME type named {@code text/enigma} can be registered for a custom
* {@code .puzzle} file extension in the following manner:
* <pre style="code">
* MimetypesFileTypeMap mimetypesFileTypeMap = (MimetypesFileTypeMap) FileTypeMap.getDefaultFileTypeMap();
* mimetypesFileTypeMap.addMimeTypes("text/enigma puzzle");
* </pre>
*/
@Override
public String getMimeType(String filePath) {
String mimeType = FileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
return ("application/octet-stream".equals(mimeType) ? null : mimeType);
String extension = StringUtils.getFilenameExtension(filePath);
MediaType result;
if (this.mimeTypes.containsKey(extension)) {
result = this.mimeTypes.get(extension);
}
else {
result = MediaTypeFactory.getMediaType(filePath);
}
return result != null ? result.toString() : null;
}
/**
* Adds a mime type mapping for use by {@link #getMimeType(String)}.
* @param fileExtension a file extension, such as {@code txt}, {@code gif}
* @param mimeType the mime type
*/
public void addMimeType(String fileExtension, MediaType mimeType) {
Assert.notNull(fileExtension, "'fileExtension' must not be null");
this.mimeTypes.put(fileExtension, mimeType);
}
@Override

22
spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -31,7 +31,7 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException; @@ -31,7 +31,7 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
/**
* Test fixture for {@link ContentNegotiationManagerFactoryBean} tests.
@ -70,7 +70,7 @@ public class ContentNegotiationManagerFactoryBeanTests { @@ -70,7 +70,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
assertEquals("Should be able to resolve file extensions by default",
Collections.singletonList(MediaType.IMAGE_GIF), manager.resolveMediaTypes(this.webRequest));
this.servletRequest.setRequestURI("/flower.xyz");
this.servletRequest.setRequestURI("/flower.foobarbaz");
assertEquals("Should ignore unknown extensions by default",
Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
@ -107,20 +107,6 @@ public class ContentNegotiationManagerFactoryBeanTests { @@ -107,20 +107,6 @@ public class ContentNegotiationManagerFactoryBeanTests {
assertEquals(Collections.singletonList(MediaType.IMAGE_GIF), manager.resolveMediaTypes(this.webRequest));
}
@Test
public void favorPathWithJafTurnedOff() throws Exception {
this.factoryBean.setFavorPathExtension(true);
this.factoryBean.setUseJaf(false);
this.factoryBean.afterPropertiesSet();
ContentNegotiationManager manager = this.factoryBean.getObject();
this.servletRequest.setRequestURI("/flower.foo");
assertEquals(Collections.emptyList(), manager.resolveMediaTypes(this.webRequest));
this.servletRequest.setRequestURI("/flower.gif");
assertEquals(Collections.emptyList(), manager.resolveMediaTypes(this.webRequest));
}
@Test(expected = HttpMediaTypeNotAcceptableException.class) // SPR-10170
public void favorPathWithIgnoreUnknownPathExtensionTurnedOff() throws Exception {
this.factoryBean.setFavorPathExtension(true);
@ -128,7 +114,7 @@ public class ContentNegotiationManagerFactoryBeanTests { @@ -128,7 +114,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
this.factoryBean.afterPropertiesSet();
ContentNegotiationManager manager = this.factoryBean.getObject();
this.servletRequest.setRequestURI("/flower.xyz");
this.servletRequest.setRequestURI("/flower.foobarbaz");
this.servletRequest.addParameter("format", "json");
manager.resolveMediaTypes(this.webRequest);

27
spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2017 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.
@ -19,7 +19,6 @@ import java.util.Arrays; @@ -19,7 +19,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.junit.Before;
import org.junit.Test;
@ -30,7 +29,8 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException; @@ -30,7 +29,8 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* A test fixture for PathExtensionContentNegotiationStrategy.
@ -70,7 +70,7 @@ public class PathExtensionContentNegotiationStrategyTests { @@ -70,7 +70,7 @@ public class PathExtensionContentNegotiationStrategyTests {
}
@Test
public void resolveMediaTypesFromJaf() throws Exception {
public void resolveMediaTypesFromMediaTypeFactory() throws Exception {
this.servletRequest.setRequestURI("test.xls");
@ -80,21 +80,6 @@ public class PathExtensionContentNegotiationStrategyTests { @@ -80,21 +80,6 @@ public class PathExtensionContentNegotiationStrategyTests {
assertEquals(Arrays.asList(new MediaType("application", "vnd.ms-excel")), mediaTypes);
}
// SPR-10334
@Test
public void getMediaTypeFromFilenameNoJaf() throws Exception {
this.servletRequest.setRequestURI("test.json");
ServletContext servletCxt = this.servletRequest.getServletContext();
PathExtensionContentNegotiationStrategy strategy = new ServletPathExtensionContentNegotiationStrategy(servletCxt);
strategy.setUseJaf(false);
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
assertEquals(Collections.<MediaType>emptyList(), mediaTypes);
}
// SPR-8678
@Test
@ -128,7 +113,7 @@ public class PathExtensionContentNegotiationStrategyTests { @@ -128,7 +113,7 @@ public class PathExtensionContentNegotiationStrategyTests {
@Test
public void resolveMediaTypesIgnoreUnknownExtension() throws Exception {
this.servletRequest.setRequestURI("test.xyz");
this.servletRequest.setRequestURI("test.foobar");
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
@ -139,7 +124,7 @@ public class PathExtensionContentNegotiationStrategyTests { @@ -139,7 +124,7 @@ public class PathExtensionContentNegotiationStrategyTests {
@Test(expected = HttpMediaTypeNotAcceptableException.class)
public void resolveMediaTypesDoNotIgnoreUnknownExtension() throws Exception {
this.servletRequest.setRequestURI("test.xyz");
this.servletRequest.setRequestURI("test.foobar");
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
strategy.setIgnoreUnknownExtensions(false);

30
spring-webflux/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -33,17 +33,14 @@ import org.springframework.web.util.UriUtils; @@ -33,17 +33,14 @@ import org.springframework.web.util.UriUtils;
* the request path and uses that as the media type lookup key.
*
* <p>If the file extension is not found in the explicit registrations provided
* to the constructor, the Java Activation Framework (JAF) is used as a fallback
* mechanism. The presence of the JAF is detected and enabled automatically but
* the {@link #setUseJaf(boolean)} property may be set to false.
* to the constructor, the {@link MediaTypeFactory} is used as a fallback
* mechanism.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class PathExtensionContentTypeResolver extends AbstractMappingContentTypeResolver {
private boolean useJaf = true;
private boolean ignoreUnknownExtensions = true;
@ -63,14 +60,6 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType @@ -63,14 +60,6 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
}
/**
* Whether to use the Java Activation Framework to look up file extensions.
* <p>By default this is set to "true" but depends on JAF being present.
*/
public void setUseJaf(boolean useJaf) {
this.useJaf = useJaf;
}
/**
* Whether to ignore requests with unknown file extension. Setting this to
* {@code false} results in {@code HttpMediaTypeNotAcceptableException}.
@ -90,11 +79,9 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType @@ -90,11 +79,9 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
@Override
protected MediaType handleNoMatch(String key) throws NotAcceptableStatusException {
if (this.useJaf) {
MediaType mediaType = MediaTypeFactory.getMediaType("file." + key);
if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
return mediaType;
}
MediaType mediaType = MediaTypeFactory.getMediaType("file." + key);
if (mediaType != null) {
return mediaType;
}
if (!this.ignoreUnknownExtensions) {
throw new NotAcceptableStatusException(getAllMediaTypes());
@ -105,7 +92,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType @@ -105,7 +92,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
/**
* A public method exposing the knowledge of the path extension resolver to
* determine the media type for a given {@link Resource}. First it checks
* the explicitly registered mappings and then falls back on JAF.
* the explicitly registered mappings and then falls back on {@link MediaTypeFactory}.
* @param resource the resource
* @return the MediaType for the extension, or {@code null} if none determined
*/
@ -120,9 +107,6 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType @@ -120,9 +107,6 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
if (mediaType == null) {
mediaType = MediaTypeFactory.getMediaType(filename);
}
if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
mediaType = null;
}
return mediaType;
}

30
spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -74,9 +74,9 @@ import org.springframework.util.CollectionUtils; @@ -74,9 +74,9 @@ import org.springframework.util.CollectionUtils;
* {@link #mediaTypes(Map)}. This will be used to resolve path extensions or a
* parameter value such as "json" to a media type such as "application/json".
*
* <p>The path extension strategy will also use the Java Activation framework
* (JAF), if available, to resolve a path extension to a MediaType. You may
* {@link #useJaf suppress} the use of JAF.
* <p>The path extension strategy will also use
* {@link org.springframework.http.MediaTypeFactory} to resolve a path extension
* to a MediaType.
*
* @author Rossen Stoyanchev
* @since 5.0
@ -93,8 +93,6 @@ public class RequestedContentTypeResolverBuilder { @@ -93,8 +93,6 @@ public class RequestedContentTypeResolverBuilder {
private boolean ignoreUnknownPathExtensions = true;
private Boolean useJaf;
private String parameterName = "format";
private RequestedContentTypeResolver contentTypeResolver;
@ -119,8 +117,9 @@ public class RequestedContentTypeResolverBuilder { @@ -119,8 +117,9 @@ public class RequestedContentTypeResolverBuilder {
* whitelisted for the purpose of Reflected File Download attack detection
* (see Spring Framework reference documentation for more details on RFD
* attack protection).
* <p>The path extension strategy will also try to use JAF (if present) to
* resolve path extensions. To change this behavior see {@link #useJaf}.
* <p>The path extension strategy will also use the
* {@link org.springframework.http.MediaTypeFactory} to resolve path
* extensions.
* @param mediaTypes media type mappings
*/
public RequestedContentTypeResolverBuilder mediaTypes(Map<String, MediaType> mediaTypes) {
@ -153,18 +152,6 @@ public class RequestedContentTypeResolverBuilder { @@ -153,18 +152,6 @@ public class RequestedContentTypeResolverBuilder {
return this;
}
/**
* When {@link #favorPathExtension favorPathExtension} is set, this
* property determines whether to allow use of JAF (Java Activation Framework)
* to resolve a path extension to a specific MediaType.
* <p>By default this is not set in which case
* {@code PathExtensionContentNegotiationStrategy} will use JAF if available.
*/
public RequestedContentTypeResolverBuilder useJaf(boolean useJaf) {
this.useJaf = useJaf;
return this;
}
/**
* Whether a request parameter ("format" by default) should be used to
* determine the requested media type. For this option to work you must
@ -224,9 +211,6 @@ public class RequestedContentTypeResolverBuilder { @@ -224,9 +211,6 @@ public class RequestedContentTypeResolverBuilder {
if (this.favorPathExtension) {
PathExtensionContentTypeResolver resolver = new PathExtensionContentTypeResolver(this.mediaTypes);
resolver.setIgnoreUnknownExtensions(this.ignoreUnknownPathExtensions);
if (this.useJaf != null) {
resolver.setUseJaf(this.useJaf);
}
resolvers.add(resolver);
}

20
spring-webflux/src/test/java/org/springframework/web/reactive/accept/CompositeContentTypeResolverBuilderTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -44,7 +44,7 @@ public class CompositeContentTypeResolverBuilderTests { @@ -44,7 +44,7 @@ public class CompositeContentTypeResolverBuilderTests {
assertEquals("Should be able to resolve file extensions by default",
Collections.singletonList(MediaType.IMAGE_GIF), resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower.xyz").toExchange();
exchange = MockServerHttpRequest.get("/flower.foobar").toExchange();
assertEquals("Should ignore unknown extensions by default",
Collections.<MediaType>emptyList(), resolver.resolveMediaTypes(exchange));
@ -80,20 +80,6 @@ public class CompositeContentTypeResolverBuilderTests { @@ -80,20 +80,6 @@ public class CompositeContentTypeResolverBuilderTests {
assertEquals(Collections.singletonList(MediaType.IMAGE_GIF), resolver.resolveMediaTypes(exchange));
}
@Test
public void favorPathWithJafTurnedOff() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
.favorPathExtension(true)
.useJaf(false)
.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower.foo").toExchange();
assertEquals(Collections.emptyList(), resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower.gif").toExchange();
assertEquals(Collections.emptyList(), resolver.resolveMediaTypes(exchange));
}
@Test(expected = NotAcceptableStatusException.class) // SPR-10170
public void favorPathWithIgnoreUnknownPathExtensionTurnedOff() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
@ -101,7 +87,7 @@ public class CompositeContentTypeResolverBuilderTests { @@ -101,7 +87,7 @@ public class CompositeContentTypeResolverBuilderTests {
.ignoreUnknownPathExtensions(false)
.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower.xyz?format=json").toExchange();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower.foobar?format=json").toExchange();
resolver.resolveMediaTypes(exchange);
}

18
spring-webflux/src/test/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolverTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -59,18 +59,6 @@ public class PathExtensionContentTypeResolverTests { @@ -59,18 +59,6 @@ public class PathExtensionContentTypeResolverTests {
assertEquals(Collections.singletonList(new MediaType("application", "vnd.ms-excel")), mediaTypes);
}
// SPR-10334
@Test
public void getMediaTypeFromFilenameNoJaf() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("test.json").toExchange();
PathExtensionContentTypeResolver resolver = new PathExtensionContentTypeResolver();
resolver.setUseJaf(false);
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.<MediaType>emptyList(), mediaTypes);
}
// SPR-9390
@Test
@ -86,7 +74,7 @@ public class PathExtensionContentTypeResolverTests { @@ -86,7 +74,7 @@ public class PathExtensionContentTypeResolverTests {
@Test
public void resolveMediaTypesIgnoreUnknownExtension() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("test.xyz").toExchange();
ServerWebExchange exchange = MockServerHttpRequest.get("test.foobar").toExchange();
PathExtensionContentTypeResolver resolver = new PathExtensionContentTypeResolver();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
@ -95,7 +83,7 @@ public class PathExtensionContentTypeResolverTests { @@ -95,7 +83,7 @@ public class PathExtensionContentTypeResolverTests {
@Test(expected = NotAcceptableStatusException.class)
public void resolveMediaTypesDoNotIgnoreUnknownExtension() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("test.xyz").toExchange();
ServerWebExchange exchange = MockServerHttpRequest.get("test.foobar").toExchange();
PathExtensionContentTypeResolver resolver = new PathExtensionContentTypeResolver();
resolver.setIgnoreUnknownExtensions(false);
resolver.resolveMediaTypes(exchange);

2
spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java

@ -103,7 +103,7 @@ public class WebFluxConfigurationSupportTests { @@ -103,7 +103,7 @@ public class WebFluxConfigurationSupportTests {
List<MediaType> list = Collections.singletonList(MediaType.APPLICATION_JSON);
assertEquals(list, resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/path.xml").toExchange();
exchange = MockServerHttpRequest.get("/path.foobar").toExchange();
assertEquals(Collections.emptyList(), resolver.resolveMediaTypes(exchange));
}

5
spring-webflux/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java

@ -52,7 +52,6 @@ import org.springframework.web.reactive.HandlerMapping; @@ -52,7 +52,6 @@ import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.server.MethodNotAllowedException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
@ -209,7 +208,7 @@ public class ResourceWebHandlerTests { @@ -209,7 +208,7 @@ public class ResourceWebHandlerTests {
setPathWithinHandlerMapping(exchange, "js/foo.js");
this.handler.handle(exchange).block(TIMEOUT);
assertEquals(MediaType.parseMediaType("text/javascript"), exchange.getResponse().getHeaders().getContentType());
assertEquals(MediaType.parseMediaType("application/javascript"), exchange.getResponse().getHeaders().getContentType());
assertResponseBody(exchange, "function foo() { console.log(\"hello world\"); }");
}
@ -219,7 +218,7 @@ public class ResourceWebHandlerTests { @@ -219,7 +218,7 @@ public class ResourceWebHandlerTests {
setPathWithinHandlerMapping(exchange, "js/baz.js");
this.handler.handle(exchange).block(TIMEOUT);
assertEquals(MediaType.parseMediaType("text/javascript"), exchange.getResponse().getHeaders().getContentType());
assertEquals(MediaType.parseMediaType("application/javascript"), exchange.getResponse().getHeaders().getContentType());
assertResponseBody(exchange, "function foo() { console.log(\"hello world\"); }");
}

2
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java

@ -95,7 +95,7 @@ public class MessageWriterResultHandlerTests { @@ -95,7 +95,7 @@ public class MessageWriterResultHandlerTests {
MethodParameter type = on(TestController.class).resolveReturnType(Resource.class);
this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5));
assertEquals("image/x-png", this.exchange.getResponse().getHeaders().getFirst("Content-Type"));
assertEquals("image/png", this.exchange.getResponse().getHeaders().getFirst("Content-Type"));
}
@Test // SPR-13631

4
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -181,7 +181,7 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq @@ -181,7 +181,7 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
assertTrue(response.hasBody());
assertEquals(951, response.getHeaders().getContentLength());
assertEquals(951, response.getBody().length);
assertEquals(new MediaType("image", "x-png"), response.getHeaders().getContentType());
assertEquals(new MediaType("image", "png"), response.getHeaders().getContentType());
}
@Test

20
spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -20,6 +20,7 @@ import java.util.Map; @@ -20,6 +20,7 @@ import java.util.Map;
import javax.servlet.ServletContext;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
import org.springframework.web.accept.ContentNegotiationStrategy;
@ -76,9 +77,8 @@ import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; @@ -76,9 +77,8 @@ import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
* type such as "application/json".
*
* <p>The path extension strategy will also use {@link ServletContext#getMimeType}
* and the Java Activation framework (JAF), if available, to resolve a path
* extension to a MediaType. You may however {@link #useJaf suppress} the use
* of JAF.
* and the {@link MediaTypeFactory} to resolve a path
* extension to a MediaType.
*
* @author Rossen Stoyanchev
* @since 3.2
@ -119,8 +119,8 @@ public class ContentNegotiationConfigurer { @@ -119,8 +119,8 @@ public class ContentNegotiationConfigurer {
* (see Spring Framework reference documentation for more details on RFD
* attack protection).
* <p>The path extension strategy will also try to use
* {@link ServletContext#getMimeType} and JAF (if present) to resolve path
* extensions. To change this behavior see the {@link #useJaf} property.
* {@link ServletContext#getMimeType} and {@link MediaTypeFactory} to resolve path
* extensions.
* @param extension the key to look up
* @param mediaType the media type
* @see #mediaTypes(Map)
@ -166,14 +166,10 @@ public class ContentNegotiationConfigurer { @@ -166,14 +166,10 @@ public class ContentNegotiationConfigurer {
}
/**
* When {@link #favorPathExtension} is set, this property determines whether
* to allow use of JAF (Java Activation Framework) to resolve a path
* extension to a specific MediaType.
* <p>By default this is not set in which case
* {@code PathExtensionContentNegotiationStrategy} will use JAF if available.
* @deprecated as 5.0, in favor of {@link MediaTypeFactory}, which has no JAF dependency.
*/
@Deprecated
public ContentNegotiationConfigurer useJaf(boolean useJaf) {
this.factory.setUseJaf(useJaf);
return this;
}

12
spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -45,7 +45,11 @@ import org.springframework.web.accept.ContentNegotiationManager; @@ -45,7 +45,11 @@ import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
import org.springframework.web.servlet.HandlerMapping;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for ResourceHttpRequestHandler.
@ -243,7 +247,7 @@ public class ResourceHttpRequestHandlerTests { @@ -243,7 +247,7 @@ public class ResourceHttpRequestHandlerTests {
@Test // SPR-13658
public void getResourceWithRegisteredMediaType() throws Exception {
ContentNegotiationManagerFactoryBean factory = new ContentNegotiationManagerFactoryBean();
factory.addMediaType("css", new MediaType("foo", "bar"));
factory.addMediaType("bar", new MediaType("foo", "bar"));
factory.afterPropertiesSet();
ContentNegotiationManager manager = factory.getObject();
@ -254,7 +258,7 @@ public class ResourceHttpRequestHandlerTests { @@ -254,7 +258,7 @@ public class ResourceHttpRequestHandlerTests {
handler.setContentNegotiationManager(manager);
handler.afterPropertiesSet();
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.bar");
handler.handleRequest(this.request, this.response);
assertEquals("foo/bar", this.response.getContentType());

1
spring-webmvc/src/test/resources/org/springframework/web/servlet/resource/test/foo.bar

@ -0,0 +1 @@ @@ -0,0 +1 @@
h1 { color:red; }
Loading…
Cancel
Save