From adc595b5f17e7d858b1faf16ccf9d74918f0f761 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 19 Jul 2016 23:30:33 +0200 Subject: [PATCH] Avoid dependency on WebUtils for extracting file extension Issue: SPR-14479 --- .../PathExtensionContentTypeResolver.java | 5 +- ...thExtensionContentNegotiationStrategy.java | 7 +- .../springframework/web/util/UriUtils.java | 27 ++++++- .../springframework/web/util/WebUtils.java | 78 ------------------- .../web/util/UriUtilsTests.java | 21 ++++- .../web/util/WebUtilsTests.java | 28 ------- .../support/ServletUriComponentsBuilder.java | 6 +- 7 files changed, 53 insertions(+), 119 deletions(-) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java index 09c1465d097..a204f3312e8 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java @@ -26,7 +26,7 @@ import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.server.NotAcceptableStatusException; import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.util.WebUtils; +import org.springframework.web.util.UriUtils; /** * A {@link RequestedContentTypeResolver} that extracts the file extension from @@ -84,8 +84,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType @Override protected String extractKey(ServerWebExchange exchange) { String path = exchange.getRequest().getURI().getRawPath(); - String filename = WebUtils.extractFullFilenameFromUrlPath(path); - String extension = StringUtils.getFilenameExtension(filename); + String extension = UriUtils.extractFileExtension(path); return (StringUtils.hasText(extension)) ? extension.toLowerCase(Locale.ENGLISH) : null; } diff --git a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java index 81d3fd1e5e2..23bcc9c712d 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java @@ -31,8 +31,8 @@ import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.util.UriUtils; import org.springframework.web.util.UrlPathHelper; -import org.springframework.web.util.WebUtils; /** * A {@code ContentNegotiationStrategy} that resolves the file extension in the @@ -114,9 +114,8 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont return null; } String path = this.urlPathHelper.getLookupPathForRequest(request); - String filename = WebUtils.extractFullFilenameFromUrlPath(path); - String extension = StringUtils.getFilenameExtension(filename); - return (StringUtils.hasText(extension)) ? extension.toLowerCase(Locale.ENGLISH) : null; + String extension = UriUtils.extractFileExtension(path); + return (StringUtils.hasText(extension) ? extension.toLowerCase(Locale.ENGLISH) : null); } @Override diff --git a/spring-web/src/main/java/org/springframework/web/util/UriUtils.java b/spring-web/src/main/java/org/springframework/web/util/UriUtils.java index c68092971fa..6b2f3e50495 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriUtils.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriUtils.java @@ -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"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import org.springframework.util.Assert; * * * @author Arjen Poutsma + * @author Juergen Hoeller * @since 3.0 * @see RFC 3986 */ @@ -213,4 +214,28 @@ public abstract class UriUtils { 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; + } + } diff --git a/spring-web/src/main/java/org/springframework/web/util/WebUtils.java b/spring-web/src/main/java/org/springframework/web/util/WebUtils.java index 65a97801b53..28b79893477 100644 --- a/spring-web/src/main/java/org/springframework/web/util/WebUtils.java +++ b/spring-web/src/main/java/org/springframework/web/util/WebUtils.java @@ -260,7 +260,6 @@ public abstract class WebUtils { return realPath; } - /** * Determine the session id of the given request, if any. * @param request current HTTP request @@ -470,20 +469,6 @@ public abstract class WebUtils { request.removeAttribute(ERROR_SERVLET_NAME_ATTRIBUTE); } - /** - * Expose the given Map as request attributes, using the keys as attribute names - * and the values as corresponding attribute values. Keys need to be Strings. - * @param request current HTTP request - * @param attributes the attributes Map - */ - public static void exposeRequestAttributes(ServletRequest request, Map attributes) { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(attributes, "Attributes Map must not be null"); - for (Map.Entry entry : attributes.entrySet()) { - request.setAttribute(entry.getKey(), entry.getValue()); - } - } - /** * Retrieve the first cookie with the given name. Note that multiple * cookies can have the same name but different paths or domains. @@ -629,69 +614,6 @@ public abstract class WebUtils { return params; } - /** - * Return the target page specified in the request. - * @param request current servlet request - * @param paramPrefix the parameter prefix to check for - * (e.g. "_target" for parameters like "_target1" or "_target2") - * @param currentPage the current page, to be returned as fallback - * if no target page specified - * @return the page specified in the request, or current page if not found - */ - public static int getTargetPage(ServletRequest request, String paramPrefix, int currentPage) { - Enumeration paramNames = request.getParameterNames(); - while (paramNames.hasMoreElements()) { - String paramName = paramNames.nextElement(); - if (paramName.startsWith(paramPrefix)) { - for (int i = 0; i < WebUtils.SUBMIT_IMAGE_SUFFIXES.length; i++) { - String suffix = WebUtils.SUBMIT_IMAGE_SUFFIXES[i]; - if (paramName.endsWith(suffix)) { - paramName = paramName.substring(0, paramName.length() - suffix.length()); - } - } - return Integer.parseInt(paramName.substring(paramPrefix.length())); - } - } - return currentPage; - } - - - /** - * Extract the URL filename from the given request URL path. - * Correctly resolves nested paths such as "/products/view.html" as well. - * @param urlPath the request URL path (e.g. "/index.html") - * @return the extracted URI filename (e.g. "index") - */ - public static String extractFilenameFromUrlPath(String urlPath) { - String filename = extractFullFilenameFromUrlPath(urlPath); - int dotIndex = filename.lastIndexOf('.'); - if (dotIndex != -1) { - filename = filename.substring(0, dotIndex); - } - return filename; - } - - /** - * Extract the full URL filename (including file extension) from the given - * request URL path. Correctly resolve nested paths such as - * "/products/view.html" and remove any path and or query parameters. - * @param urlPath the request URL path (e.g. "/products/index.html") - * @return the extracted URI filename (e.g. "index.html") - */ - public static String extractFullFilenameFromUrlPath(String urlPath) { - int end = urlPath.indexOf('?'); - if (end == -1) { - end = urlPath.indexOf('#'); - if (end == -1) { - end = urlPath.length(); - } - } - int begin = urlPath.lastIndexOf('/', end) + 1; - int paramIndex = urlPath.indexOf(';', begin); - end = (paramIndex != -1 && paramIndex < end ? paramIndex : end); - return urlPath.substring(begin, end); - } - /** * Parse the given string with matrix variables. An example string would look * like this {@code "q1=a;q1=b;q2=a,b,c"}. The resulting map would contain diff --git a/spring-web/src/test/java/org/springframework/web/util/UriUtilsTests.java b/spring-web/src/test/java/org/springframework/web/util/UriUtilsTests.java index 6480c5fa2e3..2227674abc9 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriUtilsTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriUtilsTests.java @@ -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"); * 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 Juergen Hoeller */ public class UriUtilsTests { @@ -104,4 +105,22 @@ public class UriUtilsTests { 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")); + } + } diff --git a/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java b/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java index be7a5b55348..201c7cda4f7 100644 --- a/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java @@ -55,34 +55,6 @@ public class WebUtilsTests { assertEquals("myValue4", WebUtils.findParameterValue(params, "myKey4")); } - @Test - public void extractFilenameFromUrlPath() { - assertEquals("index", WebUtils.extractFilenameFromUrlPath("index.html")); - assertEquals("index", WebUtils.extractFilenameFromUrlPath("/index.html")); - assertEquals("view", WebUtils.extractFilenameFromUrlPath("/products/view.html")); - assertEquals("view", WebUtils.extractFilenameFromUrlPath("/products/view.html?param=a")); - assertEquals("view", WebUtils.extractFilenameFromUrlPath("/products/view.html?param=/path/a")); - assertEquals("view", WebUtils.extractFilenameFromUrlPath("/products/view.html?param=/path/a.do")); - } - - @Test - public void extractFullFilenameFromUrlPath() { - assertEquals("index.html", WebUtils.extractFullFilenameFromUrlPath("index.html")); - assertEquals("index.html", WebUtils.extractFullFilenameFromUrlPath("/index.html")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html#/a")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html#/path/a")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html#/path/a.do")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html?param=a")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html?param=/path/a")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html?param=/path/a.do")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html?param=/path/a#/path/a")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products/view.html?param=/path/a.do#/path/a.do")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products;q=11/view.html?param=/path/a.do")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products;q=11/view.html;r=22?param=/path/a.do")); - assertEquals("view.html", WebUtils.extractFullFilenameFromUrlPath("/products;q=11/view.html;r=22;s=33?param=/path/a.do")); - } - @Test public void parseMatrixVariablesString() { MultiValueMap variables; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java index 852f5cd2dc7..367aed85033 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java @@ -28,8 +28,8 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.UriUtils; import org.springframework.web.util.UrlPathHelper; -import org.springframework.web.util.WebUtils; /** * A UriComponentsBuilder that extracts information from the HttpServletRequest. @@ -44,7 +44,6 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { /** * Default constructor. Protected to prevent direct instantiation. - * * @see #fromContextPath(HttpServletRequest) * @see #fromServletMapping(HttpServletRequest) * @see #fromRequest(HttpServletRequest) @@ -219,8 +218,7 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { public String removePathExtension() { String extension = null; if (this.originalPath != null) { - String filename = WebUtils.extractFullFilenameFromUrlPath(this.originalPath); - extension = StringUtils.getFilenameExtension(filename); + extension = UriUtils.extractFileExtension(this.originalPath); if (!StringUtils.isEmpty(extension)) { int end = this.originalPath.length() - (extension.length() + 1); replacePath(this.originalPath.substring(0, end));