Skip to content

Commit b10045d

Browse files
committed
Do not execute ResourceUrlEncodingFilter only once per request
In case the filter is also registered to the ERROR dispatcher, the following happens: * the filter is executed once for the regular execution * the filter should be executed a second time when dispatched to error Since the filter is a `OncePerRequestFilter`, the filter is only executed once and won't be executed when handling the error. This can lead to situations like spring-projects/spring-boot#7348 This commit makes this filter a simple `GenericFilterBean`. Issue: SPR-14891
1 parent 9bcc7c3 commit b10045d

File tree

2 files changed

+32
-47
lines changed

2 files changed

+32
-47
lines changed

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
import java.io.IOException;
2020
import javax.servlet.FilterChain;
2121
import javax.servlet.ServletException;
22+
import javax.servlet.ServletRequest;
23+
import javax.servlet.ServletResponse;
2224
import javax.servlet.http.HttpServletRequest;
2325
import javax.servlet.http.HttpServletResponse;
2426
import javax.servlet.http.HttpServletResponseWrapper;
2527

2628
import org.apache.commons.logging.Log;
2729
import org.apache.commons.logging.LogFactory;
2830

29-
import org.springframework.web.filter.OncePerRequestFilter;
31+
import org.springframework.web.filter.GenericFilterBean;
3032
import org.springframework.web.util.UrlPathHelper;
3133

