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
This commit is contained in:
Brian Clozel 2014-12-29 12:51:57 +01:00
parent 40449e2741
commit e02719e5e3
2 changed files with 88 additions and 4 deletions

View File

@ -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.
* <p>Detects include request URL if called within a RequestDispatcher include.
* <p>E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a".
* <p>E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a".
* <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
* <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
* <p>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:
* <ul>
* <li>replace all "//" by "/"</li>
* </ul>
*/
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.

View File

@ -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");