Browse Source

Merge pull request #1071 from eddumelendez/SPR-14270

pull/1160/head
Rossen Stoyanchev 10 years ago
parent
commit
b7f589547d
  1. 36
      spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java
  2. 36
      spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java

36
spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java

@ -34,20 +34,23 @@ import org.springframework.http.HttpRequest;
import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
/** /**
* Filter that wraps the request in order to override its * Filter that wraps the request in order to override its
* {@link HttpServletRequest#getServerName() getServerName()}, * {@link HttpServletRequest#getServerName() getServerName()},
* {@link HttpServletRequest#getServerPort() getServerPort()}, * {@link HttpServletRequest#getServerPort() getServerPort()},
* {@link HttpServletRequest#getScheme() getScheme()}, and * {@link HttpServletRequest#getScheme() getScheme()}, and
* {@link HttpServletRequest#isSecure() isSecure()} methods with values derived * {@link HttpServletRequest#isSecure() isSecure()} methods with values derived
* from "Fowarded" or "X-Forwarded-*" headers. In effect the wrapped request * from "Forwarded" or "X-Forwarded-*" headers. In effect the wrapped request
* reflects the client-originated protocol and address. * reflects the client-originated protocol and address.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Eddú Meléndez
* @since 4.3 * @since 4.3
*/ */
public class ForwardedHeaderFilter extends OncePerRequestFilter { public class ForwardedHeaderFilter extends OncePerRequestFilter {
@ -55,11 +58,12 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
private static final Set<String> FORWARDED_HEADER_NAMES; private static final Set<String> FORWARDED_HEADER_NAMES;
static { static {
FORWARDED_HEADER_NAMES = new HashSet<String>(4); FORWARDED_HEADER_NAMES = new HashSet<String>(5);
FORWARDED_HEADER_NAMES.add("Forwarded"); FORWARDED_HEADER_NAMES.add("Forwarded");
FORWARDED_HEADER_NAMES.add("X-Forwarded-Host"); FORWARDED_HEADER_NAMES.add("X-Forwarded-Host");
FORWARDED_HEADER_NAMES.add("X-Forwarded-Port"); FORWARDED_HEADER_NAMES.add("X-Forwarded-Port");
FORWARDED_HEADER_NAMES.add("X-Forwarded-Proto"); FORWARDED_HEADER_NAMES.add("X-Forwarded-Proto");
FORWARDED_HEADER_NAMES.add("X-Forwarded-Prefix");
} }
@ -131,6 +135,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
private final Map<String, List<String>> headers; private final Map<String, List<String>> headers;
public ForwardedHeaderRequestWrapper(HttpServletRequest request, ContextPathHelper pathHelper) { public ForwardedHeaderRequestWrapper(HttpServletRequest request, ContextPathHelper pathHelper) {
super(request); super(request);
@ -143,13 +148,23 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
this.host = uriComponents.getHost(); this.host = uriComponents.getHost();
this.port = (port == -1 ? (this.secure ? 443 : 80) : port); this.port = (port == -1 ? (this.secure ? 443 : 80) : port);
this.contextPath = (pathHelper != null ? pathHelper.getContextPath(request) : request.getContextPath()); this.contextPath = initContextPath(request, pathHelper);
this.requestUri = (pathHelper != null ? pathHelper.getRequestUri(request) : request.getRequestURI()); this.requestUri = initRequestUri(request, pathHelper);
this.requestUrl = initRequestUrl(this.scheme, this.host, port, this.requestUri); this.requestUrl = initRequestUrl(this.scheme, this.host, port, this.requestUri);
this.headers = initHeaders(request); this.headers = initHeaders(request);
} }
private static String initContextPath(HttpServletRequest request, ContextPathHelper pathHelper) {
String contextPath = (pathHelper != null ? pathHelper.getContextPath(request) : request.getContextPath());
return prependForwardedPrefix(request, contextPath);
}
private static String initRequestUri(HttpServletRequest request, ContextPathHelper pathHelper) {
String requestUri = (pathHelper != null ? pathHelper.getRequestUri(request) : request.getRequestURI());
return prependForwardedPrefix(request, requestUri);
}
private static StringBuffer initRequestUrl(String scheme, String host, int port, String path) { private static StringBuffer initRequestUrl(String scheme, String host, int port, String path) {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append(scheme).append("://").append(host); sb.append(scheme).append("://").append(host);
@ -174,6 +189,17 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
return headers; return headers;
} }
private static String prependForwardedPrefix(HttpServletRequest request, String value) {
String header = request.getHeader("X-Forwarded-Prefix");
if (StringUtils.hasText(header)) {
while (header.endsWith("/")) {
header = header.substring(0, header.length() - 1);
}
value = header + value;
}
return value;
}
@Override @Override
public String getScheme() { public String getScheme() {

36
spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java

@ -35,6 +35,7 @@ import static org.junit.Assert.assertTrue;
/** /**
* Unit tests for {@link ForwardedHeaderFilter}. * Unit tests for {@link ForwardedHeaderFilter}.
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Eddú Meléndez
*/ */
public class ForwardedHeaderFilterTests { public class ForwardedHeaderFilterTests {
@ -170,6 +171,41 @@ public class ForwardedHeaderFilterTests {
assertEquals("bar", actual.getHeader("foo")); assertEquals("bar", actual.getHeader("foo"));
} }
@Test
public void requestUriWithForwardedPrefix() throws Exception {
this.request.addHeader("X-Forwarded-Prefix", "/prefix");
this.request.setRequestURI("/mvc-showcase");
HttpServletRequest actual = filterAndGetWrappedRequest();
assertEquals("http://localhost/prefix/mvc-showcase", actual.getRequestURL().toString());
}
@Test
public void requestUriWithForwardedPrefixTrailingSlash() throws Exception {
this.request.addHeader("X-Forwarded-Prefix", "/prefix/");
this.request.setRequestURI("/mvc-showcase");
HttpServletRequest actual = filterAndGetWrappedRequest();
assertEquals("http://localhost/prefix/mvc-showcase", actual.getRequestURL().toString());
}
@Test
public void contextPathWithForwardedPrefix() throws Exception {
this.request.addHeader("X-Forwarded-Prefix", "/prefix");
this.request.setContextPath("/mvc-showcase");
String actual = filterAndGetContextPath();
assertEquals("/prefix/mvc-showcase", actual);
}
@Test
public void contextPathWithForwardedPrefixTrailingSlash() throws Exception {
this.request.addHeader("X-Forwarded-Prefix", "/prefix/");
this.request.setContextPath("/mvc-showcase");
String actual = filterAndGetContextPath();
assertEquals("/prefix/mvc-showcase", actual);
}
private String filterAndGetContextPath() throws ServletException, IOException { private String filterAndGetContextPath() throws ServletException, IOException {
return filterAndGetWrappedRequest().getContextPath(); return filterAndGetWrappedRequest().getContextPath();

Loading…
Cancel
Save