Append to X-Forwarded-* headers instead of replacing them
This fixes most of the issues people encounter when there are multiple proxies in the request. The tricky thing is that there is another header "Forwarded" that we don't recognize, but which backends probably do, at least some of the time (since it is from an actual RFC). The problem is that "Forwarded" does not contain the ports, so Spring UriComponentsBuilder cannot use it to rewrite links to a specific port. Since we do not support it already, this change doesn't make things any worse, but the corner case is there still.
This commit is contained in:
@@ -163,15 +163,39 @@ public class PreDecorationFilter extends ZuulFilter {
|
||||
}
|
||||
|
||||
private void addProxyHeaders(RequestContext ctx, Route route) {
|
||||
String host = toHostHeader(ctx.getRequest());
|
||||
String port = String.valueOf(ctx.getRequest().getServerPort());
|
||||
String proto = ctx.getRequest().getScheme();
|
||||
HttpServletRequest request = ctx.getRequest();
|
||||
String host = toHostHeader(request);
|
||||
String port = String.valueOf(request.getServerPort());
|
||||
String proto = request.getScheme();
|
||||
if (hasHeader(request, "X-Forwarded-Host")) {
|
||||
host = request.getHeader("X-Forwarded-Host") + "," + host;
|
||||
if (!hasHeader(request, "X-Forwarded-Port")) {
|
||||
if (hasHeader(request, "X-Forwarded-Proto")) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String previous : StringUtils.commaDelimitedListToStringArray(request.getHeader("X-Forwarded-Proto"))) {
|
||||
if (builder.length()>0) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append("https".equals(previous) ? "443" : "80");
|
||||
}
|
||||
builder.append(",").append(port);
|
||||
port = builder.toString();
|
||||
}
|
||||
} else {
|
||||
port = request.getHeader("X-Forwarded-Port") + "," + port;
|
||||
}
|
||||
proto = request.getHeader("X-Forwarded-Proto") + "," + proto;
|
||||
}
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Host", host);
|
||||
ctx.addZuulRequestHeader("X-Forwarded-Port", port);
|
||||
ctx.addZuulRequestHeader(ZuulHeaders.X_FORWARDED_PROTO, proto);
|
||||
addProxyPrefix(ctx, route);
|
||||
}
|
||||
|
||||
private boolean hasHeader(HttpServletRequest request, String name) {
|
||||
return StringUtils.hasLength(request.getHeader(name));
|
||||
}
|
||||
|
||||
private void addProxyPrefix(RequestContext ctx, Route route) {
|
||||
String forwardedPrefix = ctx.getRequest().getHeader("X-Forwarded-Prefix");
|
||||
String contextPath = ctx.getRequest().getContextPath();
|
||||
|
||||
@@ -103,6 +103,23 @@ public class PreDecorationFilterTests {
|
||||
assertEquals("localhost:8080", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xForwardedHostAppends() throws Exception {
|
||||
this.properties.setPrefix("/api");
|
||||
this.request.setRequestURI("/api/foo/1");
|
||||
this.request.setRemoteAddr("5.6.7.8");
|
||||
this.request.setServerPort(8080);
|
||||
this.request.addHeader("X-Forwarded-Host", "example.com");
|
||||
this.request.addHeader("X-Forwarded-Proto", "https");
|
||||
this.routeLocator.addRoute(
|
||||
new ZuulRoute("foo", "/foo/**", "foo", null, false, null, null));
|
||||
this.filter.run();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
assertEquals("example.com,localhost:8080", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
|
||||
assertEquals("443,8080", ctx.getZuulRequestHeaders().get("x-forwarded-port"));
|
||||
assertEquals("https,http", ctx.getZuulRequestHeaders().get("x-forwarded-proto"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostHeaderSet() throws Exception {
|
||||
this.properties.setPrefix("/api");
|
||||
|
||||
Reference in New Issue
Block a user