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 Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2,1 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#include "WebKitCookieManager.h"
23
24#include "SoupCookiePersistentStorageType.h"
25#include "WebCookieManagerProxy.h"
26#include "WebKitCookieManagerPrivate.h"
27#include "WebKitEnumTypes.h"
28#include "WebKitWebsiteDataManagerPrivate.h"
29#include "WebKitWebsiteDataPrivate.h"
30#include "WebsiteDataRecord.h"
31#include <glib/gi18n-lib.h>
32#include <pal/SessionID.h>
33#include <wtf/glib/GRefPtr.h>
34#include <wtf/glib/WTFGType.h>
35#include <wtf/text/CString.h>
36
37using namespace WebKit;
38
39/**
40 * SECTION: WebKitCookieManager
41 * @Short_description: Defines how to handle cookies in a #WebKitWebContext
42 * @Title: WebKitCookieManager
43 *
44 * The WebKitCookieManager defines how to set up and handle cookies.
45 * You can get it from a #WebKitWebsiteDataManager with
46 * webkit_website_data_manager_get_cookie_manager(), and use it to set where to
47 * store cookies with webkit_cookie_manager_set_persistent_storage(),
48 * or to set the acceptance policy, with webkit_cookie_manager_get_accept_policy().
49 */
50
51enum {
52 CHANGED,
53
54 LAST_SIGNAL
55};
56
57struct _WebKitCookieManagerPrivate {
58 PAL::SessionID sessionID() const
59 {
60 ASSERT(dataManager);
61 return webkitWebsiteDataManagerGetDataStore(dataManager).websiteDataStore().sessionID();
62 }
63
64 ~_WebKitCookieManagerPrivate()
65 {
66 for (auto* processPool : webkitWebsiteDataManagerGetProcessPools(dataManager))
67 processPool->supplement<WebCookieManagerProxy>()->setCookieObserverCallback(sessionID(), nullptr);
68 }
69
70 WebKitWebsiteDataManager* dataManager;
71};
72
73static guint signals[LAST_SIGNAL] = { 0, };
74
75WEBKIT_DEFINE_TYPE(WebKitCookieManager, webkit_cookie_manager, G_TYPE_OBJECT)
76
77static inline SoupCookiePersistentStorageType toSoupCookiePersistentStorageType(WebKitCookiePersistentStorage kitStorage)
78{
79 switch (kitStorage) {
80 case WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT:
81 return SoupCookiePersistentStorageType::Text;
82 case WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE:
83 return SoupCookiePersistentStorageType::SQLite;
84 default:
85 ASSERT_NOT_REACHED();
86 return SoupCookiePersistentStorageType::Text;
87 }
88}
89
90static inline WebKitCookieAcceptPolicy toWebKitCookieAcceptPolicy(HTTPCookieAcceptPolicy httpPolicy)
91{
92 switch (httpPolicy) {
93 case HTTPCookieAcceptPolicyAlways:
94 return WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS;
95 case HTTPCookieAcceptPolicyNever:
96 return WEBKIT_COOKIE_POLICY_ACCEPT_NEVER;
97 case HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:
98 return WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY;
99 default:
100 ASSERT_NOT_REACHED();
101 return WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS;
102 }
103}
104
105static inline HTTPCookieAcceptPolicy toHTTPCookieAcceptPolicy(WebKitCookieAcceptPolicy kitPolicy)
106{
107 switch (kitPolicy) {
108 case WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS:
109 return HTTPCookieAcceptPolicyAlways;
110 case WEBKIT_COOKIE_POLICY_ACCEPT_NEVER:
111 return HTTPCookieAcceptPolicyNever;
112 case WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY:
113 return HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
114 default:
115 ASSERT_NOT_REACHED();
116 return HTTPCookieAcceptPolicyAlways;
117 }
118}
119
120static void webkit_cookie_manager_class_init(WebKitCookieManagerClass* findClass)
121{
122 GObjectClass* gObjectClass = G_OBJECT_CLASS(findClass);
123
124 /**
125 * WebKitCookieManager::changed:
126 * @cookie_manager: the #WebKitCookieManager
127 *
128 * This signal is emitted when cookies are added, removed or modified.
129 */
130 signals[CHANGED] =
131 g_signal_new("changed",
132 G_TYPE_FROM_CLASS(gObjectClass),
133 G_SIGNAL_RUN_LAST,
134 0, 0, 0,
135 g_cclosure_marshal_VOID__VOID,
136 G_TYPE_NONE, 0);
137}
138
139WebKitCookieManager* webkitCookieManagerCreate(WebKitWebsiteDataManager* dataManager)
140{
141 WebKitCookieManager* manager = WEBKIT_COOKIE_MANAGER(g_object_new(WEBKIT_TYPE_COOKIE_MANAGER, nullptr));
142 manager->priv->dataManager = dataManager;
143 for (auto* processPool : webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager)) {
144 processPool->supplement<WebCookieManagerProxy>()->setCookieObserverCallback(manager->priv->sessionID(), [manager] {
145 g_signal_emit(manager, signals[CHANGED], 0);
146 });
147 }
148 return manager;
149}
150
151/**
152 * webkit_cookie_manager_set_persistent_storage:
153 * @cookie_manager: a #WebKitCookieManager
154 * @filename: the filename to read to/write from
155 * @storage: a #WebKitCookiePersistentStorage
156 *
157 * Set the @filename where non-session cookies are stored persistently using
158 * @storage as the format to read/write the cookies.
159 * Cookies are initially read from @filename to create an initial set of cookies.
160 * Then, non-session cookies will be written to @filename when the WebKitCookieManager::changed
161 * signal is emitted.
162 * By default, @cookie_manager doesn't store the cookies persistently, so you need to call this
163 * method to keep cookies saved across sessions.
164 *
165 * This method should never be called on a #WebKitCookieManager associated to an ephemeral #WebKitWebsiteDataManager.
166 */
167void webkit_cookie_manager_set_persistent_storage(WebKitCookieManager* manager, const char* filename, WebKitCookiePersistentStorage storage)
168{
169 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
170 g_return_if_fail(filename);
171 g_return_if_fail(!webkit_website_data_manager_is_ephemeral(manager->priv->dataManager));
172
173 auto sessionID = manager->priv->sessionID();
174 if (sessionID.isEphemeral())
175 return;
176
177 for (auto* processPool : webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager))
178 processPool->supplement<WebCookieManagerProxy>()->setCookiePersistentStorage(sessionID, String::fromUTF8(filename), toSoupCookiePersistentStorageType(storage));
179}
180
181/**
182 * webkit_cookie_manager_set_accept_policy:
183 * @cookie_manager: a #WebKitCookieManager
184 * @policy: a #WebKitCookieAcceptPolicy
185 *
186 * Set the cookie acceptance policy of @cookie_manager as @policy.
187 */
188void webkit_cookie_manager_set_accept_policy(WebKitCookieManager* manager, WebKitCookieAcceptPolicy policy)
189{
190 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
191
192 for (auto* processPool : webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager))
193 processPool->supplement<WebCookieManagerProxy>()->setHTTPCookieAcceptPolicy(manager->priv->sessionID(), toHTTPCookieAcceptPolicy(policy), [](CallbackBase::Error) { });
194}
195
196/**
197 * webkit_cookie_manager_get_accept_policy:
198 * @cookie_manager: a #WebKitCookieManager
199 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
200 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
201 * @user_data: (closure): the data to pass to callback function
202 *
203 * Asynchronously get the cookie acceptance policy of @cookie_manager.
204 *
205 * When the operation is finished, @callback will be called. You can then call
206 * webkit_cookie_manager_get_accept_policy_finish() to get the result of the operation.
207 */
208void webkit_cookie_manager_get_accept_policy(WebKitCookieManager* manager, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
209{
210 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
211
212 GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
213
214 // The policy is the same in all process pools having the same session ID, so just ask any.
215 const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
216 if (processPools.isEmpty()) {
217 g_task_return_int(task.get(), WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
218 return;
219 }
220
221 processPools[0]->supplement<WebCookieManagerProxy>()->getHTTPCookieAcceptPolicy(manager->priv->sessionID(), [task = WTFMove(task)](HTTPCookieAcceptPolicy policy, CallbackBase::Error) {
222 g_task_return_int(task.get(), toWebKitCookieAcceptPolicy(policy));
223 });
224}
225
226/**
227 * webkit_cookie_manager_get_accept_policy_finish:
228 * @cookie_manager: a #WebKitCookieManager
229 * @result: a #GAsyncResult
230 * @error: return location for error or %NULL to ignore
231 *
232 * Finish an asynchronous operation started with webkit_cookie_manager_get_accept_policy().
233 *
234 * Returns: the cookie acceptance policy of @cookie_manager as a #WebKitCookieAcceptPolicy.
235 */
236WebKitCookieAcceptPolicy webkit_cookie_manager_get_accept_policy_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
237{
238 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
239 g_return_val_if_fail(g_task_is_valid(result, manager), WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
240
241 gssize returnValue = g_task_propagate_int(G_TASK(result), error);
242 return returnValue == -1 ? WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY : static_cast<WebKitCookieAcceptPolicy>(returnValue);
243}
244
245/**
246 * webkit_cookie_manager_add_cookie:
247 * @cookie_manager: a #WebKitCookieManager
248 * @cookie: the #SoupCookie to be added
249 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
250 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
251 * @user_data: (closure): the data to pass to callback function
252 *
253 * Asynchronously add a #SoupCookie to the underlying storage.
254 *
255 * When the operation is finished, @callback will be called. You can then call
256 * webkit_cookie_manager_add_cookie_finish() to get the result of the operation.
257 *
258 * Since: 2.20
259 */
260void webkit_cookie_manager_add_cookie(WebKitCookieManager* manager, SoupCookie* cookie, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
261{
262 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
263 g_return_if_fail(cookie);
264
265 GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
266
267 // Cookies are read/written from/to the same SQLite database on disk regardless
268 // of the process we access them from, so just use the first process pool.
269 const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
270 processPools[0]->supplement<WebCookieManagerProxy>()->setCookies(manager->priv->sessionID(), { WebCore::Cookie(cookie) }, [task = WTFMove(task)](CallbackBase::Error error) {
271 if (error != CallbackBase::Error::None) {
272 // This can only happen in cases where the web process is not available,
273 // consider the operation "cancelled" from the point of view of the client.
274 g_task_return_new_error(task.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"));
275 return;
276 }
277
278 g_task_return_boolean(task.get(), TRUE);
279 });
280}
281
282/**
283 * webkit_cookie_manager_add_cookie_finish:
284 * @cookie_manager: a #WebKitCookieManager
285 * @result: a #GAsyncResult
286 * @error: return location for error or %NULL to ignore
287 *
288 * Finish an asynchronous operation started with webkit_cookie_manager_add_cookie().
289 *
290 * Returns: %TRUE if the cookie was added or %FALSE in case of error.
291 *
292 * Since: 2.20
293 */
294gboolean webkit_cookie_manager_add_cookie_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
295{
296 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), FALSE);
297 g_return_val_if_fail(g_task_is_valid(result, manager), FALSE);
298
299 return g_task_propagate_boolean(G_TASK(result), error);
300}
301
302/**
303 * webkit_cookie_manager_get_cookies:
304 * @cookie_manager: a #WebKitCookieManager
305 * @uri: the URI associated to the cookies to be retrieved
306 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
307 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
308 * @user_data: (closure): the data to pass to callback function
309 *
310 * Asynchronously get a list of #SoupCookie from @cookie_manager associated with @uri, which
311 * must be either an HTTP or an HTTPS URL.
312 *
313 * When the operation is finished, @callback will be called. You can then call
314 * webkit_cookie_manager_get_cookies_finish() to get the result of the operation.
315 *
316 * Since: 2.20
317 */
318void webkit_cookie_manager_get_cookies(WebKitCookieManager* manager, const gchar* uri, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
319{
320 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
321 g_return_if_fail(uri);
322
323 GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
324
325 // Cookies are read/written from/to the same SQLite database on disk regardless
326 // of the process we access them from, so just use the first process pool.
327 const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
328 processPools[0]->supplement<WebCookieManagerProxy>()->getCookies(manager->priv->sessionID(), URL(URL(), String::fromUTF8(uri)), [task = WTFMove(task)](const Vector<WebCore::Cookie>& cookies, CallbackBase::Error error) {
329 if (error != CallbackBase::Error::None) {
330 // This can only happen in cases where the web process is not available,
331 // consider the operation "cancelled" from the point of view of the client.
332 g_task_return_new_error(task.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"));
333 return;
334 }
335
336 GList* cookiesList = nullptr;
337 for (auto& cookie : cookies)
338 cookiesList = g_list_prepend(cookiesList, cookie.toSoupCookie());
339
340 g_task_return_pointer(task.get(), g_list_reverse(cookiesList), [](gpointer data) {
341 g_list_free_full(static_cast<GList*>(data), reinterpret_cast<GDestroyNotify>(soup_cookie_free));
342 });
343 });
344}
345
346/**
347 * webkit_cookie_manager_get_cookies_finish:
348 * @cookie_manager: a #WebKitCookieManager
349 * @result: a #GAsyncResult
350 * @error: return location for error or %NULL to ignore
351 *
352 * Finish an asynchronous operation started with webkit_cookie_manager_get_cookies().
353 * The return value is a #GSList of #SoupCookie instances which should be released
354 * with g_list_free_full() and soup_cookie_free().
355 *
356 * Returns: (element-type SoupCookie) (transfer full): A #GList of #SoupCookie instances.
357 *
358 * Since: 2.20
359 */
360GList* webkit_cookie_manager_get_cookies_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
361{
362 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), nullptr);
363 g_return_val_if_fail(g_task_is_valid(result, manager), nullptr);
364
365 return reinterpret_cast<GList*>(g_task_propagate_pointer(G_TASK(result), error));
366}
367
368/**
369 * webkit_cookie_manager_delete_cookie:
370 * @cookie_manager: a #WebKitCookieManager
371 * @cookie: the #SoupCookie to be deleted
372 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
373 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
374 * @user_data: (closure): the data to pass to callback function
375 *
376 * Asynchronously delete a #SoupCookie from the current session.
377 *
378 * When the operation is finished, @callback will be called. You can then call
379 * webkit_cookie_manager_delete_cookie_finish() to get the result of the operation.
380 *
381 * Since: 2.20
382 */
383void webkit_cookie_manager_delete_cookie(WebKitCookieManager* manager, SoupCookie* cookie, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
384{
385 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
386 g_return_if_fail(cookie);
387
388 GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
389
390 // Cookies are read/written from/to the same SQLite database on disk regardless
391 // of the process we access them from, so just use the first process pool.
392 const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
393 processPools[0]->supplement<WebCookieManagerProxy>()->deleteCookie(manager->priv->sessionID(), WebCore::Cookie(cookie), [task = WTFMove(task)](CallbackBase::Error error) {
394 if (error != CallbackBase::Error::None) {
395 // This can only happen in cases where the web process is not available,
396 // consider the operation "cancelled" from the point of view of the client.
397 g_task_return_new_error(task.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"));
398 return;
399 }
400
401 g_task_return_boolean(task.get(), TRUE);
402 });
403}
404
405/**
406 * webkit_cookie_manager_delete_cookie_finish:
407 * @cookie_manager: a #WebKitCookieManager
408 * @result: a #GAsyncResult
409 * @error: return location for error or %NULL to ignore
410 *
411 * Finish an asynchronous operation started with webkit_cookie_manager_delete_cookie().
412 *
413 * Returns: %TRUE if the cookie was deleted or %FALSE in case of error.
414 *
415 * Since: 2.20
416 */
417gboolean webkit_cookie_manager_delete_cookie_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
418{
419 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), FALSE);
420 g_return_val_if_fail(g_task_is_valid(result, manager), FALSE);
421
422 return g_task_propagate_boolean(G_TASK(result), error);
423}
424
425#if PLATFORM(GTK)
426/**
427 * webkit_cookie_manager_get_domains_with_cookies:
428 * @cookie_manager: a #WebKitCookieManager
429 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
430 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
431 * @user_data: (closure): the data to pass to callback function
432 *
433 * Asynchronously get the list of domains for which @cookie_manager contains cookies.
434 *
435 * When the operation is finished, @callback will be called. You can then call
436 * webkit_cookie_manager_get_domains_with_cookies_finish() to get the result of the operation.
437 *
438 * Deprecated: 2.16: Use webkit_website_data_manager_fetch() instead.
439 */
440void webkit_cookie_manager_get_domains_with_cookies(WebKitCookieManager* manager, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
441{
442 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
443
444 GTask* task = g_task_new(manager, cancellable, callback, userData);
445 webkit_website_data_manager_fetch(manager->priv->dataManager, WEBKIT_WEBSITE_DATA_COOKIES, cancellable, [](GObject* object, GAsyncResult* result, gpointer userData) {
446 GRefPtr<GTask> task = adoptGRef(G_TASK(userData));
447 GError* error = nullptr;
448 GUniquePtr<GList> dataList(webkit_website_data_manager_fetch_finish(WEBKIT_WEBSITE_DATA_MANAGER(object), result, &error));
449 if (error) {
450 g_task_return_error(task.get(), error);
451 return;
452 }
453
454 GPtrArray* domains = g_ptr_array_sized_new(g_list_length(dataList.get()));
455 for (GList* item = dataList.get(); item; item = g_list_next(item)) {
456 auto* data = static_cast<WebKitWebsiteData*>(item->data);
457 g_ptr_array_add(domains, g_strdup(webkit_website_data_get_name(data)));
458 webkit_website_data_unref(data);
459 }
460 g_ptr_array_add(domains, nullptr);
461 g_task_return_pointer(task.get(), g_ptr_array_free(domains, FALSE), reinterpret_cast<GDestroyNotify>(g_strfreev));
462 }, task);
463}
464
465/**
466 * webkit_cookie_manager_get_domains_with_cookies_finish:
467 * @cookie_manager: a #WebKitCookieManager
468 * @result: a #GAsyncResult
469 * @error: return location for error or %NULL to ignore
470 *
471 * Finish an asynchronous operation started with webkit_cookie_manager_get_domains_with_cookies().
472 * The return value is a %NULL terminated list of strings which should
473 * be released with g_strfreev().
474 *
475 * Returns: (transfer full) (array zero-terminated=1): A %NULL terminated array of domain names
476 * or %NULL in case of error.
477 *
478 * Deprecated: 2.16: Use webkit_website_data_manager_fetch_finish() instead.
479 */
480gchar** webkit_cookie_manager_get_domains_with_cookies_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
481{
482 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), nullptr);
483 g_return_val_if_fail(g_task_is_valid(result, manager), nullptr);
484
485 return reinterpret_cast<char**>(g_task_propagate_pointer(G_TASK(result), error));
486}
487
488/**
489 * webkit_cookie_manager_delete_cookies_for_domain:
490 * @cookie_manager: a #WebKitCookieManager
491 * @domain: a domain name
492 *
493 * Remove all cookies of @cookie_manager for the given @domain.
494 *
495 * Deprecated: 2.16: Use webkit_website_data_manager_remove() instead.
496 */
497void webkit_cookie_manager_delete_cookies_for_domain(WebKitCookieManager* manager, const gchar* domain)
498{
499 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
500 g_return_if_fail(domain);
501
502 WebsiteDataRecord record;
503 record.addCookieHostName(String::fromUTF8(domain));
504 auto* data = webkitWebsiteDataCreate(WTFMove(record));
505 GList dataList = { data, nullptr, nullptr };
506 webkit_website_data_manager_remove(manager->priv->dataManager, WEBKIT_WEBSITE_DATA_COOKIES, &dataList, nullptr, nullptr, nullptr);
507 webkit_website_data_unref(data);
508}
509
510/**
511 * webkit_cookie_manager_delete_all_cookies:
512 * @cookie_manager: a #WebKitCookieManager
513 *
514 * Delete all cookies of @cookie_manager
515 *
516 * Deprecated: 2.16: Use webkit_website_data_manager_clear() instead.
517 */
518void webkit_cookie_manager_delete_all_cookies(WebKitCookieManager* manager)
519{
520 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
521
522 webkit_website_data_manager_clear(manager->priv->dataManager, WEBKIT_WEBSITE_DATA_COOKIES, 0, nullptr, nullptr, nullptr);
523}
524#endif
525