Commit 7b270c4b by Dave Syer

Add support for X-Forwarded-Prefix to Zuul proxy

Fixes gh-43
parent 9c6474fb
......@@ -32,7 +32,7 @@ public class ProxyRouteLocator {
private AtomicReference<Map<String, ZuulRoute>> routes = new AtomicReference<>();
private Map<String, String> staticRoutes = new LinkedHashMap<String, String>();
private Map<String, ZuulRoute> staticRoutes = new LinkedHashMap<String, ZuulRoute>();
public ProxyRouteLocator(DiscoveryClient discovery, ZuulProperties properties) {
this.discovery = discovery;
......@@ -40,7 +40,12 @@ public class ProxyRouteLocator {
}
public void addRoute(String path, String location) {
staticRoutes.put(path, location);
staticRoutes.put(path, new ZuulRoute(path, location));
resetRoutes();
}
public void addRoute(ZuulRoute route) {
staticRoutes.put(route.getPath(), route);
resetRoutes();
}
......@@ -56,7 +61,7 @@ public class ProxyRouteLocator {
Map<String, String> values = new LinkedHashMap<String, String>();
for (String key : routes.get().keySet()) {
for (String key : routes.get().keySet()) {
String url = key;
values.put(url, routes.get().get(key).getLocation());
}
......@@ -67,26 +72,30 @@ public class ProxyRouteLocator {
public ProxyRouteSpec getMatchingRoute(String path) {
String location = null;
String targetPath = null;
String prefix = properties.getPrefix();
for (Entry<String, ZuulRoute> entry : routes.get().entrySet()) {
String pattern = entry.getKey();
if (pathMatcher.match(pattern, path)) {
ZuulRoute route = entry.getValue();
String prefix = properties.getPrefix();
location = route.getLocation();
targetPath = path;
if (path.startsWith(prefix) && properties.isStripPrefix()) {
targetPath = path.substring(prefix.length());
}
if (route.isStripPrefix()) {
int index = route.getPath().indexOf("*");
index = index > 0 ? index-1 : 0;
targetPath = path.substring(index);
int index = route.getPath().indexOf("*") - 1;
if (index > 0) {
targetPath = path.substring(prefix.length() + index);
prefix = prefix
+ path.substring(prefix.length(), prefix.length() + index);
}
}
break;
}
}
return location==null ? null : new ProxyRouteSpec(targetPath, location);
return location == null ? null : new ProxyRouteSpec(targetPath, location, prefix);
}
// Package access so ZuulHandlerMapping can reset it's mappings
void resetRoutes() {
routes.set(locateRoutes());
......@@ -97,7 +106,7 @@ public class ProxyRouteLocator {
LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
addConfiguredRoutes(routesMap);
addStaticRoutes(routesMap);
routesMap.putAll(staticRoutes);
// Add routes for discovery services by default
List<String> services = discovery.getServices();
......@@ -120,7 +129,7 @@ public class ProxyRouteLocator {
LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
for (Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
String path = entry.getKey();
// Prepend with slash if not already present.
if (!path.startsWith("/")) {
......@@ -133,7 +142,7 @@ public class ProxyRouteLocator {
path = "/" + path;
}
}
values.put(path, entry.getValue());
}
......@@ -142,12 +151,6 @@ public class ProxyRouteLocator {
}
protected void addStaticRoutes(LinkedHashMap<String, ZuulRoute> routes) {
for (Entry<String, String> entry : staticRoutes.entrySet()) {
routes.put(entry.getKey(), new ZuulRoute(entry.getKey(), entry.getValue()));
}
}
protected void addConfiguredRoutes(Map<String, ZuulRoute> routes) {
Map<String, ZuulRoute> routeEntries = properties.getRoutesWithDefaultServiceIds();
for (ZuulRoute entry : routeEntries.values()) {
......@@ -162,13 +165,14 @@ public class ProxyRouteLocator {
public String getTargetPath(String matchingRoute, String requestURI) {
String path = getRoutes().get(matchingRoute);
if (path==null) {
if (path == null) {
path = requestURI;
} else {
}
else {
}
return path;
}
@Data
......@@ -176,6 +180,7 @@ public class ProxyRouteLocator {
public static class ProxyRouteSpec {
private String path;
private String location;
private String prefix;
}
}
......@@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.ProxyRouteLocator;
import org.springframework.cloud.netflix.zuul.ProxyRouteLocator.ProxyRouteSpec;
import org.springframework.cloud.netflix.zuul.ZuulProperties;
import org.springframework.util.StringUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
......@@ -49,7 +50,7 @@ public class PreDecorationFilter extends ZuulFilter {
ProxyRouteSpec route = routeLocator.getMatchingRoute(requestURI);
if (route!=null) {
if (route != null) {
String location = route.getLocation();
......@@ -73,6 +74,9 @@ public class PreDecorationFilter extends ZuulFilter {
"X-Forwarded-Host",
ctx.getRequest().getServerName() + ":"
+ String.valueOf(ctx.getRequest().getServerPort()));
if (StringUtils.hasText(route.getPrefix())) {
ctx.addZuulRequestHeader("X-Forwarded-Prefix", route.getPrefix());
}
}
}
}
......
package org.springframework.cloud.netflix.zuul.filters.pre;
import static org.junit.Assert.assertEquals;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.zuul.ProxyRouteLocator;
import org.springframework.cloud.netflix.zuul.ZuulProperties;
import org.springframework.cloud.netflix.zuul.ZuulProperties.ZuulRoute;
import org.springframework.mock.web.MockHttpServletRequest;
import com.netflix.util.Pair;
import com.netflix.zuul.context.RequestContext;
/**
* @author Dave Syer
*
*/
public class PreDecorationFilterTests {
private PreDecorationFilter filter;
@Mock
DiscoveryClient discovery;
private ZuulProperties properties = new ZuulProperties();
private ProxyRouteLocator routeLocator;
private MockHttpServletRequest request = new MockHttpServletRequest();
@Before
public void init() {
initMocks(this);
routeLocator = new ProxyRouteLocator(discovery, properties);
filter = new PreDecorationFilter(routeLocator, properties);
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setRequest(request);
}
@Test
public void basicProperties() throws Exception {
assertEquals(5, filter.filterOrder());
assertEquals(true, filter.shouldFilter());
assertEquals("pre", filter.filterType());
}
@Test
public void prefixRouteAddsHeader() throws Exception {
properties.setPrefix("/api");
properties.setStripPrefix(true);
request.setRequestURI("/api/foo/1");
routeLocator.addRoute("/foo/**", "foo");
filter.run();
RequestContext ctx = RequestContext.getCurrentContext();
assertEquals("/foo/1", ctx.get("requestURI"));
assertEquals("localhost:80", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
assertEquals("/api", ctx.getZuulRequestHeaders().get("x-forwarded-prefix"));
assertEquals("foo", getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
}
@Test
public void prefixRouteWithRouteStrippingAddsHeader() throws Exception {
properties.setPrefix("/api");
properties.setStripPrefix(true);
request.setRequestURI("/api/foo/1");
routeLocator.addRoute(new ZuulRoute("/foo/**", "foo", null, true));
filter.run();
RequestContext ctx = RequestContext.getCurrentContext();
assertEquals("/1", ctx.get("requestURI"));
assertEquals("localhost:80", ctx.getZuulRequestHeaders().get("x-forwarded-host"));
assertEquals("/api/foo", ctx.getZuulRequestHeaders().get("x-forwarded-prefix"));
assertEquals("foo", getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid"));
}
private Object getHeader(List<Pair<String, String>> headers,
String key) {
String value = null;
for (Pair<String, String> pair : headers) {
if (pair.first().toLowerCase().equals(key.toLowerCase())) {
value = pair.second();
break;
}
}
return value;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment