View Javadoc
1   /*
2    * Copyright (c) 2002-2026 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 java.util.ArrayList;
18  import java.util.Iterator;
19  import java.util.List;
20  import java.util.Set;
21  
22  import org.htmlunit.html.HtmlPage;
23  import org.htmlunit.http.Cookie;
24  import org.htmlunit.junit.annotation.Alerts;
25  import org.junit.jupiter.api.Test;
26  
27  /**
28   * Unit tests for {@link CookieManager}.
29   *
30   * @author Daniel Gredler
31   * @author Ahmed Ashour
32   * @author Marc Guillemot
33   * @author Ronald Brill
34   */
35  public class CookieManager2Test extends SimpleWebTestCase {
36  
37      /**
38       * @throws Exception if the test fails
39       */
40      @Test
41      public void resettingCookie() throws Exception {
42          final String html = DOCTYPE_HTML
43              + "<html><head>\n"
44              + "<script>\n"
45              + "  function createCookie(name, value, days, path) {\n"
46              + "    if (days) {\n"
47              + "      var date = new Date();\n"
48              + "      date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));\n"
49              + "      var expires = '; expires=' + date.toGMTString();\n"
50              + "    }\n"
51              + "    else\n"
52              + "      var expires = '';\n"
53              + "    document.cookie = name + '=' + value + expires + '; path=' + path;\n"
54              + "  }\n"
55              + "\n"
56              + "  function readCookie(name) {\n"
57              + "    var nameEQ = name + '=';\n"
58              + "    var ca = document.cookie.split(';');\n"
59              + "    for(var i = 0; i < ca.length; i++) {\n"
60              + "      var c = ca[i];\n"
61              + "      while (c.charAt(0) == ' ')\n"
62              + "        c = c.substring(1, c.length);\n"
63              + "      if (c.indexOf(nameEQ) == 0)\n"
64              + "        return c.substring(nameEQ.length, c.length);\n"
65              + "    }\n"
66              + "    return null;\n"
67              + "  }\n"
68              + "</script></head><body>\n"
69              + "  <input id='button1' type='button' "
70              + "onclick=\"createCookie('button','button1',1,'/'); alert('cookie:' + readCookie('button'));\" "
71              + "value='Button 1'>\n"
72              + "  <input id='button2' type='button' "
73              + "onclick=\"createCookie('button','button2',1,'/'); alert('cookie:' + readCookie('button'));\" "
74              + "value='Button 2'>\n"
75              + "</form></body></html>";
76  
77          final String[] expectedAlerts = {"cookie:button1", "cookie:button2"};
78          final List<String> collectedAlerts = new ArrayList<>();
79          final HtmlPage page = loadPage(html, collectedAlerts);
80          page.getHtmlElementById("button1").click();
81          page.getHtmlElementById("button2").click();
82          assertEquals(expectedAlerts, collectedAlerts);
83      }
84  
85      /**
86       * @throws Exception if the test fails
87       */
88      @Test
89      @Alerts("my_key=§")
90      public void cookie_nullValue() throws Exception {
91          final WebClient webClient = getWebClient();
92          final MockWebConnection webConnection = new MockWebConnection();
93  
94          webConnection.setResponse(URL_FIRST, CookieManagerTest.HTML_ALERT_COOKIE);
95          webClient.setWebConnection(webConnection);
96  
97          final CookieManager mgr = webClient.getCookieManager();
98          mgr.addCookie(new Cookie(URL_FIRST.getHost(), "my_key", null, "/", null, false));
99  
100         final List<String> collectedAlerts = new ArrayList<>();
101         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
102 
103         final HtmlPage page = webClient.getPage(URL_FIRST);
104         assertEquals(getExpectedAlerts()[0], page.getTitleText());
105     }
106 
107     /**
108      * @throws Exception if the test fails
109      */
110     @Test
111     @Alerts("my_name=my_data§")
112     public void cookie_maxAgeMinusOne() throws Exception {
113         final WebClient webClient = getWebClient();
114         final MockWebConnection webConnection = new MockWebConnection();
115 
116         webConnection.setResponse(URL_FIRST, CookieManagerTest.HTML_ALERT_COOKIE);
117         webClient.setWebConnection(webConnection);
118 
119         final CookieManager mgr = webClient.getCookieManager();
120         mgr.addCookie(new Cookie(URL_FIRST.getHost(), "my_name", "my_data", "/", -1, false));
121 
122         final HtmlPage page = webClient.getPage(URL_FIRST);
123         assertEquals(getExpectedAlerts()[0], page.getTitleText());
124     }
125 
126     /**
127      * Regression test for bug 3053526: HtmlUnit was throwing an Exception when asking for cookies
128      * of "about:blank".
129      * @throws Exception if the test fails
130      */
131     @Test
132     public void cookiesForAboutBlank() throws Exception {
133         final WebClient webClient = getWebClient();
134         final HtmlPage htmlPage = webClient.getPage("about:blank");
135 
136         final Set<Cookie> cookies = webClient.getCookies(htmlPage.getUrl());
137         assertTrue(cookies.toString(), cookies.isEmpty());
138     }
139 
140     /**
141      * This was causing a ConcurrentModificationException.
142      * In "real life" the problem was arising due to changes to the cookies made from
143      * the JS processing thread.
144      * @throws Exception if the test fails
145      */
146     @Test
147     public void getCookiesShouldReturnACopyOfCurentState() throws Exception {
148         final String html = DOCTYPE_HTML
149                 + "<html><body>\n"
150                 + "<button id='it' onclick=\"document.cookie = 'foo=bla'\">click me</button>\n"
151                 + "<script>\n"
152                 + "document.cookie = 'cookie1=value1';\n"
153                 + "</script></body></html>";
154 
155         final WebClient webClient = getWebClient();
156 
157         final HtmlPage page = loadPage(html);
158         final Set<Cookie> initialCookies = webClient.getCookieManager().getCookies();
159         assertEquals(1, initialCookies.size());
160         final Iterator<Cookie> iterator = initialCookies.iterator();
161 
162         page.getHtmlElementById("it").click();
163         iterator.next(); // ConcurrentModificationException was here
164         assertEquals(1, initialCookies.size());
165         assertEquals(2, webClient.getCookieManager().getCookies().size());
166     }
167 }