Browse Source

Fix issue with extracting matrix variables

The servlet spec recommends removing path parameters from the
contextPath, servletPath, and pathInfo but not from the requestURI.
This poses a challenge for the UrlPathHelper, which determines the
lookup path by comparing the above.

This change introduces a method that matches the requestURI to the
contextPath and servletPath ignoring path parameters (i.e. matrix
variables) for comparison purposes while also preserving them in the
resulting lookup path.
pull/132/merge
Rossen Stoyanchev 12 years ago
parent
commit
d8469d118b
  1. 49
      spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java
  2. 32
      spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java
  3. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariableMethodArgumentResolver.java

49
spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java

@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest; @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@ -172,9 +173,10 @@ public class UrlPathHelper { @@ -172,9 +173,10 @@ public class UrlPathHelper {
public String getPathWithinServletMapping(HttpServletRequest request) {
String pathWithinApp = getPathWithinApplication(request);
String servletPath = getServletPath(request);
if (pathWithinApp.startsWith(servletPath)) {
String path = getRemainingPath(pathWithinApp, servletPath, false);
if (path != null) {
// Normal case: URI contains servlet path.
return pathWithinApp.substring(servletPath.length());
return path;
}
else {
// Special case: URI is different from servlet path.
@ -195,17 +197,54 @@ public class UrlPathHelper { @@ -195,17 +197,54 @@ public class UrlPathHelper {
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
String path = getRemainingPath(requestUri, contextPath, true);
if (path != null) {
// Normal case: URI contains context path.
String path = requestUri.substring(contextPath.length());
return (StringUtils.hasText(path) ? path : "/");
}
else {
// Special case: rather unusual.
return requestUri;
}
}
/**
* Match the given "mapping" to the start of the "requestUri" and if there
* is a match return the extra part. This method is needed because the
* context path and the servlet path returned by the HttpServletRequest are
* stripped of semicolon content unlike the requesUri.
*/
private String getRemainingPath(String requestUri, String mapping, boolean ignoreCase) {
int index1 = 0;
int index2 = 0;
for ( ; (index1 < requestUri.length()) && (index2 < mapping.length()); index1++, index2++) {
char c1 = requestUri.charAt(index1);
char c2 = mapping.charAt(index2);
if (c1 == ';') {
index1 = requestUri.indexOf('/', index1);
if (index1 == -1) {
return null;
}
c1 = requestUri.charAt(index1);
}
if (c1 == c2) {
continue;
}
if (ignoreCase && (Character.toLowerCase(c1) == Character.toLowerCase(c2))) {
continue;
}
return null;
}
if (index2 != mapping.length()) {
return null;
}
if (index1 == requestUri.length()) {
return "";
}
else if (requestUri.charAt(index1) == ';') {
index1 = requestUri.indexOf('/', index1);
}
return (index1 != -1) ? requestUri.substring(index1) : "";
}
/**
* Return the request URI for the given request, detecting an include request

32
spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java

@ -69,6 +69,15 @@ public class UrlPathHelperTests { @@ -69,6 +69,15 @@ public class UrlPathHelperTests {
assertEquals("Incorrect path returned", "/welcome.html", helper.getPathWithinApplication(request));
}
@Test
public void getPathWithinServlet() {
request.setContextPath("/petclinic");
request.setServletPath("/main");
request.setRequestURI("/petclinic/main/welcome.html");
assertEquals("Incorrect path returned", "/welcome.html", helper.getPathWithinServletMapping(request));
}
@Test
public void getRequestUri() {
request.setRequestURI("/welcome.html");
@ -104,6 +113,29 @@ public class UrlPathHelperTests { @@ -104,6 +113,29 @@ public class UrlPathHelperTests {
assertEquals("jsessionid should always be removed", "/foo;a=b;c=d", helper.getRequestUri(request));
}
@Test
public void getLookupPathWithSemicolonContent() {
helper.setRemoveSemicolonContent(false);
request.setContextPath("/petclinic");
request.setServletPath("/main");
request.setRequestURI("/petclinic;a=b/main;b=c/welcome.html;c=d");
assertEquals("/welcome.html;c=d", helper.getLookupPathForRequest(request));
}
@Test
public void getLookupPathWithSemicolonContentAndNullPathInfo() {
helper.setRemoveSemicolonContent(false);
request.setContextPath("/petclinic");
request.setServletPath("/welcome.html");
request.setRequestURI("/petclinic;a=b/welcome.html;c=d");
assertEquals("/welcome.html;c=d", helper.getLookupPathForRequest(request));
}
//
// suite of tests root requests for default servlets (SRV 11.2) on Websphere vs Tomcat and other containers
// see: http://jira.springframework.org/browse/SPR-7064

2
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariableMethodArgumentResolver.java

@ -116,7 +116,7 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth @@ -116,7 +116,7 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
protected void handleMissingValue(String name, MethodParameter param) throws ServletRequestBindingException {
String paramType = param.getParameterType().getName();
throw new ServletRequestBindingException(
"Missing URI path parameter '" + name + "' for method parameter type [" + paramType + "]");
"Missing matrix variable '" + name + "' for method parameter type [" + paramType + "]");
}

Loading…
Cancel
Save