From 151fad898bd296ffd7fa9eae5a57f63b4e9b4c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Windm=C3=BCller?= Date: Mon, 26 Nov 2018 22:19:42 +0100 Subject: [PATCH 1/4] Document workaround for conflicting Thymeleaf dependency (#3291) Fixes gh-3290 --- docs/src/main/asciidoc/spring-cloud-netflix.adoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 0ad291bea..891ddeca5 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -335,6 +335,16 @@ This section describes how to set up a Eureka server. To include Eureka Server in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-netflix-eureka-server`. See the http://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train. +NOTE: If your project already uses Thymeleaf as its template engine, the Freemarker templates of the Eureka server may not be loaded correctly. In this case it is necessary to configure the template loader manually: + +.application.yml +---- +spring: + freemarker: + template-loader-path: classpath:/templates/ + prefer-file-system-access: false +---- + [[spring-cloud-running-eureka-server]] === How to Run a Eureka Server From 60bb89293c997937047814c4c86e1de4fb5f2160 Mon Sep 17 00:00:00 2001 From: ailin zhou Date: Tue, 4 Dec 2018 16:19:28 +0800 Subject: [PATCH 2/4] Submit PR #3276 against the 2.0.x branch (#3297) * An enhancement when multiple HystrixConcurrencyStrategy detected. Fixes #3256 * replace exception with wran log --- .../HystrixSecurityAutoConfiguration.java | 24 +++- .../HystrixSecurityAutoConfigurationTest.java | 110 ++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfigurationTest.java diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java index 272f234e4..d2eddf08f 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java @@ -18,6 +18,9 @@ package org.springframework.cloud.netflix.hystrix.security; import javax.annotation.PostConstruct; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.AllNestedConditions; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -42,6 +45,7 @@ import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; @Conditional(HystrixSecurityCondition.class) @ConditionalOnClass({ Hystrix.class, SecurityContext.class }) public class HystrixSecurityAutoConfiguration { + private static final Log LOGGER = LogFactory.getLog(HystrixSecurityAutoConfiguration.class); @Autowired(required = false) private HystrixConcurrencyStrategy existingConcurrencyStrategy; @@ -56,18 +60,36 @@ public class HystrixSecurityAutoConfiguration { .getPropertiesStrategy(); HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance() .getCommandExecutionHook(); + HystrixConcurrencyStrategy concurrencyStrategy = detectRegisteredConcurrencyStrategy(); HystrixPlugins.reset(); // Registers existing plugins excepts the Concurrent Strategy plugin. HystrixPlugins.getInstance().registerConcurrencyStrategy( - new SecurityContextConcurrencyStrategy(existingConcurrencyStrategy)); + new SecurityContextConcurrencyStrategy(concurrencyStrategy)); HystrixPlugins.getInstance().registerEventNotifier(eventNotifier); HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher); HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy); HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook); } + private HystrixConcurrencyStrategy detectRegisteredConcurrencyStrategy() { + HystrixConcurrencyStrategy registeredStrategy = HystrixPlugins.getInstance() + .getConcurrencyStrategy(); + if (existingConcurrencyStrategy == null) { + return registeredStrategy; + } + //Hystrix registered a default Strategy. + if (registeredStrategy instanceof HystrixConcurrencyStrategyDefault){ + return existingConcurrencyStrategy; + } + //If registeredStrategy not the default and not some use bean of existingConcurrencyStrategy. + if (!existingConcurrencyStrategy.equals(registeredStrategy)){ + LOGGER.warn("Multiple HystrixConcurrencyStrategy detected. Bean of HystrixConcurrencyStrategy was used."); + } + return existingConcurrencyStrategy; + } + static class HystrixSecurityCondition extends AllNestedConditions { public HystrixSecurityCondition() { diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfigurationTest.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfigurationTest.java new file mode 100644 index 000000000..70a78e70d --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfigurationTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.netflix.hystrix.security; + +import com.netflix.hystrix.strategy.HystrixPlugins; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; +import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier; +import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook; +import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher; +import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; +import org.junit.Test; +import org.mockito.internal.util.reflection.FieldSetter; + +import java.lang.reflect.Field; + +import static org.junit.Assert.assertEquals; + +/** + * @author : ailin.zhou + */ +public class HystrixSecurityAutoConfigurationTest { + + @Test + public void testInit() throws NoSuchFieldException, IllegalAccessException { + + //save test context + HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance() + .getEventNotifier(); + HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance() + .getMetricsPublisher(); + HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance() + .getPropertiesStrategy(); + HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance() + .getCommandExecutionHook(); + HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); + + //test + testForMultiConcurrentStrategy(); + + //recover test context + HystrixPlugins.reset(); + HystrixPlugins.getInstance().registerConcurrencyStrategy(concurrencyStrategy); + HystrixPlugins.getInstance().registerEventNotifier(eventNotifier); + HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher); + HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy); + HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook); + + + } + + private void testForMultiConcurrentStrategy() throws IllegalAccessException, NoSuchFieldException { + HystrixSecurityAutoConfiguration securityStrategy = new HystrixSecurityAutoConfiguration(); + + //1.existingConcurrencyStrategy is null, registeredStrategy is default + HystrixPlugins.reset(); + securityStrategy.init(); + //result is default + assertEquals(HystrixConcurrencyStrategyDefault.getInstance(), getOriginalInSecurityConcurrencyStrategy()); + + //2.existingConcurrencyStrategy is null, registered strategy is customized + HystrixPlugins.reset(); + HystrixConcurrencyStrategy customized = new HystrixConcurrencyStrategy() { + }; + HystrixPlugins.getInstance().registerConcurrencyStrategy(customized); + securityStrategy.init(); + //result is customized + assertEquals(customized, getOriginalInSecurityConcurrencyStrategy()); + + //3.existingConcurrencyStrategy is not null, registeredStrategy is default. + HystrixPlugins.reset(); + HystrixConcurrencyStrategy existingConcurrencyStrategy = new HystrixConcurrencyStrategy() { + }; + FieldSetter.setField(securityStrategy, securityStrategy.getClass().getDeclaredField("existingConcurrencyStrategy"), existingConcurrencyStrategy); + securityStrategy.init(); + //result is existingConcurrencyStrategy + assertEquals(existingConcurrencyStrategy, getOriginalInSecurityConcurrencyStrategy()); + + //4.existingConcurrencyStrategy is not null, registeredStrategy is customized. + HystrixPlugins.reset(); + HystrixPlugins.getInstance().registerConcurrencyStrategy(customized); + FieldSetter.setField(securityStrategy, securityStrategy.getClass().getDeclaredField("existingConcurrencyStrategy"), existingConcurrencyStrategy); + securityStrategy.init(); + assertEquals(existingConcurrencyStrategy, getOriginalInSecurityConcurrencyStrategy()); + } + + private HystrixConcurrencyStrategy getOriginalInSecurityConcurrencyStrategy() throws IllegalAccessException, NoSuchFieldException { + HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); + Field existingConcurrencyStrategy = concurrencyStrategy.getClass().getDeclaredField("existingConcurrencyStrategy"); + existingConcurrencyStrategy.setAccessible(true); + HystrixConcurrencyStrategy strategyInSecurityStrategy = (HystrixConcurrencyStrategy) existingConcurrencyStrategy.get(concurrencyStrategy); + return strategyInSecurityStrategy; + } + +} \ No newline at end of file From a1f7bab91a52d85fcdd2537c8affd0bad0baee69 Mon Sep 17 00:00:00 2001 From: bhattankit Date: Thu, 6 Dec 2018 15:22:53 -0500 Subject: [PATCH 3/4] Added option to not decode URL. Fixes gh-2178 (#3306) * Added a way for consumers to override the default behavior or decoding and re-encoding URL using zuul.decodeUrl property. * Fixed gh-2178 --- docs/src/main/asciidoc/spring-cloud-netflix.adoc | 16 ++++++++++++++++ .../netflix/zuul/filters/ProxyRequestHelper.java | 8 +++++++- .../netflix/zuul/filters/ZuulProperties.java | 13 +++++++++++++ .../zuul/filters/pre/PreDecorationFilter.java | 1 + .../filters/pre/PreDecorationFilterTests.java | 16 ++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) mode change 100644 => 100755 docs/src/main/asciidoc/spring-cloud-netflix.adoc mode change 100644 => 100755 spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java mode change 100644 => 100755 spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java mode change 100644 => 100755 spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java mode change 100644 => 100755 spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc old mode 100644 new mode 100755 index 891ddeca5..6904301fb --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -1491,6 +1491,22 @@ NOTE: This special flag works only with `SimpleHostRoutingFilter`. Also, you loo query parameters with `RequestContext.getCurrentContext().setRequestQueryParams(someOverriddenParameters)`, because the query string is now fetched directly on the original `HttpServletRequest`. +=== Request URI Encoding +When processing the incoming request, request URI is decoded before matching them to routes. +The request URI is then re-encoded when the back end request is rebuilt in the route filters. +This can cause some unexpected behavior if your URI includes the encoded "/" character. + +To use the original request URI, it is possible to pass a special flag to 'ZuulProperties' so that the URI will be taken as is with the `HttpServletRequest::getRequestURI` method, as shown in the following example: + +.application.yml +[source,yaml] +---- + zuul: + decodeUrl: false +---- + +NOTE: If you are overriding request URI using `requestURI` RequestContext attribute and this flag is set to false, then the URL set in the request context will not be encoded. It will be your responsibility to make sure the URL is already encoded. + === Plain Embedded Zuul If you use `@EnableZuulServer` (instead of `@EnableZuulProxy`), you can also run a Zuul server without proxying or selectively switch on parts of the proxying platform. diff --git a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java old mode 100644 new mode 100755 index 0a5fd7cdb..7197ce98b --- a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java +++ b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java @@ -78,6 +78,8 @@ public class ProxyRequestHelper { private boolean addHostHeader = false; + private boolean urlDecoded = true; + @Deprecated //TODO Remove in 2.1.x public ProxyRequestHelper() {} @@ -86,6 +88,7 @@ public class ProxyRequestHelper { this.ignoredHeaders.addAll(zuulProperties.getIgnoredHeaders()); this.traceRequestBody = zuulProperties.isTraceRequestBody(); this.addHostHeader = zuulProperties.isAddHostHeader(); + this.urlDecoded = zuulProperties.isDecodeUrl(); } public void setWhitelistHosts(Set whitelistHosts) { @@ -114,7 +117,10 @@ public class ProxyRequestHelper { String contextURI = (String) context.get(REQUEST_URI_KEY); if (contextURI != null) { try { - uri = UriUtils.encodePath(contextURI, characterEncoding(request)); + uri = contextURI; + if (this.urlDecoded) { + uri = UriUtils.encodePath(contextURI, characterEncoding(request)); + } } catch (Exception e) { log.debug( diff --git a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java old mode 100644 new mode 100755 index c37b39e54..04f7e6fd0 --- a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java +++ b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java @@ -140,6 +140,11 @@ public class ZuulProperties { */ private boolean removeSemicolonContent = true; + /** + * Flag to indicate whether to decode the matched URL or use it as is. + */ + private boolean decodeUrl = true; + /** * List of sensitive headers that are not passed to downstream requests. Defaults to a * "safe" set of headers that commonly contain user credentials. It's OK to remove @@ -764,6 +769,14 @@ public class ZuulProperties { this.removeSemicolonContent = removeSemicolonContent; } + public boolean isDecodeUrl() { + return decodeUrl; + } + + public void setDecodeUrl(boolean decodeUrl) { + this.decodeUrl = decodeUrl; + } + public Set getSensitiveHeaders() { return sensitiveHeaders; } diff --git a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java old mode 100644 new mode 100755 index 5ff66507f..aa291e045 --- a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java +++ b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java @@ -88,6 +88,7 @@ public class PreDecorationFilter extends ZuulFilter { this.routeLocator = routeLocator; this.properties = properties; this.urlPathHelper.setRemoveSemicolonContent(properties.isRemoveSemicolonContent()); + this.urlPathHelper.setUrlDecode(properties.isDecodeUrl()); this.dispatcherServletPath = dispatcherServletPath; this.proxyRequestHelper = proxyRequestHelper; } diff --git a/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java b/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java old mode 100644 new mode 100755 index ad1033901..947fc3eb1 --- a/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java +++ b/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java @@ -329,6 +329,22 @@ public class PreDecorationFilterTests { getHeader(ctx.getOriginResponseHeaders(), "x-zuul-serviceid")); } + @Test + public void dontDecodeUrl() { + this.properties.setPrefix("/api"); + this.properties.setStripPrefix(true); + this.properties.setDecodeUrl(false); + this.request.setRequestURI("/api/foo/encoded%2Fpath"); + this.request.setContextPath("/context-path"); + this.routeLocator.addRoute( + new ZuulRoute("foo", "/foo/**", "foo", null, false, null, null)); + this.filter = new PreDecorationFilter(this.routeLocator, "/", this.properties, + this.proxyRequestHelper); + this.filter.run(); + RequestContext ctx = RequestContext.getCurrentContext(); + assertEquals("/foo/encoded%2Fpath", ctx.get(REQUEST_URI_KEY)); + } + @Test public void routeIgnoreContextPathIfPrefixHeader() { this.properties.setStripPrefix(false); From 89ed8219cb6754d168584028cad3f904e435613a Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Thu, 26 Apr 2018 12:06:29 -0400 Subject: [PATCH 4/4] Conditionally use ZuulServletFilter instead of ZuulServlet Using the filter instead of the servlet allow unhandled/ignored requests to pass through Zuul to be handled by something else, as opposed to the servlet which cannot do so. See https://github.com/spring-cloud/spring-cloud-netflix/issues/2887 --- .../zuul/ZuulServerAutoConfiguration.java | 21 +++++++- .../cloud/netflix/zuul/ZuulServletFilter.java | 48 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServletFilter.java diff --git a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration.java b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration.java index aa4bf8206..8e42db4c9 100644 --- a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration.java +++ b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration.java @@ -18,6 +18,7 @@ package org.springframework.cloud.netflix.zuul; import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.List; @@ -28,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.cloud.client.actuator.HasFeatures; @@ -59,6 +61,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.core.Ordered; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -66,6 +69,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.netflix.zuul.FilterLoader; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.filters.FilterRegistry; +import com.netflix.zuul.filters.ZuulServletFilter; import com.netflix.zuul.http.ZuulServlet; import com.netflix.zuul.monitoring.CounterFactory; import com.netflix.zuul.monitoring.TracerFactory; @@ -81,7 +85,7 @@ import static java.util.Collections.emptyList; */ @Configuration @EnableConfigurationProperties({ ZuulProperties.class }) -@ConditionalOnClass(ZuulServlet.class) +@ConditionalOnClass({ZuulServlet.class, ZuulServletFilter.class}) @ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class) // Make sure to get the ServerProperties from the same place as a normal web app would // FIXME @Import(ServerPropertiesAutoConfiguration.class) @@ -150,6 +154,7 @@ public class ZuulServerAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "zuulServlet") + @ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false", matchIfMissing = true) public ServletRegistrationBean zuulServlet() { ServletRegistrationBean servlet = new ServletRegistrationBean<>(new ZuulServlet(), this.zuulProperties.getServletPattern()); @@ -159,6 +164,20 @@ public class ZuulServerAutoConfiguration { return servlet; } + @Bean + @ConditionalOnMissingBean(name = "zuulServletFilter") + @ConditionalOnProperty(name = "zuul.use-filter", havingValue = "true", matchIfMissing = false) + public FilterRegistrationBean zuulServletFilter(){ + final FilterRegistrationBean filterRegistration = new FilterRegistrationBean<>(); + filterRegistration.setUrlPatterns(Collections.singleton(this.zuulProperties.getServletPattern())); + filterRegistration.setFilter(new ZuulServletFilter()); + filterRegistration.setOrder(Ordered.LOWEST_PRECEDENCE); + // The whole point of exposing this servlet is to provide a route that doesn't + // buffer requests. + filterRegistration.addInitParameter("buffer-requests", "false"); + return filterRegistration; + } + // pre filters @Bean diff --git a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServletFilter.java b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServletFilter.java new file mode 100644 index 000000000..93f3c2e00 --- /dev/null +++ b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServletFilter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.netflix.zuul; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import com.netflix.zuul.context.RequestContext; + +/** + * @author Craig Andrews + */ +public class ZuulServletFilter extends com.netflix.zuul.filters.ZuulServletFilter { + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, + FilterChain filterChain) throws IOException, ServletException { + + // Workaround https://github.com/Netflix/zuul/pull/430 + // This class can be removed, and com.netflix.zuul.filters.ZuulServletFilter used in its place, + // when using a Zuul release with that change in it. + + // Marks this request as having passed through the "Zuul engine", as opposed to servlets + // explicitly bound in web.xml, for which requests will not have the same data attached + RequestContext context = RequestContext.getCurrentContext(); + context.setZuulEngineRan(); + + super.doFilter(servletRequest, servletResponse, filterChain); + } +}