Commit 065d91fd by Dave Syer

Allow user to map physical routes in zuul.route

E.g. zuul: route: testclient: /testing123/** # service mapping http://localhost:8081: /stores/** # physical mapping
parent ce1fcb15
......@@ -2,9 +2,6 @@ package org.springframework.cloud.netflix.zuul;
import java.util.Map;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.http.ZuulServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
......@@ -17,9 +14,13 @@ import org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter;
import org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.http.ZuulServlet;
/**
* @author Spencer Gibb
*/
......@@ -69,7 +70,7 @@ public class ZuulConfiguration {
@Bean
public PreDecorationFilter preDecorationFilter() {
return new PreDecorationFilter();
return new PreDecorationFilter(routes(), zuulProperties);
}
@Bean
......@@ -87,6 +88,11 @@ public class ZuulConfiguration {
return filter;
}
@Bean
public SimpleHostRoutingFilter simpleHostRoutingFilter() {
return new SimpleHostRoutingFilter();
}
// post filters
@Bean
public SendResponseFilter sendResponseFilter() {
......
package org.springframework.cloud.netflix.zuul.filters.pre;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import static com.google.common.collect.Iterables.tryFind;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.RouteLocator;
import org.springframework.cloud.netflix.zuul.ZuulProperties;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import static com.google.common.collect.Iterables.*;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
public class PreDecorationFilter extends ZuulFilter {
private static Logger LOG = LoggerFactory.getLogger(PreDecorationFilter.class);
@Autowired
private RouteLocator routeLocator;
@Autowired
private ZuulProperties properties;
private PathMatcher pathMatcher = new AntPathMatcher();
public PreDecorationFilter(RouteLocator routeLocator, ZuulProperties properties) {
this.routeLocator = routeLocator;
this.properties = properties;
}
@Override
public int filterOrder() {
return 5;
......@@ -53,9 +60,12 @@ public class PreDecorationFilter extends ZuulFilter {
String proxyMapping = properties.getMapping();
final String uriPart;
if (properties.isStripMapping()) {
uriPart = requestURI.replace(proxyMapping, ""); //TODO: better strategy?
} else {
if (StringUtils.hasText(proxyMapping) && properties.isStripMapping()
&& requestURI.startsWith(proxyMapping)) {
// TODO: better strategy?
uriPart = requestURI.substring(proxyMapping.length());
}
else {
uriPart = requestURI;
}
ctx.put("requestURI", uriPart);
......@@ -70,22 +80,42 @@ public class PreDecorationFilter extends ZuulFilter {
});
if (route.isPresent()) {
String serviceId = routesMap.get(route.get());
String target = routesMap.get(route.get());
if (target != null) {
if (serviceId != null) {
if (target.startsWith("http:") || target.startsWith("https:")) {
ctx.setRouteHost(getUrl(target));
ctx.addOriginResponseHeader("X-Zuul-Service", target);
}
else {
// set serviceId for use in filters.route.RibbonRequest
ctx.set("serviceId", serviceId);
ctx.set("serviceId", target);
ctx.setRouteHost(null);
ctx.addOriginResponseHeader("X-Zuul-ServiceId", serviceId);
ctx.addOriginResponseHeader("X-Zuul-ServiceId", target);
}
if (properties.isAddProxyHeaders()) {
ctx.addZuulRequestHeader("X-Forwarded-Host", ctx.getRequest().getServerName() + ":" + String.valueOf(ctx.getRequest().getServerPort()));
ctx.addZuulRequestHeader(
"X-Forwarded-Host",
ctx.getRequest().getServerName() + ":"
+ String.valueOf(ctx.getRequest().getServerPort()));
}
}
} else {
LOG.warn("No route found for uri: "+requestURI);
}
else {
LOG.warn("No route found for uri: " + requestURI);
ctx.set("error.status_code", HttpServletResponse.SC_NOT_FOUND);
}
return null;
}
private URL getUrl(String target) {
try {
return new URL(target);
}
catch (MalformedURLException e) {
throw new IllegalStateException("Target URL is malformed", e);
}
}
}
package org.springframework.cloud.netflix.zuul.filters.route;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.constants.ZuulConstants;
import com.netflix.zuul.context.Debug;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.util.HTTPRequestUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.params.ClientPNames;
......@@ -37,23 +54,16 @@ import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.constants.ZuulConstants;
import com.netflix.zuul.context.Debug;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.util.HTTPRequestUtils;
public class SimpleHostRoutingFilter extends ZuulFilter {
......@@ -100,9 +110,6 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
}, 30000, 5000);
}
public SimpleHostRoutingFilter() {
}
private static final ClientConnectionManager newConnectionManager() throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
......@@ -195,15 +202,16 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
}
public Object run() {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
Header[] headers = buildZuulRequestHeaders(request);
String verb = getVerb(request);
InputStream requestEntity = getRequestBody(request);
HttpClient httpclient = CLIENT.get();
String uri = request.getRequestURI();
if (RequestContext.getCurrentContext().get("requestURI") != null) {
uri = (String) RequestContext.getCurrentContext().get("requestURI");
if (context.get("requestURI") != null) {
uri = (String) context.get("requestURI");
}
try {
......@@ -212,10 +220,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
setResponse(response);
}
catch (Exception e) {
if (Debug.debugRequest()) {
Debug.addRequestDebug("ZUUL:: ERROR " + e.getMessage());
}
throw new RuntimeException(e);
context.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
context.set("error.exception", e);
}
return null;
}
......
......@@ -41,28 +41,66 @@ public class RouteLocatorTests {
public void testGetRoutes() {
ZuulProperties properties = new ZuulProperties();
RouteLocator routeLocator = new RouteLocator(this.discovery, properties);
properties.setIgnoredServices(Lists.newArrayList(IGNOREDSERVICE));
properties.getRoute().put(ASERVICE, "/"+ASERVICE + "/**");
when(discovery.getServices()).thenReturn(
Lists.newArrayList(MYSERVICE, IGNOREDSERVICE));
Map<String, String> routesMap = routeLocator.getRoutes();
assertNotNull("routesMap was null", routesMap);
assertFalse("routesMap was empty", routesMap.isEmpty());
assertMapping(routesMap, MYSERVICE);
assertMapping(routesMap, ASERVICE);
}
@Test
public void testGetPhysicalRoutes() {
ZuulProperties properties = new ZuulProperties();
RouteLocator routeLocator = new RouteLocator(this.discovery, properties);
properties.getRoute().put("http://" + ASERVICE, "/"+ASERVICE + "/**");
Map<String, String> routesMap = routeLocator.getRoutes();
assertNotNull("routesMap was null", routesMap);
assertFalse("routesMap was empty", routesMap.isEmpty());
assertMapping(routesMap, "http://" + ASERVICE, ASERVICE);
}
@Test
public void testIgnoreRoutes() {
ZuulProperties properties = new ZuulProperties();
RouteLocator routeLocator = new RouteLocator(this.discovery, properties);
properties.setIgnoredServices(Lists.newArrayList(IGNOREDSERVICE));
when(discovery.getServices()).thenReturn(
Lists.newArrayList(IGNOREDSERVICE));
Map<String, String> routesMap = routeLocator.getRoutes();
String serviceId = routesMap.get(getMapping(IGNOREDSERVICE));
assertNull("routes did not ignore " + IGNOREDSERVICE, serviceId);
}
protected void assertMapping(Map<String, String> routesMap, String expectedServiceId) {
String mapping = getMapping(expectedServiceId);
String serviceId = routesMap.get(mapping);
assertEquals("routesMap had wrong value for " + mapping, expectedServiceId,
serviceId);
@Test
public void testAutoRoutes() {
ZuulProperties properties = new ZuulProperties();
RouteLocator routeLocator = new RouteLocator(this.discovery, properties);
when(discovery.getServices()).thenReturn(
Lists.newArrayList(MYSERVICE));
Map<String, String> routesMap = routeLocator.getRoutes();
assertNotNull("routesMap was null", routesMap);
assertFalse("routesMap was empty", routesMap.isEmpty());
assertMapping(routesMap, MYSERVICE);
}
protected void assertMapping(Map<String, String> routesMap, String serviceId) {
assertMapping(routesMap, serviceId, serviceId);
}
protected void assertMapping(Map<String, String> routesMap, String expectedRoute, String key) {
String mapping = getMapping(key);
String route = routesMap.get(mapping);
assertEquals("routesMap had wrong value for " + mapping, expectedRoute,
route);
}
private String getMapping(String serviceId) {
......
......@@ -17,5 +17,5 @@ zuul:
#mapping: /api
#strip-mapping: true
route:
testclient: /testing123
#stores: /
testclient: /testing123/**
http://localhost:8081: /stores/**
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