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