diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java index 47298400c60..e8c2bc99b77 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java @@ -17,14 +17,19 @@ package org.springframework.web.servlet.resource; import java.io.IOException; +import java.io.InputStream; import java.util.List; +import javax.activation.FileTypeMap; +import javax.activation.MimetypesFileTypeMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpRequestHandler; @@ -63,6 +68,9 @@ import org.springframework.web.servlet.support.WebContentGenerator; */ public class ResourceHttpRequestHandler extends WebContentGenerator implements HttpRequestHandler { + private static final boolean jafPresent = + ClassUtils.isPresent("javax.activation.FileTypeMap", ResourceHttpRequestHandler.class.getClassLoader()); + private List locations; @@ -109,15 +117,13 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H MediaType mediaType = getMediaType(resource); if (mediaType != null) { if (logger.isDebugEnabled()) { - logger.debug("Determined media type [" + mediaType + "] for " + resource); + logger.debug("Determined media type '" + mediaType + "' for " + resource); } } else { if (logger.isDebugEnabled()) { - logger.debug("No media type found for " + resource + " - returning 404"); + logger.debug("No media type found for " + resource + " - not sending a content-type header"); } - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; } // header phase @@ -190,7 +196,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H */ protected MediaType getMediaType(Resource resource) { String mimeType = getServletContext().getMimeType(resource.getFilename()); - return (StringUtils.hasText(mimeType) ? MediaType.parseMediaType(mimeType) : null); + if (StringUtils.hasText(mimeType)) { + return new MediaType(mimeType); + } + else if (jafPresent) { + return ActivationMediaTypeFactory.getMediaType(resource.getFilename()); + } + else { + return null; + } } /** @@ -207,7 +221,10 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H throw new IOException("Resource content too long (beyond Integer.MAX_VALUE): " + resource); } response.setContentLength((int) length); - response.setContentType(mediaType.toString()); + + if (mediaType != null) { + response.setContentType(mediaType.toString()); + } } /** @@ -221,4 +238,48 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream()); } + + /** + * Inner class to avoid hard-coded JAF dependency. + */ + private static class ActivationMediaTypeFactory { + + private static final FileTypeMap fileTypeMap; + + static { + fileTypeMap = loadFileTypeMapFromContextSupportModule(); + } + + 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 + } + finally { + if (inputStream != null) { + try { + inputStream.close(); + } + catch (IOException ex) { + // ignore + } + } + } + } + return FileTypeMap.getDefaultFileTypeMap(); + } + + public static MediaType getMediaType(String filename) { + String mediaType = fileTypeMap.getContentType(filename); + return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null); + } + } + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java index 7d82a8c16af..e980f444a3d 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java @@ -78,14 +78,14 @@ import org.springframework.web.util.WebUtils; * media type. The default name of the parameter is format and it can be configured using the * {@link #setParameterName(String) parameterName} property. *
  • If there is no match in the {@link #setMediaTypes(Map) mediaTypes} property and if the Java Activation - * Framework (JAF) is both {@linkplain #setUseJaf enabled} and present on the class path, + * Framework (JAF) is both {@linkplain #setUseJaf enabled} and present on the classpath, * {@link FileTypeMap#getContentType(String)} is used instead.
  • *
  • If the previous steps did not result in a media type, and * {@link #setIgnoreAcceptHeader ignoreAcceptHeader} is {@code false}, the request {@code Accept} header is * used.
  • * * - * Once the requested media type has been determined, this resolver queries each delegate view resolver for a + *

    Once the requested media type has been determined, this resolver queries each delegate view resolver for a * {@link View} and determines if the requested media type is {@linkplain MediaType#includes(MediaType) compatible} * with the view's {@linkplain View#getContentType() content type}). The most compatible view is returned. * @@ -407,7 +407,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport *

    The default implementation will check the {@linkplain #setMediaTypes(Map) media types} * property first for a defined mapping. If not present, and if the Java Activation Framework * can be found on the classpath, it will call {@link FileTypeMap#getContentType(String)} - *

    This method can be overriden to provide a different algorithm. + *

    This method can be overridden to provide a different algorithm. * @param filename the current request file name (i.e. {@code hotels.html}) * @return the media type, if any */ @@ -418,8 +418,14 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport } extension = extension.toLowerCase(Locale.ENGLISH); MediaType mediaType = this.mediaTypes.get(extension); - if (mediaType == null && this.useJaf && jafPresent) { - mediaType = ActivationMediaTypeFactory.getMediaType(filename); + if (mediaType == null) { + String mimeType = getServletContext().getMimeType(filename); + if (StringUtils.hasText(mimeType)) { + mediaType = new MediaType(mimeType); + } + else if (this.useJaf && jafPresent) { + mediaType = ActivationMediaTypeFactory.getMediaType(filename); + } if (mediaType != null) { this.mediaTypes.putIfAbsent(extension, mediaType); } @@ -506,6 +512,18 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport } + private static final View NOT_ACCEPTABLE_VIEW = new View() { + + public String getContentType() { + return null; + } + + public void render(Map model, HttpServletRequest request, HttpServletResponse response) { + response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE); + } + }; + + /** * Inner class to avoid hard-coded JAF dependency. */ @@ -549,22 +567,10 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport return FileTypeMap.getDefaultFileTypeMap(); } - public static MediaType getMediaType(String fileName) { - String mediaType = fileTypeMap.getContentType(fileName); + public static MediaType getMediaType(String filename) { + String mediaType = fileTypeMap.getContentType(filename); return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null); } } - - private static final View NOT_ACCEPTABLE_VIEW = new View() { - - public String getContentType() { - return null; - } - - public void render(Map model, HttpServletRequest request, HttpServletResponse response) { - response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE); - } - }; - }