diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAddCookies.java b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAddCookies.java index cd6cdac1cd..25a6b50be0 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAddCookies.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAddCookies.java @@ -108,23 +108,20 @@ public void process(final HttpRequest request, final EntityDetails entity, final Args.notNull(request, "HTTP request"); Args.notNull(context, "HTTP context"); + final HttpClientContext clientContext = HttpClientContext.cast(context); + final String exchangeId = clientContext.getExchangeId(); + + // Discard the CookieSpec and CookieOrigin of a previous exchange executed with + // this context so the response interceptor never processes Set-Cookie headers + // against the origin of another request + clientContext.setCookieSpec(null); + clientContext.setCookieOrigin(null); + final String method = request.getMethod(); if (Method.CONNECT.isSame(method) || Method.TRACE.isSame(method)) { return; } - // Check if a Cookie header is already present - if (request.containsHeader(HttpHeaders.COOKIE)) { - if (LOG.isDebugEnabled()) { - LOG.debug("Skipping cookie addition, Cookie header already present in the request"); - } - // Skip adding cookies if the Cookie header is already present - return; - } - - final HttpClientContext clientContext = HttpClientContext.cast(context); - final String exchangeId = clientContext.getExchangeId(); - // Obtain cookie store final CookieStore cookieStore = clientContext.getCookieStore(); if (cookieStore == null) { @@ -184,6 +181,21 @@ public void process(final HttpRequest request, final EntityDetails entity, final return; } final CookieSpec cookieSpec = factory.create(clientContext); + + // Stick the CookieSpec and CookieOrigin instances to the HTTP context + // so they could be obtained by the response interceptor + clientContext.setCookieSpec(cookieSpec); + clientContext.setCookieOrigin(cookieOrigin); + + // Check if a Cookie header is already present + if (request.containsHeader(HttpHeaders.COOKIE)) { + if (LOG.isDebugEnabled()) { + LOG.debug("{} Skipping cookie addition, Cookie header already present in the request", exchangeId); + } + // Skip adding cookies if the Cookie header is already present + return; + } + // Get all cookies available in the HTTP state final List cookies = cookieStore.getCookies(); // Find cookies matching the given origin @@ -218,11 +230,6 @@ public void process(final HttpRequest request, final EntityDetails entity, final request.addHeader(header); } } - - // Stick the CookieSpec and CookieOrigin instances to the HTTP context - // so they could be obtained by the response interceptor - clientContext.setCookieSpec(cookieSpec); - clientContext.setCookieOrigin(cookieOrigin); } } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRequestAddCookies.java b/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRequestAddCookies.java index f59631082c..c3b231d3fc 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRequestAddCookies.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRequestAddCookies.java @@ -488,6 +488,62 @@ void testSkipAddingCookiesWhenCookieHeaderPresent() throws Exception { Assertions.assertEquals(1, headers.length); Assertions.assertEquals("existingCookie=existingValue", headers[0].getValue()); } + + @Test + void testCookieOriginUpdatedWhenCookieHeaderPresent() throws Exception { + final HttpClientContext context = HttpClientContext.create(); + context.setCookieStore(this.cookieStore); + context.setCookieSpecRegistry(this.cookieSpecRegistry); + + final HttpRequestInterceptor interceptor = RequestAddCookies.INSTANCE; + + // First exchange on this context: cookies are matched for localhost.local + final HttpRequest request1 = new BasicHttpRequest("GET", this.target, "/"); + context.setRoute(new HttpRoute(this.target, null, false)); + interceptor.process(request1, null, context); + Assertions.assertEquals("localhost.local", context.getCookieOrigin().getHost()); + + // Second exchange on the same context to a different host with an explicit Cookie header + final HttpHost otherHost = new HttpHost("other.local", 80); + final HttpRequest request2 = new BasicHttpRequest("GET", otherHost, "/stuff/"); + request2.addHeader("Cookie", "existingCookie=existingValue"); + context.setRoute(new HttpRoute(otherHost, null, false)); + interceptor.process(request2, null, context); + + final Header[] headers = request2.getHeaders("Cookie"); + Assertions.assertEquals(1, headers.length); + Assertions.assertEquals("existingCookie=existingValue", headers[0].getValue()); + + // The cookie origin must describe the request being executed, not the previous one + final CookieOrigin cookieOrigin = context.getCookieOrigin(); + Assertions.assertNotNull(cookieOrigin); + Assertions.assertEquals("other.local", cookieOrigin.getHost()); + Assertions.assertEquals(80, cookieOrigin.getPort()); + Assertions.assertEquals("/stuff/", cookieOrigin.getPath()); + Assertions.assertNotNull(context.getCookieSpec()); + } + + @Test + void testCookieOriginResetForTraceRequest() throws Exception { + final HttpClientContext context = HttpClientContext.create(); + context.setCookieStore(this.cookieStore); + context.setCookieSpecRegistry(this.cookieSpecRegistry); + + final HttpRequestInterceptor interceptor = RequestAddCookies.INSTANCE; + + final HttpRequest request1 = new BasicHttpRequest("GET", this.target, "/"); + context.setRoute(new HttpRoute(this.target, null, false)); + interceptor.process(request1, null, context); + Assertions.assertNotNull(context.getCookieOrigin()); + + final HttpHost otherHost = new HttpHost("other.local", 80); + final HttpRequest request2 = new BasicHttpRequest("TRACE", otherHost, "/"); + context.setRoute(new HttpRoute(otherHost, null, false)); + interceptor.process(request2, null, context); + + Assertions.assertNull(context.getCookieOrigin()); + Assertions.assertNull(context.getCookieSpec()); + } @Test void testAddCookiesWithRequestPathContainingQuery() throws Exception { final HttpRequest request = new BasicHttpRequest("GET", "/stuff?foo=bar");