From 87109b348cf1fcae2d4aefe64f9ce6b8fcf389a0 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 8 Jan 2013 09:21:17 -0500 Subject: [PATCH] Add decoding matrix variable values Issue: SPR-10140 --- .../web/util/UrlPathHelper.java | 29 ++++++++++++ .../RequestMappingInfoHandlerMapping.java | 9 ++-- ...RequestMappingInfoHandlerMappingTests.java | 47 ++++++++++++------- 3 files changed, 66 insertions(+), 19 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 67b7a4c024..72b592108a 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 @@ -27,6 +27,8 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; /** @@ -491,6 +493,33 @@ public class UrlPathHelper { } } + /** + * Decode the given matrix variables via + * {@link #decodeRequestString(HttpServletRequest, String)} unless + * {@link #setUrlDecode(boolean)} is set to {@code true} in which case it is + * assumed the URL path from which the variables were extracted is already + * decoded through a call to + * {@link #getLookupPathForRequest(HttpServletRequest)}. + * + * @param request current HTTP request + * @param vars URI variables extracted from the URL path + * @return the same Map or a new Map instance + */ + public MultiValueMap decodeMatrixVariables(HttpServletRequest request, MultiValueMap vars) { + if (this.urlDecode) { + return vars; + } + else { + MultiValueMap decodedVars = new LinkedMultiValueMap (vars.size()); + for (String key : vars.keySet()) { + for (String value : vars.get(key)) { + decodedVars.add(key, decodeInternal(request, value)); + } + } + return decodedVars; + } + } + private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request) { if (request.getAttribute(WEBSPHERE_URI_ATTRIBUTE) == null) { // Regular servlet container: behaves as expected in any case, diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java index dfdfc05ed2..7654d31498 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java @@ -100,7 +100,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables); if (isMatrixVariableContentAvailable()) { - request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(uriVariables)); + request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(request, uriVariables)); } if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) { @@ -113,7 +113,9 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe return !getUrlPathHelper().shouldRemoveSemicolonContent(); } - private Map> extractMatrixVariables(Map uriVariables) { + private Map> extractMatrixVariables( + HttpServletRequest request, Map uriVariables) { + Map> result = new LinkedHashMap>(); for (Entry uriVar : uriVariables.entrySet()) { String uriVarValue = uriVar.getValue(); @@ -134,7 +136,8 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe uriVariables.put(uriVar.getKey(), uriVarValue.substring(0, semicolonIndex)); } - result.put(uriVar.getKey(), WebUtils.parseMatrixVariables(matrixVariables)); + MultiValueMap vars = WebUtils.parseMatrixVariables(matrixVariables); + result.put(uriVar.getKey(), getUrlPathHelper().decodeMatrixVariables(request, vars)); } return result; } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java index e0764f7e7b..841318af71 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java @@ -310,48 +310,63 @@ public class RequestMappingInfoHandlerMappingTests { MultiValueMap matrixVariables; Map uriVariables; - String lookupPath = "/cars;colors=red,blue,green;year=2012"; - - // Pattern "/{cars}" : matrix variables stripped from "cars" variable - request = new MockHttpServletRequest(); - testHandleMatch(request, "/{cars}", lookupPath); + testHandleMatch(request, "/{cars}", "/cars;colors=red,blue,green;year=2012"); matrixVariables = getMatrixVariables(request, "cars"); + uriVariables = getUriTemplateVariables(request); + assertNotNull(matrixVariables); assertEquals(Arrays.asList("red", "blue", "green"), matrixVariables.get("colors")); assertEquals("2012", matrixVariables.getFirst("year")); - - uriVariables = getUriTemplateVariables(request); assertEquals("cars", uriVariables.get("cars")); - // Pattern "/{cars:[^;]+}{params}" : "cars" and "params" variables unchanged - request = new MockHttpServletRequest(); - testHandleMatch(request, "/{cars:[^;]+}{params}", lookupPath); + testHandleMatch(request, "/{cars:[^;]+}{params}", "/cars;colors=red,blue,green;year=2012"); matrixVariables = getMatrixVariables(request, "params"); + uriVariables = getUriTemplateVariables(request); + assertNotNull(matrixVariables); assertEquals(Arrays.asList("red", "blue", "green"), matrixVariables.get("colors")); assertEquals("2012", matrixVariables.getFirst("year")); - - uriVariables = getUriTemplateVariables(request); assertEquals("cars", uriVariables.get("cars")); assertEquals(";colors=red,blue,green;year=2012", uriVariables.get("params")); - // matrix variables not present : "params" variable is empty - request = new MockHttpServletRequest(); testHandleMatch(request, "/{cars:[^;]+}{params}", "/cars"); matrixVariables = getMatrixVariables(request, "params"); - assertNull(matrixVariables); - uriVariables = getUriTemplateVariables(request); + + assertNull(matrixVariables); assertEquals("cars", uriVariables.get("cars")); assertEquals("", uriVariables.get("params")); } + @Test + public void matrixVariablesDecoding() { + + MockHttpServletRequest request; + + UrlPathHelper urlPathHelper = new UrlPathHelper(); + urlPathHelper.setUrlDecode(false); + urlPathHelper.setRemoveSemicolonContent(false); + + this.handlerMapping.setUrlPathHelper(urlPathHelper ); + + request = new MockHttpServletRequest(); + testHandleMatch(request, "/path{filter}", "/path;mvar=a%2fb"); + + MultiValueMap matrixVariables = getMatrixVariables(request, "filter"); + Map uriVariables = getUriTemplateVariables(request); + + assertNotNull(matrixVariables); + assertEquals(Arrays.asList("a/b"), matrixVariables.get("mvar")); + assertEquals(";mvar=a/b", uriVariables.get("filter")); + } + + private void testHandleMatch(MockHttpServletRequest request, String pattern, String lookupPath) { PatternsRequestCondition patterns = new PatternsRequestCondition(pattern); RequestMappingInfo info = new RequestMappingInfo(patterns, null, null, null, null, null, null);