From e2e193eaa7529ccc5ca5a6355952329097ef7b1f Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Tue, 4 Nov 2014 15:17:35 -0700 Subject: [PATCH] added support for standalone zuul server with @EnableZuulServer. Removed old zuul module. fixes gh-14 --- .../main/asciidoc/spring-cloud-netflix.adoc | 15 +- pom.xml | 2 +- .../zuul/AbstractZuulConfiguration.java | 81 ++++ .../cloud/netflix/zuul/Routes.java | 5 - .../cloud/netflix/zuul/ZuulProperties.java | 11 + .../netflix/zuul/ZuulProxyConfiguration.java | 94 ++-- .../netflix/zuul/ZuulProxyProperties.java | 2 + .../zuul/filters/pre/PreDecorationFilter.java | 8 +- ...ication.java => ZuulProxyApplication.java} | 6 +- ...ts.java => ZuulProxyApplicationTests.java} | 4 +- .../src/test/resources/application.yml | 8 +- spring-cloud-netflix-zuul-server/pom.xml | 77 ++++ .../cloud/netflix/zuul/EnableZuulServer.java | 19 + .../netflix/zuul/ZuulServerConfiguration.java | 54 +++ .../netflix/zuul/ZuulServerProperties.java | 16 + .../netflix/zuul/ZuulServerApplication.java | 16 + .../zuul/ZuulServerApplicationTests.java | 20 + .../src/test/resources/application.yml | 15 + spring-cloud-netflix-zuul/pom.xml | 84 ---- .../cloud/netflix/zuul/Application.java | 69 --- .../cloud/netflix/zuul/FilterIntializer.java | 65 --- .../cloud/netflix/zuul/ZuulController.java | 28 -- .../cloud/netflix/zuul/ZuulProperties.java | 32 -- .../AbstractServletWrappingController.java | 42 -- .../main/resources/META-INF/spring.factories | 8 - .../src/main/resources/application.yml | 48 -- .../src/main/resources/bootstrap.yml | 6 - .../filters/post/SendResponse.groovy | 170 ------- .../main/resources/filters/post/Stats.groovy | 43 -- .../main/resources/filters/pre/Debug.groovy | 42 -- .../resources/filters/pre/DebugRequest.groovy | 55 --- .../filters/pre/PreDecorationFilter.groovy | 52 --- .../filters/route/RibbonRequest.groovy | 284 ------------ .../filters/route/SimpleHostRequest.groovy | 434 ------------------ 34 files changed, 368 insertions(+), 1547 deletions(-) create mode 100644 spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/AbstractZuulConfiguration.java create mode 100644 spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProperties.java rename spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/{Application.java => ZuulProxyApplication.java} (81%) rename spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/{ApplicationTests.java => ZuulProxyApplicationTests.java} (82%) create mode 100644 spring-cloud-netflix-zuul-server/pom.xml create mode 100644 spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/EnableZuulServer.java create mode 100644 spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerConfiguration.java create mode 100644 spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerProperties.java create mode 100644 spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplication.java create mode 100644 spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplicationTests.java create mode 100644 spring-cloud-netflix-zuul-server/src/test/resources/application.yml delete mode 100644 spring-cloud-netflix-zuul/pom.xml delete mode 100644 spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/Application.java delete mode 100644 spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/FilterIntializer.java delete mode 100644 spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulController.java delete mode 100644 spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulProperties.java delete mode 100644 spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/util/AbstractServletWrappingController.java delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/META-INF/spring.factories delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/application.yml delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/bootstrap.yml delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/filters/post/SendResponse.groovy delete mode 100755 spring-cloud-netflix-zuul/src/main/resources/filters/post/Stats.groovy delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/filters/pre/Debug.groovy delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/filters/pre/DebugRequest.groovy delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/filters/pre/PreDecorationFilter.groovy delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/filters/route/RibbonRequest.groovy delete mode 100644 spring-cloud-netflix-zuul/src/main/resources/filters/route/SimpleHostRequest.groovy diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index a715542f..68c1bd71 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -432,9 +432,20 @@ Zuul's rule engine allows rules and filters to be written in essentially any JVM [[netflix-zuul-reverse-proxy]] === Embedded Zuul Reverse Proxy -Spring Cloud has created an embedded Zuul proxy to ease the development of a very common use case where a UI application wants to proxy calls to one or more back end services. To enable it, annotate a Spring Boot main class with `@EnableZuulProxy`. This forwards local calls to `/proxy/*` to the appropriate service. The proxy uses Ribbon to locate an instance to forward to via Eureka. Forwarding to the service is protected by a Hystrix circuit breaker. Rules are configured via the Spring environment. The Config Server is an ideal place for the Zuul configuration. Configuration rules look like the following: +Spring Cloud has created an embedded Zuul proxy to ease the development of a very common use case where a UI application wants to proxy calls to one or more back end services. To enable it, annotate a Spring Boot main class with `@EnableZuulProxy`. This forwards local calls to `/proxy/*` to the appropriate service. The proxy uses Ribbon to locate an instance to forward to via Eureka. Forwarding to the service is protected by a Hystrix circuit breaker. Rules are configured via the Spring environment. The Config Server is an ideal place for the Zuul configuration. Zuul Embedded Proxy configuration rules look like the following: zuul.proxy.route.users: /users -This means that http calls to /proxy/users to the users service. This proxy configuration is useful for services that host a user interface to proxy to the backend services it requires. +This means that http calls to /proxy/users get forwarded to the users service. This proxy configuration is useful for services that host a user interface to proxy to the backend services it requires. By default, the proxy mapping gets stripped from the request before forwarding. + +[[netflix-zuul-server]] +=== Standalone Zuul Server + +Spring Cloud has created a standalone Zuul server. To enable it, annotate a Spring Boot main class with `@EnableZuulServer`. This routes all calls to the appropriate service. The server uses Ribbon to locate an instance to forward to via Eureka. Forwarding to the service is protected by a Hystrix circuit breaker. Rules are configured via the Spring environment. The Config Server is an ideal place for the Zuul configuration. Zuul Server configuration rules look like the following: + + zuul.server.route.users: /users + +This means that http calls to /users get forwarded to the users service. + +Since zuul, by default, intercepts all requests (`/*`), to enable actuator, you should set the `management.port`. diff --git a/pom.xml b/pom.xml index ce717893..0172ce15 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ spring-cloud-netflix-hystrix-dashboard spring-cloud-netflix-eureka-server spring-cloud-netflix-turbine - spring-cloud-netflix-zuul + spring-cloud-netflix-zuul-server docs diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/AbstractZuulConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/AbstractZuulConfiguration.java new file mode 100644 index 00000000..85acfbf2 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/AbstractZuulConfiguration.java @@ -0,0 +1,81 @@ +package org.springframework.cloud.netflix.zuul; + +import com.netflix.zuul.context.ContextLifecycleFilter; +import com.netflix.zuul.http.ZuulServlet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.trace.TraceRepository; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter; +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.route.RibbonRoutingFilter; +import org.springframework.context.annotation.Bean; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author Spencer Gibb + */ +public abstract class AbstractZuulConfiguration { + + @Autowired(required=false) + private TraceRepository traces; + + protected abstract ZuulProperties getProperties(); + + @Bean + public Routes routes() { + return new Routes(getProperties().getRoutePrefix()); + } + + @Bean + public ServletRegistrationBean zuulServlet() { + return new ServletRegistrationBean(new ZuulServlet(), getProperties().getMapping()+"/*"); + } + + @Bean + public FilterRegistrationBean contextLifecycleFilter() { + Collection urlPatterns = new ArrayList<>(); + urlPatterns.add(getProperties().getMapping()+"/*"); + + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new ContextLifecycleFilter()); + filterRegistrationBean.setUrlPatterns(urlPatterns); + + return filterRegistrationBean; + } + + @Bean + public FilterInitializer zuulFilterInitializer() { + return new FilterInitializer(); + } + + // pre filters + @Bean + public DebugFilter debugFilter() { + return new DebugFilter(); + } + + @Bean + public PreDecorationFilter preDecorationFilter() { + return new PreDecorationFilter(); + } + + // route filters + @Bean + public RibbonRoutingFilter ribbonRoutingFilter() { + RibbonRoutingFilter filter = new RibbonRoutingFilter(); + if (traces!=null) { + filter.setTraces(traces); + } + return filter; + } + + // post filters + @Bean + public SendResponseFilter sendResponseFilter() { + return new SendResponseFilter(); + } + +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/Routes.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/Routes.java index 430f66d4..c0cf9d23 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/Routes.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/Routes.java @@ -25,11 +25,6 @@ public class Routes { private Field propertySourcesField; private String keyPrefix; - public Routes() { - keyPrefix = "zuul.proxy.route."; - initField(); - } - public Routes(String keyPrefix) { this.keyPrefix = keyPrefix; initField(); diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProperties.java new file mode 100644 index 00000000..837715e7 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProperties.java @@ -0,0 +1,11 @@ +package org.springframework.cloud.netflix.zuul; + +/** + * @author Spencer Gibb + */ +public interface ZuulProperties { + public String getMapping(); + public boolean isStripMapping(); + public String getRoutePrefix(); + public boolean isAddProxyHeaders(); +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyConfiguration.java index 0f9c1de0..b2802c1b 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyConfiguration.java @@ -1,23 +1,11 @@ package org.springframework.cloud.netflix.zuul; -import java.util.ArrayList; -import java.util.Collection; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.boot.context.embedded.FilterRegistrationBean; -import org.springframework.boot.context.embedded.ServletRegistrationBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter; -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.route.RibbonRoutingFilter; -import com.netflix.zuul.context.ContextLifecycleFilter; import com.netflix.zuul.http.ZuulServlet; /** @@ -27,65 +15,41 @@ import com.netflix.zuul.http.ZuulServlet; @EnableConfigurationProperties(ZuulProxyProperties.class) @ConditionalOnClass(ZuulServlet.class) @ConditionalOnExpression("${zuul.proxy.enabled:true}") -public class ZuulProxyConfiguration { - - @Autowired - private ZuulProxyProperties props; - - @Autowired(required=false) - private TraceRepository traces; +public class ZuulProxyConfiguration extends AbstractZuulConfiguration { @Bean - public FilterRegistrationBean contextLifecycleFilter() { - Collection urlPatterns = new ArrayList<>(); - urlPatterns.add(props.getMapping()+"/*"); - - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new ContextLifecycleFilter()); - filterRegistrationBean.setUrlPatterns(urlPatterns); - - return filterRegistrationBean; + public ZuulProxyProperties zuulProxyProperties() { + return new ZuulProxyProperties(); } @Bean - public ServletRegistrationBean zuulServlet() { - return new ServletRegistrationBean(new ZuulServlet(), props.getMapping()+"/*"); + //ZuulProxyProperties doesn't implement ZuulProperties so there are not 2 implementations (see ZuulServerConfiguration + public ZuulProperties zuulProperties() { + return new ZuulProperties() { + @Override + public String getMapping() { + return zuulProxyProperties().getMapping(); + } + + @Override + public boolean isStripMapping() { + return zuulProxyProperties().isStripMapping(); + } + + @Override + public String getRoutePrefix() { + return zuulProxyProperties().getRoutePrefix(); + } + + @Override + public boolean isAddProxyHeaders() { + return zuulProxyProperties().isAddProxyHeaders(); + } + }; } - @Bean - Routes routes() { - return new Routes(); + @Override + protected ZuulProperties getProperties() { + return zuulProperties(); } - - @Bean - FilterInitializer zuulFilterInitializer() { - return new FilterInitializer(); - } - - // pre filters - @Bean - public DebugFilter debugFilter() { - return new DebugFilter(); - } - - @Bean - public PreDecorationFilter preDecorationFilter() { - return new PreDecorationFilter(); - } - - // route filters - @Bean - public RibbonRoutingFilter ribbonRoutingFilter() { - RibbonRoutingFilter filter = new RibbonRoutingFilter(); - if (traces!=null) { - filter.setTraces(traces); - } - return filter; - } - - // post filters - @Bean - public SendResponseFilter sendResponseFilter() { - return new SendResponseFilter(); - } - } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyProperties.java index 80d30d20..81af0265 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyProperties.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulProxyProperties.java @@ -11,4 +11,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; public class ZuulProxyProperties { private String mapping = "/proxy"; private boolean stripMapping = true; // this is currently the default behaviour + private String routePrefix = "zuul.proxy.route."; + private boolean addProxyHeaders = false; // TODO: current CF demo's rely on this } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java index 1be07c07..f342e6f3 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.netflix.zuul.Routes; -import org.springframework.cloud.netflix.zuul.ZuulProxyProperties; +import org.springframework.cloud.netflix.zuul.ZuulProperties; import javax.annotation.Nullable; import java.util.LinkedHashMap; @@ -21,7 +21,7 @@ public class PreDecorationFilter extends ZuulFilter { private Routes routes; @Autowired - private ZuulProxyProperties properties; + private ZuulProperties properties; @Override public int filterOrder() { @@ -71,6 +71,10 @@ public class PreDecorationFilter extends ZuulFilter { ctx.set("serviceId", serviceId); ctx.setRouteHost(null); ctx.addOriginResponseHeader("X-Zuul-ServiceId", serviceId); + + if (properties.isAddProxyHeaders()) { + ctx.addZuulRequestHeader("X-Forwarded-Host", ctx.getRequest().getServerName() + ":" + String.valueOf(ctx.getRequest().getServerPort())); + } } } else { LOG.warn("No route found for uri: "+requestURI); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/Application.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ZuulProxyApplication.java similarity index 81% rename from spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/Application.java rename to spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ZuulProxyApplication.java index 40363afe..38128e6a 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/Application.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ZuulProxyApplication.java @@ -4,7 +4,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -14,8 +13,7 @@ import org.springframework.web.bind.annotation.RestController; @EnableAutoConfiguration @RestController @EnableZuulProxy -@EnableEurekaClient -public class Application { +public class ZuulProxyApplication { @RequestMapping("/testing123") public String testing123() { @@ -28,7 +26,7 @@ public class Application { } public static void main(String[] args) { - new SpringApplicationBuilder(Application.class).web(true).run(args); + new SpringApplicationBuilder(ZuulProxyApplication.class).web(true).run(args); } } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ApplicationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ZuulProxyApplicationTests.java similarity index 82% rename from spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ApplicationTests.java rename to spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ZuulProxyApplicationTests.java index e1e56c9d..528b9c8e 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ApplicationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/sample/ZuulProxyApplicationTests.java @@ -8,10 +8,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = Application.class) +@SpringApplicationConfiguration(classes = ZuulProxyApplication.class) @WebAppConfiguration @IntegrationTest("server.port=0") -public class ApplicationTests { +public class ZuulProxyApplicationTests { @Test public void contextLoads() { diff --git a/spring-cloud-netflix-core/src/test/resources/application.yml b/spring-cloud-netflix-core/src/test/resources/application.yml index 20dbfa6b..37b93257 100644 --- a/spring-cloud-netflix-core/src/test/resources/application.yml +++ b/spring-cloud-netflix-core/src/test/resources/application.yml @@ -10,8 +10,8 @@ eureka: zuul: proxy: mapping: /api - stripMapping: false + stripMapping: true route: - testclient: /api/testing123 - stores: /api/stores - customers: /api/customers + testclient: /testing123 + stores: /stores + customers: /customers diff --git a/spring-cloud-netflix-zuul-server/pom.xml b/spring-cloud-netflix-zuul-server/pom.xml new file mode 100644 index 00000000..c81fe7d8 --- /dev/null +++ b/spring-cloud-netflix-zuul-server/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + spring-cloud-netflix-zuul-server + jar + Spring Cloud Netflix Zuul Server + http://projects.spring.io/spring-cloud/ + + org.springframework.cloud + spring-cloud-netflix + 1.0.0.BUILD-SNAPSHOT + .. + + + + + + + + + + + + + org.springframework.cloud + spring-cloud-netflix-core + + + com.netflix.eureka + eureka-client + + + com.netflix.hystrix + hystrix-core + + + com.netflix.hystrix + hystrix-metrics-event-stream + + + com.netflix.hystrix + hystrix-javanica + + + com.netflix.ribbon + ribbon + + + com.netflix.ribbon + ribbon-core + + + com.netflix.ribbon + ribbon-eureka + + + com.netflix.ribbon + ribbon-httpclient + + + com.netflix.zuul + zuul-core + + + org.projectlombok + lombok + + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + diff --git a/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/EnableZuulServer.java b/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/EnableZuulServer.java new file mode 100644 index 00000000..dede28d5 --- /dev/null +++ b/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/EnableZuulServer.java @@ -0,0 +1,19 @@ +package org.springframework.cloud.netflix.zuul; + +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.cloud.netflix.hystrix.EnableHystrix; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.*; + +/** + * @author Spencer Gibb + */ +@EnableHystrix +@EnableEurekaClient +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(ZuulServerConfiguration.class) +public @interface EnableZuulServer { +} diff --git a/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerConfiguration.java b/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerConfiguration.java new file mode 100644 index 00000000..9b22b0e0 --- /dev/null +++ b/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerConfiguration.java @@ -0,0 +1,54 @@ +package org.springframework.cloud.netflix.zuul; + +import com.netflix.zuul.http.ZuulServlet; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Spencer Gibb + */ +@Configuration +@ConditionalOnClass(ZuulServlet.class) +@EnableConfigurationProperties(ZuulServerProperties.class) +@ConditionalOnExpression("${zuul.server.enabled:true}") +public class ZuulServerConfiguration extends AbstractZuulConfiguration { + + @Bean + public ZuulServerProperties zuulServerProperties() { + return new ZuulServerProperties(); + } + + @Bean + //ZuulServerProperties doesn't implement ZuulProperties so there are not 2 implementations (see ZuulProxyConfiguration + public ZuulProperties zuulProperties() { + return new ZuulProperties() { + @Override + public String getMapping() { + return zuulServerProperties().getMapping(); + } + + @Override + public boolean isStripMapping() { + return zuulServerProperties().isStripMapping(); + } + + @Override + public String getRoutePrefix() { + return zuulServerProperties().getRoutePrefix(); + } + + @Override + public boolean isAddProxyHeaders() { + return zuulServerProperties().isAddProxyHeaders(); + } + }; + } + + @Override + protected ZuulProperties getProperties() { + return zuulProperties(); + } +} diff --git a/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerProperties.java b/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerProperties.java new file mode 100644 index 00000000..01d2bebd --- /dev/null +++ b/spring-cloud-netflix-zuul-server/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerProperties.java @@ -0,0 +1,16 @@ +package org.springframework.cloud.netflix.zuul; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Spencer Gibb + */ +@Data +@ConfigurationProperties("zuul.server") +public class ZuulServerProperties { + private String mapping = ""; + private boolean stripMapping = false; + private String routePrefix = "zuul.server.route."; + private boolean addProxyHeaders = true; +} diff --git a/spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplication.java b/spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplication.java new file mode 100644 index 00000000..5c9c105d --- /dev/null +++ b/spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplication.java @@ -0,0 +1,16 @@ +package org.springframework.cloud.netflix.zuul; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableAutoConfiguration +@EnableZuulServer +public class ZuulServerApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(ZuulServerApplication.class).web(true).run(args); + } + +} diff --git a/spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplicationTests.java b/spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplicationTests.java new file mode 100644 index 00000000..55b69182 --- /dev/null +++ b/spring-cloud-netflix-zuul-server/src/test/java/org/springframework/cloud/netflix/zuul/ZuulServerApplicationTests.java @@ -0,0 +1,20 @@ +package org.springframework.cloud.netflix.zuul; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = ZuulServerApplication.class) +@WebAppConfiguration +@IntegrationTest("server.port=0") +public class ZuulServerApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-cloud-netflix-zuul-server/src/test/resources/application.yml b/spring-cloud-netflix-zuul-server/src/test/resources/application.yml new file mode 100644 index 00000000..5d9b04a2 --- /dev/null +++ b/spring-cloud-netflix-zuul-server/src/test/resources/application.yml @@ -0,0 +1,15 @@ +server: + port: 9876 +management: + port: 9877 +spring: + application: + name: testzuulserver + +zuul: + server: + route: + testclient: /testing123 + stores: /stores + customers: /customers + diff --git a/spring-cloud-netflix-zuul/pom.xml b/spring-cloud-netflix-zuul/pom.xml deleted file mode 100644 index 4e2640f3..00000000 --- a/spring-cloud-netflix-zuul/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - 4.0.0 - spring-cloud-netflix-zuul - jar - Spring Cloud Netflix Zuul - http://projects.spring.io/spring-cloud/ - - org.springframework.cloud - spring-cloud-netflix - 1.0.0.BUILD-SNAPSHOT - .. - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - maven-deploy-plugin - - true - - - - - - - 1.0.0.BUILD-SNAPSHOT - - - - - - org.springframework.cloud - spring-cloud-config - ${spring-cloud-config.version} - pom - import - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.cloud - spring-cloud-netflix-core - - - org.springframework.cloud - spring-cloud-config-client - - - com.netflix.hystrix - hystrix-core - - - com.netflix.hystrix - hystrix-metrics-event-stream - - - com.netflix.ribbon - ribbon-core - - - com.netflix.ribbon - ribbon-eureka - - - com.netflix.ribbon - ribbon-httpclient - - - com.netflix.zuul - zuul-core - - - diff --git a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/Application.java b/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/Application.java deleted file mode 100644 index fbea9781..00000000 --- a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/Application.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.spring.cloud.netflix.zuul; - -import com.netflix.zuul.context.ContextLifecycleFilter; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.context.embedded.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.cloud.netflix.hystrix.HystrixStreamEndpoint; -import org.springframework.cloud.netflix.zuul.Routes; -import org.springframework.scheduling.annotation.EnableScheduling; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * User: spencergibb - * Date: 4/24/14 - * Time: 8:57 PM - */ -@Configuration -@EnableAutoConfiguration -@EnableScheduling -@ComponentScan(basePackageClasses = Application.class) -public class Application { - - @Bean - ZuulProperties routerProperties() { - return new ZuulProperties(); - } - - @Bean - public FilterRegistrationBean contextLifecycleFilter() { - Collection urlPatterns = new ArrayList<>(); - urlPatterns.add("/*"); - - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new ContextLifecycleFilter()); - filterRegistrationBean.setUrlPatterns(urlPatterns); - - return filterRegistrationBean; - } - - //TODO: replace with auto config - @Bean - HystrixStreamEndpoint hystrixStreamEndpoint() { - return new HystrixStreamEndpoint(); - } - - @Bean - Routes routes() { - return new Routes(); - } - - @Bean - FilterIntializer filterIntializer() { - return new FilterIntializer(); - } - - @Bean - ZuulController zuulController() { - return new ZuulController(); - } - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/FilterIntializer.java b/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/FilterIntializer.java deleted file mode 100644 index 896e2d70..00000000 --- a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/FilterIntializer.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.spring.cloud.netflix.zuul; - -import com.netflix.zuul.FilterFileManager; -import com.netflix.zuul.FilterLoader; -import com.netflix.zuul.groovy.GroovyCompiler; -import com.netflix.zuul.groovy.GroovyFileFilter; -import com.netflix.zuul.monitoring.MonitoringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -/** - * User: spencergibb - * Date: 4/24/14 - * Time: 9:23 PM - * TODO: .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) - */ -public class FilterIntializer implements ServletContextListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(FilterIntializer.class); - - @Autowired - ZuulProperties props; - - @Override - public void contextInitialized(ServletContextEvent sce) { - - LOGGER.info("Starting filter initialzer context listener"); - - //FIXME: mocks monitoring infrastructure as we don't need it for this simple app - MonitoringHelper.initMocks(); - - // initializes groovy filesystem poller - initGroovyFilterManager(); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - LOGGER.info("Stopping filter initializer context listener"); - } - - private void initGroovyFilterManager() { - - //TODO: pluggable filter initialzer - FilterLoader.getInstance().setCompiler(new GroovyCompiler()); - - final String scriptRoot = props.getFilterRoot(); - LOGGER.info("Using file system script: " + scriptRoot); - - try { - FilterFileManager.setFilenameFilter(new GroovyFileFilter()); - FilterFileManager.init(5, - scriptRoot + "/pre", - scriptRoot + "/route", - scriptRoot + "/post" - ); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulController.java b/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulController.java deleted file mode 100644 index 6f322a3c..00000000 --- a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulController.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.spring.cloud.netflix.zuul; - -import com.netflix.zuul.http.ZuulServlet; -import io.spring.cloud.util.AbstractServletWrappingController; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.ModelAndView; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * User: spencergibb - * Date: 4/24/14 - * Time: 9:12 PM - */ -@Controller -public class ZuulController extends AbstractServletWrappingController { - - public ZuulController() { - super(ZuulServlet.class, "zuulServlet"); - } - - @RequestMapping("/**") - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response) throws Exception { - return this.controller.handleRequest(request, response); - } -} diff --git a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulProperties.java b/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulProperties.java deleted file mode 100644 index 4baa725c..00000000 --- a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/netflix/zuul/ZuulProperties.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.spring.cloud.netflix.zuul; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -import static java.util.concurrent.TimeUnit.MINUTES; - -/** - * User: spencergibb - * Date: 5/2/14 - * Time: 9:20 PM - */ -@ConfigurationProperties("zuul") -public class ZuulProperties { - private String filterRoot; - private long cacheRefresh = MINUTES.toMillis(5L); - - public String getFilterRoot() { - return filterRoot; - } - - public void setFilterRoot(String filterRoot) { - this.filterRoot = filterRoot; - } - - public long getCacheRefresh() { - return cacheRefresh; - } - - public void setCacheRefresh(long cacheRefresh) { - this.cacheRefresh = cacheRefresh; - } -} diff --git a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/util/AbstractServletWrappingController.java b/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/util/AbstractServletWrappingController.java deleted file mode 100644 index ac423a43..00000000 --- a/spring-cloud-netflix-zuul/src/main/java/io/spring/cloud/util/AbstractServletWrappingController.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.spring.cloud.util; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.web.context.ServletContextAware; -import org.springframework.web.servlet.mvc.ServletWrappingController; - -import javax.servlet.ServletContext; - -/** - * User: spencergibb - * Date: 5/1/14 - * Time: 10:03 AM - */ -public abstract class AbstractServletWrappingController implements InitializingBean, - ApplicationContextAware, ServletContextAware { - - protected final ServletWrappingController controller = new ServletWrappingController(); - - public AbstractServletWrappingController(Class servletClass, String servletName) { - controller.setServletClass(servletClass); - controller.setServletName(servletName); - } - - @Override - public void afterPropertiesSet() throws Exception { - this.controller.afterPropertiesSet(); - } - - @Override - public void setServletContext(ServletContext servletContext) { - this.controller.setServletContext(servletContext); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.controller.setApplicationContext(applicationContext); - } - -} diff --git a/spring-cloud-netflix-zuul/src/main/resources/META-INF/spring.factories b/spring-cloud-netflix-zuul/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 28c1089f..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,8 +0,0 @@ -#org.springframework.context.ApplicationListener=\ -#org.springframework.cloud.netflix.eureka.EurekaStartingListener,\ -#org.springframework.cloud.netflix.eureka.EurekaUpListener,\ -#org.springframework.cloud.netflix.eureka.EurekaOutOfServiceListener - -#org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -#org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration,\ -#org.springframework.cloud.netflix.feign.FeignAutoConfiguration diff --git a/spring-cloud-netflix-zuul/src/main/resources/application.yml b/spring-cloud-netflix-zuul/src/main/resources/application.yml deleted file mode 100644 index 81b093df..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/application.yml +++ /dev/null @@ -1,48 +0,0 @@ -info: - component: Platform Router (Zuul) - -endpoints: - restart: - enabled: true - shutdown: - enabled: true - -server: - port: 6080 - -management: - port: 6081 - -logging: - level: INFO - -logging: - level: - com: - netflix: WARN - - -eureka: - client: - #Region where eureka is deployed -For AWS specify one of the AWS regions, for other datacenters specify a arbitrary string - #indicating the region.This is normally specified as a -D option (eg) -Deureka.region=us-east-1 - region: default - - - #For eureka clients running in eureka server, it needs to connect to servers in other zones - preferSameZone: false - - #Change this if you want to use a DNS based lookup for determining other eureka servers. For example - #of specifying the DNS entries, check the eureka-client-test.properties, eureka-client-prod.properties - #shouldUseDns: false - - us-east-1: - availabilityZones: default - - #serviceUrl: - #default: http://localhost:8761/eureka/ - #defaultZone: http://localhost:8761/eureka/ - - instance: - #Virtual host name by which the clients identifies this service - virtualHostName: ${spring.application.name} diff --git a/spring-cloud-netflix-zuul/src/main/resources/bootstrap.yml b/spring-cloud-netflix-zuul/src/main/resources/bootstrap.yml deleted file mode 100644 index 2041e99a..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,6 +0,0 @@ -spring: - application: - name: zuul - platform: - config: - uri: http://localhost:${config.port:8888} \ No newline at end of file diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/post/SendResponse.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/post/SendResponse.groovy deleted file mode 100644 index 0018a40d..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/post/SendResponse.groovy +++ /dev/null @@ -1,170 +0,0 @@ -package filters.post - -import com.netflix.config.DynamicBooleanProperty - -import com.netflix.config.DynamicIntProperty -import com.netflix.config.DynamicPropertyFactory -import com.netflix.util.Pair -import com.netflix.zuul.ZuulFilter -import com.netflix.zuul.constants.ZuulConstants -import com.netflix.zuul.constants.ZuulHeaders -import com.netflix.zuul.context.Debug -import com.netflix.zuul.context.RequestContext - -import javax.servlet.http.HttpServletResponse -import java.util.zip.GZIPInputStream - -class SendResponseFilter extends ZuulFilter { - - static DynamicBooleanProperty INCLUDE_DEBUG_HEADER = - DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_INCLUDE_DEBUG_HEADER, false); - - static DynamicIntProperty INITIAL_STREAM_BUFFER_SIZE = - DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_INITIAL_STREAM_BUFFER_SIZE, 1024); - - static DynamicBooleanProperty SET_CONTENT_LENGTH = DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_SET_CONTENT_LENGTH, false); - - @Override - String filterType() { - return 'post' - } - - @Override - int filterOrder() { - return 1000 - } - - boolean shouldFilter() { - return !RequestContext.currentContext.getZuulResponseHeaders().isEmpty() || - RequestContext.currentContext.getResponseDataStream() != null || - RequestContext.currentContext.responseBody != null - } - - Object run() { - addResponseHeaders() - writeResponse() - } - - void writeResponse() { - RequestContext context = RequestContext.currentContext - - // there is no body to send - if (context.getResponseBody() == null && context.getResponseDataStream() == null) return; - - HttpServletResponse servletResponse = context.getResponse() - servletResponse.setCharacterEncoding("UTF-8") - - OutputStream outStream = servletResponse.getOutputStream(); - InputStream is = null - try { - if (RequestContext.currentContext.responseBody != null) { - String body = RequestContext.currentContext.responseBody - writeResponse(new ByteArrayInputStream(body.bytes), outStream) - return; - } - - boolean isGzipRequested = false - final String requestEncoding = context.getRequest().getHeader(ZuulHeaders.ACCEPT_ENCODING) - if (requestEncoding != null && requestEncoding.equals("gzip")) - isGzipRequested = true; - - is = context.getResponseDataStream(); - InputStream inputStream = is - if (is != null) { - if (context.sendZuulResponse()) { - // if origin response is gzipped, and client has not requested gzip, decompress stream - // before sending to client - // else, stream gzip directly to client - if (context.getResponseGZipped() && !isGzipRequested) - try { - inputStream = new GZIPInputStream(is); - - } catch (java.util.zip.ZipException e) { - println("gzip expected but not received assuming unencoded response" + RequestContext.currentContext.getRequest().getRequestURL().toString()) - inputStream = is - } - else if (context.getResponseGZipped() && isGzipRequested) - servletResponse.setHeader(ZuulHeaders.CONTENT_ENCODING, "gzip") - writeResponse(inputStream, outStream) - } - } - - } finally { - try { - is?.close(); - - outStream.flush() - outStream.close() - } catch (IOException e) { - - } - } - } - - def writeResponse(InputStream zin, OutputStream out) { - byte[] bytes = new byte[INITIAL_STREAM_BUFFER_SIZE.get()]; - int bytesRead = -1; - while ((bytesRead = zin.read(bytes)) != -1) { -// if (Debug.debugRequest() && !Debug.debugRequestHeadersOnly()) { -// Debug.addRequestDebug("OUTBOUND: < " + new String(bytes, 0, bytesRead)); -// } - - try { - out.write(bytes, 0, bytesRead); - out.flush(); - } catch (IOException e) { - //ignore - e.printStackTrace() - } - - // doubles buffer size if previous read filled it - if (bytesRead == bytes.length) { - bytes = new byte[bytes.length * 2] - } - } - } - - private void addResponseHeaders() { - RequestContext context = RequestContext.getCurrentContext(); - HttpServletResponse servletResponse = context.getResponse(); - List> zuulResponseHeaders = context.getZuulResponseHeaders(); - String debugHeader = "" - - List rd - - rd = (List) RequestContext.getCurrentContext().get("routingDebug"); - rd?.each { - debugHeader += "[[[${it}]]]"; - } - - /* - rd = (List) RequestContext.getCurrentContext().get("requestDebug"); - rd?.each { - debugHeader += "[[[REQUEST_DEBUG::${it}]]]"; - } - */ - - if (INCLUDE_DEBUG_HEADER.get()) servletResponse.addHeader("X-Zuul-Debug-Header", debugHeader) - - if (Debug.debugRequest()) { - zuulResponseHeaders?.each { Pair it -> - servletResponse.addHeader(it.first(), it.second()) - Debug.addRequestDebug("OUTBOUND: < " + it.first() + ":" + it.second()) - } - } else { - zuulResponseHeaders?.each { Pair it -> - servletResponse.addHeader(it.first(), it.second()) - } - } - - RequestContext ctx = RequestContext.getCurrentContext() - Integer contentLength = ctx.getOriginContentLength() - - // only inserts Content-Length if origin provides it and origin response is not gzipped - if (SET_CONTENT_LENGTH.get()) { - if (contentLength != null && !ctx.getResponseGZipped()) - servletResponse.setContentLength(contentLength) - } - } - -} \ No newline at end of file diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/post/Stats.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/post/Stats.groovy deleted file mode 100755 index 46fa9a56..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/post/Stats.groovy +++ /dev/null @@ -1,43 +0,0 @@ -package filters.post - -import com.netflix.zuul.ZuulFilter - -import com.netflix.zuul.context.RequestContext - -class Stats extends ZuulFilter { - @Override - String filterType() { - return "post" - } - - @Override - int filterOrder() { - return 2000 - } - - @Override - boolean shouldFilter() { - return true - } - - @Override - Object run() { - dumpRoutingDebug() - dumpRequestDebug() - } - - public void dumpRequestDebug() { - List rd = (List) RequestContext.getCurrentContext().get("requestDebug"); - rd?.each { - println("REQUEST_DEBUG::${it}"); - } - } - - public void dumpRoutingDebug() { - List rd = (List) RequestContext.getCurrentContext().get("routingDebug"); - rd?.each { - println("ZUUL_DEBUG::${it}"); - } - } - -} diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/pre/Debug.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/pre/Debug.groovy deleted file mode 100644 index 2a499102..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/pre/Debug.groovy +++ /dev/null @@ -1,42 +0,0 @@ -package filters.pre - -import com.netflix.config.DynamicBooleanProperty -import com.netflix.config.DynamicPropertyFactory -import com.netflix.config.DynamicStringProperty -import com.netflix.zuul.ZuulFilter -import com.netflix.zuul.constants.ZuulConstants -import com.netflix.zuul.context.RequestContext - -class DebugFilter extends ZuulFilter { - - static final DynamicBooleanProperty routingDebug = DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_DEBUG_REQUEST, true) - static final DynamicStringProperty debugParameter = DynamicPropertyFactory.getInstance().getStringProperty(ZuulConstants.ZUUL_DEBUG_PARAMETER, "d") - - @Override - String filterType() { - return 'pre' - } - - @Override - int filterOrder() { - return 1 - } - - boolean shouldFilter() { - if ("true".equals(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get()))) return true; - return routingDebug.get(); - - } - - Object run() { - RequestContext ctx = RequestContext.getCurrentContext() - ctx.setDebugRouting(true) - ctx.setDebugRequest(true) - return null; - } - - -} - - - diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/pre/DebugRequest.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/pre/DebugRequest.groovy deleted file mode 100644 index 1f028624..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/pre/DebugRequest.groovy +++ /dev/null @@ -1,55 +0,0 @@ -package filters.pre - -import com.netflix.zuul.ZuulFilter - -import com.netflix.zuul.context.Debug -import com.netflix.zuul.context.RequestContext - -import javax.servlet.http.HttpServletRequest - -class DebugRequest extends ZuulFilter { - @Override - String filterType() { - return 'pre' - } - - @Override - int filterOrder() { - return 10000 - } - - @Override - boolean shouldFilter() { - return Debug.debugRequest() - } - - @Override - Object run() { - HttpServletRequest req = RequestContext.currentContext.request as HttpServletRequest - - Debug.addRequestDebug("REQUEST:: " + req.getScheme() + " " + req.getRemoteAddr() + ":" + req.getRemotePort()) - - Debug.addRequestDebug("REQUEST:: > " + req.getMethod() + " " + req.getRequestURI() + " " + req.getProtocol()) - - Iterator headerIt = req.getHeaderNames().iterator() - while (headerIt.hasNext()) { - String name = (String) headerIt.next() - String value = req.getHeader(name) - Debug.addRequestDebug("REQUEST:: > " + name + ":" + value) - - } - - final RequestContext ctx = RequestContext.getCurrentContext() - if (!ctx.isChunkedRequestBody()) { - InputStream inp = ctx.request.getInputStream() - String body = null - if (inp != null) { - body = inp.getText() - Debug.addRequestDebug("REQUEST:: > " + body) - - } - } - return null; - } - -} diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/pre/PreDecorationFilter.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/pre/PreDecorationFilter.groovy deleted file mode 100644 index c273aa61..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/pre/PreDecorationFilter.groovy +++ /dev/null @@ -1,52 +0,0 @@ -package filters.pre - -import com.netflix.zuul.context.RequestContext -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.cloud.netflix.zuul.Routes -import org.springframework.cloud.netflix.zuul.SpringFilter - -class PreDecorationFilter extends SpringFilter { - private static Logger LOG = LoggerFactory.getLogger(PreDecorationFilter.class); - - @Override - int filterOrder() { - return 5 - } - - @Override - String filterType() { - return "pre" - } - - @Override - boolean shouldFilter() { - return true; - } - - @Override - Object run() { - RequestContext ctx = RequestContext.getCurrentContext() - - def requestURI = ctx.getRequest().getRequestURI() - - Routes routes = getBean(Routes.class) - - def routesMap = routes.getRoutes() - def route = routesMap.keySet().find { path -> - //TODO: use ant matchers? - if (requestURI.startsWith(path)) { - return true - } - return false - } - def serviceId = routesMap.get(route) - - if (serviceId != null) { - // set serviceId for use in filters.route.RibbonRequest - ctx.set("serviceId", serviceId) - ctx.setRouteHost(null) - ctx.addOriginResponseHeader("X-Zuul-ServiceId", serviceId); - } - } -} diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/route/RibbonRequest.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/route/RibbonRequest.groovy deleted file mode 100644 index e712a3cd..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/route/RibbonRequest.groovy +++ /dev/null @@ -1,284 +0,0 @@ -package filters.route - -import com.netflix.client.ClientException -import com.netflix.client.ClientFactory -import com.netflix.client.IClient -import com.netflix.client.http.HttpRequest -import com.netflix.client.http.HttpResponse -import com.netflix.hystrix.exception.HystrixRuntimeException -import com.netflix.niws.client.http.RestClient -import com.netflix.zuul.ZuulFilter -import com.netflix.zuul.context.Debug -import com.netflix.zuul.context.RequestContext -import com.netflix.zuul.exception.ZuulException -import com.netflix.zuul.util.HTTPRequestUtils -import com.sun.jersey.core.util.MultivaluedMapImpl -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.cloud.netflix.zuul.RibbonCommand - -import javax.servlet.http.HttpServletRequest -import javax.ws.rs.core.MultivaluedMap -import java.util.zip.GZIPInputStream - -import static HttpRequest.Verb -import static org.springframework.cloud.netflix.feign.FeignConfigurer.setServiceListClassAndVIP - -class RibbonRequest extends ZuulFilter { - - private static final Logger LOG = LoggerFactory.getLogger(RibbonRequest.class); - - public static final String CONTENT_ENCODING = "Content-Encoding"; - - @Override - String filterType() { - return 'route' - } - - @Override - int filterOrder() { - return 10 - } - - boolean shouldFilter() { - def ctx = RequestContext.currentContext - return (ctx.getRouteHost() == null && ctx.get("serviceId") != null && ctx.sendZuulResponse()) - } - - Object run() { - RequestContext context = RequestContext.currentContext - HttpServletRequest request = context.getRequest(); - - MultivaluedMap headers = buildZuulRequestHeaders(request) - MultivaluedMap params = buildZuulRequestQueryParams(request) - Verb verb = getVerb(request); - Object requestEntity = getRequestBody(request) - - def serviceId = context.get("serviceId") - - //TODO: can this be set be default? or an implementation of an interface? - setServiceListClassAndVIP(serviceId) - - IClient restClient = ClientFactory.getNamedClient(serviceId); - - String uri = request.getRequestURI() - if (context.requestURI != null) { - uri = context.requestURI - } - //remove double slashes - uri = uri.replace("//", "/") - - HttpResponse response = forward(restClient, verb, uri, headers, params, requestEntity) - setResponse(response) - return response - } - - - - void debug(RestClient restClient, Verb verb, uri, MultivaluedMap headers, MultivaluedMap params, InputStream requestEntity) { - - if (Debug.debugRequest()) { - - headers.each { - Debug.addRequestDebug("ZUUL:: > ${it.key} ${it.value[0]}") - } - String query = "" - params.each { - it.value.each { v -> - query += it.key + "=" + v + "&" - } - } - - Debug.addRequestDebug("ZUUL:: > ${verb.verb()} ${uri}?${query} HTTP/1.1") - RequestContext ctx = RequestContext.getCurrentContext() - if (!ctx.isChunkedRequestBody()) { - if (requestEntity != null) { - debugRequestEntity(ctx.request.getInputStream()) - } - } - } - } - - void debugRequestEntity(InputStream inputStream) { - if (!Debug.debugRequestHeadersOnly()) { - String entity = inputStream.getText() - Debug.addRequestDebug("ZUUL:: > ${entity}") - } - } - - - - def HttpResponse forward(RestClient restClient, Verb verb, uri, MultivaluedMap headers, - MultivaluedMap params, InputStream requestEntity) { - debug(restClient, verb, uri, headers, params, requestEntity) - - RibbonCommand command = new RibbonCommand(restClient, verb, uri, headers, params, requestEntity); - try { - HttpResponse response = command.execute(); - return response - } catch (HystrixRuntimeException e) { - if (e?.fallbackException?.cause instanceof ClientException) { - ClientException ex = e.fallbackException.cause as ClientException - throw new ZuulException(ex, "Forwarding error", 500, ex.getErrorType().toString()) - } - throw new ZuulException(e, "Forwarding error", 500, e.failureType.toString()) - } - - } - - - def getRequestBody(HttpServletRequest request) { - Object requestEntity = null; - try { - requestEntity = RequestContext.currentContext.requestEntity - if (requestEntity == null) { - requestEntity = request.getInputStream(); - } - } catch (IOException e) { - LOG.error(e); - } - - return requestEntity - } - - - - def MultivaluedMap buildZuulRequestQueryParams(HttpServletRequest request) { - - Map> map = HTTPRequestUtils.getInstance().getQueryParams() - - MultivaluedMap params = new MultivaluedMapImpl(); - if (map == null) return params; - map.entrySet().each { - it.value.each { v -> - params.add(it.key, v) - } - - } - return params - } - - - def MultivaluedMap buildZuulRequestHeaders(HttpServletRequest request) { - - RequestContext context = RequestContext.currentContext - - MultivaluedMap headers = new MultivaluedMapImpl(); - Enumeration headerNames = request.getHeaderNames(); - while (headerNames?.hasMoreElements()) { - String name = (String) headerNames.nextElement(); - String value = request.getHeader(name); - if (!name.toLowerCase().contains("content-length")) headers.putSingle(name, value); - } - Map zuulRequestHeaders = context.getZuulRequestHeaders(); - - zuulRequestHeaders.keySet().each { - headers.putSingle((String) it, (String) zuulRequestHeaders[it]) - } - - headers.putSingle("accept-encoding", "deflate, gzip") - - if (headers.containsKey("transfer-encoding")) - headers.remove("transfer-encoding") - - return headers - } - - - - Verb getVerb(HttpServletRequest request) { - String sMethod = request.getMethod(); - return getVerb(sMethod); - } - - Verb getVerb(String sMethod) { - if (sMethod == null) return Verb.GET; - sMethod = sMethod.toLowerCase(); - if (sMethod.equals("post")) return Verb.POST; - if (sMethod.equals("put")) return Verb.PUT; - if (sMethod.equals("delete")) return Verb.DELETE; - if (sMethod.equals("options")) return Verb.OPTIONS; - if (sMethod.equals("head")) return Verb.HEAD; - return Verb.GET; - } - - void setResponse(HttpResponse resp) { - RequestContext context = RequestContext.getCurrentContext() - - context.setResponseStatusCode(resp.getStatus()); - if (resp.hasEntity()) { - context.responseDataStream = resp.inputStream; - } - - String contentEncoding = resp.getHeaders().get(CONTENT_ENCODING)?.first(); - - if (contentEncoding != null && HTTPRequestUtils.getInstance().isGzipped(contentEncoding)) { - context.setResponseGZipped(true); - } else { - context.setResponseGZipped(false); - } - - if (Debug.debugRequest()) { - resp.getHeaders().keySet().each { key -> - boolean isValidHeader = isValidHeader(key) - - Collection list = resp.getHeaders().get(key) - list.each { header -> - context.addOriginResponseHeader(key, header) - - if (key.equalsIgnoreCase("content-length")) - context.setOriginContentLength(header); - - if (isValidHeader) { - context.addZuulResponseHeader(key, header); - Debug.addRequestDebug("ORIGIN_RESPONSE:: < ${key} ${header}") - } - } - } - - if (context.responseDataStream) { - byte[] origBytes = context.getResponseDataStream().bytes - InputStream inStream = new ByteArrayInputStream(origBytes); - if (context.getResponseGZipped()) - inStream = new GZIPInputStream(inStream); - String responseEntity = inStream.getText() - Debug.addRequestDebug("ORIGIN_RESPONSE:: < ${responseEntity}") - context.setResponseDataStream(new ByteArrayInputStream(origBytes)) - } - - } else { - resp.getHeaders().keySet().each { key -> - boolean isValidHeader = isValidHeader(key) - Collection list = resp.getHeaders().get(key) - list.each { header -> - context.addOriginResponseHeader(key, header) - - if (key.equalsIgnoreCase("content-length")) - context.setOriginContentLength(header); - - if (isValidHeader) { - context.addZuulResponseHeader(key, header); - } - } - } - } - - - } - - boolean isValidHeader(String headerName) { - switch (headerName.toLowerCase()) { - case "connection": - case "content-length": - case "content-encoding": - case "server": - case "transfer-encoding": - return false - default: - return true - } - } - -} - - diff --git a/spring-cloud-netflix-zuul/src/main/resources/filters/route/SimpleHostRequest.groovy b/spring-cloud-netflix-zuul/src/main/resources/filters/route/SimpleHostRequest.groovy deleted file mode 100644 index cd2e9627..00000000 --- a/spring-cloud-netflix-zuul/src/main/resources/filters/route/SimpleHostRequest.groovy +++ /dev/null @@ -1,434 +0,0 @@ -package filters.route - -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 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.HttpPost -import org.apache.http.client.methods.HttpPut -import org.apache.http.client.params.ClientPNames -import org.apache.http.conn.ClientConnectionManager -import org.apache.http.conn.scheme.PlainSocketFactory -import org.apache.http.conn.scheme.Scheme -import org.apache.http.conn.scheme.SchemeRegistry -import org.apache.http.conn.ssl.SSLSocketFactory -import org.apache.http.entity.InputStreamEntity -import org.apache.http.impl.client.DefaultHttpClient -import org.apache.http.impl.client.DefaultHttpRequestRetryHandler -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager -import org.apache.http.message.BasicHeader -import org.apache.http.message.BasicHttpRequest -import org.apache.http.params.CoreConnectionPNames -import org.apache.http.params.HttpParams -import org.apache.http.protocol.HttpContext -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import javax.net.ssl.SSLContext -import javax.net.ssl.TrustManager -import javax.net.ssl.X509TrustManager -import javax.servlet.http.HttpServletRequest -import java.security.* -import java.security.cert.CertificateException -import java.security.cert.X509Certificate -import java.util.concurrent.atomic.AtomicReference -import java.util.zip.GZIPInputStream - -class SimpleHostRoutingFilter extends ZuulFilter { - - public static final String CONTENT_ENCODING = "Content-Encoding"; - - private static final Logger LOG = LoggerFactory.getLogger(SimpleHostRoutingFilter.class); - private static final Runnable CLIENTLOADER = new Runnable() { - @Override - void run() { - loadClient(); - } - } - - private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, 10000) - private static final DynamicIntProperty CONNECTION_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, 2000) - - private static final AtomicReference CLIENT = new AtomicReference(newClient()); - - private static final Timer CONNECTION_MANAGER_TIMER = new Timer(true); - - // cleans expired connections at an interval - static { - SOCKET_TIMEOUT.addCallback(CLIENTLOADER) - CONNECTION_TIMEOUT.addCallback(CLIENTLOADER) - CONNECTION_MANAGER_TIMER.schedule(new TimerTask() { - @Override - void run() { - try { - final HttpClient hc = CLIENT.get(); - if (hc == null) return; - hc.getConnectionManager().closeExpiredConnections(); - } catch (Throwable t) { - LOG.error("error closing expired connections", t); - } - } - }, 30000, 5000) - } - - public SimpleHostRoutingFilter() {} - - private static final ClientConnectionManager newConnectionManager() { - - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null, null); - - SSLSocketFactory sf = new MySSLSocketFactory(trustStore); - sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - registry.register(new Scheme("https", sf, 443)); - registry.register(new Scheme("https", sf, 8443)); - - ClientConnectionManager cm = new ThreadSafeClientConnManager(registry); - cm.setMaxTotal(Integer.parseInt(System.getProperty("zuul.max.host.connections", "200"))); - cm.setDefaultMaxPerRoute(Integer.parseInt(System.getProperty("zuul.max.host.connections", "20"))); - return cm; - } - - @Override - String filterType() { - return 'route' - } - - @Override - int filterOrder() { - return 100 - } - - boolean shouldFilter() { - return RequestContext.currentContext.getRouteHost() != null && RequestContext.currentContext.sendZuulResponse() - } - - private static final void loadClient() { - final HttpClient oldClient = CLIENT.get(); - CLIENT.set(newClient()) - if (oldClient != null) { - CONNECTION_MANAGER_TIMER.schedule(new TimerTask() { - @Override - void run() { - try { - oldClient.getConnectionManager().shutdown(); - } catch (Throwable t) { - LOG.error("error shutting down old connection manager", t); - } - } - }, 30000); - } - - } - - private static final HttpClient newClient() { - // I could statically cache the connection manager but we will probably want to make some of its properties - // dynamic in the near future also - HttpClient httpclient = new DefaultHttpClient(newConnectionManager()); - HttpParams httpParams = httpclient.getParams(); - httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SOCKET_TIMEOUT.get()) - httpParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, CONNECTION_TIMEOUT.get()) - httpclient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false)) - httpParams.setParameter(ClientPNames.COOKIE_POLICY, org.apache.http.client.params.CookiePolicy.IGNORE_COOKIES); - httpclient.setRedirectStrategy(new org.apache.http.client.RedirectStrategy() { - @Override - boolean isRedirected(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) { - return false - } - - @Override - org.apache.http.client.methods.HttpUriRequest getRedirect(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) { - return null - } - }) - return httpclient - } - - Object run() { - HttpServletRequest request = RequestContext.currentContext.getRequest(); - Header[] headers = buildZuulRequestHeaders(request) - String verb = getVerb(request); - InputStream requestEntity = getRequestBody(request) - HttpClient httpclient = CLIENT.get() - - String uri = request.getRequestURI() - if (RequestContext.currentContext.requestURI != null) { - uri = RequestContext.currentContext.requestURI - } - - try { - HttpResponse response = forward(httpclient, verb, uri, request, headers, requestEntity) - setResponse(response) - } - catch (Exception e) { - if (Debug.debugRequest()) { - Debug.addRequestDebug("ZUUL:: ERROR " + e.getMessage()) - } - throw e; - } - return null - } - - def InputStream debug(HttpClient httpclient, String verb, String uri, HttpServletRequest request, Header[] headers, InputStream requestEntity) { - - if (Debug.debugRequest()) { - - Debug.addRequestDebug("ZUUL:: host=${RequestContext.currentContext.getRouteHost()}") - - headers.each { - Debug.addRequestDebug("ZUUL::> ${it.name} ${it.value}") - } - String query = request.queryString - - Debug.addRequestDebug("ZUUL:: > ${verb} ${uri}?${query} HTTP/1.1") - if (requestEntity != null) { - requestEntity = debugRequestEntity(requestEntity) - } - - } - return requestEntity - } - - InputStream debugRequestEntity(InputStream inputStream) { - if (Debug.debugRequestHeadersOnly()) return inputStream - if (inputStream == null) return null - String entity = inputStream.getText() - Debug.addRequestDebug("ZUUL::> ${entity}") - return new ByteArrayInputStream(entity.bytes) - } - - def HttpResponse forward(HttpClient httpclient, String verb, String uri, HttpServletRequest request, Header[] headers, InputStream requestEntity) { - - requestEntity = debug(httpclient, verb, uri, request, headers, requestEntity) - - org.apache.http.HttpHost httpHost - - httpHost = getHttpHost() - - org.apache.http.HttpRequest httpRequest; - - switch (verb) { - case 'POST': - httpRequest = new HttpPost(uri + getQueryString()) - InputStreamEntity entity = new InputStreamEntity(requestEntity, request.getContentLength()) - httpRequest.setEntity(entity) - break - case 'PUT': - httpRequest = new HttpPut(uri + getQueryString()) - InputStreamEntity entity = new InputStreamEntity(requestEntity, request.getContentLength()) - httpRequest.setEntity(entity) - break; - default: - httpRequest = new BasicHttpRequest(verb, uri + getQueryString()) - LOG.debug(uri + getQueryString()) - } - - try { - httpRequest.setHeaders(headers) - LOG.debug(httpHost.getHostName() + " " + httpHost.getPort() + " " + httpHost.getSchemeName()) - HttpResponse zuulResponse = forwardRequest(httpclient, httpHost, httpRequest) - return zuulResponse - } finally { - // When HttpClient instance is no longer needed, - // shut down the connection manager to ensure - // immediate deallocation of all system resources -// httpclient.getConnectionManager().shutdown(); - } - - } - - HttpResponse forwardRequest(HttpClient httpclient, HttpHost httpHost, HttpRequest httpRequest) { - return httpclient.execute(httpHost, httpRequest); - } - - String getQueryString() { - HttpServletRequest request = RequestContext.currentContext.getRequest(); - String query = request.getQueryString() - return (query != null) ? "?${query}" : ""; - } - - HttpHost getHttpHost() { - HttpHost httpHost - URL host = RequestContext.currentContext.getRouteHost() - - httpHost = new HttpHost(host.getHost(), host.getPort(), host.getProtocol()) - - return httpHost - } - - - def getRequestBody(HttpServletRequest request) { - Object requestEntity = null; - try { - requestEntity = request.getInputStream(); - } catch (IOException e) { - //no requestBody is ok. - } - return requestEntity - } - - boolean isValidHeader(String name) { - if (name.toLowerCase().contains("content-length")) return false; - if (!RequestContext.currentContext.responseGZipped) { - if (name.toLowerCase().contains("accept-encoding")) return false; - } - return true; - } - - def Header[] buildZuulRequestHeaders(HttpServletRequest request) { - - def headers = new ArrayList() - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String name = (String) headerNames.nextElement(); - String value = request.getHeader(name); - if (isValidHeader(name)) headers.add(new BasicHeader(name, value)) - } - - Map zuulRequestHeaders = RequestContext.getCurrentContext().getZuulRequestHeaders(); - - zuulRequestHeaders.keySet().each { - String name = it.toLowerCase() - BasicHeader h = headers.find { BasicHeader he -> he.name == name } - if (h != null) { - headers.remove(h) - } - headers.add(new BasicHeader((String) it, (String) zuulRequestHeaders[it])) - } - - if (RequestContext.currentContext.responseGZipped) { - headers.add(new BasicHeader("accept-encoding", "deflate, gzip")) - } - return headers - } - - - - String getVerb(HttpServletRequest request) { - String sMethod = request.getMethod(); - return sMethod.toUpperCase(); - } - - String getVerb(String sMethod) { - if (sMethod == null) return "GET"; - sMethod = sMethod.toLowerCase(); - if (sMethod.equalsIgnoreCase("post")) return "POST" - if (sMethod.equalsIgnoreCase("put")) return "PUT" - if (sMethod.equalsIgnoreCase("delete")) return "DELETE" - if (sMethod.equalsIgnoreCase("options")) return "OPTIONS" - if (sMethod.equalsIgnoreCase("head")) return "HEAD" - return "GET" - } - - void setResponse(HttpResponse response) { - RequestContext context = RequestContext.getCurrentContext() - - RequestContext.currentContext.set("hostZuulResponse", response) - RequestContext.getCurrentContext().setResponseStatusCode(response.getStatusLine().statusCode) - RequestContext.getCurrentContext().responseDataStream = response?.entity?.content - - boolean isOriginResponseGzipped = false - - for (Header h : response.getHeaders(CONTENT_ENCODING)) { - if (HTTPRequestUtils.getInstance().isGzipped(h.value)) { - isOriginResponseGzipped = true; - break; - } - } - context.setResponseGZipped(isOriginResponseGzipped); - - - if (Debug.debugRequest()) { - response.getAllHeaders()?.each { Header header -> - if (isValidHeader(header)) { - RequestContext.getCurrentContext().addZuulResponseHeader(header.name, header.value); - Debug.addRequestDebug("ORIGIN_RESPONSE:: < ${header.name}, ${header.value}") - } - } - - if (context.responseDataStream) { - byte[] origBytes = context.getResponseDataStream().bytes - ByteArrayInputStream byteStream = new ByteArrayInputStream(origBytes) - InputStream inputStream = byteStream - if (RequestContext.currentContext.responseGZipped) { - inputStream = new GZIPInputStream(byteStream); - } - - - context.setResponseDataStream(new ByteArrayInputStream(origBytes)) - } - - } else { - response.getAllHeaders()?.each { Header header -> - RequestContext ctx = RequestContext.getCurrentContext() - ctx.addOriginResponseHeader(header.name, header.value) - - if (header.name.equalsIgnoreCase("content-length")) - ctx.setOriginContentLength(header.value) - - if (isValidHeader(header)) { - ctx.addZuulResponseHeader(header.name, header.value); - } - } - } - - } - - boolean isValidHeader(Header header) { - switch (header.name.toLowerCase()) { - case "connection": - case "content-length": - case "content-encoding": - case "server": - case "transfer-encoding": - return false - default: - return true - } - } - - public static class MySSLSocketFactory extends SSLSocketFactory { - SSLContext sslContext = SSLContext.getInstance("TLS"); - - public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - super(truststore); - - TrustManager tm = new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - } - - public X509Certificate[] getAcceptedIssuers() { - return null; - } - }; - - TrustManager[] tms = new TrustManager[1]; - tms[0] = tm; - sslContext.init(null, tms, null); - } - - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - } - - @Override - public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); - } - } -} \ No newline at end of file