Browse Source

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.
pull/6/head
Dave Syer 8 years ago
parent
commit
a38b7b71ac
  1. 30
      spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java
  2. 17
      spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java

30
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java

@ -163,15 +163,39 @@ public class PreDecorationFilter extends ZuulFilter { @@ -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();

17
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java

@ -103,6 +103,23 @@ public class PreDecorationFilterTests { @@ -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");

Loading…
Cancel
Save