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; }