Browse Source

Fix OutOfBoundsExceptio in ResourceUrlEncodingFilter

Prior to this change, the `ResourceUrlEncodingFilter` would try to
lookup resources URLs as soon as the given URL would be longer than the
expected context+servlet prefix path. This can lead to
OutOfBoundsExceptions when the provided URL does not start with that
prefix and still has the required length.

This commit makes sure that all candidate URLs for resources lookup are
prefixed with the cached servlet and context path. This underlines the
fact that the `ResourceUrlEncodingFilter` does not support relative URLs
for now and delegates to the native servlet implementation in that case.

Issue: SPR-13861
pull/942/head
Brian Clozel 9 years ago
parent
commit
2f6d86b7aa
  1. 18
      spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java
  2. 21
      spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilterTests.java

18
spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@ -37,6 +37,7 @@ import org.springframework.web.filter.OncePerRequestFilter; @@ -37,6 +37,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
* @author Jeremy Grelle
* @author Rossen Stoyanchev
* @author Sam Brannen
* @author Brian Clozel
* @since 4.1
*/
public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
@ -56,9 +57,11 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter { @@ -56,9 +57,11 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
private final HttpServletRequest request;
/* Cache the index of the path within the DispatcherServlet mapping */
/* Cache the index and prefix of the path within the DispatcherServlet mapping */
private Integer indexLookupPath;
private String prefixLookupPath;
public ResourceUrlEncodingResponseWrapper(HttpServletRequest request, HttpServletResponse wrapped) {
super(wrapped);
this.request = request;
@ -72,15 +75,14 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter { @@ -72,15 +75,14 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
return super.encodeURL(url);
}
initIndexLookupPath(resourceUrlProvider);
if (url.length() >= this.indexLookupPath) {
String prefix = url.substring(0, this.indexLookupPath);
initLookupPath(resourceUrlProvider);
if (url.startsWith(this.prefixLookupPath)) {
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 + suffix);
return super.encodeURL(this.prefixLookupPath + lookupPath + suffix);
}
}
@ -92,16 +94,18 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter { @@ -92,16 +94,18 @@ public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR);
}
private void initIndexLookupPath(ResourceUrlProvider urlProvider) {
private void initLookupPath(ResourceUrlProvider urlProvider) {
if (this.indexLookupPath == null) {
String requestUri = urlProvider.getPathHelper().getRequestUri(this.request);
String lookupPath = urlProvider.getPathHelper().getLookupPathForRequest(this.request);
this.indexLookupPath = requestUri.lastIndexOf(lookupPath);
this.prefixLookupPath = requestUri.substring(0, this.indexLookupPath);
if ("/".equals(lookupPath) && !"/".equals(requestUri)) {
String contextPath = urlProvider.getPathHelper().getContextPath(this.request);
if (requestUri.equals(contextPath)) {
this.indexLookupPath = requestUri.length();
this.prefixLookupPath = requestUri;
}
}
}

21
spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilterTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@ -150,6 +150,25 @@ public class ResourceUrlEncodingFilterTests { @@ -150,6 +150,25 @@ public class ResourceUrlEncodingFilterTests {
});
}
// SPR-13847
@Test
public void encodeUrlPreventStringOutOfBounds() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/context-path/index");
request.setContextPath("/context-path");
request.setServletPath("");
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("index?key=value");
assertEquals("index?key=value", result);
}
});
}
protected ResourceUrlProvider createResourceUrlProvider(List<ResourceResolver> resolvers) {
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
handler.setLocations(Arrays.asList(new ClassPathResource("test/", getClass())));

Loading…
Cancel
Save