Fix media type regression in resource handling
Issue: SPR-14577
This commit is contained in:
parent
417a9d4559
commit
3b95e0b6e0
|
@ -67,6 +67,10 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String, MediaType> getMediaTypes() {
|
||||||
|
return this.mediaTypes;
|
||||||
|
}
|
||||||
|
|
||||||
protected List<MediaType> getAllMediaTypes() {
|
protected List<MediaType> getAllMediaTypes() {
|
||||||
return new ArrayList<>(this.mediaTypes.values());
|
return new ArrayList<>(this.mediaTypes.values());
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@ package org.springframework.web.servlet.resource;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
|
@ -51,6 +53,7 @@ import org.springframework.web.HttpRequestHandler;
|
||||||
import org.springframework.web.accept.ContentNegotiationManager;
|
import org.springframework.web.accept.ContentNegotiationManager;
|
||||||
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
|
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
|
||||||
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
||||||
|
import org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy;
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
@ -111,7 +114,9 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||||
|
|
||||||
private ContentNegotiationManager contentNegotiationManager;
|
private ContentNegotiationManager contentNegotiationManager;
|
||||||
|
|
||||||
private final ContentNegotiationManagerFactoryBean cnmFactoryBean = new ContentNegotiationManagerFactoryBean();
|
private ServletPathExtensionContentNegotiationStrategy pathExtensionStrategy;
|
||||||
|
|
||||||
|
private ServletContext servletContext;
|
||||||
|
|
||||||
private CorsConfiguration corsConfiguration;
|
private CorsConfiguration corsConfiguration;
|
||||||
|
|
||||||
|
@ -254,7 +259,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initServletContext(ServletContext servletContext) {
|
protected void initServletContext(ServletContext servletContext) {
|
||||||
this.cnmFactoryBean.setServletContext(servletContext);
|
this.servletContext = servletContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -268,16 +273,13 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||||
this.resourceResolvers.add(new PathResourceResolver());
|
this.resourceResolvers.add(new PathResourceResolver());
|
||||||
}
|
}
|
||||||
initAllowedLocations();
|
initAllowedLocations();
|
||||||
if (this.contentNegotiationManager == null) {
|
|
||||||
this.cnmFactoryBean.afterPropertiesSet();
|
|
||||||
this.contentNegotiationManager = this.cnmFactoryBean.getObject();
|
|
||||||
}
|
|
||||||
if (this.resourceHttpMessageConverter == null) {
|
if (this.resourceHttpMessageConverter == null) {
|
||||||
this.resourceHttpMessageConverter = new ResourceHttpMessageConverter();
|
this.resourceHttpMessageConverter = new ResourceHttpMessageConverter();
|
||||||
}
|
}
|
||||||
if (this.resourceRegionHttpMessageConverter == null) {
|
if (this.resourceRegionHttpMessageConverter == null) {
|
||||||
this.resourceRegionHttpMessageConverter = new ResourceRegionHttpMessageConverter();
|
this.resourceRegionHttpMessageConverter = new ResourceRegionHttpMessageConverter();
|
||||||
}
|
}
|
||||||
|
this.pathExtensionStrategy = initPathExtensionStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -300,6 +302,19 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ServletPathExtensionContentNegotiationStrategy initPathExtensionStrategy() {
|
||||||
|
Map<String, MediaType> mediaTypes = null;
|
||||||
|
if (getContentNegotiationManager() != null) {
|
||||||
|
PathExtensionContentNegotiationStrategy strategy =
|
||||||
|
getContentNegotiationManager().getStrategy(PathExtensionContentNegotiationStrategy.class);
|
||||||
|
if (strategy != null) {
|
||||||
|
mediaTypes = new HashMap<>(strategy.getMediaTypes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ServletPathExtensionContentNegotiationStrategy(this.servletContext, mediaTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a resource request.
|
* Processes a resource request.
|
||||||
* <p>Checks for the existence of the requested resource in the configured list of locations.
|
* <p>Checks for the existence of the requested resource in the configured list of locations.
|
||||||
|
@ -511,28 +526,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||||
* @return the corresponding media type, or {@code null} if none found
|
* @return the corresponding media type, or {@code null} if none found
|
||||||
*/
|
*/
|
||||||
protected MediaType getMediaType(HttpServletRequest request, Resource resource) {
|
protected MediaType getMediaType(HttpServletRequest request, Resource resource) {
|
||||||
MediaType mediaType = null;
|
return this.pathExtensionStrategy.getMediaTypeForResource(resource);
|
||||||
|
|
||||||
Class<PathExtensionContentNegotiationStrategy> clazz = PathExtensionContentNegotiationStrategy.class;
|
|
||||||
PathExtensionContentNegotiationStrategy strategy = this.contentNegotiationManager.getStrategy(clazz);
|
|
||||||
if (strategy != null) {
|
|
||||||
mediaType = strategy.getMediaTypeForResource(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaType == null) {
|
|
||||||
ServletWebRequest webRequest = new ServletWebRequest(request);
|
|
||||||
try {
|
|
||||||
List<MediaType> mediaTypes = getContentNegotiationManager().resolveMediaTypes(webRequest);
|
|
||||||
if (!mediaTypes.isEmpty()) {
|
|
||||||
mediaType = mediaTypes.get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpMediaTypeNotAcceptableException ex) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mediaType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -248,37 +248,38 @@ public class ResourceHttpRequestHandlerTests {
|
||||||
ContentNegotiationManager manager = factory.getObject();
|
ContentNegotiationManager manager = factory.getObject();
|
||||||
|
|
||||||
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
||||||
this.handler = new ResourceHttpRequestHandler();
|
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||||
this.handler.setLocations(paths);
|
handler.setServletContext(new MockServletContext());
|
||||||
this.handler.setContentNegotiationManager(manager);
|
handler.setLocations(paths);
|
||||||
this.handler.afterPropertiesSet();
|
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.css");
|
||||||
this.handler.handleRequest(this.request, this.response);
|
handler.handleRequest(this.request, this.response);
|
||||||
|
|
||||||
assertEquals("foo/bar", this.response.getContentType());
|
assertEquals("foo/bar", this.response.getContentType());
|
||||||
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13658
|
@Test // SPR-14577
|
||||||
public void getResourceWithRegisteredMediaTypeDefaultStrategy() throws Exception {
|
public void getMediaTypeWithFavorPathExtensionOff() throws Exception {
|
||||||
ContentNegotiationManagerFactoryBean factory = new ContentNegotiationManagerFactoryBean();
|
ContentNegotiationManagerFactoryBean factory = new ContentNegotiationManagerFactoryBean();
|
||||||
factory.setFavorPathExtension(false);
|
factory.setFavorPathExtension(false);
|
||||||
factory.setDefaultContentType(new MediaType("foo", "bar"));
|
|
||||||
factory.afterPropertiesSet();
|
factory.afterPropertiesSet();
|
||||||
ContentNegotiationManager manager = factory.getObject();
|
ContentNegotiationManager manager = factory.getObject();
|
||||||
|
|
||||||
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
||||||
this.handler = new ResourceHttpRequestHandler();
|
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||||
this.handler.setLocations(paths);
|
handler.setServletContext(new MockServletContext());
|
||||||
this.handler.setContentNegotiationManager(manager);
|
handler.setLocations(paths);
|
||||||
this.handler.afterPropertiesSet();
|
handler.setContentNegotiationManager(manager);
|
||||||
|
handler.afterPropertiesSet();
|
||||||
|
|
||||||
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
|
this.request.addHeader("Accept", "application/json,text/plain,*/*");
|
||||||
this.handler.handleRequest(this.request, this.response);
|
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.html");
|
||||||
|
handler.handleRequest(this.request, this.response);
|
||||||
|
|
||||||
assertEquals("foo/bar", this.response.getContentType());
|
assertEquals("text/html", this.response.getContentType());
|
||||||
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-14368
|
@Test // SPR-14368
|
||||||
|
@ -297,13 +298,13 @@ public class ResourceHttpRequestHandlerTests {
|
||||||
};
|
};
|
||||||
|
|
||||||
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
||||||
this.handler = new ResourceHttpRequestHandler();
|
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||||
this.handler.setServletContext(servletContext);
|
handler.setServletContext(servletContext);
|
||||||
this.handler.setLocations(paths);
|
handler.setLocations(paths);
|
||||||
this.handler.afterPropertiesSet();
|
handler.afterPropertiesSet();
|
||||||
|
|
||||||
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
|
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
|
||||||
this.handler.handleRequest(this.request, this.response);
|
handler.handleRequest(this.request, this.response);
|
||||||
|
|
||||||
assertEquals("foo/bar", this.response.getContentType());
|
assertEquals("foo/bar", this.response.getContentType());
|
||||||
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
||||||
|
@ -412,6 +413,7 @@ public class ResourceHttpRequestHandlerTests {
|
||||||
|
|
||||||
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
|
||||||
handler.setResourceResolvers(Collections.singletonList(pathResolver));
|
handler.setResourceResolvers(Collections.singletonList(pathResolver));
|
||||||
|
handler.setServletContext(new MockServletContext());
|
||||||
handler.setLocations(Arrays.asList(location1, location2));
|
handler.setLocations(Arrays.asList(location1, location2));
|
||||||
handler.afterPropertiesSet();
|
handler.afterPropertiesSet();
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ public class ResourceUrlProviderTests {
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
this.locations.add(new ClassPathResource("test/", getClass()));
|
this.locations.add(new ClassPathResource("test/", getClass()));
|
||||||
this.locations.add(new ClassPathResource("testalternatepath/", getClass()));
|
this.locations.add(new ClassPathResource("testalternatepath/", getClass()));
|
||||||
|
this.handler.setServletContext(new MockServletContext());
|
||||||
this.handler.setLocations(locations);
|
this.handler.setLocations(locations);
|
||||||
this.handler.afterPropertiesSet();
|
this.handler.afterPropertiesSet();
|
||||||
this.handlerMap.put("/resources/**", this.handler);
|
this.handlerMap.put("/resources/**", this.handler);
|
||||||
|
|
Loading…
Reference in New Issue