Add Support for ForwardedHeaderFilter sendRedirect
Previously ForwrdedHeaderFilter did not ensure that HttpServletResponse.sendRedirect worked properly based on X-Forwarded-* headers. This commit updates ForwardedHeaderFilter to overrided the HttpServletResponse.sendRedirect method to ensure X-Forwarded-* headers are honored. Issue SPR-15020
This commit is contained in:
committed by
Rossen Stoyanchev
parent
e16d753439
commit
5e774e0b44
@@ -28,26 +28,31 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
* Filter that wraps the request in order to override its
|
||||
* Filter that wraps the request and response in order to override its
|
||||
* {@link HttpServletRequest#getServerName() getServerName()},
|
||||
* {@link HttpServletRequest#getServerPort() getServerPort()},
|
||||
* {@link HttpServletRequest#getScheme() getScheme()}, and
|
||||
* {@link HttpServletRequest#isSecure() isSecure()} methods with values derived
|
||||
* from "Forwarded" or "X-Forwarded-*" headers. In effect the wrapped request
|
||||
* reflects the client-originated protocol and address.
|
||||
* {@link HttpServletRequest#getScheme() getScheme()},
|
||||
* {@link HttpServletRequest#isSecure() isSecure()},
|
||||
* {@link HttpServletResponse#sendRedirect(String) sendRedirect(String)},
|
||||
* methods with values derived from "Forwarded" or "X-Forwarded-*"
|
||||
* headers. In effect the wrapped request and response reflects the
|
||||
* client-originated protocol and address.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Eddú Meléndez
|
||||
* @author Rob Winch
|
||||
* @since 4.3
|
||||
*/
|
||||
public class ForwardedHeaderFilter extends OncePerRequestFilter {
|
||||
@@ -93,7 +98,9 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
filterChain.doFilter(new ForwardedHeaderRequestWrapper(request, this.pathHelper), response);
|
||||
ForwardedHeaderRequestWrapper wrappedRequest = new ForwardedHeaderRequestWrapper(request, this.pathHelper);
|
||||
ForwardedHeaderResponseWrapper wrappedResponse = new ForwardedHeaderResponseWrapper(response, wrappedRequest);
|
||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
||||
}
|
||||
|
||||
|
||||
@@ -222,4 +229,52 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ForwardedHeaderResponseWrapper extends HttpServletResponseWrapper {
|
||||
|
||||
private static final String FOLDER_SEPARATOR = "/";
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
|
||||
public ForwardedHeaderResponseWrapper(HttpServletResponse response, HttpServletRequest request) {
|
||||
super(response);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRedirect(String location) throws IOException {
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(location);
|
||||
|
||||
// Absolute location
|
||||
if (builder.build().getScheme() != null) {
|
||||
super.sendRedirect(location);
|
||||
return;
|
||||
}
|
||||
|
||||
// Network-path reference
|
||||
if(location.startsWith("//")) {
|
||||
String scheme = this.request.getScheme();
|
||||
super.sendRedirect(builder.scheme(scheme).toUriString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Relative to Servlet container root or to current request
|
||||
String path;
|
||||
if (location.startsWith(FOLDER_SEPARATOR)) {
|
||||
path = this.request.getContextPath() + location;
|
||||
}
|
||||
else {
|
||||
path = StringUtils.applyRelativePath(this.request.getRequestURI(), location);
|
||||
}
|
||||
|
||||
String result = UriComponentsBuilder
|
||||
.fromHttpRequest(new ServletServerHttpRequest(this.request))
|
||||
.replacePath(path)
|
||||
.build().normalize().toUriString();
|
||||
|
||||
super.sendRedirect(result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user