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  
28  package org.apache.http.impl.cookie;
29  
30  import java.util.ArrayList;
31  import java.util.List;
32  
33  import org.apache.http.Header;
34  import org.apache.http.client.utils.DateUtils;
35  import org.apache.http.cookie.ClientCookie;
36  import org.apache.http.cookie.Cookie;
37  import org.apache.http.cookie.CookieOrigin;
38  import org.apache.http.cookie.CookieSpec;
39  import org.apache.http.cookie.MalformedCookieException;
40  import org.apache.http.message.BasicHeader;
41  import org.junit.Assert;
42  import org.junit.Test;
43  
44  /**
45   * Test cases for RFC2109 cookie spec
46   */
47  public class TestCookieRFC2109Spec {
48  
49      @SuppressWarnings("unused")
50      @Test
51      public void testConstructor() throws Exception {
52          new RFC2109Spec();
53          new RFC2109Spec(null, false);
54          new RFC2109Spec(new String[] { DateUtils.PATTERN_RFC1036 }, false);
55      }
56  
57      @Test
58      public void testParseVersion() throws Exception {
59          final Header header = new BasicHeader("Set-Cookie","cookie-name=cookie-value; version=1");
60  
61          final CookieSpec cookiespec = new RFC2109Spec();
62          final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
63          final List<Cookie> cookies = cookiespec.parse(header, origin);
64          for (int i = 0; i < cookies.size(); i++) {
65              cookiespec.validate(cookies.get(i), origin);
66          }
67          Assert.assertEquals("Found 1 cookie.",1,cookies.size());
68          Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
69          Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
70          Assert.assertEquals("Version",1,cookies.get(0).getVersion());
71      }
72  
73      /**
74       * Test domain equals host
75       */
76      @Test
77      public void testCookiesomainEqualsHost() throws Exception {
78          final Header header = new BasicHeader("Set-Cookie",
79              "cookie-name=cookie-value; domain=www.b.com; version=1");
80  
81          final CookieSpec cookiespec = new RFC2109Spec();
82          final CookieOrigin origin = new CookieOrigin("www.b.com", 80, "/", false);
83          final List<Cookie> cookies = cookiespec.parse(header, origin);
84          for (int i = 0; i < cookies.size(); i++) {
85              cookiespec.validate(cookies.get(i), origin);
86          }
87          Assert.assertNotNull(cookies);
88          Assert.assertEquals(1, cookies.size());
89          Assert.assertEquals("www.b.com", cookies.get(0).getDomain());
90      }
91  
92      /**
93       * Domain does not start with a dot
94       */
95      @Test
96      public void testParseWithIllegalDomain1() throws Exception {
97          final Header header = new BasicHeader("Set-Cookie",
98              "cookie-name=cookie-value; domain=a.b.com; version=1");
99  
100         final CookieSpec cookiespec = new RFC2109Spec();
101         final CookieOrigin origin = new CookieOrigin("www.a.b.com", 80, "/", false);
102         try {
103             final List<Cookie> cookies = cookiespec.parse(header, origin);
104             for (int i = 0; i < cookies.size(); i++) {
105                 cookiespec.validate(cookies.get(i), origin);
106             }
107             Assert.fail("MalformedCookieException should have been thrown");
108         } catch (final MalformedCookieException e) {
109             // expected
110         }
111     }
112 
113     /**
114      * Domain must have alt least one embedded dot
115      */
116     @Test
117     public void testParseWithIllegalDomain2() throws Exception {
118         final Header header = new BasicHeader("Set-Cookie",
119             "cookie-name=cookie-value; domain=.com; version=1");
120 
121         final CookieSpec cookiespec = new RFC2109Spec();
122         final CookieOrigin origin = new CookieOrigin("b.com", 80, "/", false);
123         try {
124             final List<Cookie> cookies = cookiespec.parse(header, origin);
125             for (int i = 0; i < cookies.size(); i++) {
126                 cookiespec.validate(cookies.get(i), origin);
127             }
128             Assert.fail("MalformedCookieException should have been thrown");
129         } catch (final MalformedCookieException e) {
130             // expected
131         }
132     }
133 
134     /**
135      * Host minus domain may not contain any dots
136      */
137     @Test
138     public void testParseWithIllegalDomain4() throws Exception {
139         final Header header = new BasicHeader("Set-Cookie",
140             "cookie-name=cookie-value; domain=.c.com; version=1");
141 
142         final CookieSpec cookiespec = new RFC2109Spec();
143         final CookieOrigin origin = new CookieOrigin("a.b.c.com", 80, "/", false);
144         try {
145             final List<Cookie> cookies = cookiespec.parse(header, origin);
146             for (int i = 0; i < cookies.size(); i++) {
147                 cookiespec.validate(cookies.get(i), origin);
148             }
149             Assert.fail("MalformedCookieException should have been thrown");
150         } catch (final MalformedCookieException e) {
151             // expected
152         }
153     }
154 
155     /**
156      * Tests if that invalid second domain level cookie gets
157      * rejected in the strict mode, but gets accepted in the
158      * browser compatibility mode.
159      */
160     @Test
161     public void testSecondDomainLevelCookie() throws Exception {
162         final BasicClientCookie cookie = new BasicClientCookie("name", null);
163         cookie.setDomain(".sourceforge.net");
164         cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
165         cookie.setPath("/");
166         cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
167 
168         final CookieSpec cookiespec = new RFC2109Spec();
169         final CookieOrigin origin = new CookieOrigin("sourceforge.net", 80, "/", false);
170         try {
171             cookiespec.validate(cookie, origin);
172             Assert.fail("MalformedCookieException should have been thrown");
173         } catch (final MalformedCookieException e) {
174             // Expected
175         }
176     }
177 
178     @Test
179     public void testSecondDomainLevelCookieMatch() throws Exception {
180         final BasicClientCookie cookie = new BasicClientCookie("name", null);
181         cookie.setDomain(".sourceforge.net");
182         cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
183         cookie.setPath("/");
184         cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
185 
186         final CookieSpec cookiespec = new RFC2109Spec();
187         final CookieOrigin origin = new CookieOrigin("sourceforge.net", 80, "/", false);
188         Assert.assertFalse(cookiespec.match(cookie, origin));
189     }
190 
191     @Test
192     public void testParseWithWrongPath() throws Exception {
193         final Header header = new BasicHeader("Set-Cookie",
194             "cookie-name=cookie-value; domain=127.0.0.1; path=/not/just/root");
195 
196         final CookieSpec cookiespec = new RFC2109Spec();
197         final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
198         try {
199             final List<Cookie> cookies = cookiespec.parse(header, origin);
200             for (int i = 0; i < cookies.size(); i++) {
201                 cookiespec.validate(cookies.get(i), origin);
202             }
203             Assert.fail("MalformedCookieException exception should have been thrown");
204         } catch (final MalformedCookieException e) {
205             // expected
206         }
207     }
208 
209     /**
210      * Tests if cookie constructor rejects cookie name containing blanks.
211      */
212     @Test
213     public void testCookieNameWithBlanks() throws Exception {
214         final Header setcookie = new BasicHeader("Set-Cookie", "invalid name=");
215         final CookieSpec cookiespec = new RFC2109Spec();
216         final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
217         try {
218             final List<Cookie> cookies = cookiespec.parse(setcookie, origin);
219             for (int i = 0; i < cookies.size(); i++) {
220                 cookiespec.validate(cookies.get(i), origin);
221             }
222             Assert.fail("MalformedCookieException exception should have been thrown");
223         } catch (final MalformedCookieException e) {
224             // expected
225         }
226     }
227 
228     /**
229      * Tests if cookie constructor rejects cookie name starting with $.
230      */
231     @Test
232     public void testCookieNameStartingWithDollarSign() throws Exception {
233         final Header setcookie = new BasicHeader("Set-Cookie", "$invalid_name=");
234         final CookieSpec cookiespec = new RFC2109Spec();
235         final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
236         try {
237             final List<Cookie> cookies = cookiespec.parse(setcookie, origin);
238             for (int i = 0; i < cookies.size(); i++) {
239                 cookiespec.validate(cookies.get(i), origin);
240             }
241             Assert.fail("MalformedCookieException exception should have been thrown");
242         } catch (final MalformedCookieException e) {
243             // expected
244         }
245     }
246 
247     /**
248      * Tests if default cookie validator rejects cookies originating from a host without domain
249      * where domain attribute does not match the host of origin
250      */
251     @Test
252     public void testInvalidDomainWithSimpleHostName() throws Exception {
253         final CookieSpec cookiespec = new RFC2109Spec();
254         Header header = new BasicHeader("Set-Cookie",
255             "name=\"value\"; version=\"1\"; path=\"/\"; domain=\".mydomain.com\"");
256         final CookieOrigin origin1 = new CookieOrigin("host", 80, "/", false);
257         List<Cookie> cookies = cookiespec.parse(header, origin1);
258         try {
259             cookiespec.validate(cookies.get(0), origin1);
260             Assert.fail("MalformedCookieException must have thrown");
261         }
262         catch(final MalformedCookieException expected) {
263         }
264         final CookieOrigin origin2 = new CookieOrigin("host2", 80, "/", false);
265         header = new BasicHeader("Set-Cookie",
266             "name=\"value\"; version=\"1\"; path=\"/\"; domain=\"host1\"");
267         cookies = cookiespec.parse(header, origin2);
268         try {
269             cookiespec.validate(cookies.get(0), origin2);
270             Assert.fail("MalformedCookieException must have thrown");
271         }
272         catch(final MalformedCookieException expected) {
273         }
274     }
275 
276     /**
277      * Tests if cookie values with embedded comma are handled correctly.
278      */
279     @Test
280     public void testCookieWithComma() throws Exception {
281         final Header header = new BasicHeader("Set-Cookie", "a=b,c");
282 
283         final CookieSpec cookiespec = new RFC2109Spec();
284         final CookieOrigin origin = new CookieOrigin("localhost", 80, "/", false);
285         final List<Cookie> cookies = cookiespec.parse(header, origin);
286         Assert.assertEquals("number of cookies", 2, cookies.size());
287         Assert.assertEquals("a", cookies.get(0).getName());
288         Assert.assertEquals("b", cookies.get(0).getValue());
289         Assert.assertEquals("c", cookies.get(1).getName());
290         Assert.assertEquals(null, cookies.get(1).getValue());
291     }
292 
293     /**
294      * Tests RFC 2109 compiant cookie formatting.
295      */
296     @Test
297     public void testRFC2109CookieFormatting() throws Exception {
298         final CookieSpec cookiespec = new RFC2109Spec(null, false);
299         Header header = new BasicHeader("Set-Cookie",
300             "name=\"value\"; version=1; path=\"/\"; domain=\".mydomain.com\"");
301         final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
302         List<Cookie> cookies  = cookiespec.parse(header, origin);
303         cookiespec.validate(cookies.get(0), origin);
304         List<Header> headers = cookiespec.formatCookies(cookies);
305         Assert.assertNotNull(headers);
306         Assert.assertEquals(1, headers.size());
307         Assert.assertEquals("$Version=1; name=\"value\"; $Path=\"/\"; $Domain=\".mydomain.com\"",
308                 headers.get(0).getValue());
309 
310         header = new BasicHeader( "Set-Cookie",
311             "name=value; path=/; domain=.mydomain.com");
312         cookies = cookiespec.parse(header, origin);
313         cookiespec.validate(cookies.get(0), origin);
314         headers = cookiespec.formatCookies(cookies);
315         Assert.assertNotNull(headers);
316         Assert.assertEquals(1, headers.size());
317         Assert.assertEquals("$Version=0; name=value; $Path=/; $Domain=.mydomain.com",
318                 headers.get(0).getValue());
319     }
320 
321     @Test
322     public void testRFC2109CookiesFormatting() throws Exception {
323         final CookieSpec cookiespec = new RFC2109Spec(null, true);
324         Header header = new BasicHeader("Set-Cookie",
325             "name1=value1; path=/; domain=.mydomain.com, " +
326             "name2=\"value2\"; version=\"1\"; path=\"/\"; domain=\".mydomain.com\"");
327         final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
328         List<Cookie> cookies = cookiespec.parse(header, origin);
329         for (int i = 0; i < cookies.size(); i++) {
330             cookiespec.validate(cookies.get(i), origin);
331         }
332         Assert.assertNotNull(cookies);
333         Assert.assertEquals(2, cookies.size());
334         List<Header> headers  = cookiespec.formatCookies(cookies);
335         Assert.assertNotNull(headers);
336         Assert.assertEquals(1, headers.size());
337         Assert.assertEquals(
338             "$Version=0; name1=value1; $Path=/; $Domain=.mydomain.com; " +
339             "name2=value2; $Path=/; $Domain=.mydomain.com",
340             headers.get(0).getValue());
341 
342         header = new BasicHeader("Set-Cookie",
343             "name1=value1; version=1; path=/; domain=.mydomain.com, " +
344             "name2=\"value2\"; version=\"1\"; path=\"/\"; domain=\".mydomain.com\"");
345         cookies = cookiespec.parse(header, origin);
346         for (int i = 0; i < cookies.size(); i++) {
347             cookiespec.validate(cookies.get(i), origin);
348         }
349         Assert.assertNotNull(cookies);
350         Assert.assertEquals(2, cookies.size());
351         headers = cookiespec.formatCookies(cookies);
352         Assert.assertEquals(
353             "$Version=1; name1=\"value1\"; $Path=\"/\"; $Domain=\".mydomain.com\"; " +
354             "name2=\"value2\"; $Path=\"/\"; $Domain=\".mydomain.com\"",
355             headers.get(0).getValue());
356     }
357 
358     /**
359      * Tests if null cookie values are handled correctly.
360      */
361     @Test
362     public void testNullCookieValueFormatting() {
363         final BasicClientCookie cookie = new BasicClientCookie("name", null);
364         cookie.setDomain(".whatever.com");
365         cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
366         cookie.setPath("/");
367         cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
368 
369         final CookieSpec cookiespec = new RFC2109Spec();
370         List<Cookie> cookies = new ArrayList<Cookie>();
371         cookies.add(cookie);
372         List<Header> headers = cookiespec.formatCookies(cookies);
373         Assert.assertNotNull(headers);
374         Assert.assertEquals(1, headers.size());
375         Assert.assertEquals("$Version=0; name=; $Path=/; $Domain=.whatever.com",
376                 headers.get(0).getValue());
377 
378         cookie.setVersion(1);
379         cookies = new ArrayList<Cookie>();
380         cookies.add(cookie);
381         headers = cookiespec.formatCookies(cookies);
382         Assert.assertNotNull(headers);
383         Assert.assertEquals(1, headers.size());
384         Assert.assertEquals("$Version=1; name=; $Path=\"/\"; $Domain=\".whatever.com\"",
385                 headers.get(0).getValue());
386     }
387 
388     @Test
389     public void testCookieNullDomainNullPathFormatting() {
390         final BasicClientCookie cookie = new BasicClientCookie("name", null);
391         cookie.setPath("/");
392         cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
393 
394         final CookieSpec cookiespec = new RFC2109Spec();
395         List<Cookie> cookies = new ArrayList<Cookie>();
396         cookies.add(cookie);
397         List<Header> headers = cookiespec.formatCookies(cookies);
398         Assert.assertNotNull(headers);
399         Assert.assertEquals(1, headers.size());
400         Assert.assertEquals("$Version=0; name=; $Path=/", headers.get(0).getValue());
401 
402         cookie.removeAttribute(ClientCookie.DOMAIN_ATTR);
403         cookie.removeAttribute(ClientCookie.PATH_ATTR);
404         cookies = new ArrayList<Cookie>();
405         cookies.add(cookie);
406         headers = cookiespec.formatCookies(cookies);
407         Assert.assertNotNull(headers);
408         Assert.assertEquals(1, headers.size());
409         Assert.assertEquals("$Version=0; name=", headers.get(0).getValue());
410     }
411 
412     @Test
413     public void testCookieOrderingByPath() {
414         final BasicClientCookie c1 = new BasicClientCookie("name1", "value1");
415         c1.setPath("/a/b/c");
416         c1.setAttribute(ClientCookie.PATH_ATTR, c1.getPath());
417         final BasicClientCookie c2 = new BasicClientCookie("name2", "value2");
418         c2.setPath("/a/b");
419         c2.setAttribute(ClientCookie.PATH_ATTR, c2.getPath());
420         final BasicClientCookie c3 = new BasicClientCookie("name3", "value3");
421         c3.setPath("/a");
422         c3.setAttribute(ClientCookie.PATH_ATTR, c3.getPath());
423         final BasicClientCookie c4 = new BasicClientCookie("name4", "value4");
424         c4.setPath("/");
425         c4.setAttribute(ClientCookie.PATH_ATTR, c4.getPath());
426 
427         final CookieSpec cookiespec = new RFC2109Spec(null, true);
428         final List<Cookie> cookies = new ArrayList<Cookie>();
429         cookies.add(c2);
430         cookies.add(c4);
431         cookies.add(c1);
432         cookies.add(c3);
433         final List<Header> headers = cookiespec.formatCookies(cookies);
434         Assert.assertNotNull(headers);
435         Assert.assertEquals(1, headers.size());
436         Assert.assertEquals("$Version=0; name1=value1; $Path=/a/b/c; " +
437                 "name2=value2; $Path=/a/b; " +
438                 "name3=value3; $Path=/a; " +
439                 "name4=value4; $Path=/", headers.get(0).getValue());
440     }
441 
442     @Test(expected=MalformedCookieException.class)
443     public void testVersion1CookieWithInvalidExpires() throws Exception {
444         final CookieSpec cookiespec = new RFC2109Spec();
445         final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
446 
447         final Header origHeader = new BasicHeader("Set-Cookie",
448             "test=\"test\"; Version=1; Expires=Mon, 11-Feb-2013 10:39:19 GMT; Path=/");
449         cookiespec.parse(origHeader, origin);
450     }
451 
452     @Test
453     public void testInvalidInput() throws Exception {
454         final CookieSpec cookiespec = new RFC2109Spec();
455         try {
456             cookiespec.parse(null, null);
457             Assert.fail("IllegalArgumentException must have been thrown");
458         } catch (final IllegalArgumentException ex) {
459             // expected
460         }
461         try {
462             cookiespec.parse(new BasicHeader("Set-Cookie", "name=value"), null);
463             Assert.fail("IllegalArgumentException must have been thrown");
464         } catch (final IllegalArgumentException ex) {
465             // expected
466         }
467         try {
468             cookiespec.validate(null, null);
469             Assert.fail("IllegalArgumentException must have been thrown");
470         } catch (final IllegalArgumentException ex) {
471             // expected
472         }
473         try {
474             cookiespec.formatCookies(null);
475             Assert.fail("IllegalArgumentException must have been thrown");
476         } catch (final IllegalArgumentException ex) {
477             // expected
478         }
479         try {
480             final List<Cookie> cookies = new ArrayList<Cookie>();
481             cookiespec.formatCookies(cookies);
482             Assert.fail("IllegalArgumentException must have been thrown");
483         } catch (final IllegalArgumentException ex) {
484             // expected
485         }
486     }
487 
488 }