View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.protocol;
28  
29  import java.util.Date;
30  
31  import org.apache.hc.client5.http.HttpRoute;
32  import org.apache.hc.client5.http.RouteInfo.LayerType;
33  import org.apache.hc.client5.http.RouteInfo.TunnelType;
34  import org.apache.hc.client5.http.cookie.StandardCookieSpec;
35  import org.apache.hc.client5.http.config.RequestConfig;
36  import org.apache.hc.client5.http.cookie.BasicCookieStore;
37  import org.apache.hc.client5.http.cookie.CookieOrigin;
38  import org.apache.hc.client5.http.cookie.CookieSpec;
39  import org.apache.hc.client5.http.cookie.CookieSpecFactory;
40  import org.apache.hc.client5.http.cookie.CookieStore;
41  import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
42  import org.apache.hc.client5.http.impl.cookie.IgnoreCookieSpecFactory;
43  import org.apache.hc.client5.http.impl.cookie.RFC6265CookieSpecFactory;
44  import org.apache.hc.client5.http.impl.cookie.RFC6265StrictSpec;
45  import org.apache.hc.core5.http.Header;
46  import org.apache.hc.core5.http.HttpHost;
47  import org.apache.hc.core5.http.HttpRequest;
48  import org.apache.hc.core5.http.HttpRequestInterceptor;
49  import org.apache.hc.core5.http.config.Lookup;
50  import org.apache.hc.core5.http.config.RegistryBuilder;
51  import org.apache.hc.core5.http.message.BasicHttpRequest;
52  import org.apache.hc.core5.http.protocol.HttpCoreContext;
53  import org.junit.Assert;
54  import org.junit.Before;
55  import org.junit.Test;
56  import org.mockito.ArgumentMatchers;
57  import org.mockito.Mockito;
58  
59  public class TestRequestAddCookies {
60  
61      private HttpHost target;
62      private CookieStore cookieStore;
63      private Lookup<CookieSpecFactory> cookieSpecRegistry;
64  
65      @Before
66      public void setUp() {
67          this.target = new HttpHost("localhost.local", 80);
68          this.cookieStore = new BasicCookieStore();
69          final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value1");
70          cookie1.setDomain("localhost.local");
71          cookie1.setPath("/");
72          this.cookieStore.addCookie(cookie1);
73          final BasicClientCookie cookie2 = new BasicClientCookie("name2", "value2");
74          cookie2.setDomain("localhost.local");
75          cookie2.setPath("/");
76          this.cookieStore.addCookie(cookie2);
77  
78          this.cookieSpecRegistry = RegistryBuilder.<CookieSpecFactory>create()
79              .register(StandardCookieSpec.RELAXED, new RFC6265CookieSpecFactory(
80                      RFC6265CookieSpecFactory.CompatibilityLevel.RELAXED, null))
81              .register(StandardCookieSpec.STRICT,  new RFC6265CookieSpecFactory(
82                      RFC6265CookieSpecFactory.CompatibilityLevel.STRICT, null))
83              .register(StandardCookieSpec.IGNORE, new IgnoreCookieSpecFactory())
84              .build();
85      }
86  
87      @Test(expected=NullPointerException.class)
88      public void testRequestParameterCheck() throws Exception {
89          final HttpClientContext context = HttpClientContext.create();
90          final HttpRequestInterceptor interceptor = new RequestAddCookies();
91          interceptor.process(null, null, context);
92      }
93  
94      @Test(expected=NullPointerException.class)
95      public void testContextParameterCheck() throws Exception {
96          final HttpRequest request = new BasicHttpRequest("GET", "/");
97          final HttpRequestInterceptor interceptor = new RequestAddCookies();
98          interceptor.process(request, null, null);
99      }
100 
101     @Test
102     public void testAddCookies() throws Exception {
103         final HttpRequest request = new BasicHttpRequest("GET", "/");
104 
105         final HttpRoute route = new HttpRoute(this.target, null, false);
106 
107         final HttpClientContext context = HttpClientContext.create();
108         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
109         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
110         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
111 
112         final HttpRequestInterceptor interceptor = new RequestAddCookies();
113         interceptor.process(request, null, context);
114 
115         final Header[] headers = request.getHeaders("Cookie");
116         Assert.assertNotNull(headers);
117         Assert.assertEquals(1, headers.length);
118         Assert.assertEquals("name1=value1; name2=value2", headers[0].getValue());
119 
120         final CookieOrigin cookieOrigin = context.getCookieOrigin();
121         Assert.assertNotNull(cookieOrigin);
122         Assert.assertEquals(this.target.getHostName(), cookieOrigin.getHost());
123         Assert.assertEquals(this.target.getPort(), cookieOrigin.getPort());
124         Assert.assertEquals("/", cookieOrigin.getPath());
125         Assert.assertFalse(cookieOrigin.isSecure());
126     }
127 
128     @Test
129     public void testCookiesForConnectRequest() throws Exception {
130         final HttpRequest request = new BasicHttpRequest("CONNECT", "www.somedomain.com");
131 
132         final HttpRoute route = new HttpRoute(this.target, null, false);
133 
134         final HttpClientContext context = HttpClientContext.create();
135         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
136         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
137         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
138 
139         final HttpRequestInterceptor interceptor = new RequestAddCookies();
140         interceptor.process(request, null, context);
141 
142         final Header[] headers = request.getHeaders("Cookie");
143         Assert.assertNotNull(headers);
144         Assert.assertEquals(0, headers.length);
145     }
146 
147     @Test
148     public void testNoCookieStore() throws Exception {
149         final HttpRequest request = new BasicHttpRequest("GET", "/");
150 
151         final HttpRoute route = new HttpRoute(this.target, null, false);
152 
153         final HttpClientContext context = HttpClientContext.create();
154         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
155         context.setAttribute(HttpClientContext.COOKIE_STORE, null);
156         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
157 
158         final HttpRequestInterceptor interceptor = new RequestAddCookies();
159         interceptor.process(request, null, context);
160 
161         final Header[] headers = request.getHeaders("Cookie");
162         Assert.assertNotNull(headers);
163         Assert.assertEquals(0, headers.length);
164     }
165 
166     @Test
167     public void testNoCookieSpecRegistry() throws Exception {
168         final HttpRequest request = new BasicHttpRequest("GET", "/");
169 
170         final HttpRoute route = new HttpRoute(this.target, null, false);
171 
172         final HttpClientContext context = HttpClientContext.create();
173         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
174         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
175         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, null);
176 
177         final HttpRequestInterceptor interceptor = new RequestAddCookies();
178         interceptor.process(request, null, context);
179 
180         final Header[] headers = request.getHeaders("Cookie");
181         Assert.assertNotNull(headers);
182         Assert.assertEquals(0, headers.length);
183     }
184 
185     @Test
186     public void testNoHttpConnection() throws Exception {
187         final HttpRequest request = new BasicHttpRequest("GET", "/");
188 
189         final HttpClientContext context = HttpClientContext.create();
190         context.setAttribute(HttpCoreContext.CONNECTION_ENDPOINT, null);
191         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
192         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
193 
194         final HttpRequestInterceptor interceptor = new RequestAddCookies();
195         interceptor.process(request, null, context);
196 
197         final Header[] headers = request.getHeaders("Cookie");
198         Assert.assertNotNull(headers);
199         Assert.assertEquals(0, headers.length);
200     }
201 
202     @Test
203     public void testAddCookiesUsingExplicitCookieSpec() throws Exception {
204         final HttpRequest request = new BasicHttpRequest("GET", "/");
205         final RequestConfig config = RequestConfig.custom()
206                 .setCookieSpec(StandardCookieSpec.STRICT)
207                 .build();
208         final HttpRoute route = new HttpRoute(this.target, null, false);
209 
210         final HttpClientContext context = HttpClientContext.create();
211         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
212         context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
213         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
214         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
215 
216         final HttpRequestInterceptor interceptor = new RequestAddCookies();
217         interceptor.process(request, null, context);
218 
219         final CookieSpec cookieSpec = context.getCookieSpec();
220         Assert.assertTrue(cookieSpec instanceof RFC6265StrictSpec);
221 
222         final Header[] headers1 = request.getHeaders("Cookie");
223         Assert.assertNotNull(headers1);
224         Assert.assertEquals(1, headers1.length);
225         Assert.assertEquals("name1=value1; name2=value2", headers1[0].getValue());
226     }
227 
228     @Test
229     public void testAuthScopeInvalidRequestURI() throws Exception {
230         final HttpRequest request = new BasicHttpRequest("GET", "crap:");
231 
232         final HttpRoute route = new HttpRoute(this.target, null, false);
233 
234         final HttpClientContext context = HttpClientContext.create();
235         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
236         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
237         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
238 
239         final HttpRequestInterceptor interceptor = new RequestAddCookies();
240         interceptor.process(request, null, context);
241     }
242 
243     @Test
244     public void testAuthScopeRemotePortWhenDirect() throws Exception {
245         final HttpRequest request = new BasicHttpRequest("GET", "/stuff");
246 
247         this.target = new HttpHost("localhost.local");
248         final HttpRoute route = new HttpRoute(new HttpHost("localhost.local", 1234), null, false);
249 
250         final HttpClientContext context = HttpClientContext.create();
251         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
252         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
253         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
254 
255         final HttpRequestInterceptor interceptor = new RequestAddCookies();
256         interceptor.process(request, null, context);
257 
258         final CookieOrigin cookieOrigin = context.getCookieOrigin();
259         Assert.assertNotNull(cookieOrigin);
260         Assert.assertEquals(this.target.getHostName(), cookieOrigin.getHost());
261         Assert.assertEquals(1234, cookieOrigin.getPort());
262         Assert.assertEquals("/stuff", cookieOrigin.getPath());
263         Assert.assertFalse(cookieOrigin.isSecure());
264     }
265 
266     @Test
267     public void testAuthDefaultHttpPortWhenProxy() throws Exception {
268         final HttpRequest request = new BasicHttpRequest("GET", "/stuff");
269 
270         this.target = new HttpHost("localhost.local");
271         final HttpRoute route = new HttpRoute(
272                 new HttpHost("localhost.local", 80), null, new HttpHost("localhost", 8888), false);
273 
274         final HttpClientContext context = HttpClientContext.create();
275         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
276         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
277         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
278 
279         final HttpRequestInterceptor interceptor = new RequestAddCookies();
280         interceptor.process(request, null, context);
281 
282         final CookieOrigin cookieOrigin = context.getCookieOrigin();
283         Assert.assertNotNull(cookieOrigin);
284         Assert.assertEquals(this.target.getHostName(), cookieOrigin.getHost());
285         Assert.assertEquals(80, cookieOrigin.getPort());
286         Assert.assertEquals("/stuff", cookieOrigin.getPath());
287         Assert.assertFalse(cookieOrigin.isSecure());
288     }
289 
290     @Test
291     public void testAuthDefaultHttpsPortWhenProxy() throws Exception {
292         final HttpRequest request = new BasicHttpRequest("GET", "/stuff");
293 
294         this.target = new HttpHost("https", "localhost", -1);
295         final HttpRoute route = new HttpRoute(
296                 new HttpHost("https", "localhost", 443), null,
297                 new HttpHost("http", "localhost", 8888), true, TunnelType.TUNNELLED, LayerType.LAYERED);
298 
299         final HttpClientContext context = HttpClientContext.create();
300         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
301         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
302         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
303 
304         final HttpRequestInterceptor interceptor = new RequestAddCookies();
305         interceptor.process(request, null, context);
306 
307         final CookieOrigin cookieOrigin = context.getCookieOrigin();
308         Assert.assertNotNull(cookieOrigin);
309         Assert.assertEquals(this.target.getHostName(), cookieOrigin.getHost());
310         Assert.assertEquals(443, cookieOrigin.getPort());
311         Assert.assertEquals("/stuff", cookieOrigin.getPath());
312         Assert.assertTrue(cookieOrigin.isSecure());
313     }
314 
315     @Test
316     public void testExcludeExpiredCookies() throws Exception {
317         final HttpRequest request = new BasicHttpRequest("GET", "/");
318 
319         final BasicClientCookie cookie3 = new BasicClientCookie("name3", "value3");
320         cookie3.setDomain("localhost.local");
321         cookie3.setPath("/");
322         cookie3.setExpiryDate(new Date(System.currentTimeMillis() + 100));
323         this.cookieStore.addCookie(cookie3);
324 
325         Assert.assertEquals(3, this.cookieStore.getCookies().size());
326 
327         this.cookieStore = Mockito.spy(this.cookieStore);
328 
329         final HttpRoute route = new HttpRoute(this.target, null, false);
330 
331         final HttpClientContext context = HttpClientContext.create();
332         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
333         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
334         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
335 
336         // Make sure the third cookie expires
337         Thread.sleep(200);
338 
339         final HttpRequestInterceptor interceptor = new RequestAddCookies();
340         interceptor.process(request, null, context);
341 
342         final Header[] headers = request.getHeaders("Cookie");
343         Assert.assertNotNull(headers);
344         Assert.assertEquals(1, headers.length);
345         Assert.assertEquals("name1=value1; name2=value2", headers[0].getValue());
346 
347         Mockito.verify(this.cookieStore, Mockito.times(1)).clearExpired(ArgumentMatchers.<Date>any());
348     }
349 
350     @Test
351     public void testNoMatchingCookies() throws Exception {
352         final HttpRequest request = new BasicHttpRequest("GET", "/");
353 
354         this.cookieStore.clear();
355         final BasicClientCookie cookie3 = new BasicClientCookie("name3", "value3");
356         cookie3.setDomain("www.somedomain.com");
357         cookie3.setPath("/");
358         this.cookieStore.addCookie(cookie3);
359 
360         final HttpRoute route = new HttpRoute(this.target, null, false);
361 
362         final HttpClientContext context = HttpClientContext.create();
363         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
364         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
365         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
366 
367         final HttpRequestInterceptor interceptor = new RequestAddCookies();
368         interceptor.process(request, null, context);
369 
370         final Header[] headers = request.getHeaders("Cookie");
371         Assert.assertNotNull(headers);
372         Assert.assertEquals(0, headers.length);
373     }
374 
375     // Helper method
376     private BasicClientCookie makeCookie(final String name, final String value, final String domain, final String path) {
377         final BasicClientCookie cookie = new BasicClientCookie(name, value);
378         cookie.setDomain(domain);
379         cookie.setPath(path);
380         return cookie;
381     }
382 
383     @Test
384     // Test for ordering adapted from test in Commons HC 3.1
385     public void testCookieOrder() throws Exception {
386         final HttpRequest request = new BasicHttpRequest("GET", "/foobar/yada/yada");
387 
388         this.cookieStore.clear();
389 
390         cookieStore.addCookie(makeCookie("nomatch", "value", "localhost.local", "/noway"));
391         cookieStore.addCookie(makeCookie("name2",   "value", "localhost.local", "/foobar/yada"));
392         cookieStore.addCookie(makeCookie("name3",   "value", "localhost.local", "/foobar"));
393         cookieStore.addCookie(makeCookie("name1",   "value", "localhost.local", "/foobar/yada/yada"));
394 
395         final HttpRoute route = new HttpRoute(this.target, null, false);
396 
397         final HttpClientContext context = HttpClientContext.create();
398         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
399         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
400         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
401 
402         final HttpRequestInterceptor interceptor = new RequestAddCookies();
403         interceptor.process(request, null, context);
404 
405         final Header[] headers1 = request.getHeaders("Cookie");
406         Assert.assertNotNull(headers1);
407         Assert.assertEquals(1, headers1.length);
408 
409         Assert.assertEquals("name1=value; name2=value; name3=value", headers1[0].getValue());
410     }
411 
412 }