View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit;
16  
17  import static org.htmlunit.CookieManagerTest.HTML_ALERT_COOKIE;
18  import static org.junit.Assert.fail;
19  
20  import java.net.InetAddress;
21  import java.net.URL;
22  import java.net.UnknownHostException;
23  import java.nio.charset.StandardCharsets;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.htmlunit.junit.BrowserRunner;
29  import org.htmlunit.junit.annotation.Alerts;
30  import org.htmlunit.junit.annotation.HtmlUnitNYI;
31  import org.htmlunit.util.MimeType;
32  import org.htmlunit.util.NameValuePair;
33  import org.junit.Before;
34  import org.junit.BeforeClass;
35  import org.junit.Test;
36  import org.junit.runner.RunWith;
37  import org.openqa.selenium.By;
38  import org.openqa.selenium.WebDriver;
39  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
40  
41  /**
42   * Unit tests for {@link CookieManager}.
43   *
44   * These tests require a special setup in {@code etc/hosts}:
45   * <pre>
46   * 127.0.0.1       host1.htmlunit-dev.org
47   * 127.0.0.1       host2.htmlunit-dev.org
48   * 127.0.0.1       htmlunit-dev.org
49   * 127.0.0.1       htmlunit-dev
50   * </pre>
51   *
52   * @author Ronald Brill
53   * @author Ahmed Ashour
54   * @author Jacob Childress
55   */
56  @RunWith(BrowserRunner.class)
57  public class CookieManager4Test extends WebDriverTestCase {
58  
59      /** "htmlunit-dev.org". */
60      public static final String DOMAIN = "htmlunit-dev.org";
61      /** "http://host1." + DOMAIN + ":" + PORT + '/'. */
62      public static final String URL_HOST1 = "http://host1." + DOMAIN + ":" + PORT + '/';
63      private static final String URL_HOST2 = "http://host2." + DOMAIN + ":" + PORT + '/';
64      /** "http://" + DOMAIN + ":" + PORT + '/'. */
65      public static final String URL_HOST3 = "http://" + DOMAIN + ":" + PORT + '/';
66      /** "http://" + "htmlunit" + ":" + PORT + '/'. */
67      public static final String URL_HOST4 = "http://" + "htmlunit-dev" + ":" + PORT + '/';
68  
69      /**
70       * {@link org.junit.Assume Assumes} that the host configurations are present.
71       *
72       * @throws Exception if the test fails
73       */
74      @BeforeClass
75      public static void checkSettings() throws Exception {
76          try {
77              InetAddress.getByName(new URL(URL_HOST1).getHost());
78          }
79          catch (final UnknownHostException e) {
80              fail("Host configuration '" + URL_HOST1 + "' is not present");
81          }
82  
83          try {
84              InetAddress.getByName(new URL(URL_HOST2).getHost());
85          }
86          catch (final UnknownHostException e) {
87              fail("Host configuration '" + URL_HOST2 + "' is not present");
88          }
89  
90          try {
91              InetAddress.getByName(new URL(URL_HOST3).getHost());
92          }
93          catch (final UnknownHostException e) {
94              fail("Host configuration '" + URL_HOST3 + "' is not present");
95          }
96  
97          try {
98              InetAddress.getByName(new URL(URL_HOST4).getHost());
99          }
100         catch (final UnknownHostException e) {
101             fail("Host configuration '" + URL_HOST4 + "' is not present");
102         }
103     }
104 
105     /**
106      * Clear browser cookies.
107      *
108      * @throws Exception if the test fails
109      */
110     @Before
111     public void clearCookies() throws Exception {
112         shutDownAll();
113 
114         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><head></head><body></body></html>");
115         startWebServer(getMockWebConnection(), null);
116         final WebDriver driver = getWebDriver();
117         driver.get(URL_HOST1);
118         driver.manage().deleteAllCookies();
119         driver.get(URL_HOST2);
120         driver.manage().deleteAllCookies();
121         driver.get(URL_HOST3);
122         driver.manage().deleteAllCookies();
123         driver.get(URL_HOST4);
124         driver.manage().deleteAllCookies();
125         stopWebServers();
126     }
127 
128     /**
129      * @throws Exception if the test fails
130      */
131     @Test
132     @Alerts("c1=1; c2=2")
133     public void domain() throws Exception {
134         final List<NameValuePair> responseHeader = new ArrayList<>();
135         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=." + DOMAIN + "; Path=/"));
136         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=" + DOMAIN + "; Path=/"));
137         responseHeader.add(new NameValuePair("Set-Cookie", "c3=3; Domain=." + DOMAIN + ":" + PORT + "; Path=/"));
138         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
139                 MimeType.TEXT_HTML, responseHeader);
140 
141         final URL firstUrl = new URL(URL_HOST1);
142         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
143         verifyTitle2(getWebDriver(), getExpectedAlerts());
144     }
145 
146     /**
147      * @throws Exception if the test fails
148      */
149     @Test
150     @Alerts(DEFAULT = {"c1=1; c2=2; c3=3; c4=4",
151                        "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
152                        "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
153                        "c3=3; path=/; domain=.host1.htmlunit-dev.org; sameSite=Lax",
154                        "c4=4; path=/; domain=.host1.htmlunit-dev.org; sameSite=Lax"},
155             FF = {"c1=1; c2=2; c3=3; c4=4",
156                   "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
157                   "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None",
158                   "c3=3; path=/; domain=.host1.htmlunit-dev.org; sameSite=None",
159                   "c4=4; path=/; domain=.host1.htmlunit-dev.org; sameSite=None"},
160             FF_ESR = {"c1=1; c2=2; c3=3; c4=4",
161                       "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
162                       "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None",
163                       "c3=3; path=/; domain=.host1.htmlunit-dev.org; sameSite=None",
164                       "c4=4; path=/; domain=.host1.htmlunit-dev.org; sameSite=None"})
165     @HtmlUnitNYI(CHROME = {"c1=1; c2=2; c3=3; c4=4",
166                            "c1=1; path=/; domain=.htmlunit-dev.org",
167                            "c2=2; path=/; domain=.htmlunit-dev.org",
168                            "c3=3; path=/; domain=.host1.htmlunit-dev.org",
169                            "c4=4; path=/; domain=.host1.htmlunit-dev.org"},
170             EDGE = {"c1=1; c2=2; c3=3; c4=4",
171                     "c1=1; path=/; domain=.htmlunit-dev.org",
172                     "c2=2; path=/; domain=.htmlunit-dev.org",
173                     "c3=3; path=/; domain=.host1.htmlunit-dev.org",
174                     "c4=4; path=/; domain=.host1.htmlunit-dev.org"},
175             FF = {"c1=1; c2=2; c3=3; c4=4",
176                   "c1=1; path=/; domain=.htmlunit-dev.org",
177                   "c2=2; path=/; domain=.htmlunit-dev.org",
178                   "c3=3; path=/; domain=.host1.htmlunit-dev.org",
179                   "c4=4; path=/; domain=.host1.htmlunit-dev.org"},
180             FF_ESR = {"c1=1; c2=2; c3=3; c4=4",
181                       "c1=1; path=/; domain=.htmlunit-dev.org",
182                       "c2=2; path=/; domain=.htmlunit-dev.org",
183                       "c3=3; path=/; domain=.host1.htmlunit-dev.org",
184                       "c4=4; path=/; domain=.host1.htmlunit-dev.org"})
185     public void storedDomain1() throws Exception {
186         final List<NameValuePair> responseHeader = new ArrayList<>();
187         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=." + DOMAIN + "; Path=/"));
188         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=" + DOMAIN + "; Path=/"));
189         responseHeader.add(new NameValuePair("Set-Cookie", "c3=3; Domain=.host1." + DOMAIN + "; Path=/"));
190         responseHeader.add(new NameValuePair("Set-Cookie", "c4=4; Domain=host1." + DOMAIN + "; Path=/"));
191         responseHeader.add(new NameValuePair("Set-Cookie", "c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/"));
192         responseHeader.add(new NameValuePair("Set-Cookie", "c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/"));
193         responseHeader.add(new NameValuePair("Set-Cookie", "c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/"));
194         responseHeader.add(new NameValuePair("Set-Cookie", "c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/"));
195 
196         responseHeader.add(new NameValuePair("Set-Cookie", "c9=9; Domain=.org; Path=/"));
197         responseHeader.add(new NameValuePair("Set-Cookie", "c10=10; Domain=org; Path=/"));
198         responseHeader.add(new NameValuePair("Set-Cookie", "c11=11; Domain=.htmlunit-dev; Path=/"));
199         responseHeader.add(new NameValuePair("Set-Cookie", "c12=12; Domain=htmlunit-dev; Path=/"));
200 
201         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
202                 MimeType.TEXT_HTML, responseHeader);
203 
204         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
205         verifyTitle2(driver, getExpectedAlerts()[0]);
206 
207         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c1").toString());
208         assertEquals(getExpectedAlerts()[2], driver.manage().getCookieNamed("c2").toString());
209         assertEquals(getExpectedAlerts()[3], driver.manage().getCookieNamed("c3").toString());
210         assertEquals(getExpectedAlerts()[4], driver.manage().getCookieNamed("c4").toString());
211     }
212 
213     /**
214      * @throws Exception if the test fails
215      */
216     @Test
217     @Alerts(DEFAULT = {"c1=1; c2=2",
218                        "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
219                        "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=Lax"},
220             FF = {"c1=1; c2=2",
221                   "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
222                   "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"},
223             FF_ESR = {"c1=1; c2=2",
224                       "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
225                       "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"})
226     @HtmlUnitNYI(
227             CHROME = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
228             EDGE = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
229             FF = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
230             FF_ESR = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"})
231     public void storedDomain2() throws Exception {
232         final List<NameValuePair> responseHeader = new ArrayList<>();
233         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=." + DOMAIN + "; Path=/"));
234         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=" + DOMAIN + "; Path=/"));
235         responseHeader.add(new NameValuePair("Set-Cookie", "c3=3; Domain=.host1." + DOMAIN + "; Path=/"));
236         responseHeader.add(new NameValuePair("Set-Cookie", "c4=4; Domain=host1." + DOMAIN + "; Path=/"));
237         responseHeader.add(new NameValuePair("Set-Cookie", "c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/"));
238         responseHeader.add(new NameValuePair("Set-Cookie", "c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/"));
239         responseHeader.add(new NameValuePair("Set-Cookie", "c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/"));
240         responseHeader.add(new NameValuePair("Set-Cookie", "c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/"));
241 
242         responseHeader.add(new NameValuePair("Set-Cookie", "c9=9; Domain=.org; Path=/"));
243         responseHeader.add(new NameValuePair("Set-Cookie", "c10=10; Domain=org; Path=/"));
244         responseHeader.add(new NameValuePair("Set-Cookie", "c11=11; Domain=.htmlunit-dev; Path=/"));
245         responseHeader.add(new NameValuePair("Set-Cookie", "c12=12; Domain=htmlunit-dev; Path=/"));
246 
247         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
248                 MimeType.TEXT_HTML, responseHeader);
249 
250         final WebDriver driver = loadPage2(new URL(URL_HOST2), StandardCharsets.ISO_8859_1);
251         verifyTitle2(driver, getExpectedAlerts()[0]);
252 
253         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c1").toString());
254         assertEquals(getExpectedAlerts()[2], driver.manage().getCookieNamed("c2").toString());
255     }
256 
257     /**
258      * @throws Exception if the test fails
259      */
260     @Test
261     @Alerts(DEFAULT = {"c1=1; c2=2",
262                        "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
263                        "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=Lax"},
264             FF = {"c1=1; c2=2",
265                   "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
266                   "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"},
267             FF_ESR = {"c1=1; c2=2",
268                       "c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
269                       "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"})
270     @HtmlUnitNYI(
271             CHROME = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
272             EDGE = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
273             FF = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
274             FF_ESR = {"c1=1; c2=2", "c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"})
275     public void storedDomain3() throws Exception {
276         final List<NameValuePair> responseHeader = new ArrayList<>();
277         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=." + DOMAIN + "; Path=/"));
278         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=" + DOMAIN + "; Path=/"));
279         responseHeader.add(new NameValuePair("Set-Cookie", "c3=3; Domain=.host1." + DOMAIN + "; Path=/"));
280         responseHeader.add(new NameValuePair("Set-Cookie", "c4=4; Domain=host1." + DOMAIN + "; Path=/"));
281         responseHeader.add(new NameValuePair("Set-Cookie", "c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/"));
282         responseHeader.add(new NameValuePair("Set-Cookie", "c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/"));
283         responseHeader.add(new NameValuePair("Set-Cookie", "c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/"));
284         responseHeader.add(new NameValuePair("Set-Cookie", "c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/"));
285 
286         responseHeader.add(new NameValuePair("Set-Cookie", "c9=9; Domain=.org; Path=/"));
287         responseHeader.add(new NameValuePair("Set-Cookie", "c10=10; Domain=org; Path=/"));
288         responseHeader.add(new NameValuePair("Set-Cookie", "c11=11; Domain=.htmlunit-dev; Path=/"));
289         responseHeader.add(new NameValuePair("Set-Cookie", "c12=12; Domain=htmlunit-dev; Path=/"));
290 
291         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
292                 MimeType.TEXT_HTML, responseHeader);
293 
294         final WebDriver driver = loadPage2(new URL(URL_HOST3), StandardCharsets.ISO_8859_1);
295         verifyTitle2(driver, getExpectedAlerts()[0]);
296 
297         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c1").toString());
298         assertEquals(getExpectedAlerts()[2], driver.manage().getCookieNamed("c2").toString());
299     }
300 
301     /**
302      * @throws Exception if the test fails
303      */
304     @Test
305     @Alerts(DEFAULT = {"c11=11; c12=12",
306                        "c12=12; path=/; domain=htmlunit-dev; sameSite=Lax",
307                        "c11=11; path=/; domain=htmlunit-dev; sameSite=Lax"},
308             FF = {"c11=11; c12=12",
309                   "c12=12; path=/; domain=htmlunit-dev; sameSite=None",
310                   "c11=11; path=/; domain=htmlunit-dev; sameSite=None"},
311             FF_ESR = {"c11=11; c12=12",
312                       "c12=12; path=/; domain=htmlunit-dev; sameSite=None",
313                       "c11=11; path=/; domain=htmlunit-dev; sameSite=None"})
314     @HtmlUnitNYI(CHROME = {"c12=12", "c12=12; path=/; domain=htmlunit-dev", "c11=11; path=/; domain=htmlunit-dev"},
315             EDGE = {"c12=12", "c12=12; path=/; domain=htmlunit-dev", "c11=11; path=/; domain=htmlunit-dev"},
316             FF = {"c11=11; c12=12", "c12=12; path=/; domain=htmlunit-dev", "c11=11; path=/; domain=htmlunit-dev"},
317             FF_ESR = {"c11=11; c12=12", "c12=12; path=/; domain=htmlunit-dev", "c11=11; path=/; domain=htmlunit-dev"})
318     public void storedDomain4() throws Exception {
319         final List<NameValuePair> responseHeader = new ArrayList<>();
320         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=." + DOMAIN + "; Path=/"));
321         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=" + DOMAIN + "; Path=/"));
322         responseHeader.add(new NameValuePair("Set-Cookie", "c3=3; Domain=.host1." + DOMAIN + "; Path=/"));
323         responseHeader.add(new NameValuePair("Set-Cookie", "c4=4; Domain=host1." + DOMAIN + "; Path=/"));
324         responseHeader.add(new NameValuePair("Set-Cookie", "c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/"));
325         responseHeader.add(new NameValuePair("Set-Cookie", "c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/"));
326         responseHeader.add(new NameValuePair("Set-Cookie", "c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/"));
327         responseHeader.add(new NameValuePair("Set-Cookie", "c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/"));
328 
329         responseHeader.add(new NameValuePair("Set-Cookie", "c9=9; Domain=.org; Path=/"));
330         responseHeader.add(new NameValuePair("Set-Cookie", "c10=10; Domain=org; Path=/"));
331         responseHeader.add(new NameValuePair("Set-Cookie", "c11=11; Domain=.htmlunit-dev; Path=/"));
332         responseHeader.add(new NameValuePair("Set-Cookie", "c12=12; Domain=htmlunit-dev; Path=/"));
333 
334         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
335                 MimeType.TEXT_HTML, responseHeader);
336 
337         final WebDriver driver = loadPage2(new URL(URL_HOST4), StandardCharsets.ISO_8859_1);
338         verifyTitle2(driver, getExpectedAlerts()[0]);
339 
340         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c12").toString());
341         if (driver.manage().getCookieNamed("c11") != null) {
342             assertEquals(getExpectedAlerts()[2], driver.manage().getCookieNamed("c11").toString());
343         }
344     }
345 
346     /**
347      * @throws Exception if the test fails
348      */
349     @Test
350     @Alerts(DEFAULT = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
351                        "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
352                        "c3=3; path=/; domain=.host1.htmlunit-dev.org; sameSite=Lax",
353                        "c4=4; path=/; domain=.host1.htmlunit-dev.org; sameSite=Lax"},
354             FF = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
355                   "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None",
356                   "c3=3; path=/; domain=.host1.htmlunit-dev.org; sameSite=None",
357                   "c4=4; path=/; domain=.host1.htmlunit-dev.org; sameSite=None"},
358             FF_ESR = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
359                       "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None",
360                       "c3=3; path=/; domain=.host1.htmlunit-dev.org; sameSite=None",
361                       "c4=4; path=/; domain=.host1.htmlunit-dev.org; sameSite=None"})
362     @HtmlUnitNYI(
363             CHROME = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org",
364                       "c3=3; path=/; domain=.host1.htmlunit-dev.org", "c4=4; path=/; domain=.host1.htmlunit-dev.org"},
365             EDGE = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org",
366                     "c3=3; path=/; domain=.host1.htmlunit-dev.org", "c4=4; path=/; domain=.host1.htmlunit-dev.org"},
367             FF = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org",
368                   "c3=3; path=/; domain=.host1.htmlunit-dev.org", "c4=4; path=/; domain=.host1.htmlunit-dev.org"},
369             FF_ESR = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org",
370                       "c3=3; path=/; domain=.host1.htmlunit-dev.org", "c4=4; path=/; domain=.host1.htmlunit-dev.org"})
371     public void storedDomainFromJs1() throws Exception {
372         final String html = DOCTYPE_HTML
373                 + "<html>\n"
374                 + "<head>\n"
375                 + "</head>\n"
376                 + "<body>\n"
377                 + "<p>Cookie Domain Test</p>\n"
378                 + "<script>\n"
379                 + "  document.cookie = 'c1=1; Domain=." + DOMAIN + "; Path=/';\n"
380                 + "  document.cookie = 'c2=2; Domain=" + DOMAIN + "; Path=/';\n"
381                 + "  document.cookie = 'c3=3; Domain=.host1." + DOMAIN + "; Path=/';\n"
382                 + "  document.cookie = 'c4=4; Domain=host1." + DOMAIN + "; Path=/';\n"
383                 + "  document.cookie = 'c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/';\n"
384                 + "  document.cookie = 'c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/';\n"
385                 + "  document.cookie = 'c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
386                 + "  document.cookie = 'c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
387                 + "  document.cookie = 'c9=9; Domain=.org; Path=/';\n"
388                 + "  document.cookie = 'c10=10; Domain=org; Path=/';\n"
389                 + "  document.cookie = 'c11=11; Domain=.htmlunit; Path=/';\n"
390                 + "  document.cookie = 'c12=12; Domain=htmlunit; Path=/';\n"
391                 + "</script>\n"
392                 + "</body>\n"
393                 + "</html>";
394 
395         final WebDriver driver = loadPage2(html, new URL(URL_HOST1));
396         verifyTitle2(driver);
397 
398         assertEquals(4, driver.manage().getCookies().size());
399         assertEquals(getExpectedAlerts()[0], driver.manage().getCookieNamed("c1").toString());
400         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c2").toString());
401         assertEquals(getExpectedAlerts()[2], driver.manage().getCookieNamed("c3").toString());
402         assertEquals(getExpectedAlerts()[3], driver.manage().getCookieNamed("c4").toString());
403     }
404 
405     /**
406      * @throws Exception if the test fails
407      */
408     @Test
409     @Alerts(DEFAULT = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
410                        "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=Lax"},
411             FF = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
412                   "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"},
413             FF_ESR = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
414                       "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"})
415     @HtmlUnitNYI(CHROME = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
416             EDGE = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
417             FF = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
418             FF_ESR = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"})
419     public void storedDomainFromJs2() throws Exception {
420         final String html = DOCTYPE_HTML
421                 + "<html>\n"
422                 + "<head>\n"
423                 + "</head>\n"
424                 + "<body>\n"
425                 + "<p>Cookie Domain Test</p>\n"
426                 + "<script>\n"
427                 + "  document.cookie = 'c1=1; Domain=." + DOMAIN + "; Path=/';\n"
428                 + "  document.cookie = 'c2=2; Domain=" + DOMAIN + "; Path=/';\n"
429                 + "  document.cookie = 'c3=3; Domain=.host1." + DOMAIN + "; Path=/';\n"
430                 + "  document.cookie = 'c4=4; Domain=host1." + DOMAIN + "; Path=/';\n"
431                 + "  document.cookie = 'c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/';\n"
432                 + "  document.cookie = 'c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/';\n"
433                 + "  document.cookie = 'c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
434                 + "  document.cookie = 'c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
435                 + "  document.cookie = 'c9=9; Domain=.org; Path=/';\n"
436                 + "  document.cookie = 'c10=10; Domain=org; Path=/';\n"
437                 + "  document.cookie = 'c11=11; Domain=.htmlunit; Path=/';\n"
438                 + "  document.cookie = 'c12=12; Domain=htmlunit; Path=/';\n"
439                 + "</script>\n"
440                 + "</body>\n"
441                 + "</html>";
442 
443         final WebDriver driver = loadPage2(html, new URL(URL_HOST2));
444         verifyTitle2(driver);
445 
446         assertEquals(2, driver.manage().getCookies().size());
447         assertEquals(getExpectedAlerts()[0], driver.manage().getCookieNamed("c1").toString());
448         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c2").toString());
449     }
450 
451     /**
452      * @throws Exception if the test fails
453      */
454     @Test
455     @Alerts(DEFAULT = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=Lax",
456                        "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=Lax"},
457             FF = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
458                   "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"},
459             FF_ESR = {"c1=1; path=/; domain=.htmlunit-dev.org; sameSite=None",
460                       "c2=2; path=/; domain=.htmlunit-dev.org; sameSite=None"})
461     @HtmlUnitNYI(CHROME = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
462             EDGE = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
463             FF = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"},
464             FF_ESR = {"c1=1; path=/; domain=.htmlunit-dev.org", "c2=2; path=/; domain=.htmlunit-dev.org"})
465     public void storedDomainFromJs3() throws Exception {
466         final String html = DOCTYPE_HTML
467                 + "<html>\n"
468                 + "<head>\n"
469                 + "</head>\n"
470                 + "<body>\n"
471                 + "<p>Cookie Domain Test</p>\n"
472                 + "<script>\n"
473                 + "  document.cookie = 'c1=1; Domain=." + DOMAIN + "; Path=/';\n"
474                 + "  document.cookie = 'c2=2; Domain=" + DOMAIN + "; Path=/';\n"
475                 + "  document.cookie = 'c3=3; Domain=.host1." + DOMAIN + "; Path=/';\n"
476                 + "  document.cookie = 'c4=4; Domain=host1." + DOMAIN + "; Path=/';\n"
477                 + "  document.cookie = 'c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/';\n"
478                 + "  document.cookie = 'c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/';\n"
479                 + "  document.cookie = 'c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
480                 + "  document.cookie = 'c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
481                 + "  document.cookie = 'c9=9; Domain=.org; Path=/';\n"
482                 + "  document.cookie = 'c10=10; Domain=org; Path=/';\n"
483                 + "  document.cookie = 'c11=11; Domain=.htmlunit; Path=/';\n"
484                 + "  document.cookie = 'c12=12; Domain=htmlunit; Path=/';\n"
485                 + "</script>\n"
486                 + "</body>\n"
487                 + "</html>";
488 
489         final WebDriver driver = loadPage2(html, new URL(URL_HOST3));
490         verifyTitle2(driver);
491 
492         assertEquals(2, driver.manage().getCookies().size());
493         assertEquals(getExpectedAlerts()[0], driver.manage().getCookieNamed("c1").toString());
494         assertEquals(getExpectedAlerts()[1], driver.manage().getCookieNamed("c2").toString());
495     }
496 
497     /**
498      * @throws Exception if the test fails
499      */
500     @Test
501     @Alerts(DEFAULT = {"2",
502                        "c12=12; path=/; domain=htmlunit-dev; sameSite=Lax",
503                        "c11=11; path=/; domain=htmlunit-dev; sameSite=Lax"},
504             FF = {"2",
505                   "c12=12; path=/; domain=htmlunit-dev; sameSite=None",
506                   "c11=11; path=/; domain=htmlunit-dev; sameSite=None"},
507             FF_ESR = {"2",
508                       "c12=12; path=/; domain=htmlunit-dev; sameSite=None",
509                       "c11=11; path=/; domain=htmlunit-dev; sameSite=None"})
510     @HtmlUnitNYI(CHROME = {"1", "c12=12; path=/; domain=htmlunit-dev"},
511             EDGE = {"1", "c12=12; path=/; domain=htmlunit-dev"},
512             FF = {"2", "c12=12; path=/; domain=htmlunit-dev", "c11=11; path=/; domain=htmlunit-dev"},
513             FF_ESR = {"2", "c12=12; path=/; domain=htmlunit-dev", "c11=11; path=/; domain=htmlunit-dev"})
514     public void storedDomainFromJs4() throws Exception {
515         final String html = DOCTYPE_HTML
516                 + "<html>\n"
517                 + "<head>\n"
518                 + "</head>\n"
519                 + "<body>\n"
520                 + "<p>Cookie Domain Test</p>\n"
521                 + "<script>\n"
522                 + "  document.cookie = 'c1=1; Domain=." + DOMAIN + "; Path=/';\n"
523                 + "  document.cookie = 'c2=2; Domain=" + DOMAIN + "; Path=/';\n"
524                 + "  document.cookie = 'c3=3; Domain=.host1." + DOMAIN + "; Path=/';\n"
525                 + "  document.cookie = 'c4=4; Domain=host1." + DOMAIN + "; Path=/';\n"
526                 + "  document.cookie = 'c5=5; Domain=." + DOMAIN + ":" + PORT + "; Path=/';\n"
527                 + "  document.cookie = 'c6=6; Domain=" + DOMAIN + ":" + PORT + "; Path=/';\n"
528                 + "  document.cookie = 'c7=7; Domain=.host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
529                 + "  document.cookie = 'c8=8; Domain=host1." + DOMAIN + ":" + PORT + "; Path=/';\n"
530                 + "  document.cookie = 'c9=9; Domain=.org; Path=/';\n"
531                 + "  document.cookie = 'c10=10; Domain=org; Path=/';\n"
532                 + "  document.cookie = 'c11=11; Domain=.htmlunit-dev; Path=/';\n"
533                 + "  document.cookie = 'c12=12; Domain=htmlunit-dev; Path=/';\n"
534                 + "</script>\n"
535                 + "</body>\n"
536                 + "</html>";
537 
538         final WebDriver driver = loadPage2(html, new URL(URL_HOST4));
539         verifyTitle2(driver);
540 
541         final String[] expected = getExpectedAlerts();
542         assertEquals(Integer.parseInt(expected[0]), driver.manage().getCookies().size());
543         assertEquals(expected[1], driver.manage().getCookieNamed("c12").toString());
544         if (Integer.parseInt(expected[0]) > 1) {
545             assertEquals(expected[2], driver.manage().getCookieNamed("c11").toString());
546         }
547     }
548 
549     /**
550      * @throws Exception if the test fails
551      */
552     @Test
553     @Alerts("c1=1; c2=2")
554     public void domainDuplicate() throws Exception {
555         final List<NameValuePair> responseHeader = new ArrayList<>();
556         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=" + DOMAIN + "; Path=/"));
557         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=" + DOMAIN + "; Path=/"));
558         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
559                 MimeType.TEXT_HTML, responseHeader);
560 
561         final URL firstUrl = new URL(URL_HOST1);
562 
563         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
564         verifyTitle2(getWebDriver(), getExpectedAlerts());
565     }
566 
567     /**
568      * @throws Exception if the test fails
569      */
570     @Test
571     @Alerts("c1=1; c2=2")
572     public void domainDuplicateLeadingDot() throws Exception {
573         final List<NameValuePair> responseHeader = new ArrayList<>();
574         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=host1." + DOMAIN + "; Path=/"));
575         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=.host1." + DOMAIN + "; Path=/"));
576         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "Ok",
577                 MimeType.TEXT_HTML, responseHeader);
578 
579         final URL firstUrl = new URL(URL_HOST1);
580 
581         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
582         verifyTitle2(getWebDriver(), getExpectedAlerts());
583     }
584 
585     /**
586      * @throws Exception if the test fails
587      */
588     @Test
589     public void domainDuplicateLeadingDotSend() throws Exception {
590         final String html = DOCTYPE_HTML
591                 + "<html><body>\n"
592                 + "<a href='next.html'>next page</a>\n"
593                 + "</body></html>";
594 
595         final List<NameValuePair> responseHeader = new ArrayList<>();
596         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=host1." + DOMAIN + "; Path=/"));
597         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=.host1." + DOMAIN + "; Path=/"));
598 
599         getMockWebConnection().setDefaultResponse(html, 200, "Ok", MimeType.TEXT_HTML, responseHeader);
600 
601         final WebDriver webDriver = getWebDriver();
602         webDriver.manage().deleteAllCookies();
603 
604         loadPageWithAlerts2(new URL(URL_HOST1));
605         WebRequest lastRequest = getMockWebConnection().getLastWebRequest();
606         assertNull(lastRequest.getAdditionalHeaders().get(HttpHeader.COOKIE));
607 
608         webDriver.findElement(By.linkText("next page")).click();
609         lastRequest = getMockWebConnection().getLastWebRequest();
610         assertEquals("c1=1; c2=2", lastRequest.getAdditionalHeaders().get(HttpHeader.COOKIE));
611     }
612 
613     /**
614      * @throws Exception if the test fails
615      */
616     @Test
617     public void domainDuplicateLeadingDotRedirect() throws Exception {
618         final String html = DOCTYPE_HTML
619                 + "<html><body>\n"
620                 + "<a href='next.html'>next page</a>\n"
621                 + "</body></html>";
622 
623         final List<NameValuePair> responseHeader = new ArrayList<>();
624         responseHeader.add(new NameValuePair("Set-Cookie", "c1=1; Domain=host1." + DOMAIN
625                                                 + "; path=/; expires=Fri, 04-Feb-2099 09:00:32 GMT"));
626         responseHeader.add(new NameValuePair("Set-Cookie", "c2=2; Domain=.host1." + DOMAIN
627                                                 + "; path=/; expires=Fri, 04-Feb-2099 09:00:32 GMT"));
628 
629         getMockWebConnection().setDefaultResponse(html, 200, "Ok", MimeType.TEXT_HTML, responseHeader);
630 
631         responseHeader.add(new NameValuePair("Location", URL_HOST1 + "next.html"));
632         getMockWebConnection().setResponse(new URL(URL_HOST1), "redirect", 301, "Ok", MimeType.TEXT_HTML,
633                 responseHeader);
634 
635         final WebDriver webDriver = getWebDriver();
636         webDriver.manage().deleteAllCookies();
637 
638         final int startCount = getMockWebConnection().getRequestCount();
639         loadPageWithAlerts2(new URL(URL_HOST1));
640         assertEquals(2, getMockWebConnection().getRequestCount() - startCount);
641         final WebRequest lastRequest = getMockWebConnection().getLastWebRequest();
642         assertEquals("c1=1; c2=2", lastRequest.getAdditionalHeaders().get(HttpHeader.COOKIE));
643     }
644 
645     /**
646      * @throws Exception if the test fails
647      */
648     @Test
649     @Alerts("c4=4")
650     public void domain2() throws Exception {
651         final List<NameValuePair> responseHeader1 = new ArrayList<>();
652         responseHeader1.add(new NameValuePair("Set-Cookie", "c1=1; Path=/"));
653         responseHeader1.add(new NameValuePair("Set-Cookie", "c2=2; Domain=host1." + DOMAIN + "; Path=/"));
654         responseHeader1.add(new NameValuePair("Set-Cookie", "c3=3; Domain=host2." + DOMAIN + "; Path=/"));
655         responseHeader1.add(new NameValuePair("Set-Cookie", "c4=4; Domain=" + DOMAIN + "; Path=/"));
656         responseHeader1.add(new NameValuePair("Set-Cookie", "c5=5; Domain=.org; Path=/"));
657 
658         final String html = DOCTYPE_HTML
659             + "<html>\n"
660             + "<head></head>\n"
661             + "<body>\n"
662             + "<p>Cookie Domain Test</p>\n"
663             + "<script>\n"
664             + "  location.replace('" + URL_HOST3 + "');\n"
665             + "</script>\n"
666             + "</body>\n"
667             + "</html>";
668 
669         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE);
670         final URL firstUrl = new URL(URL_HOST1);
671         getMockWebConnection().setResponse(firstUrl, html, 200, "Ok", MimeType.TEXT_HTML, responseHeader1);
672 
673         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
674         verifyTitle2(getWebDriver(), getExpectedAlerts());
675     }
676 
677     /**
678      * @throws Exception if the test fails
679      */
680     @Test
681     @Alerts("c1=1; c4=4")
682     public void domain3() throws Exception {
683         final List<NameValuePair> responseHeader1 = new ArrayList<>();
684         responseHeader1.add(new NameValuePair("Set-Cookie", "c1=1; Path=/"));
685         responseHeader1.add(new NameValuePair("Set-Cookie", "c2=2; Domain=host1." + DOMAIN + "; Path=/"));
686         responseHeader1.add(new NameValuePair("Set-Cookie", "c3=3; Domain=host2." + DOMAIN + "; Path=/"));
687         responseHeader1.add(new NameValuePair("Set-Cookie", "c4=4; Domain=" + DOMAIN + "; Path=/"));
688         responseHeader1.add(new NameValuePair("Set-Cookie", "c5=5; Domain=.org; Path=/"));
689 
690         final String html = DOCTYPE_HTML
691             + "<html>\n"
692             + "<head></head>\n"
693             + "<body>\n"
694             + "<p>Cookie Domain Test</p>\n"
695             + "<script>\n"
696             + "  location.replace('" + URL_HOST3 + "test.html');\n"
697             + "</script>\n"
698             + "</body>\n"
699             + "</html>";
700 
701         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE);
702         final URL firstUrl = new URL(URL_HOST3);
703         getMockWebConnection().setResponse(firstUrl, html, 200, "Ok", MimeType.TEXT_HTML, responseHeader1);
704 
705         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
706         verifyTitle2(getWebDriver(), getExpectedAlerts());
707     }
708 
709     /**
710      * @throws Exception if the test fails
711      */
712     @Test
713     @Alerts("cross-domain=1")
714     public void differentHostsSameDomain() throws Exception {
715         final List<NameValuePair> responseHeader1 = new ArrayList<>();
716         responseHeader1.add(new NameValuePair("Set-Cookie", "cross-domain=1; Domain=." + DOMAIN + "; Path=/"));
717 
718         final String html = DOCTYPE_HTML
719             + "<html>\n"
720             + "<head></head>\n"
721             + "<body>\n"
722             + "<p>Cookie Domain Test</p>\n"
723             + "<script>\n"
724             + "  location.replace('" + URL_HOST2 + "');\n"
725             + "</script>\n"
726             + "</body>\n"
727             + "</html>";
728 
729         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE);
730         final URL firstUrl = new URL(URL_HOST1);
731         getMockWebConnection().setResponse(firstUrl, html, 200, "Ok", MimeType.TEXT_HTML, responseHeader1);
732 
733         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
734         verifyTitle2(getWebDriver(), getExpectedAlerts());
735     }
736 
737     /**
738      * @throws Exception if the test fails
739      */
740     @Test
741     @Alerts("cross-domain=1")
742     public void differentHostsSameDomainCookieFromJS() throws Exception {
743         final String html = DOCTYPE_HTML
744             + "<html>\n"
745             + "<head>\n"
746             + "</head>\n"
747             + "<body>\n"
748             + "<p>Cookie Domain Test</p>\n"
749             + "<script>\n"
750             + "  document.cookie='cross-domain=1; Domain=." + DOMAIN + "; Path=/';\n"
751             + "  location.replace('" + URL_HOST2 + "');\n"
752             + "</script>\n"
753             + "</body>\n"
754             + "</html>";
755 
756         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE);
757         final URL firstUrl = new URL(URL_HOST1);
758         getMockWebConnection().setResponse(firstUrl, html);
759 
760         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
761         verifyTitle2(getWebDriver(), getExpectedAlerts());
762     }
763 
764     /**
765      * @throws Exception if the test fails
766      */
767     @Test
768     @Alerts("cross-domain=1")
769     public void differentHostsSameDomainCookieFromMeta() throws Exception {
770         final String html = DOCTYPE_HTML
771             + "<html>\n"
772             + "<head>\n"
773             + "  <meta http-equiv='Set-Cookie', content='cross-domain=1; Domain=." + DOMAIN + "; Path=/'>\n"
774             + "</head>\n"
775             + "<body>\n"
776             + "<p>Cookie Domain Test</p>\n"
777             + "<script>\n"
778             + "  location.replace('" + URL_HOST2 + "');\n"
779             + "</script>\n"
780             + "</body>\n"
781             + "</html>";
782 
783         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE);
784         final URL firstUrl = new URL(URL_HOST1);
785         getMockWebConnection().setResponse(firstUrl, html);
786 
787         loadPage2(firstUrl, StandardCharsets.ISO_8859_1);
788         verifyTitle2(getWebDriver(), getExpectedAlerts());
789     }
790 
791     private void testCookies(final URL url, final String cookie1, final String cookie2) throws Exception {
792         final List<NameValuePair> responseHeader = new ArrayList<>();
793         responseHeader.add(new NameValuePair("Set-Cookie", cookie1));
794         responseHeader.add(new NameValuePair("Set-Cookie", cookie2));
795         getMockWebConnection().setDefaultResponse(CookieManagerTest.HTML_ALERT_COOKIE, 200, "OK", MimeType.TEXT_HTML,
796                 responseHeader);
797 
798         loadPage2(url, StandardCharsets.ISO_8859_1);
799         verifyTitle2(getWebDriver(), getExpectedAlerts());
800     }
801 
802     /**
803      * @throws Exception if the test fails
804      */
805     @Test
806     @Alerts("key1=\"Hi there\"; key2=Howdy")
807     public void unqualifiedHost() throws Exception {
808         testCookies(new URL(URL_HOST4), "key1=\"Hi there\"", "key2=Howdy");
809     }
810 
811     /**
812      * @throws Exception if the test fails
813      */
814     @Test
815     @Alerts("key1=\"Hi there\"; key2=Howdy")
816     public void fullyQualifiedHost() throws Exception {
817         testCookies(new URL(URL_HOST1), "key1=\"Hi there\"", "key2=Howdy");
818     }
819 
820     /**
821      * @throws Exception if the test fails
822      */
823     @Test
824     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; c6=strict; c7=stRiCT; first=1")
825     public void sameSite() throws Exception {
826         final List<NameValuePair> responseHeader = new ArrayList<>();
827         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
828         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
829         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
830         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
831         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
832         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
833         responseHeader.add(new NameValuePair("Set-Cookie", "c6=strict; SameSite=strict"));
834         responseHeader.add(new NameValuePair("Set-Cookie", "c7=stRiCT; SameSite=stRiCT"));
835 
836         getMockWebConnection().setDefaultResponse("");
837         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
838                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
839 
840         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
841         verifyTitle2(driver, getExpectedAlerts());
842         driver.get(URL_HOST1 + "foo");
843 
844         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
845 
846         // strange check, but there is no order
847         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
848         assertEquals(70, lastCookies.length());
849 
850         assertTrue("lastCookies: " + lastCookies, lastCookies.contains("first=1")
851                     && lastCookies.contains("c2=Lax")
852                     && lastCookies.contains("c3=Strict")
853                     && lastCookies.contains("c4=empty")
854                     && lastCookies.contains("c5=unknown")
855                     && lastCookies.contains("c6=strict")
856                     && lastCookies.contains("c7=stRiCT"));
857 
858         if (driver instanceof HtmlUnitDriver) {
859             final CookieManager mgr = getWebClient().getCookieManager();
860             assertEquals(8, mgr.getCookies().size());
861             assertNull(mgr.getCookie("first").getSameSite());
862             assertEquals("lax", mgr.getCookie("c2").getSameSite());
863             assertEquals("strict", mgr.getCookie("c3").getSameSite());
864             assertEquals("", mgr.getCookie("c4").getSameSite());
865             assertEquals("unknown", mgr.getCookie("c5").getSameSite());
866             assertEquals("strict", mgr.getCookie("c6").getSameSite());
867             assertEquals("strict", mgr.getCookie("c7").getSameSite());
868         }
869     }
870 
871     /**
872      * @throws Exception if the test fails
873      */
874     @Test
875     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; first=1")
876     public void sameSiteOtherSubdomain() throws Exception {
877         final List<NameValuePair> responseHeader = new ArrayList<>();
878         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
879 
880         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
881         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
882         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
883         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
884         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
885 
886         getMockWebConnection().setDefaultResponse("");
887         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
888                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
889 
890         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
891         verifyTitle2(driver, getExpectedAlerts());
892         driver.get(URL_HOST2 + "foo");
893 
894         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
895 
896         // strange check, but there is no order
897         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
898         assertNull(lastCookies);
899     }
900 
901     /**
902      * @throws Exception if the test fails
903      */
904     @Test
905     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; first=1")
906     public void sameSiteOriginOtherSubdomain() throws Exception {
907         final List<NameValuePair> responseHeader = new ArrayList<>();
908         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
909 
910         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
911         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
912         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
913         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
914         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
915 
916         getMockWebConnection().setDefaultResponse("");
917         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
918                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
919 
920         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
921         verifyTitle2(driver, getExpectedAlerts());
922         driver.get(URL_HOST2 + "foo");
923         driver.get(URL_HOST1 + "foo");
924 
925         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
926 
927         // strange check, but there is no order
928         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
929         assertEquals(48, lastCookies.length());
930 
931         assertTrue("lastCookies: " + lastCookies, lastCookies.contains("first=1")
932                     && lastCookies.contains("c2=Lax")
933                     && lastCookies.contains("c3=Strict")
934                     && lastCookies.contains("c4=empty")
935                     && lastCookies.contains("c5=unknown"));
936 
937         if (driver instanceof HtmlUnitDriver) {
938             final CookieManager mgr = getWebClient().getCookieManager();
939             assertEquals(6, mgr.getCookies().size());
940             assertNull(mgr.getCookie("first").getSameSite());
941             assertEquals("lax", mgr.getCookie("c2").getSameSite());
942             assertEquals("strict", mgr.getCookie("c3").getSameSite());
943             assertEquals("", mgr.getCookie("c4").getSameSite());
944             assertEquals("unknown", mgr.getCookie("c5").getSameSite());
945         }
946     }
947 
948     /**
949      * @throws Exception if the test fails
950      */
951     @Test
952     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; first=1")
953     public void sameSiteIncludeFromSameDomain() throws Exception {
954         final List<NameValuePair> responseHeader = new ArrayList<>();
955         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
956 
957         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
958         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
959         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
960         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
961         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
962 
963         final String html = DOCTYPE_HTML
964                 + "<html><head>\n"
965                 + "  <link rel='stylesheet' href='" + URL_HOST1 + "css/style.css'>\n"
966                 + "</head>\n"
967                 + "<body>\n"
968                 + "</body></html>";
969         getMockWebConnection().setDefaultResponse("");
970         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
971                 200, "OK", MimeType.TEXT_HTML, responseHeader);
972         getMockWebConnection().setResponse(new URL(URL_HOST1 + "include"), html,
973                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
974 
975         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
976         verifyTitle2(driver, getExpectedAlerts());
977         driver.get(URL_HOST1 + "include");
978 
979         assertEquals(URL_HOST1 + "css/style.css", getMockWebConnection().getLastWebRequest().getUrl());
980         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
981 
982         // strange check, but there is no order
983         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
984         assertEquals(48, lastCookies.length());
985 
986         assertTrue("lastCookies: " + lastCookies, lastCookies.contains("first=1")
987                     && lastCookies.contains("c2=Lax")
988                     && lastCookies.contains("c3=Strict")
989                     && lastCookies.contains("c4=empty")
990                     && lastCookies.contains("c5=unknown"));
991 
992         if (driver instanceof HtmlUnitDriver) {
993             final CookieManager mgr = getWebClient().getCookieManager();
994             assertEquals(6, mgr.getCookies().size());
995             assertNull(mgr.getCookie("first").getSameSite());
996             assertEquals("lax", mgr.getCookie("c2").getSameSite());
997             assertEquals("strict", mgr.getCookie("c3").getSameSite());
998             assertEquals("", mgr.getCookie("c4").getSameSite());
999             assertEquals("unknown", mgr.getCookie("c5").getSameSite());
1000         }
1001     }
1002 
1003     /**
1004      * @throws Exception if the test fails
1005      */
1006     @Test
1007     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; first=1")
1008     public void sameSiteIncludeFromSubDomain() throws Exception {
1009         final List<NameValuePair> responseHeader = new ArrayList<>();
1010         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
1011 
1012         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
1013         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
1014         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
1015         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
1016         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
1017 
1018         final String html = DOCTYPE_HTML
1019                 + "<html><head>\n"
1020                 + "  <link rel='stylesheet' href='" + URL_HOST1 + "css/style.css'>\n"
1021                 + "</head>\n"
1022                 + "<body>\n"
1023                 + "</body></html>";
1024         getMockWebConnection().setDefaultResponse("");
1025         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
1026                 200, "OK", MimeType.TEXT_HTML, responseHeader);
1027         getMockWebConnection().setResponse(new URL(URL_HOST2), html,
1028                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
1029 
1030         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
1031         verifyTitle2(driver, getExpectedAlerts());
1032         driver.get(URL_HOST2);
1033 
1034         assertEquals(URL_HOST1 + "css/style.css", getMockWebConnection().getLastWebRequest().getUrl());
1035         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
1036 
1037         // strange check, but there is no order
1038         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
1039         assertEquals(48, lastCookies.length());
1040 
1041         assertTrue("lastCookies: " + lastCookies, lastCookies.contains("first=1")
1042                     && lastCookies.contains("c2=Lax")
1043                     && lastCookies.contains("c3=Strict")
1044                     && lastCookies.contains("c4=empty")
1045                     && lastCookies.contains("c5=unknown"));
1046 
1047         if (driver instanceof HtmlUnitDriver) {
1048             final CookieManager mgr = getWebClient().getCookieManager();
1049             assertEquals(12, mgr.getCookies().size());
1050             assertNull(mgr.getCookie("first").getSameSite());
1051             assertEquals("lax", mgr.getCookie("c2").getSameSite());
1052             assertEquals("strict", mgr.getCookie("c3").getSameSite());
1053             assertEquals("", mgr.getCookie("c4").getSameSite());
1054             assertEquals("unknown", mgr.getCookie("c5").getSameSite());
1055         }
1056     }
1057 
1058     /**
1059      * @throws Exception if the test fails
1060      */
1061     @Test
1062     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; first=1")
1063     public void sameSiteIFrameFromSameDomain() throws Exception {
1064         final List<NameValuePair> responseHeader = new ArrayList<>();
1065         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
1066 
1067         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
1068         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
1069         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
1070         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
1071         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
1072 
1073         final String html = DOCTYPE_HTML
1074                 + "<html><head>\n"
1075                 + "</head>\n"
1076                 + "<body>\n"
1077                 + "<iframe src='" + URL_HOST1 + "iframe.html'></iframe>\n"
1078                 + "</body></html>";
1079         getMockWebConnection().setDefaultResponse("");
1080         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
1081                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
1082         getMockWebConnection().setResponse(new URL(URL_HOST1 + "include"), html,
1083                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
1084 
1085         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
1086         verifyTitle2(driver, getExpectedAlerts());
1087         driver.get(URL_HOST1 + "include");
1088 
1089         assertEquals(URL_HOST1 + "iframe.html", getMockWebConnection().getLastWebRequest().getUrl());
1090         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
1091 
1092         // strange check, but there is no order
1093         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
1094         assertEquals(48, lastCookies.length());
1095 
1096         assertTrue("lastCookies: " + lastCookies, lastCookies.contains("first=1")
1097                     && lastCookies.contains("c2=Lax")
1098                     && lastCookies.contains("c3=Strict")
1099                     && lastCookies.contains("c4=empty")
1100                     && lastCookies.contains("c5=unknown"));
1101 
1102         if (driver instanceof HtmlUnitDriver) {
1103             final CookieManager mgr = getWebClient().getCookieManager();
1104             assertEquals(6, mgr.getCookies().size());
1105             assertNull(mgr.getCookie("first").getSameSite());
1106             assertEquals("lax", mgr.getCookie("c2").getSameSite());
1107             assertEquals("strict", mgr.getCookie("c3").getSameSite());
1108             assertEquals("", mgr.getCookie("c4").getSameSite());
1109             assertEquals("unknown", mgr.getCookie("c5").getSameSite());
1110         }
1111     }
1112 
1113     /**
1114      * @throws Exception if the test fails
1115      */
1116     @Test
1117     @Alerts("c2=Lax; c3=Strict; c4=empty; c5=unknown; first=1")
1118     public void sameSiteIFrameFromSubDomain() throws Exception {
1119         final List<NameValuePair> responseHeader = new ArrayList<>();
1120         responseHeader.add(new NameValuePair("Set-Cookie", "first=1;"));
1121 
1122         responseHeader.add(new NameValuePair("Set-Cookie", "c1=None; SameSite=None; Secure"));
1123         responseHeader.add(new NameValuePair("Set-Cookie", "c2=Lax; SameSite=Lax"));
1124         responseHeader.add(new NameValuePair("Set-Cookie", "c3=Strict; SameSite=Strict"));
1125         responseHeader.add(new NameValuePair("Set-Cookie", "c4=empty; SameSite="));
1126         responseHeader.add(new NameValuePair("Set-Cookie", "c5=unknown; SameSite=unknown"));
1127 
1128         final String html = DOCTYPE_HTML
1129                 + "<html><head>\n"
1130                 + "</head>\n"
1131                 + "<body>\n"
1132                 + "<iframe src='" + URL_HOST1 + "iframe.html'></iframe>\n"
1133                 + "</body></html>";
1134         getMockWebConnection().setDefaultResponse("");
1135         getMockWebConnection().setResponse(new URL(URL_HOST1), HTML_ALERT_COOKIE,
1136                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
1137         getMockWebConnection().setResponse(new URL(URL_HOST2 + "include"), html,
1138                                         200, "OK", MimeType.TEXT_HTML, responseHeader);
1139 
1140         final WebDriver driver = loadPage2(new URL(URL_HOST1), StandardCharsets.ISO_8859_1);
1141         verifyTitle2(driver, getExpectedAlerts());
1142         driver.get(URL_HOST2 + "include");
1143 
1144         assertEquals(URL_HOST1 + "iframe.html", getMockWebConnection().getLastWebRequest().getUrl());
1145         final Map<String, String> lastHeaders = getMockWebConnection().getLastAdditionalHeaders();
1146 
1147         // strange check, but there is no order
1148         final String lastCookies = lastHeaders.get(HttpHeader.COOKIE);
1149         assertEquals(48, lastCookies.length());
1150 
1151         assertTrue("lastCookies: " + lastCookies, lastCookies.contains("first=1")
1152                     && lastCookies.contains("c2=Lax")
1153                     && lastCookies.contains("c3=Strict")
1154                     && lastCookies.contains("c4=empty")
1155                     && lastCookies.contains("c5=unknown"));
1156 
1157         if (driver instanceof HtmlUnitDriver) {
1158             final CookieManager mgr = getWebClient().getCookieManager();
1159             assertEquals(12, mgr.getCookies().size());
1160             assertNull(mgr.getCookie("first").getSameSite());
1161             assertEquals("lax", mgr.getCookie("c2").getSameSite());
1162             assertEquals("strict", mgr.getCookie("c3").getSameSite());
1163             assertEquals("", mgr.getCookie("c4").getSameSite());
1164             assertEquals("unknown", mgr.getCookie("c5").getSameSite());
1165         }
1166     }
1167 
1168     /**
1169      * Test for issue #270.
1170      * @throws Exception in case of error
1171      */
1172     @Test
1173     @Alerts("JDSessionID=1234567890")
1174     public void issue270() throws Exception {
1175         final List<NameValuePair> responseHeader1 = new ArrayList<>();
1176         responseHeader1.add(new NameValuePair("Set-Cookie", "first=1; path=/c"));
1177 
1178         final String html = DOCTYPE_HTML
1179             + "<html>\n"
1180             + "<head></head>\n"
1181             + "<body><script>\n"
1182 
1183             + "function setCookie(name, value, expires, path, domain, secure) {\n"
1184             + "  var curCookie = name + '=' + escape(value) +\n"
1185             + "    ((expires) ? '; expires=' + expires.toGMTString() : '') +\n"
1186             + "    ((path) ? '; path=' + path : '') +\n"
1187             + "    ((domain) ? '; domain=' + domain : '') +\n"
1188             + "    ((secure) ? '; secure' : '');\n"
1189 
1190             + "  document.cookie = curCookie;\n"
1191             + "}\n"
1192 
1193             + "var now = new Date();\n"
1194             + "now.setTime(now.getTime() + 60 * 60 * 1000);\n"
1195             + "setCookie('JDSessionID', '1234567890', now, '/', 'htmlunit-dev.org');\n"
1196 
1197 //             + "alert('cookies: ' + document.cookie);\n"
1198 
1199             + "</script></body>\n"
1200             + "</html>";
1201 
1202         final URL firstUrl = new URL(URL_HOST1);
1203         getMockWebConnection().setResponse(firstUrl, html);
1204         loadPage2(html, firstUrl);
1205 
1206         loadPage2(HTML_ALERT_COOKIE, firstUrl);
1207         verifyTitle2(getWebDriver(), getExpectedAlerts());
1208     }
1209 
1210     @Override
1211     protected final WebDriver getWebDriver() {
1212         final WebDriver driver = super.getWebDriver();
1213         if (driver instanceof HtmlUnitDriver) {
1214             // set timeout to fail fast when the url not mapped
1215             ((HtmlUnitDriver) driver).getWebClient().getOptions().setTimeout(1000);
1216         }
1217 
1218         return driver;
1219     }
1220 }