1/*
2 * Copyright (C) 2012 Igalia S.L.
3 * Copyright (C) 2017 Endless Mobile, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22
23#include "WebKitTestServer.h"
24#include "WebViewTest.h"
25#include <WebCore/GUniquePtrSoup.h>
26#include <glib/gstdio.h>
27
28static WebKitTestServer* kServer;
29
30static const char* kFirstPartyDomain = "127.0.0.1";
31static const char* kThirdPartyDomain = "localhost";
32
33static const char* kCookieName = "foo";
34static const char* kCookieValue = "bar";
35static const char* kCookiePath = "/";
36
37static const char* kCookiePathNew = "/new";
38static const char* kCookieValueNew = "new-value";
39
40static const char* kIndexHtmlFormat =
41 "<html><body>"
42 " <p>WebKitGTK+ Cookie Manager test</p>"
43 " <img src='http://localhost:%u/image.png' width=5 height=5></img>"
44 "</body></html>";
45
46class CookieManagerTest: public WebViewTest {
47public:
48 MAKE_GLIB_TEST_FIXTURE(CookieManagerTest);
49
50 static void cookiesChangedCallback(WebKitCookieManager*, CookieManagerTest* test)
51 {
52 test->m_cookiesChanged = true;
53 if (test->m_finishLoopWhenCookiesChange && !(--test->m_cookiesExpectedToChangeCount))
54 g_main_loop_quit(test->m_mainLoop);
55 }
56
57 CookieManagerTest()
58 : WebViewTest()
59 , m_cookieManager(webkit_web_context_get_cookie_manager(m_webContext.get()))
60 {
61 g_assert_true(webkit_website_data_manager_get_cookie_manager(webkit_web_context_get_website_data_manager(m_webContext.get())) == m_cookieManager);
62 g_signal_connect(m_cookieManager, "changed", G_CALLBACK(cookiesChangedCallback), this);
63 }
64
65 ~CookieManagerTest()
66 {
67 g_strfreev(m_domains);
68 g_list_free_full(m_cookies, reinterpret_cast<GDestroyNotify>(soup_cookie_free));
69
70 g_signal_handlers_disconnect_matched(m_cookieManager, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
71 if (m_cookiesTextFile)
72 g_unlink(m_cookiesTextFile.get());
73 if (m_cookiesSQLiteFile)
74 g_unlink(m_cookiesSQLiteFile.get());
75 }
76
77 void setPersistentStorage(WebKitCookiePersistentStorage storage)
78 {
79 const char* filename = 0;
80 switch (storage) {
81 case WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT:
82 if (!m_cookiesTextFile)
83 m_cookiesTextFile.reset(g_build_filename(Test::dataDirectory(), "cookies.txt", nullptr));
84 filename = m_cookiesTextFile.get();
85 break;
86 case WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE:
87 if (!m_cookiesSQLiteFile)
88 m_cookiesSQLiteFile.reset(g_build_filename(Test::dataDirectory(), "cookies.db", nullptr));
89 filename = m_cookiesSQLiteFile.get();
90 break;
91 default:
92 g_assert_not_reached();
93 }
94 webkit_cookie_manager_set_persistent_storage(m_cookieManager, filename, storage);
95 }
96
97 static void getAcceptPolicyReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
98 {
99 GUniqueOutPtr<GError> error;
100 WebKitCookieAcceptPolicy policy = webkit_cookie_manager_get_accept_policy_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
101 g_assert_no_error(error.get());
102
103 CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
104 test->m_acceptPolicy = policy;
105 g_main_loop_quit(test->m_mainLoop);
106 }
107
108 WebKitCookieAcceptPolicy getAcceptPolicy()
109 {
110 m_acceptPolicy = WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY;
111 webkit_cookie_manager_get_accept_policy(m_cookieManager, 0, getAcceptPolicyReadyCallback, this);
112 g_main_loop_run(m_mainLoop);
113
114 return m_acceptPolicy;
115 }
116
117 static void addCookieReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
118 {
119 GUniqueOutPtr<GError> error;
120 bool added = webkit_cookie_manager_add_cookie_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
121 g_assert_no_error(error.get());
122 g_assert_true(added);
123
124 CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
125 g_main_loop_quit(test->m_mainLoop);
126 }
127
128 void addCookie(SoupCookie* cookie)
129 {
130 webkit_cookie_manager_add_cookie(m_cookieManager, cookie, 0, addCookieReadyCallback, this);
131 g_main_loop_run(m_mainLoop);
132 }
133
134 static void getCookiesReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
135 {
136 GUniqueOutPtr<GError> error;
137 GList* cookies = webkit_cookie_manager_get_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
138 g_assert_no_error(error.get());
139
140 CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
141 test->m_cookies = cookies;
142 g_main_loop_quit(test->m_mainLoop);
143 }
144
145 GList* getCookies(const char* uri)
146 {
147 g_list_free_full(m_cookies, reinterpret_cast<GDestroyNotify>(soup_cookie_free));
148 m_cookies = nullptr;
149 webkit_cookie_manager_get_cookies(m_cookieManager, uri, 0, getCookiesReadyCallback, this);
150 g_main_loop_run(m_mainLoop);
151
152 return m_cookies;
153 }
154
155 static void deleteCookieReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
156 {
157 GUniqueOutPtr<GError> error;
158 bool deleted = webkit_cookie_manager_delete_cookie_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
159 g_assert_no_error(error.get());
160 g_assert_true(deleted);
161
162 CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
163 g_main_loop_quit(test->m_mainLoop);
164 }
165
166 void deleteCookie(SoupCookie* cookie)
167 {
168 webkit_cookie_manager_delete_cookie(m_cookieManager, cookie, 0, deleteCookieReadyCallback, this);
169 g_main_loop_run(m_mainLoop);
170 }
171
172 void setAcceptPolicy(WebKitCookieAcceptPolicy policy)
173 {
174 webkit_cookie_manager_set_accept_policy(m_cookieManager, policy);
175 }
176
177 static void getDomainsReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
178 {
179 GUniqueOutPtr<GError> error;
180 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
181 char** domains = webkit_cookie_manager_get_domains_with_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
182 G_GNUC_END_IGNORE_DEPRECATIONS;
183 g_assert_no_error(error.get());
184
185 CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
186 test->m_domains = domains;
187 g_main_loop_quit(test->m_mainLoop);
188 }
189
190 char** getDomains()
191 {
192 g_strfreev(m_domains);
193 m_domains = 0;
194 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
195 webkit_cookie_manager_get_domains_with_cookies(m_cookieManager, 0, getDomainsReadyCallback, this);
196 G_GNUC_END_IGNORE_DEPRECATIONS;
197 g_main_loop_run(m_mainLoop);
198
199 return m_domains;
200 }
201
202 bool hasDomain(const char* domain)
203 {
204 if (!m_domains)
205 return false;
206
207 for (size_t i = 0; m_domains[i]; ++i) {
208 if (g_str_equal(m_domains[i], domain))
209 return true;
210 }
211 return false;
212 }
213
214 void deleteCookiesForDomain(const char* domain)
215 {
216 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
217 webkit_cookie_manager_delete_cookies_for_domain(m_cookieManager, domain);
218 G_GNUC_END_IGNORE_DEPRECATIONS;
219 }
220
221 void deleteAllCookies()
222 {
223 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
224 webkit_cookie_manager_delete_all_cookies(m_cookieManager);
225 G_GNUC_END_IGNORE_DEPRECATIONS;
226 }
227
228 void waitUntilCookiesChanged(int cookiesExpectedToChangeCount = 1)
229 {
230 m_cookiesChanged = false;
231 m_cookiesExpectedToChangeCount = cookiesExpectedToChangeCount;
232 m_finishLoopWhenCookiesChange = true;
233 g_main_loop_run(m_mainLoop);
234 m_finishLoopWhenCookiesChange = false;
235 }
236
237 WebKitCookieManager* m_cookieManager { nullptr };
238 WebKitCookieAcceptPolicy m_acceptPolicy { WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY };
239 char** m_domains { nullptr };
240 GList* m_cookies { nullptr };
241 bool m_cookiesChanged { false };
242 int m_cookiesExpectedToChangeCount { 0 };
243 bool m_finishLoopWhenCookiesChange { false };
244 GUniquePtr<char> m_cookiesTextFile;
245 GUniquePtr<char> m_cookiesSQLiteFile;
246};
247
248static void testCookieManagerAcceptPolicy(CookieManagerTest* test, gconstpointer)
249{
250 // Default policy is NO_THIRD_PARTY.
251 g_assert_cmpint(test->getAcceptPolicy(), ==, WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
252 test->loadURI(kServer->getURIForPath("/index.html").data());
253 test->waitUntilLoadFinished();
254 char** domains = test->getDomains();
255 g_assert_nonnull(domains);
256 g_assert_cmpint(g_strv_length(domains), ==, 1);
257 g_assert_cmpstr(domains[0], ==, kFirstPartyDomain);
258 test->deleteAllCookies();
259
260 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
261 g_assert_cmpint(test->getAcceptPolicy(), ==, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
262 test->loadURI(kServer->getURIForPath("/index.html").data());
263 test->waitUntilLoadFinished();
264 domains = test->getDomains();
265 g_assert_nonnull(domains);
266 g_assert_cmpint(g_strv_length(domains), ==, 2);
267 g_assert_true(test->hasDomain(kFirstPartyDomain));
268 g_assert_true(test->hasDomain(kThirdPartyDomain));
269 test->deleteAllCookies();
270
271 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_NEVER);
272 g_assert_cmpint(test->getAcceptPolicy(), ==, WEBKIT_COOKIE_POLICY_ACCEPT_NEVER);
273 test->loadURI(kServer->getURIForPath("/index.html").data());
274 test->waitUntilLoadFinished();
275 domains = test->getDomains();
276 g_assert_nonnull(domains);
277 g_assert_cmpint(g_strv_length(domains), ==, 0);
278}
279
280static void testCookieManagerAddCookie(CookieManagerTest* test, gconstpointer)
281{
282 // Load the html content, with the default NO_THIRD_PARTY accept policy,
283 // which will automatically add one cookie.
284 test->loadURI(kServer->getURIForPath("/index.html").data());
285 test->waitUntilLoadFinished();
286 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
287
288 // Check the cookies that have been added for the domain.
289 GUniquePtr<char> uri(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
290 GList* foundCookies = test->getCookies(uri.get());
291 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
292
293 SoupCookie* foundCookie = static_cast<SoupCookie*>(foundCookies->data);
294 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
295 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
296 g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
297 g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
298
299 // Try to add now a cookie with same (name, domain, path) than the ones already added.
300 GUniquePtr<SoupCookie> firstCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePath, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
301 test->addCookie(firstCookie.get());
302
303 // Still one cookie, since (name, domain, path) are the same than the already existing
304 // one, but the new value is now stored as replaced by the recently added cookie.
305 foundCookies = test->getCookies(uri.get());
306 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
307
308 foundCookie = static_cast<SoupCookie*>(foundCookies->data);
309 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
310 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
311 g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
312 g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValueNew);
313
314 // Now create another cookie with a different path and add it.
315 GUniquePtr<SoupCookie> secondCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
316 test->addCookie(secondCookie.get());
317 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
318
319 // Retrieve the list of cookies for the same domain and path again now and check.
320 uri.reset(g_strdup_printf("%s://%s%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain, kCookiePathNew));
321 foundCookies = test->getCookies(uri.get());
322
323 // We have now two cookies that would apply to the passed URL, one is the cookie initially
324 // loaded with the web content and the other cookie the one we manually added.
325 g_assert_cmpint(g_list_length(foundCookies), ==, 2);
326
327 // Add a third new cookie for a different domain than the previous ones.
328 GUniquePtr<SoupCookie> thirdCookie(soup_cookie_new(kCookieName, kCookieValueNew, kThirdPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
329 test->addCookie(thirdCookie.get());
330
331 // Only one cookie now, since the domain is different.
332 uri.reset(g_strdup_printf("%s://%s%s", SOUP_URI_SCHEME_HTTP, kThirdPartyDomain, kCookiePathNew));
333 foundCookies = test->getCookies(uri.get());
334 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
335 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
336
337 foundCookie = static_cast<SoupCookie*>(foundCookies->data);
338 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
339 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kThirdPartyDomain);
340 g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePathNew);
341 g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValueNew);
342
343 // Finally, delete all cookies and check they are all gone.
344 test->deleteAllCookies();
345 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
346}
347
348static void testCookieManagerGetCookies(CookieManagerTest* test, gconstpointer)
349{
350 // Load the html content and retrieve the two cookies automatically added with ALWAYS policy.
351 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
352 test->loadURI(kServer->getURIForPath("/index.html").data());
353 test->waitUntilLoadFinished();
354 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
355
356 // Retrieve the first cookie using a HTTP scheme.
357 GUniquePtr<char> uri(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
358 GList* foundCookies = test->getCookies(uri.get());
359 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
360
361 SoupCookie* foundCookie = static_cast<SoupCookie*>(foundCookies->data);
362 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
363 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
364 g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
365 g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
366
367 // Retrieve the second cookie using a HTTPS scheme.
368 uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTPS, kThirdPartyDomain));
369 foundCookies = test->getCookies(uri.get());
370 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
371
372 foundCookie = static_cast<SoupCookie*>(foundCookies->data);
373 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
374 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kThirdPartyDomain);
375 g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
376 g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
377
378 // Create a new cookie and add it to the first domain.
379 GUniquePtr<SoupCookie> newCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
380 test->addCookie(newCookie.get());
381
382 // We should get two cookies that would apply to the same URL passed, since
383 // http://127.0.0.1/new is a subset of the http://127.0.0.1/ URL.
384 uri.reset(g_strdup_printf("%s://%s%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain, kCookiePathNew));
385 foundCookies = test->getCookies(uri.get());
386 g_assert_cmpint(g_list_length(foundCookies), ==, 2);
387
388 // We have now two cookies that would apply to the passed URL, one is the cookie initially
389 // loaded with the web content and the other cookie the one we manually added.
390 g_assert_cmpint(g_list_length(foundCookies), ==, 2);
391
392 bool newPathChecked = false;
393 const char* pathFound = nullptr;
394 const char* valueFound = nullptr;
395 for (uint i = 0; i < 2; i++) {
396 foundCookie = static_cast<SoupCookie*>(g_list_nth_data(foundCookies, i));
397 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
398 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
399
400 // Cookies will have different values for 'value' and 'path', so make sure that
401 // we check for both possibilities, but different ones for each cookie found.
402 pathFound = soup_cookie_get_path(foundCookie);
403 valueFound = soup_cookie_get_value(foundCookie);
404 if (i > 0) {
405 if (newPathChecked) {
406 g_assert_cmpstr(pathFound, ==, kCookiePath);
407 g_assert_cmpstr(valueFound, ==, kCookieValue);
408 } else {
409 g_assert_cmpstr(pathFound, ==, kCookiePathNew);
410 g_assert_cmpstr(valueFound, ==, kCookieValueNew);
411 }
412 } else {
413 if (g_strcmp0(pathFound, kCookiePath)) {
414 g_assert_cmpstr(pathFound, ==, kCookiePathNew);
415 g_assert_cmpstr(valueFound, ==, kCookieValueNew);
416 newPathChecked = true;
417 }
418
419 if (g_strcmp0(pathFound, kCookiePathNew)) {
420 g_assert_cmpstr(pathFound, ==, kCookiePath);
421 g_assert_cmpstr(valueFound, ==, kCookieValue);
422 newPathChecked = false;
423 }
424 }
425 }
426
427 // We should get 1 cookie only if we specify http://127.0.0.1/, though.
428 uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
429 foundCookies = test->getCookies(uri.get());
430 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
431
432 foundCookie = static_cast<SoupCookie*>(foundCookies->data);
433 g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
434 g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
435 g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
436 g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
437
438 // Finally, delete all cookies and try to retrieve them again, one by one.
439 test->deleteAllCookies();
440 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
441
442 uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
443 foundCookies = test->getCookies(uri.get());
444 g_assert_null(foundCookies);
445}
446
447static void testCookieManagerDeleteCookie(CookieManagerTest* test, gconstpointer)
448{
449 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
450 test->loadURI(kServer->getURIForPath("/index.html").data());
451 test->waitUntilLoadFinished();
452
453 // Initially, there should be two cookies available.
454 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
455
456 // Delete the cookie for the first party domain.
457 GUniquePtr<char> uri(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
458 GList* foundCookies = test->getCookies(uri.get());
459 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
460
461 GUniquePtr<SoupCookie> firstPartyCookie(soup_cookie_copy(static_cast<SoupCookie*>(foundCookies->data)));
462 test->deleteCookie(firstPartyCookie.get());
463 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
464
465 // Try deleting a non-existent cookie (wrong name).
466 GUniquePtr<SoupCookie> wrongCookie(soup_cookie_new("wrong-name", kCookieValue, kThirdPartyDomain, kCookiePath, -1));
467 test->deleteCookie(wrongCookie.get());
468 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
469
470 // Try deleting a non-existent cookie (wrong domain).
471 wrongCookie.reset(soup_cookie_new(kCookieName, kCookieValue, "wrong-domain", kCookiePath, -1));
472 test->deleteCookie(wrongCookie.get());
473 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
474
475 // Try deleting a non-existent cookie (wrong path).
476 wrongCookie.reset(soup_cookie_new(kCookieName, kCookieValue, kThirdPartyDomain, "wrong-path", -1));
477 test->deleteCookie(wrongCookie.get());
478 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
479
480 // Delete the cookie for the third party domain.
481 uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kThirdPartyDomain));
482 foundCookies = test->getCookies(uri.get());
483 g_assert_cmpint(g_list_length(foundCookies), ==, 1);
484
485 GUniquePtr<SoupCookie> thirdPartyCookie(soup_cookie_copy(static_cast<SoupCookie*>(foundCookies->data)));
486 test->deleteCookie(thirdPartyCookie.get());
487 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
488
489 // Finally, add a new cookie now we don't have any and delete it afterwards.
490 GUniquePtr<SoupCookie> newCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
491 test->addCookie(newCookie.get());
492 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
493 test->deleteCookie(newCookie.get());
494 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
495}
496
497static void testCookieManagerDeleteCookies(CookieManagerTest* test, gconstpointer)
498{
499 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
500 test->loadURI(kServer->getURIForPath("/index.html").data());
501 test->waitUntilLoadFinished();
502 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
503
504 // Delete first party cookies.
505 test->deleteCookiesForDomain(kFirstPartyDomain);
506 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
507
508 // Delete third party cookies.
509 test->deleteCookiesForDomain(kThirdPartyDomain);
510 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
511
512 test->loadURI(kServer->getURIForPath("/index.html").data());
513 test->waitUntilLoadFinished();
514 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
515
516 // Delete all cookies.
517 test->deleteAllCookies();
518 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
519}
520
521static void testCookieManagerCookiesChanged(CookieManagerTest* test, gconstpointer)
522{
523 g_assert_false(test->m_cookiesChanged);
524 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
525 test->loadURI(kServer->getURIForPath("/index.html").data());
526 test->waitUntilLoadFinished();
527 g_assert_true(test->m_cookiesChanged);
528
529 test->deleteCookiesForDomain(kFirstPartyDomain);
530 test->waitUntilCookiesChanged();
531 g_assert_true(test->m_cookiesChanged);
532
533 test->deleteAllCookies();
534 test->waitUntilCookiesChanged();
535 g_assert_true(test->m_cookiesChanged);
536}
537
538class CookiePersistentStorageTest : public CookieManagerTest {
539public:
540 MAKE_GLIB_TEST_FIXTURE_WITH_SETUP_TEARDOWN(CookiePersistentStorageTest, setup, teardown);
541
542 static void setup()
543 {
544 WebViewTest::shouldInitializeWebViewInConstructor = false;
545 }
546
547 static void teardown()
548 {
549 WebViewTest::shouldInitializeWebViewInConstructor = true;
550 }
551};
552
553static void testCookieManagerPersistentStorage(CookiePersistentStorageTest* test, gconstpointer)
554{
555 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
556
557 g_unlink(test->m_cookiesTextFile.get());
558 g_unlink(test->m_cookiesSQLiteFile.get());
559
560 // Text storage using a new file.
561 test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
562 char** domains = test->getDomains();
563 g_assert_nonnull(domains);
564 g_assert_cmpint(g_strv_length(domains), ==, 0);
565
566 // Initialization of web view is deferred to ensure it's not required for
567 // setting persistent storage to work.
568 test->initializeWebView();
569 test->loadURI(kServer->getURIForPath("/index.html").data());
570 test->waitUntilLoadFinished();
571 g_assert_true(test->m_cookiesChanged);
572 domains = test->getDomains();
573 g_assert_nonnull(domains);
574 g_assert_cmpint(g_strv_length(domains), ==, 2);
575 g_assert_true(g_file_test(test->m_cookiesTextFile.get(), G_FILE_TEST_EXISTS));
576
577 // SQLite storage using a new file.
578 test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
579 domains = test->getDomains();
580 g_assert_nonnull(domains);
581 g_assert_cmpint(g_strv_length(domains), ==, 0);
582
583 test->loadURI(kServer->getURIForPath("/index.html").data());
584 test->waitUntilLoadFinished();
585 g_assert_true(test->m_cookiesChanged);
586 domains = test->getDomains();
587 g_assert_nonnull(domains);
588 g_assert_cmpint(g_strv_length(domains), ==, 2);
589 g_assert_true(g_file_test(test->m_cookiesSQLiteFile.get(), G_FILE_TEST_EXISTS));
590
591 // Text storage using an existing file.
592 test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
593 domains = test->getDomains();
594 g_assert_nonnull(domains);
595 g_assert_cmpint(g_strv_length(domains), ==, 2);
596 test->deleteAllCookies();
597 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
598
599 // SQLite storage with an existing file.
600 test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
601 domains = test->getDomains();
602 g_assert_nonnull(domains);
603 g_assert_cmpint(g_strv_length(domains), ==, 2);
604 test->deleteAllCookies();
605 g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
606}
607
608static void testCookieManagerPersistentStorageDeleteAll(CookieManagerTest* test, gconstpointer)
609{
610 // This checks that we can remove all the cookies of an existing file before a web process is created.
611 // See bug https://bugs.webkit.org/show_bug.cgi?id=175265.
612 static const char cookiesFileFormat[] = "127.0.0.1\tFALSE\t/\tFALSE\t%ld\tfoo\tbar\nlocalhost\tFALSE\t/\tFALSE\t%ld\tbaz\tqux\n";
613 time_t expires = time(nullptr) + 60;
614 GUniquePtr<char> cookiesFileContents(g_strdup_printf(cookiesFileFormat, expires, expires));
615 GUniquePtr<char> cookiesFile(g_build_filename(Test::dataDirectory(), "cookies.txt", nullptr));
616 g_assert_true(g_file_set_contents(cookiesFile.get(), cookiesFileContents.get(), -1, nullptr));
617
618 test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
619 test->deleteAllCookies();
620 // Changed signal is emitted for every deleted cookie, twice in this case.
621 test->waitUntilCookiesChanged(2);
622
623 // Ensure the web process is created and load something without cookies.
624 test->m_cookiesChanged = false;
625 test->loadURI(kServer->getURIForPath("/no-cookies.html").data());
626 test->waitUntilLoadFinished();
627 g_assert_false(test->m_cookiesChanged);
628 char** domains = test->getDomains();
629 g_assert_nonnull(domains);
630 g_assert_cmpint(g_strv_length(domains), ==, 0);
631}
632
633static void ephemeralViewloadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test)
634{
635 if (loadEvent != WEBKIT_LOAD_FINISHED)
636 return;
637 g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewloadChanged), test);
638 test->quitMainLoop();
639}
640
641static void testCookieManagerEphemeral(CookieManagerTest* test, gconstpointer)
642{
643 test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
644 test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
645 char** domains = test->getDomains();
646 g_assert_nonnull(domains);
647 g_assert_cmpint(g_strv_length(domains), ==, 0);
648
649 auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
650#if PLATFORM(WPE)
651 "backend", Test::createWebViewBackend(),
652#endif
653 "web-context", webkit_web_view_get_context(test->m_webView),
654 "is-ephemeral", TRUE,
655 nullptr));
656 g_assert_true(webkit_web_view_is_ephemeral(webView.get()));
657 g_assert_false(webkit_web_context_is_ephemeral(webkit_web_view_get_context(webView.get())));
658
659 g_signal_connect(webView.get(), "load-changed", G_CALLBACK(ephemeralViewloadChanged), test);
660 webkit_web_view_load_uri(webView.get(), kServer->getURIForPath("/index.html").data());
661 g_main_loop_run(test->m_mainLoop);
662
663 domains = test->getDomains();
664 g_assert_nonnull(domains);
665 g_assert_cmpint(g_strv_length(domains), ==, 0);
666
667 auto* viewDataManager = webkit_web_view_get_website_data_manager(webView.get());
668 g_assert_true(WEBKIT_IS_WEBSITE_DATA_MANAGER(viewDataManager));
669 test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(viewDataManager));
670 g_assert_true(viewDataManager != webkit_web_context_get_website_data_manager(webkit_web_view_get_context(test->m_webView)));
671 auto* cookieManager = webkit_website_data_manager_get_cookie_manager(viewDataManager);
672 g_assert_true(WEBKIT_IS_COOKIE_MANAGER(cookieManager));
673 test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(cookieManager));
674 g_assert_true(cookieManager != test->m_cookieManager);
675 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
676 webkit_cookie_manager_get_domains_with_cookies(cookieManager, nullptr, [](GObject* object, GAsyncResult* result, gpointer userData) {
677 auto* test = static_cast<CookieManagerTest*>(userData);
678 GUniquePtr<char*> domains(webkit_cookie_manager_get_domains_with_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, nullptr));
679 g_assert_nonnull(domains);
680 g_assert_cmpint(g_strv_length(domains.get()), ==, 1);
681 g_assert_cmpstr(domains.get()[0], ==, kFirstPartyDomain);
682 test->quitMainLoop();
683 }, test);
684 G_GNUC_END_IGNORE_DEPRECATIONS;
685 g_main_loop_run(test->m_mainLoop);
686}
687
688static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
689{
690 if (message->method != SOUP_METHOD_GET) {
691 soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
692 return;
693 }
694
695 soup_message_set_status(message, SOUP_STATUS_OK);
696 gchar* header_str = g_strdup_printf("%s=%s; Max-Age=60", kCookieName, kCookieValue);
697
698 if (g_str_equal(path, "/index.html")) {
699 char* indexHtml = g_strdup_printf(kIndexHtmlFormat, soup_server_get_port(server));
700 soup_message_headers_replace(message->response_headers, "Set-Cookie", header_str);
701 soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, indexHtml, strlen(indexHtml));
702 } else if (g_str_equal(path, "/image.png"))
703 soup_message_headers_replace(message->response_headers, "Set-Cookie", header_str);
704 else if (g_str_equal(path, "/no-cookies.html")) {
705 static const char* indexHtml = "<html><body><p>No cookies</p></body></html>";
706 soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, indexHtml, strlen(indexHtml));
707 } else
708 soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
709 soup_message_body_complete(message->response_body);
710}
711
712void beforeAll()
713{
714 kServer = new WebKitTestServer();
715 kServer->run(serverCallback);
716
717 CookieManagerTest::add("WebKitCookieManager", "accept-policy", testCookieManagerAcceptPolicy);
718 CookieManagerTest::add("WebKitCookieManager", "add-cookie", testCookieManagerAddCookie);
719 CookieManagerTest::add("WebKitCookieManager", "get-cookies", testCookieManagerGetCookies);
720 CookieManagerTest::add("WebKitCookieManager", "delete-cookie", testCookieManagerDeleteCookie);
721 CookieManagerTest::add("WebKitCookieManager", "delete-cookies", testCookieManagerDeleteCookies);
722 CookieManagerTest::add("WebKitCookieManager", "cookies-changed", testCookieManagerCookiesChanged);
723 CookiePersistentStorageTest::add("WebKitCookieManager", "persistent-storage", testCookieManagerPersistentStorage);
724 CookieManagerTest::add("WebKitCookieManager", "persistent-storage-delete-all", testCookieManagerPersistentStorageDeleteAll);
725 CookieManagerTest::add("WebKitCookieManager", "ephemeral", testCookieManagerEphemeral);
726}
727
728void afterAll()
729{
730 delete kServer;
731}
732