Avoid dependency on WebUtils for extracting file extension

Issue: SPR-14479
(cherry picked from commit adc595b)
This commit is contained in:
Juergen Hoeller 2016-07-19 23:30:33 +02:00
parent e0d81b97bb
commit b583aa1579
5 changed files with 66 additions and 15 deletions

View File

@ -35,8 +35,8 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.WebUtils;
/** /**
* A {@code ContentNegotiationStrategy} that resolves the file extension in the * A {@code ContentNegotiationStrategy} that resolves the file extension in the
@ -118,9 +118,8 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
return null; return null;
} }
String path = this.urlPathHelper.getLookupPathForRequest(request); String path = this.urlPathHelper.getLookupPathForRequest(request);
String filename = WebUtils.extractFullFilenameFromUrlPath(path); String extension = UriUtils.extractFileExtension(path);
String extension = StringUtils.getFilenameExtension(filename); return (StringUtils.hasText(extension) ? extension.toLowerCase(Locale.ENGLISH) : null);
return (StringUtils.hasText(extension)) ? extension.toLowerCase(Locale.ENGLISH) : null;
} }
@Override @Override
@ -128,7 +127,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
throws HttpMediaTypeNotAcceptableException { throws HttpMediaTypeNotAcceptableException {
if (this.useJaf && JAF_PRESENT) { if (this.useJaf && JAF_PRESENT) {
MediaType mediaType = JafMediaTypeFactory.getMediaType("file." + extension); MediaType mediaType = ActivationMediaTypeFactory.getMediaType("file." + extension);
if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
return mediaType; return mediaType;
} }
@ -157,7 +156,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
mediaType = lookupMediaType(extension); mediaType = lookupMediaType(extension);
} }
if (mediaType == null && JAF_PRESENT) { if (mediaType == null && JAF_PRESENT) {
mediaType = JafMediaTypeFactory.getMediaType(filename); mediaType = ActivationMediaTypeFactory.getMediaType(filename);
} }
if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
mediaType = null; mediaType = null;
@ -169,7 +168,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
/** /**
* Inner class to avoid hard-coded dependency on JAF. * Inner class to avoid hard-coded dependency on JAF.
*/ */
private static class JafMediaTypeFactory { private static class ActivationMediaTypeFactory {
private static final FileTypeMap fileTypeMap; private static final FileTypeMap fileTypeMap;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -34,6 +34,7 @@ import org.springframework.util.Assert;
* </ul> * </ul>
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0 * @since 3.0
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a> * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>
*/ */
@ -213,4 +214,28 @@ public abstract class UriUtils {
return (changed ? new String(bos.toByteArray(), encoding) : source); return (changed ? new String(bos.toByteArray(), encoding) : source);
} }
/**
* Extract the file extension from the given URI path.
* @param path the URI path (e.g. "/products/index.html")
* @return the extracted file extension (e.g. "html")
* @since 4.3.2
*/
public static String extractFileExtension(String path) {
int end = path.indexOf('?');
if (end == -1) {
end = path.indexOf('#');
if (end == -1) {
end = path.length();
}
}
int begin = path.lastIndexOf('/', end) + 1;
int paramIndex = path.indexOf(';', begin);
end = (paramIndex != -1 && paramIndex < end ? paramIndex : end);
int extIndex = path.lastIndexOf('.', end);
if (extIndex != -1 && extIndex > begin) {
return path.substring(extIndex + 1, end);
}
return null;
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -278,7 +278,6 @@ public abstract class WebUtils {
return realPath; return realPath;
} }
/** /**
* Determine the session id of the given request, if any. * Determine the session id of the given request, if any.
* @param request current HTTP request * @param request current HTTP request
@ -353,7 +352,9 @@ public abstract class WebUtils {
* @param clazz the class to instantiate for a new attribute * @param clazz the class to instantiate for a new attribute
* @return the value of the session attribute, newly created if not found * @return the value of the session attribute, newly created if not found
* @throws IllegalArgumentException if the session attribute could not be instantiated * @throws IllegalArgumentException if the session attribute could not be instantiated
* @deprecated as of Spring 4.3.2, in favor of custom code for such purposes
*/ */
@Deprecated
public static Object getOrCreateSessionAttribute(HttpSession session, String name, Class<?> clazz) public static Object getOrCreateSessionAttribute(HttpSession session, String name, Class<?> clazz)
throws IllegalArgumentException { throws IllegalArgumentException {
@ -527,7 +528,9 @@ public abstract class WebUtils {
* and the values as corresponding attribute values. Keys need to be Strings. * and the values as corresponding attribute values. Keys need to be Strings.
* @param request current HTTP request * @param request current HTTP request
* @param attributes the attributes Map * @param attributes the attributes Map
* @deprecated as of Spring 4.3.2, in favor of custom code for such purposes
*/ */
@Deprecated
public static void exposeRequestAttributes(ServletRequest request, Map<String, ?> attributes) { public static void exposeRequestAttributes(ServletRequest request, Map<String, ?> attributes) {
Assert.notNull(request, "Request must not be null"); Assert.notNull(request, "Request must not be null");
Assert.notNull(attributes, "Attributes Map must not be null"); Assert.notNull(attributes, "Attributes Map must not be null");
@ -689,7 +692,9 @@ public abstract class WebUtils {
* @param currentPage the current page, to be returned as fallback * @param currentPage the current page, to be returned as fallback
* if no target page specified * if no target page specified
* @return the page specified in the request, or current page if not found * @return the page specified in the request, or current page if not found
* @deprecated as of Spring 4.3.2, in favor of custom code for such purposes
*/ */
@Deprecated
public static int getTargetPage(ServletRequest request, String paramPrefix, int currentPage) { public static int getTargetPage(ServletRequest request, String paramPrefix, int currentPage) {
Enumeration<String> paramNames = request.getParameterNames(); Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) { while (paramNames.hasMoreElements()) {
@ -713,7 +718,9 @@ public abstract class WebUtils {
* Correctly resolves nested paths such as "/products/view.html" as well. * Correctly resolves nested paths such as "/products/view.html" as well.
* @param urlPath the request URL path (e.g. "/index.html") * @param urlPath the request URL path (e.g. "/index.html")
* @return the extracted URI filename (e.g. "index") * @return the extracted URI filename (e.g. "index")
* @deprecated as of Spring 4.3.2, in favor of custom code for such purposes
*/ */
@Deprecated
public static String extractFilenameFromUrlPath(String urlPath) { public static String extractFilenameFromUrlPath(String urlPath) {
String filename = extractFullFilenameFromUrlPath(urlPath); String filename = extractFullFilenameFromUrlPath(urlPath);
int dotIndex = filename.lastIndexOf('.'); int dotIndex = filename.lastIndexOf('.');
@ -729,7 +736,10 @@ public abstract class WebUtils {
* "/products/view.html" and remove any path and or query parameters. * "/products/view.html" and remove any path and or query parameters.
* @param urlPath the request URL path (e.g. "/products/index.html") * @param urlPath the request URL path (e.g. "/products/index.html")
* @return the extracted URI filename (e.g. "index.html") * @return the extracted URI filename (e.g. "index.html")
* @deprecated as of Spring 4.3.2, in favor of custom code for such purposes
* (or {@link UriUtils#extractFileExtension} for the file extension use case)
*/ */
@Deprecated
public static String extractFullFilenameFromUrlPath(String urlPath) { public static String extractFullFilenameFromUrlPath(String urlPath) {
int end = urlPath.indexOf('?'); int end = urlPath.indexOf('?');
if (end == -1) { if (end == -1) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ import static org.junit.Assert.*;
/** /**
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Juergen Hoeller
*/ */
public class UriUtilsTests { public class UriUtilsTests {
@ -104,4 +105,22 @@ public class UriUtilsTests {
UriUtils.decode("foo%2", ENC); UriUtils.decode("foo%2", ENC);
} }
@Test
public void extractFileExtension() {
assertEquals("html", UriUtils.extractFileExtension("index.html"));
assertEquals("html", UriUtils.extractFileExtension("/index.html"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html#/a"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html#/path/a"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html#/path/a.do"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html?param=a"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html?param=/path/a"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html?param=/path/a.do"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html?param=/path/a#/path/a"));
assertEquals("html", UriUtils.extractFileExtension("/products/view.html?param=/path/a.do#/path/a.do"));
assertEquals("html", UriUtils.extractFileExtension("/products;q=11/view.html?param=/path/a.do"));
assertEquals("html", UriUtils.extractFileExtension("/products;q=11/view.html;r=22?param=/path/a.do"));
assertEquals("html", UriUtils.extractFileExtension("/products;q=11/view.html;r=22;s=33?param=/path/a.do"));
}
} }

View File

@ -28,8 +28,8 @@ import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.WebUtils;
/** /**
* A UriComponentsBuilder that extracts information from the HttpServletRequest. * A UriComponentsBuilder that extracts information from the HttpServletRequest.
@ -44,7 +44,6 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/** /**
* Default constructor. Protected to prevent direct instantiation. * Default constructor. Protected to prevent direct instantiation.
*
* @see #fromContextPath(HttpServletRequest) * @see #fromContextPath(HttpServletRequest)
* @see #fromServletMapping(HttpServletRequest) * @see #fromServletMapping(HttpServletRequest)
* @see #fromRequest(HttpServletRequest) * @see #fromRequest(HttpServletRequest)
@ -219,8 +218,7 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
public String removePathExtension() { public String removePathExtension() {
String extension = null; String extension = null;
if (this.originalPath != null) { if (this.originalPath != null) {
String filename = WebUtils.extractFullFilenameFromUrlPath(this.originalPath); extension = UriUtils.extractFileExtension(this.originalPath);
extension = StringUtils.getFilenameExtension(filename);
if (!StringUtils.isEmpty(extension)) { if (!StringUtils.isEmpty(extension)) {
int end = this.originalPath.length() - (extension.length() + 1); int end = this.originalPath.length() - (extension.length() + 1);
replacePath(this.originalPath.substring(0, end)); replacePath(this.originalPath.substring(0, end));