From e02719e5e3abe088878d842a26919e76a0876da7 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 29 Dec 2014 12:51:57 +0100 Subject: [PATCH] Fix path mapping issue in default servlet mode Prior to this commit, some requests would be wrongly mapped to "/" when: * requests ends with "//" such as "/foo/bar//" * the DispatcherServlet is mapped as the default ("/") * the app container sanitizes the servletPath In those cases, the path extraction algorithm was wrongly guessing the path of the current request. This commit detects if the app container sanitized the servletPath for the current request. If so, it uses a sanitized version of the requestUri to extract the path information. Issue: SPR-12372 --- .../web/util/UrlPathHelper.java | 38 +++++++++++-- .../web/util/UrlPathHelperTests.java | 54 ++++++++++++++++++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java index a9e6adb5ad6..245c9981f13 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java +++ b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java @@ -165,6 +165,8 @@ public class UrlPathHelper { * i.e. the part of the request's URL beyond the part that called the servlet, * or "" if the whole URL has been used to identify the servlet. *

Detects include request URL if called within a RequestDispatcher include. + *

E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a". + *

E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a". *

E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a". *

E.g.: servlet mapping = "/test"; request URI = "/test" -> "". *

E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "". @@ -174,7 +176,17 @@ public class UrlPathHelper { public String getPathWithinServletMapping(HttpServletRequest request) { String pathWithinApp = getPathWithinApplication(request); String servletPath = getServletPath(request); - String path = getRemainingPath(pathWithinApp, servletPath, false); + String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp); + String path; + + // if the app container sanitized the servletPath, check against the sanitized version + if(servletPath.indexOf(sanitizedPathWithinApp) != -1) { + path = getRemainingPath(sanitizedPathWithinApp, servletPath, false); + } + else { + path = getRemainingPath(pathWithinApp, servletPath, false); + } + if (path != null) { // Normal case: URI contains servlet path. return path; @@ -243,7 +255,7 @@ public class UrlPathHelper { if (c1 == c2) { continue; } - if (ignoreCase && (Character.toLowerCase(c1) == Character.toLowerCase(c2))) { + else if (ignoreCase && (Character.toLowerCase(c1) == Character.toLowerCase(c2))) { continue; } return null; @@ -251,7 +263,7 @@ public class UrlPathHelper { if (index2 != mapping.length()) { return null; } - if (index1 == requestUri.length()) { + else if (index1 == requestUri.length()) { return ""; } else if (requestUri.charAt(index1) == ';') { @@ -260,6 +272,26 @@ public class UrlPathHelper { return (index1 != -1 ? requestUri.substring(index1) : ""); } + /** + * Sanitize the given path with the following rules: + *

+ */ + private String getSanitizedPath(final String path) { + String sanitized = path; + while (true) { + int index = sanitized.indexOf("//"); + if (index < 0) { + break; + } + else { + sanitized = sanitized.substring(0, index) + sanitized.substring(index + 1); + } + } + return sanitized; + } + /** * Return the request URI for the given request, detecting an include request * URL if called within a RequestDispatcher include. diff --git a/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java b/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java index 7ef440766ad..a18b154a196 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -78,6 +78,16 @@ public class UrlPathHelperTests { assertEquals("Incorrect path returned", "/welcome.html", helper.getPathWithinServletMapping(request)); } + @Test + public void alwaysUseFullPath() { + helper.setAlwaysUseFullPath(true); + request.setContextPath("/petclinic"); + request.setServletPath("/main"); + request.setRequestURI("/petclinic/main/welcome.html"); + + assertEquals("Incorrect path returned", "/main/welcome.html", helper.getLookupPathForRequest(request)); + } + // SPR-11101 @Test @@ -194,6 +204,28 @@ public class UrlPathHelperTests { assertEquals("/foo/", helper.getLookupPathForRequest(request)); } + //SPR-12372 + @Test + public void defaultServletEndingWithDoubleSlash() throws Exception { + request.setContextPath("/SPR-12372"); + request.setPathInfo(null); + request.setServletPath("/foo/bar/"); + request.setRequestURI("/SPR-12372/foo//bar/"); + + assertEquals("/foo//bar/", helper.getLookupPathForRequest(request)); + + request.setServletPath("/foo/bar/"); + request.setRequestURI("/SPR-12372/foo/bar//"); + + assertEquals("/foo/bar//", helper.getLookupPathForRequest(request)); + + // "normal" case + request.setServletPath("/foo/bar//"); + request.setRequestURI("/SPR-12372/foo/bar//"); + + assertEquals("/foo/bar//", helper.getLookupPathForRequest(request)); + } + @Test public void wasDefaultServletRoot() throws Exception { request.setContextPath("/test"); @@ -366,6 +398,26 @@ public class UrlPathHelperTests { tomcatCasualServletFolder(); } + @Test + public void getOriginatingRequestUri() { + request.setAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE, "/path"); + request.setRequestURI("/forwarded"); + assertEquals("/path", helper.getOriginatingRequestUri(request)); + } + + @Test + public void getOriginatingRequestUriWebsphere() { + request.setAttribute(WEBSPHERE_URI_ATTRIBUTE, "/path"); + request.setRequestURI("/forwarded"); + assertEquals("/path", helper.getOriginatingRequestUri(request)); + } + + @Test + public void getOriginatingRequestUriDefault() { + request.setRequestURI("/forwarded"); + assertEquals("/forwarded", helper.getOriginatingRequestUri(request)); + } + @Test public void getOriginatingQueryString() { request.setQueryString("forward=on");