From dd1c5bb495e66ec51ac290023e95fab8ae854a78 Mon Sep 17 00:00:00 2001 From: Jakub Stachowski Date: Sat, 11 Jul 2015 20:21:41 +0200 Subject: [PATCH] Build query string from context instead of original request Recreate query string from either getCurrentContext().getRequestQueryParams() or original request as fallback. This allows to override query string params in pre filters. fixes gh-426 --- .../route/SimpleHostRoutingFilter.java | 18 +++++++-- .../zuul/SampleZuulProxyApplicationTests.java | 40 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java index cc534ec4..5238ace0 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java @@ -18,8 +18,10 @@ package org.springframework.cloud.netflix.zuul.filters.route; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.Socket; import java.net.URL; +import java.net.URLEncoder; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; @@ -259,10 +261,20 @@ public class SimpleHostRoutingFilter extends ZuulFilter { return httpclient.execute(httpHost, httpRequest); } - private String getQueryString() { + private String getQueryString() throws UnsupportedEncodingException { HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); - String query = request.getQueryString(); - return (query != null) ? "?" + query : ""; + MultiValueMap params=helper.buildZuulRequestQueryParams(request); + StringBuilder query=new StringBuilder(); + for (Map.Entry> entry : params.entrySet()) { + String key=URLEncoder.encode(entry.getKey(), "UTF-8"); + for (String value : entry.getValue()) { + query.append("&"); + query.append(key); + query.append("="); + query.append(URLEncoder.encode(value, "UTF-8")); + } + } + return (query.length()>0) ? "?" + query.substring(1) : ""; } private HttpHost getHttpHost(URL host) { 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 d1e7c52f..5c3c3f0e 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 @@ -19,6 +19,9 @@ package org.springframework.cloud.netflix.zuul; import static org.junit.Assert.assertEquals; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,6 +34,8 @@ import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.TestRestTemplate; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.RibbonClients; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; +import org.springframework.cloud.netflix.zuul.RoutesEndpoint; import org.springframework.cloud.netflix.zuul.filters.ProxyRouteLocator; import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute; import org.springframework.context.annotation.Bean; @@ -42,10 +47,12 @@ import org.springframework.http.ResponseEntity; 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.PathVariable; 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.bind.annotation.RestController; import com.netflix.appinfo.EurekaInstanceConfig; @@ -53,6 +60,7 @@ import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SampleZuulProxyApplication.class) @@ -153,6 +161,28 @@ public class SampleZuulProxyApplicationTests { assertEquals("Hello space", result.getBody()); } + @Test + public void simpleHostRouteWithOriginalQString() { + routes.addRoute("/self/**", "http://localhost:" + this.port); + this.endpoint.reset(); + ResponseEntity result = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/self/qstring?original=value1&original=value2", HttpMethod.GET, + new HttpEntity<>((Void) null), String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("Received {original=[value1, value2]}", result.getBody()); + } + + @Test + public void simpleHostRouteWithOverriddenQString() { + routes.addRoute("/self/**", "http://localhost:" + this.port); + this.endpoint.reset(); + ResponseEntity result = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/self/qstring?override=true&different=key", HttpMethod.GET, + new HttpEntity<>((Void) null), String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("Received {key=[overridden]}", result.getBody()); + } + } // Don't use @SpringBootApplication because we don't want to component scan @@ -190,6 +220,11 @@ class SampleZuulProxyApplication { return "Posted " + id + "!"; } + @RequestMapping(value = "/qstring") + public String qstring(@RequestParam MultiValueMap params) { + return "Received "+params.toString(); + } + @RequestMapping("/") public String home() { return "Hello world"; @@ -215,6 +250,11 @@ class SampleZuulProxyApplication { @Override public Object run() { + if (RequestContext.getCurrentContext().getRequest().getParameterMap().containsKey("override")) { + Map> overridden=new HashMap<>(); + overridden.put("key", Arrays.asList("overridden")); + RequestContext.getCurrentContext().setRequestQueryParams(overridden); + } return null; }