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.