3234
/**
@@ -41,16 +43,20 @@
4143
* @author Brian Clozel
4244
* @since 4.1
4345
*/
44-
public class ResourceUrlEncodingFilter extends OncePerRequestFilter {
46+
public class ResourceUrlEncodingFilter extends GenericFilterBean {
4547

4648
private static final Log logger = LogFactory.getLog(ResourceUrlEncodingFilter.class);
4749

4850

4951
@Override
50-
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
51-
throws ServletException, IOException {
52-
53-
filterChain.doFilter(request, new ResourceUrlEncodingResponseWrapper(request, response));
52+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
53+
throws IOException, ServletException {
54+
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
55+
throw new ServletException("ResourceUrlEncodingFilter just supports HTTP requests");
56+
}
57+
HttpServletRequest httpRequest = (HttpServletRequest) request;
58+
HttpServletResponse httpResponse = (HttpServletResponse) response;
59+
filterChain.doFilter(httpRequest, new ResourceUrlEncodingResponseWrapper(httpRequest, httpResponse));
5460
}
5561

5662

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

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,9 @@
1515
*/
1616
package org.springframework.web.servlet.resource;
1717

18-
import java.io.IOException;
1918
import java.util.Arrays;
2019
import java.util.Collections;
2120
import java.util.List;
22-
23-
import javax.servlet.FilterChain;
24-
import javax.servlet.ServletException;
25-
import javax.servlet.ServletRequest;
26-
import javax.servlet.ServletResponse;
2721
import javax.servlet.http.HttpServletResponse;
2822

2923
import org.junit.Before;
@@ -33,7 +27,7 @@
3327
import org.springframework.mock.web.test.MockHttpServletRequest;
3428
import org.springframework.mock.web.test.MockHttpServletResponse;
3529

36-
import static org.junit.Assert.*;
30+
import static org.junit.Assert.assertEquals;
3731

3832
/**
3933
* Unit tests for {@code ResourceUrlEncodingFilter}.
@@ -64,12 +58,9 @@ public void encodeURL() throws Exception {
6458
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
6559
MockHttpServletResponse response = new MockHttpServletResponse();
6660

67-
this.filter.doFilterInternal(request, response, new FilterChain() {
68-
@Override
69-
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
70-
String result = ((HttpServletResponse)response).encodeURL("/resources/bar.css");
71-
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", result);
72-
}
61+
this.filter.doFilter(request, response, (req, res) -> {
62+
String result = ((HttpServletResponse) res).encodeURL("/resources/bar.css");
63+
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", result);
7364
});
7465
}
7566

@@ -80,12 +71,9 @@ public void encodeURLWithContext() throws Exception {
8071
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
8172
MockHttpServletResponse response = new MockHttpServletResponse();
8273

83-
this.filter.doFilterInternal(request, response, new FilterChain() {
84-
@Override
85-
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
86-
String result = ((HttpServletResponse)response).encodeURL("/context/resources/bar.css");
87-
assertEquals("/context/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", result);
88-
}
74+
this.filter.doFilter(request, response, (req, res) -> {
75+
String result = ((HttpServletResponse) res).encodeURL("/context/resources/bar.css");
76+
assertEquals("/context/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", result);
8977
});
9078
}
9179

@@ -97,8 +85,8 @@ public void encodeContextPathUrlWithoutSuffix() throws Exception {
9785
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
9886
MockHttpServletResponse response = new MockHttpServletResponse();
9987

100-
this.filter.doFilterInternal(request, response, (request1, response1) -> {
101-
String result = ((HttpServletResponse) response1).encodeURL("/context/resources/bar.css");
88+
this.filter.doFilter(request, response, (req, res) -> {
89+
String result = ((HttpServletResponse) res).encodeURL("/context/resources/bar.css");
10290
assertEquals("/context/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", result);
10391
});
10492
}
@@ -110,8 +98,8 @@ public void encodeContextPathUrlWithSuffix() throws Exception {
11098
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
11199
MockHttpServletResponse response = new MockHttpServletResponse();
112100

113-
this.filter.doFilterInternal(request, response, (request1, response1) -> {
114-
String result = ((HttpServletResponse) response1).encodeURL("/context/resources/bar.css");
101+
this.filter.doFilter(request, response, (req, res) -> {
102+
String result = ((HttpServletResponse) res).encodeURL("/context/resources/bar.css");
115103
assertEquals("/context/resources/bar-11e16cf79faee7ac698c805cf28248d2.css", result);
116104
});
117105
}
@@ -124,12 +112,9 @@ public void encodeEmptyURLWithContext() throws Exception {
124112
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
125113
MockHttpServletResponse response = new MockHttpServletResponse();
126114

127-
this.filter.doFilterInternal(request, response, new FilterChain() {
128-
@Override
129-
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
130-
String result = ((HttpServletResponse)response).encodeURL("?foo=1");
131-
assertEquals("?foo=1", result);
132-
}
115+
this.filter.doFilter(request, response, (req, res) -> {
116+
String result = ((HttpServletResponse) res).encodeURL("?foo=1");
117+
assertEquals("?foo=1", result);
133118
});
134119
}
135120

@@ -141,12 +126,9 @@ public void encodeURLWithRequestParams() throws Exception {
141126
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
142127
MockHttpServletResponse response = new MockHttpServletResponse();
143128

144-
this.filter.doFilterInternal(request, response, new FilterChain() {
145-
@Override
146-
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
147-
String result = ((HttpServletResponse)response).encodeURL("/resources/bar.css?foo=bar&url=http://example.org");
148-
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css?foo=bar&url=http://example.org", result);
149-
}
129+
this.filter.doFilter(request, response, (req, res) -> {
130+
String result = ((HttpServletResponse) res).encodeURL("/resources/bar.css?foo=bar&url=http://example.org");
131+
assertEquals("/resources/bar-11e16cf79faee7ac698c805cf28248d2.css?foo=bar&url=http://example.org", result);
150132
});
151133
}
152134

@@ -159,12 +141,9 @@ public void encodeUrlPreventStringOutOfBounds() throws Exception {
159141
request.setAttribute(ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
160142
MockHttpServletResponse response = new MockHttpServletResponse();
161143

162-
this.filter.doFilterInternal(request, response, new FilterChain() {
163-
@Override
164-
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
165-
String result = ((HttpServletResponse)response).encodeURL("index?key=value");
166-
assertEquals("index?key=value", result);
167-
}
144+
this.filter.doFilter(request, response, (req, res) -> {
145+
String result = ((HttpServletResponse) res).encodeURL("index?key=value");
146+
assertEquals("index?key=value", result);
168147
});
169148
}
170149

0 commit comments

Comments
 (0)