From 0b9c3de320df81acd06dcfd927faadf72fb66409 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 25 Aug 2015 13:47:30 +0200 Subject: [PATCH] Sanitize request URL in ResourceUrlEncodingFilter Prior to this change, ResourceUrlEncodingFilter and ResourceUrlProvider would try to resolve the resource path using the full request URL (i.e. request path and request parameters), whereas the request path is the only information to consider. This would lead to StringIndexOutOfBoundsExceptions when the path + request params information was given to the AntPathMatcher. This commit makes the appropriate change to both ResourceUrlEncodingFilter and ResourceUrlProvider, in order to only select the request path. Issue: SPR-13374 --- .../resource/ResourceUrlEncodingFilter.java | 11 +++++++++-- .../servlet/resource/ResourceUrlProvider.java | 15 +++++++++++---- .../ResourceUrlEncodingFilterTests.java | 19 ++++++++++++++++++- .../resource/ResourceUrlProviderTests.java | 13 +++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java index 9a05345099c..22251e5d3e1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java @@ -74,10 +74,12 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter { initIndexLookupPath(resourceUrlProvider); if (url.length() >= this.indexLookupPath) { String prefix = url.substring(0, this.indexLookupPath); - String lookupPath = url.substring(this.indexLookupPath); + int suffixIndex = getQueryParamsIndex(url); + String suffix = url.substring(suffixIndex); + String lookupPath = url.substring(this.indexLookupPath, suffixIndex); lookupPath = resourceUrlProvider.getForLookupPath(lookupPath); if (lookupPath != null) { - return super.encodeURL(prefix + lookupPath); + return super.encodeURL(prefix + lookupPath + suffix); } } return super.encodeURL(url); @@ -95,6 +97,11 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter { this.indexLookupPath = requestUri.lastIndexOf(lookupPath); } } + + private int getQueryParamsIndex(String url) { + int index = url.indexOf("?"); + return index > 0 ? index : url.length(); + } } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java index 416a04e689a..194ed961664 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java @@ -172,11 +172,13 @@ public class ResourceUrlProvider implements ApplicationListener 0 ? index : lookupPath.length(); + } + /** * Compare the given path against configured resource handler mappings and * if a match is found use the {@code ResourceResolver} chain of the matched diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilterTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilterTests.java index e94a2a615ff..bcd6bfc33de 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilterTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -106,6 +106,23 @@ public class ResourceUrlEncodingFilterTests { }); } + // SPR-13374 + @Test + public void encodeURLWithRequestParams() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); + request.setContextPath("/"); + request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider); + MockHttpServletResponse response = new MockHttpServletResponse(); + + this.filter.doFilterInternal(request, response, new FilterChain() { + @Override + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + String result = ((HttpServletResponse)response).encodeURL("/resources/bar.css?foo=bar&url=http://example.org"); + assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css?foo=bar&url=http://example.org", result); + } + }); + } + protected ResourceUrlProvider createResourceUrlProvider(List resolvers) { ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); handler.setLocations(Arrays.asList(new ClassPathResource("test/", getClass()))); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java index 98966a01f02..bd0a6ac911f 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java @@ -29,6 +29,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; +import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockServletContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; @@ -74,6 +75,18 @@ public class ResourceUrlProviderTests { assertEquals("/resources/foo.css", url); } + // SPR-13374 + @Test + public void getStaticResourceUrlRequestWithRequestParams() { + initTranslator(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContextPath("/"); + request.setRequestURI("/"); + + String url = this.translator.getForRequestUrl(request, "/resources/foo.css?foo=bar&url=http://example.org"); + assertEquals("/resources/foo.css?foo=bar&url=http://example.org", url); + } + @Test public void getFingerprintedResourceUrl() { Map versionStrategyMap = new HashMap<>();