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.hc.client5.http.impl.cookie;
29  
30  import java.util.Arrays;
31  import java.util.Collections;
32  import java.util.List;
33  
34  import org.apache.hc.client5.http.cookie.CommonCookieAttributeHandler;
35  import org.apache.hc.client5.http.cookie.Cookie;
36  import org.apache.hc.client5.http.cookie.CookieOrigin;
37  import org.apache.hc.client5.http.cookie.MalformedCookieException;
38  import org.apache.hc.core5.http.Header;
39  import org.apache.hc.core5.http.message.BasicHeader;
40  import org.junit.jupiter.api.Assertions;
41  import org.junit.jupiter.api.Test;
42  import org.mockito.ArgumentMatchers;
43  import org.mockito.Mockito;
44  
45  public class TestRFC6265CookieSpec {
46  
47      @Test
48      public void testParseCookieBasics() throws Exception {
49          final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
50          Mockito.when(h1.getAttributeName()).thenReturn("this");
51          final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
52          Mockito.when(h2.getAttributeName()).thenReturn("that");
53  
54          final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
55  
56          final Header header = new BasicHeader("Set-Cookie", "name = value ; this = stuff;");
57          final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
58          final List<Cookie> cookies = cookiespec.parse(header, origin);
59  
60          Assertions.assertEquals(1, cookies.size());
61          final Cookie cookie = cookies.get(0);
62          Assertions.assertEquals("name", cookie.getName());
63          Assertions.assertEquals("value", cookie.getValue());
64          Assertions.assertEquals("/path", cookie.getPath());
65          Assertions.assertEquals("host", cookie.getDomain());
66          Assertions.assertEquals("stuff", cookie.getAttribute("this"));
67          Assertions.assertNull(cookie.getAttribute("that"));
68  
69          Mockito.verify(h1).parse(ArgumentMatchers.any(), ArgumentMatchers.eq("stuff"));
70          Mockito.verify(h2, Mockito.never()).parse(ArgumentMatchers.any(), ArgumentMatchers.anyString());
71      }
72  
73      @Test
74      public void testParseCookieQuotedValue() throws Exception {
75          final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
76  
77          final Header header = new BasicHeader("Set-Cookie", "name = \" one, two, three; four \" ; this = stuff;");
78          final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
79          final List<Cookie> cookies = cookiespec.parse(header, origin);
80  
81          Assertions.assertEquals(1, cookies.size());
82          final Cookie cookie = cookies.get(0);
83          Assertions.assertEquals("name", cookie.getName());
84          Assertions.assertEquals(" one, two, three; four ", cookie.getValue());
85          Assertions.assertEquals("stuff", cookie.getAttribute("this"));
86      }
87  
88      @Test
89      public void testParseCookieWrongHeader() throws Exception {
90          final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
91  
92          final Header header = new BasicHeader("Set-Cookie2", "blah");
93          final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
94          Assertions.assertThrows(MalformedCookieException.class, () ->
95                  cookiespec.parse(header, origin));
96      }
97  
98      @Test
99      public void testParseCookieMissingName() throws Exception {
100         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
101 
102         final Header header = new BasicHeader("Set-Cookie", "=blah ; this = stuff;");
103         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
104         final List<Cookie> cookies = cookiespec.parse(header, origin);
105         Assertions.assertEquals(0, cookies.size());
106     }
107 
108     @Test
109     public void testParseCookieMissingValue1() throws Exception {
110         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
111 
112         final Header header = new BasicHeader("Set-Cookie", "blah");
113         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
114         final List<Cookie> cookies = cookiespec.parse(header, origin);
115         Assertions.assertEquals(0, cookies.size());
116     }
117 
118     @Test
119     public void testParseCookieMissingValue2() throws Exception {
120         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
121 
122         final Header header = new BasicHeader("Set-Cookie", "blah;");
123         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
124         Assertions.assertThrows(MalformedCookieException.class, () ->
125                 cookiespec.parse(header, origin));
126     }
127 
128     @Test
129     public void testParseCookieEmptyValue() throws Exception {
130         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
131 
132         final Header header = new BasicHeader("Set-Cookie", "blah=;");
133         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
134         final List<Cookie> cookies = cookiespec.parse(header, origin);
135         Assertions.assertEquals(1, cookies.size());
136         final Cookie cookie = cookies.get(0);
137         Assertions.assertEquals("blah", cookie.getName());
138         Assertions.assertEquals("", cookie.getValue());
139     }
140 
141     @Test
142     public void testParseCookieWithAttributes() throws Exception {
143         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
144         Mockito.when(h1.getAttributeName()).thenReturn("this");
145         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
146         Mockito.when(h2.getAttributeName()).thenReturn("that");
147 
148         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
149 
150         final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 = v ; p2 = v,0; p3 ; p4");
151         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
152         final List<Cookie> cookies = cookiespec.parse(header, origin);
153 
154         Assertions.assertEquals(1, cookies.size());
155         final Cookie cookie = cookies.get(0);
156         Assertions.assertEquals("name", cookie.getName());
157         Assertions.assertEquals("value", cookie.getValue());
158         Assertions.assertEquals("v", cookie.getAttribute("p1"));
159         Assertions.assertEquals("v,0", cookie.getAttribute("p2"));
160         Assertions.assertTrue(cookie.containsAttribute("p3"));
161         Assertions.assertTrue(cookie.containsAttribute("p4"));
162         Assertions.assertFalse(cookie.containsAttribute("p5"));
163     }
164 
165     @Test
166     public void testParseCookieWithAttributes2() throws Exception {
167         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
168         Mockito.when(h1.getAttributeName()).thenReturn("this");
169         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
170         Mockito.when(h2.getAttributeName()).thenReturn("that");
171 
172         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
173 
174         final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 = v");
175         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
176         final List<Cookie> cookies = cookiespec.parse(header, origin);
177 
178         Assertions.assertEquals(1, cookies.size());
179         final Cookie cookie = cookies.get(0);
180         Assertions.assertEquals("name", cookie.getName());
181         Assertions.assertEquals("value", cookie.getValue());
182         Assertions.assertEquals("v", cookie.getAttribute("p1"));
183     }
184 
185     @Test
186     public void testParseCookieWithAttributes3() throws Exception {
187         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
188         Mockito.when(h1.getAttributeName()).thenReturn("this");
189         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
190         Mockito.when(h2.getAttributeName()).thenReturn("that");
191 
192         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
193 
194         final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 =");
195         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
196         final List<Cookie> cookies = cookiespec.parse(header, origin);
197 
198         Assertions.assertEquals(1, cookies.size());
199         final Cookie cookie = cookies.get(0);
200         Assertions.assertEquals("name", cookie.getName());
201         Assertions.assertEquals("value", cookie.getValue());
202         Assertions.assertEquals("", cookie.getAttribute("p1"));
203     }
204 
205     @Test
206     public void testValidateCookieBasics() throws Exception {
207         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
208         Mockito.when(h1.getAttributeName()).thenReturn("this");
209         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
210         Mockito.when(h2.getAttributeName()).thenReturn("that");
211 
212         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
213 
214         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
215         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
216         cookiespec.validate(cookie, origin);
217 
218         Mockito.verify(h1).validate(cookie, origin);
219         Mockito.verify(h2).validate(cookie, origin);
220     }
221 
222     @Test
223     public void testMatchCookie() throws Exception {
224         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
225         Mockito.when(h1.getAttributeName()).thenReturn("this");
226         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
227         Mockito.when(h2.getAttributeName()).thenReturn("that");
228 
229         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
230 
231         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
232         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
233 
234         Mockito.when(h1.match(cookie, origin)).thenReturn(true);
235         Mockito.when(h2.match(cookie, origin)).thenReturn(true);
236 
237         Assertions.assertTrue(cookiespec.match(cookie, origin));
238 
239         Mockito.verify(h1).match(cookie, origin);
240         Mockito.verify(h2).match(cookie, origin);
241     }
242 
243     @Test
244     public void testMatchCookieNoMatch() throws Exception {
245         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
246         Mockito.when(h1.getAttributeName()).thenReturn("this");
247         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
248         Mockito.when(h2.getAttributeName()).thenReturn("that");
249 
250         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
251 
252         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
253         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
254 
255         Mockito.when(h1.match(cookie, origin)).thenReturn(false);
256         Mockito.when(h2.match(cookie, origin)).thenReturn(false);
257 
258         Assertions.assertFalse(cookiespec.match(cookie, origin));
259 
260         Mockito.verify(h1).match(cookie, origin);
261         Mockito.verify(h2, Mockito.never()).match(cookie, origin);
262     }
263 
264     @Test
265     public void testFormatCookiesBasics() throws Exception {
266         final Cookie cookie1 = new BasicClientCookie("name1", "value");
267 
268         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
269         final List<Header> headers = cookiespec.formatCookies(Collections.singletonList(cookie1));
270         Assertions.assertNotNull(headers);
271         Assertions.assertEquals(1, headers.size());
272         final Header header = headers.get(0);
273         Assertions.assertEquals("Cookie", header.getName());
274         Assertions.assertEquals("name1=value", header.getValue());
275     }
276 
277     @Test
278     public void testFormatCookiesIllegalCharsInValue() throws Exception {
279         final Cookie cookie1 = new BasicClientCookie("name1", "value");
280         final Cookie cookie2 = new BasicClientCookie("name2", "some value");
281         final Cookie cookie3 = new BasicClientCookie("name3", "\"\\\"");
282         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec();
283         final List<Header> headers = cookiespec.formatCookies(Arrays.asList(cookie1, cookie2, cookie3));
284         Assertions.assertNotNull(headers);
285         Assertions.assertEquals(1, headers.size());
286         final Header header = headers.get(0);
287         Assertions.assertEquals("Cookie", header.getName());
288         Assertions.assertEquals("name1=value; name2=\"some value\"; name3=\"\\\"\\\\\\\"\"", header.getValue());
289     }
290 
291     @Test
292     public void testParseCookieMultipleAttributes() throws Exception {
293         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
294         Mockito.when(h1.getAttributeName()).thenReturn("this");
295 
296         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1);
297 
298         final Header header = new BasicHeader("Set-Cookie", "name = value ; this = stuff; this = morestuff;");
299         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
300         cookiespec.parse(header, origin);
301 
302         Mockito.verify(h1).parse(ArgumentMatchers.any(), ArgumentMatchers.eq("morestuff"));
303         Mockito.verify(h1, Mockito.times(1)).parse(ArgumentMatchers.any(), ArgumentMatchers.anyString());
304     }
305 
306     @Test
307     public void testParseCookieMaxAgeOverExpires() throws Exception {
308         final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
309         Mockito.when(h1.getAttributeName()).thenReturn("Expires");
310         final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
311         Mockito.when(h2.getAttributeName()).thenReturn("Max-Age");
312 
313         final RFC6265CookieSpec cookiespec = new RFC6265CookieSpec(h1, h2);
314 
315         final Header header = new BasicHeader("Set-Cookie", "name = value ; expires = stuff; max-age = otherstuff;");
316         final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
317         cookiespec.parse(header, origin);
318 
319         Mockito.verify(h1, Mockito.never()).parse(ArgumentMatchers.any(), ArgumentMatchers.anyString());
320         Mockito.verify(h2).parse(ArgumentMatchers.any(), ArgumentMatchers.eq("otherstuff"));
321     }
322 
323 }