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 02ca6dc7..59e14869 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 @@ -87,7 +87,8 @@ public class ZuulProxyConfiguration extends ZuulConfiguration { @Bean public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator) { return new PreDecorationFilter(routeLocator, - this.zuulProperties.isAddProxyHeaders()); + this.zuulProperties.isAddProxyHeaders(), + this.zuulProperties.isRemoveSemicolonContent()); } // route filters diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java index 0aa5ff29..d3f1737f 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java @@ -74,6 +74,8 @@ public class ZuulProperties { private boolean traceRequestBody = true; + private boolean removeSemicolonContent = true; + public Set getIgnoredHeaders() { Set ignoredHeaders = new LinkedHashSet<>(this.ignoredHeaders); if (ClassUtils.isPresent( 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 696d8f5d..127d2753 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 @@ -39,9 +39,10 @@ public class PreDecorationFilter extends ZuulFilter { private UrlPathHelper urlPathHelper = new UrlPathHelper(); - public PreDecorationFilter(RouteLocator routeLocator, boolean addProxyHeaders) { + public PreDecorationFilter(RouteLocator routeLocator, boolean addProxyHeaders, boolean removeSemicolonContent) { this.routeLocator = routeLocator; this.addProxyHeaders = addProxyHeaders; + this.urlPathHelper.setRemoveSemicolonContent(removeSemicolonContent); } @Override diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java index 40144212..47a84571 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java @@ -50,6 +50,8 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.MatrixVariable; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -60,19 +62,20 @@ import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.netflix.niws.client.http.RestClient; +import lombok.SneakyThrows; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import lombok.SneakyThrows; - @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SampleZuulProxyApplication.class) @WebAppConfiguration -@IntegrationTest({ "server.port: 0", +@IntegrationTest({"server.port: 0", "zuul.routes.other: /test/**=http://localhost:7777/local", "zuul.routes.another: /another/twolevel/**", "zuul.routes.simple: /simple/**", - "zuul.routes.badhost: /badhost/**", "zuul.ignoredHeaders: X-Header" }) + "zuul.routes.badhost: /badhost/**", "zuul.ignoredHeaders: X-Header", + "zuul.removeSemicolonContent: false"}) @DirtiesContext public class SampleZuulProxyApplicationTests extends ZuulProxyTestBase { @@ -121,13 +124,25 @@ public class SampleZuulProxyApplicationTests extends ZuulProxyTestBase { assertEquals("/query?foo=bar", result.getBody()); } + @Test + public void simpleHostRouteWithMatrix() { + this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/"); + this.endpoint.reset(); + ResponseEntity result = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/self/matrix/my;q=2;p=1/more;x=2", + HttpMethod.GET, new HttpEntity<>((Void) null), String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("my=1-2;more=2", result.getBody()); + } + @Test public void simpleHostRouteWithEncodedQuery() { this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/"); this.endpoint.reset(); ResponseEntity result = new TestRestTemplate().exchange( - "http://localhost:" + this.port + "/self/query?foo={foo}", HttpMethod.GET, - new HttpEntity<>((Void) null), String.class, "weird#chars"); + "http://localhost:" + this.port + "/self/query?foo={foo}", + HttpMethod.GET, new HttpEntity<>((Void) null), String.class, + "weird#chars"); assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals("/query?foo=weird#chars", result.getBody()); } @@ -175,12 +190,12 @@ public class SampleZuulProxyApplicationTests extends ZuulProxyTestBase { @RibbonClient(name = "another", configuration = AnotherRibbonClientConfiguration.class) }) class SampleZuulProxyApplication extends ZuulProxyTestBase.AbstractZuulProxyApplication { - @RequestMapping(value = "/trailing-slash") + @RequestMapping("/trailing-slash") public String trailingSlash(HttpServletRequest request) { return request.getRequestURI(); } - @RequestMapping(value = "/add-header") + @RequestMapping("/add-header") public ResponseEntity addHeader(HttpServletRequest request) { HttpHeaders headers = new HttpHeaders(); headers.set("X-Header", "FOO"); @@ -189,11 +204,19 @@ class SampleZuulProxyApplication extends ZuulProxyTestBase.AbstractZuulProxyAppl return result; } - @RequestMapping(value = "/query") + @RequestMapping("/query") public String addQuery(HttpServletRequest request, @RequestParam String foo) { return request.getRequestURI() + "?foo=" + foo; } + @RequestMapping("/matrix/{name}/{another}") + public String matrix(@PathVariable("name") String name, + @MatrixVariable(value = "p", pathVar = "name") int p, + @MatrixVariable(value = "q", pathVar = "name") int q, + @PathVariable("another") String another, @MatrixVariable(value = "x", pathVar = "another") int x) { + return name + "=" + p + "-" + q + ";" + another + "=" + x; + } + @Bean public RibbonCommandFactory ribbonCommandFactory( SpringClientFactory clientFactory) { diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java index c8489fa4..3cd32427 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java @@ -27,6 +27,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; @@ -182,7 +184,7 @@ public abstract class ZuulProxyTestBase { assertEquals("Received {key=[overridden]}", result.getBody()); } - protected static abstract class AbstractZuulProxyApplication { + protected static abstract class AbstractZuulProxyApplication extends DelegatingWebMvcConfiguration { @RequestMapping("/testing123") public String testing123() { @@ -258,6 +260,13 @@ public abstract class ZuulProxyTestBase { } }; } + + @Override + public RequestMappingHandlerMapping requestMappingHandlerMapping() { + RequestMappingHandlerMapping mapping = super.requestMappingHandlerMapping(); + mapping.setRemoveSemicolonContent(false); + return mapping; + } } } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java index 14f7cb6f..c98fcc7c 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilterTests.java @@ -54,7 +54,8 @@ public class PreDecorationFilterTests { initMocks(this); this.routeLocator = new DiscoveryClientRouteLocator("/", this.discovery, this.properties); - this.filter = new PreDecorationFilter(this.routeLocator, true); + this.filter = new PreDecorationFilter(this.routeLocator, true, + this.properties.isRemoveSemicolonContent()); RequestContext ctx = RequestContext.getCurrentContext(); ctx.clear(); ctx.setRequest(this.request);