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