diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClient.java index 09539007..5fa34dc0 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClient.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClient.java @@ -36,7 +36,7 @@ import com.netflix.loadbalancer.ILoadBalancer; public class RibbonLoadBalancingHttpClient extends AbstractLoadBalancingClient { - private final HttpClient delegate = HttpClientBuilder.create().build(); + private final HttpClient delegate = HttpClientBuilder.create().disableCookieManagement().build(); public RibbonLoadBalancingHttpClient() { super(); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java index 0947b0e8..483294c1 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java @@ -17,9 +17,15 @@ package org.springframework.cloud.netflix.zuul.filters.route.apache; +import com.netflix.client.RetryHandler; +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ServerList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.web.ErrorAttributes; import org.springframework.boot.test.SpringApplicationConfiguration; @@ -28,6 +34,8 @@ import org.springframework.boot.test.WebIntegrationTest; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.cloud.netflix.ribbon.StaticServerList; +import org.springframework.cloud.netflix.ribbon.apache.RibbonLoadBalancingHttpClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory; import org.springframework.cloud.netflix.zuul.filters.route.support.ZuulProxyTestBase; @@ -44,9 +52,16 @@ 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.RestController; +import org.springframework.web.util.WebUtils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.springframework.http.HttpHeaders.SET_COOKIE; /** * @author Spencer Gibb @@ -55,7 +70,8 @@ import static org.junit.Assert.assertTrue; @SpringApplicationConfiguration(classes = HttpClientRibbonCommandIntegrationTests.TestConfig.class) @WebIntegrationTest(randomPort = true, value = { "zuul.routes.other: /test/**=http://localhost:7777/local", - "zuul.routes.another: /another/twolevel/**", "zuul.routes.simple: /simple/**" }) + "zuul.routes.another: /another/twolevel/**", "zuul.routes.simple: /simple/**", + "zuul.routes.singleton: /singleton/**", "zuul.routes.singleton.sensitiveHeaders: " }) @DirtiesContext public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase { @@ -96,6 +112,33 @@ public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase { assertEquals("Deleted 1!", result.getBody()); } + @Test + public void ribbonLoadBalancingHttpClientCookiePolicy() { + ResponseEntity result = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/simple/downstream_cookie", HttpMethod.POST, + new HttpEntity<>((Void) null), String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("Cookie 434354454!", result.getBody()); + assertNull(result.getHeaders().getFirst(SET_COOKIE)); + + + // if new instance of RibbonLoadBalancingHttpClient is getting created every time + // and HttpClient is not reused then there are no concerns for the shared cookie storage + // but since https://github.com/spring-cloud/spring-cloud-netflix/issues/1150 is on the way a + result = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/singleton/downstream_cookie", HttpMethod.POST, + new HttpEntity<>((Void) null), String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("Cookie 434354454!", result.getBody()); + assertEquals("jsessionid=434354454", result.getHeaders().getFirst(SET_COOKIE)); + + result = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/singleton/downstream_cookie", HttpMethod.GET, + new HttpEntity<>((Void) null), String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("Cookie null!", result.getBody()); + } + @Test public void ribbonCommandFactoryOverridden() { assertTrue("ribbonCommandFactory not a HttpClientRibbonCommandFactory", @@ -108,7 +151,8 @@ public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase { @EnableZuulProxy @RibbonClients({ @RibbonClient(name = "simple", configuration = ZuulProxyTestBase.SimpleRibbonClientConfiguration.class), - @RibbonClient(name = "another", configuration = ZuulProxyTestBase.AnotherRibbonClientConfiguration.class) }) + @RibbonClient(name = "another", configuration = ZuulProxyTestBase.AnotherRibbonClientConfiguration.class), + @RibbonClient(name = "singleton", configuration = SingletonRibbonClientConfiguration.class) }) static class TestConfig extends ZuulProxyTestBase.AbstractZuulProxyApplication { @RequestMapping(value = "/local/{id}", method = RequestMethod.PATCH) @@ -116,6 +160,21 @@ public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase { return "Patched " + id + "!"; } + @RequestMapping(value = "/downstream_cookie", method = RequestMethod.POST) + public String setDownstreamCookie(HttpServletResponse response) + { + response.addCookie(new Cookie("jsessionid", "434354454")); + return "Cookie 434354454!"; + } + + @RequestMapping(value = "/downstream_cookie", method = RequestMethod.GET) + public String readDownstreamCookie(HttpServletRequest request) + { + final Cookie cookie = WebUtils.getCookie(request, "jsessionid"); + return "Cookie " + cookie + "!"; + } + + @Bean public RibbonCommandFactory ribbonCommandFactory( final SpringClientFactory clientFactory) { @@ -127,4 +186,28 @@ public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase { return new ZuulProxyTestBase.MyErrorController(errorAttributes); } } + + // Load balancer with fixed server list and defined ribbon rest client + @Configuration + public static class SingletonRibbonClientConfiguration { + + @Value("${local.server.port}") + private int port; + + @Bean + public ServerList ribbonServerList() { + return new StaticServerList<>(new Server("localhost", this.port)); + } + + @Bean + public RibbonLoadBalancingHttpClient ribbonClient(IClientConfig config, ILoadBalancer loadBalancer, RetryHandler retryHandler) + { + final RibbonLoadBalancingHttpClient client = new RibbonLoadBalancingHttpClient(); + client.setLoadBalancer(loadBalancer); + client.setRetryHandler(retryHandler); + client.initWithNiwsConfig(config); + return client; + } + + } }