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