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:
Dave Syer
2016-10-25 12:56:49 +01:00
parent 139ab95438
commit a38b7b71ac
2 changed files with 44 additions and 3 deletions

View File

@@ -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();

View File

@@ -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");