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
This commit is contained in:
parent
952a3170e6
commit
2f6d86b7aa
|
@ -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;
|
|||
* @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 {
|
|||
|
||||
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 {
|
|||
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 {
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
});
|
||||
}
|
||||
|
||||
// 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…
Reference in New Issue