1/* 2 * Copyright (C) 2012 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2,1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "WebKitCookieManager.h" 22 23#include "SoupCookiePersistentStorageType.h" 24#include "WebCookieManagerProxy.h" 25#include "WebKitCookieManagerPrivate.h" 26#include "WebKitEnumTypes.h" 27#include <wtf/gobject/GRefPtr.h> 28#include <wtf/text/CString.h> 29 30using namespace WebKit; 31 32/** 33 * SECTION: WebKitCookieManager 34 * @Short_description: Defines how to handle cookies in a #WebKitWebContext 35 * @Title: WebKitCookieManager 36 * 37 * The #WebKitCookieManager defines how to handle cookies in a 38 * #WebKitWebContext. Get it from the context with 39 * webkit_web_context_get_cookie_manager(), and use it to set where to 40 * store cookies, with webkit_cookie_manager_set_persistent_storage(), 41 * to get the list of domains with cookies, with 42 * webkit_cookie_manager_get_domains_with_cookies(), or to set the 43 * acceptance policy, with webkit_cookie_manager_get_accept_policy() 44 * (among other actions). 45 * 46 */ 47 48enum { 49 CHANGED, 50 51 LAST_SIGNAL 52}; 53 54struct _WebKitCookieManagerPrivate { 55 ~_WebKitCookieManagerPrivate() 56 { 57 webCookieManager->stopObservingCookieChanges(); 58 } 59 60 RefPtr<WebCookieManagerProxy> webCookieManager; 61}; 62 63static guint signals[LAST_SIGNAL] = { 0, }; 64 65WEBKIT_DEFINE_TYPE(WebKitCookieManager, webkit_cookie_manager, G_TYPE_OBJECT) 66 67COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT, SoupCookiePersistentStorageText); 68COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE, SoupCookiePersistentStorageSQLite); 69 70COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS, HTTPCookieAcceptPolicyAlways); 71COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_COOKIE_POLICY_ACCEPT_NEVER, HTTPCookieAcceptPolicyNever); 72COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY, HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain); 73 74static void webkit_cookie_manager_class_init(WebKitCookieManagerClass* findClass) 75{ 76 GObjectClass* gObjectClass = G_OBJECT_CLASS(findClass); 77 78 /** 79 * WebKitCookieManager::changed: 80 * @cookie_manager: the #WebKitCookieManager 81 * 82 * This signal is emitted when cookies are added, removed or modified. 83 */ 84 signals[CHANGED] = 85 g_signal_new("changed", 86 G_TYPE_FROM_CLASS(gObjectClass), 87 G_SIGNAL_RUN_LAST, 88 0, 0, 0, 89 g_cclosure_marshal_VOID__VOID, 90 G_TYPE_NONE, 0); 91} 92 93static void cookiesDidChange(WKCookieManagerRef, const void* clientInfo) 94{ 95 g_signal_emit(WEBKIT_COOKIE_MANAGER(clientInfo), signals[CHANGED], 0); 96} 97 98WebKitCookieManager* webkitCookieManagerCreate(WebCookieManagerProxy* webCookieManager) 99{ 100 WebKitCookieManager* manager = WEBKIT_COOKIE_MANAGER(g_object_new(WEBKIT_TYPE_COOKIE_MANAGER, NULL)); 101 manager->priv->webCookieManager = webCookieManager; 102 103 WKCookieManagerClient wkCookieManagerClient = { 104 kWKCookieManagerClientCurrentVersion, 105 manager, // clientInfo 106 cookiesDidChange 107 }; 108 WKCookieManagerSetClient(toAPI(webCookieManager), &wkCookieManagerClient); 109 manager->priv->webCookieManager->startObservingCookieChanges(); 110 111 return manager; 112} 113 114/** 115 * webkit_cookie_manager_set_persistent_storage: 116 * @cookie_manager: a #WebKitCookieManager 117 * @filename: the filename to read to/write from 118 * @storage: a #WebKitCookiePersistentStorage 119 * 120 * Set the @filename where non-session cookies are stored persistently using 121 * @storage as the format to read/write the cookies. 122 * Cookies are initially read from @filename to create an initial set of cookies. 123 * Then, non-session cookies will be written to @filename when the WebKitCookieManager::changed 124 * signal is emitted. 125 * By default, @cookie_manager doesn't store the cookies persistenly, so you need to call this 126 * method to keep cookies saved across sessions. 127 */ 128void webkit_cookie_manager_set_persistent_storage(WebKitCookieManager* manager, const char* filename, WebKitCookiePersistentStorage storage) 129{ 130 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager)); 131 g_return_if_fail(filename); 132 133 manager->priv->webCookieManager->stopObservingCookieChanges(); 134 manager->priv->webCookieManager->setCookiePersistentStorage(String::fromUTF8(filename), storage); 135 manager->priv->webCookieManager->startObservingCookieChanges(); 136} 137 138/** 139 * webkit_cookie_manager_set_accept_policy: 140 * @cookie_manager: a #WebKitCookieManager 141 * @policy: a #WebKitCookieAcceptPolicy 142 * 143 * Set the cookie acceptance policy of @cookie_manager as @policy. 144 */ 145void webkit_cookie_manager_set_accept_policy(WebKitCookieManager* manager, WebKitCookieAcceptPolicy policy) 146{ 147 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager)); 148 149 manager->priv->webCookieManager->setHTTPCookieAcceptPolicy(policy); 150} 151 152struct GetAcceptPolicyAsyncData { 153 WKHTTPCookieAcceptPolicy policy; 154 GRefPtr<GCancellable> cancellable; 155}; 156WEBKIT_DEFINE_ASYNC_DATA_STRUCT(GetAcceptPolicyAsyncData) 157 158static void webkitCookieManagerGetAcceptPolicyCallback(WKHTTPCookieAcceptPolicy policy, WKErrorRef, void* context) 159{ 160 GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context)); 161 GetAcceptPolicyAsyncData* data = static_cast<GetAcceptPolicyAsyncData*>(g_simple_async_result_get_op_res_gpointer(result.get())); 162 GError* error = 0; 163 if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error)) 164 g_simple_async_result_take_error(result.get(), error); 165 else 166 data->policy = policy; 167 g_simple_async_result_complete(result.get()); 168} 169 170/** 171 * webkit_cookie_manager_get_accept_policy: 172 * @cookie_manager: a #WebKitCookieManager 173 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore 174 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied 175 * @user_data: (closure): the data to pass to callback function 176 * 177 * Asynchronously get the cookie acceptance policy of @cookie_manager. 178 * 179 * When the operation is finished, @callback will be called. You can then call 180 * webkit_cookie_manager_get_accept_policy_finish() to get the result of the operation. 181 */ 182void webkit_cookie_manager_get_accept_policy(WebKitCookieManager* manager, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) 183{ 184 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager)); 185 186 GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(manager), callback, userData, 187 reinterpret_cast<gpointer>(webkit_cookie_manager_get_accept_policy)); 188 GetAcceptPolicyAsyncData* data = createGetAcceptPolicyAsyncData(); 189 data->cancellable = cancellable; 190 g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyGetAcceptPolicyAsyncData)); 191 192 manager->priv->webCookieManager->getHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicyCallback::create(result, webkitCookieManagerGetAcceptPolicyCallback)); 193} 194 195/** 196 * webkit_cookie_manager_get_accept_policy_finish: 197 * @cookie_manager: a #WebKitCookieManager 198 * @result: a #GAsyncResult 199 * @error: return location for error or %NULL to ignore 200 * 201 * Finish an asynchronous operation started with webkit_cookie_manager_get_accept_policy(). 202 * 203 * Returns: the cookie acceptance policy of @cookie_manager as a #WebKitCookieAcceptPolicy. 204 */ 205WebKitCookieAcceptPolicy webkit_cookie_manager_get_accept_policy_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error) 206{ 207 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY); 208 g_return_val_if_fail(G_IS_ASYNC_RESULT(result), WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY); 209 210 GSimpleAsyncResult* simpleResult = G_SIMPLE_ASYNC_RESULT(result); 211 g_warn_if_fail(g_simple_async_result_get_source_tag(simpleResult) == webkit_cookie_manager_get_accept_policy); 212 213 if (g_simple_async_result_propagate_error(simpleResult, error)) 214 return WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY; 215 216 GetAcceptPolicyAsyncData* data = static_cast<GetAcceptPolicyAsyncData*>(g_simple_async_result_get_op_res_gpointer(simpleResult)); 217 return static_cast<WebKitCookieAcceptPolicy>(data->policy); 218} 219 220struct GetDomainsWithCookiesAsyncData { 221 GRefPtr<GPtrArray> domains; 222 GRefPtr<GCancellable> cancellable; 223}; 224WEBKIT_DEFINE_ASYNC_DATA_STRUCT(GetDomainsWithCookiesAsyncData) 225 226static void webkitCookieManagerGetDomainsWithCookiesCallback(WKArrayRef wkDomains, WKErrorRef, void* context) 227{ 228 GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context)); 229 GetDomainsWithCookiesAsyncData* data = static_cast<GetDomainsWithCookiesAsyncData*>(g_simple_async_result_get_op_res_gpointer(result.get())); 230 GError* error = 0; 231 if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error)) 232 g_simple_async_result_take_error(result.get(), error); 233 else { 234 ImmutableArray* domains = toImpl(wkDomains); 235 data->domains = adoptGRef(g_ptr_array_new_with_free_func(g_free)); 236 for (size_t i = 0; i < domains->size(); ++i) { 237 WebString* domainString = static_cast<WebString*>(domains->at(i)); 238 String domain = domainString->string(); 239 if (domain.isEmpty()) 240 continue; 241 g_ptr_array_add(data->domains.get(), g_strdup(domain.utf8().data())); 242 } 243 g_ptr_array_add(data->domains.get(), 0); 244 } 245 g_simple_async_result_complete(result.get()); 246} 247 248/** 249 * webkit_cookie_manager_get_domains_with_cookies: 250 * @cookie_manager: a #WebKitCookieManager 251 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore 252 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied 253 * @user_data: (closure): the data to pass to callback function 254 * 255 * Asynchronously get the list of domains for which @cookie_manager contains cookies. 256 * 257 * When the operation is finished, @callback will be called. You can then call 258 * webkit_cookie_manager_get_domains_with_cookies_finish() to get the result of the operation. 259 */ 260void webkit_cookie_manager_get_domains_with_cookies(WebKitCookieManager* manager, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) 261{ 262 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager)); 263 264 GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(manager), callback, userData, 265 reinterpret_cast<gpointer>(webkit_cookie_manager_get_domains_with_cookies)); 266 GetDomainsWithCookiesAsyncData* data = createGetDomainsWithCookiesAsyncData(); 267 data->cancellable = cancellable; 268 g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyGetDomainsWithCookiesAsyncData)); 269 manager->priv->webCookieManager->getHostnamesWithCookies(ArrayCallback::create(result, webkitCookieManagerGetDomainsWithCookiesCallback)); 270} 271 272/** 273 * webkit_cookie_manager_get_domains_with_cookies_finish: 274 * @cookie_manager: a #WebKitCookieManager 275 * @result: a #GAsyncResult 276 * @error: return location for error or %NULL to ignore 277 * 278 * Finish an asynchronous operation started with webkit_cookie_manager_get_domains_with_cookies(). 279 * The return value is a %NULL terminated list of strings which should 280 * be released with g_strfreev(). 281 * 282 * Returns: (transfer full) (array zero-terminated=1): A %NULL terminated array of domain names 283 * or %NULL in case of error. 284 */ 285gchar** webkit_cookie_manager_get_domains_with_cookies_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error) 286{ 287 g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), 0); 288 g_return_val_if_fail(G_IS_ASYNC_RESULT(result), 0); 289 290 GSimpleAsyncResult* simpleResult = G_SIMPLE_ASYNC_RESULT(result); 291 g_warn_if_fail(g_simple_async_result_get_source_tag(simpleResult) == webkit_cookie_manager_get_domains_with_cookies); 292 293 if (g_simple_async_result_propagate_error(simpleResult, error)) 294 return 0; 295 296 GetDomainsWithCookiesAsyncData* data = static_cast<GetDomainsWithCookiesAsyncData*>(g_simple_async_result_get_op_res_gpointer(simpleResult)); 297 return reinterpret_cast<char**>(g_ptr_array_free(data->domains.leakRef(), FALSE)); 298} 299 300/** 301 * webkit_cookie_manager_delete_cookies_for_domain: 302 * @cookie_manager: a #WebKitCookieManager 303 * @domain: a domain name 304 * 305 * Remove all cookies of @cookie_manager for the given @domain. 306 */ 307void webkit_cookie_manager_delete_cookies_for_domain(WebKitCookieManager* manager, const gchar* domain) 308{ 309 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager)); 310 g_return_if_fail(domain); 311 312 manager->priv->webCookieManager->deleteCookiesForHostname(String::fromUTF8(domain)); 313} 314 315/** 316 * webkit_cookie_manager_delete_all_cookies: 317 * @cookie_manager: a #WebKitCookieManager 318 * 319 * Delete all cookies of @cookie_manager 320 */ 321void webkit_cookie_manager_delete_all_cookies(WebKitCookieManager* manager) 322{ 323 g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager)); 324 325 manager->priv->webCookieManager->deleteAllCookies(); 326} 327