Title: [225054] trunk
Revision
225054
Author
[email protected]
Date
2017-11-20 14:02:46 -0800 (Mon, 20 Nov 2017)

Log Message

[GTK] New API to add, retrieve and delete cookies via WebKitCookieManager
https://bugs.webkit.org/show_bug.cgi?id=177932

Reviewed by Carlos Garcia Campos.

Source/WebCore:

Implemented setCookie(), getCookies() and deleteCookie() in the Soup
backend, and refactored some utility functions and conversions out of
NetworkStorageSessionSoup into a new CookieSoup.cpp file, so
that we now can convert between SoupCookie* and WebCore::Cookie
easily from anywhere (this is now needed from the UI Process).

* platform/Cookie.h: Add declarations for the new conversions.
* platform/SourcesSoup.txt: Add CookieSoup.cpp.
* platform/network/soup/CookieSoup.cpp: Added.
(WebCore::Cookie::Cookie): New constructor, creates a WebCore::Cookie out of a SoupCookie*.
(WebCore::msToSoupDate): Moved from NetworkStorageSessionSoup.cpp.
(WebCore::Cookie::toSoupCookie): New, based on toSoupCookie() from NetworkStorageSessionSoup.cpp.
* platform/network/soup/NetworkStorageSessionSoup.cpp:
(WebCore::NetworkStorageSession::setCookies): Used the new implicit conversion.
(WebCore::NetworkStorageSession::setCookie): Newly implemented.
(WebCore::NetworkStorageSession::deleteCookie): Newly implemented.
(WebCore::NetworkStorageSession::getCookies): Newly implemented.

Source/WebKit:

Added new API to WebKitCookieManager to add, retrieve and delete complete
cookies into/out-of a running session, and updated documentation sections.

* UIProcess/API/glib/WebKitCookieManager.cpp:
(webkit_cookie_manager_add_cookie): New function.
(webkit_cookie_manager_add_cookie_finish): Ditto.
(webkit_cookie_manager_get_cookies): Ditto.
(webkit_cookie_manager_get_cookies_finish): Ditto.
(webkit_cookie_manager_delete_cookie): Ditto.
(webkit_cookie_manager_delete_cookie_finish): Ditto.
* UIProcess/API/gtk/WebKitCookieManager.h: Added new functions.
* UIProcess/API/wpe/WebKitCookieManager.h: Ditto.
* UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt: Ditto.

Tools:

Added new test cases to cover the newly added API for WebKitCookieManager:
webkit_cookie_manager_add_cookie, webkit_cookie_manager_get_cookies and
webkit_cookie_manager_delete_cookie.

* TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp:
(testCookieManagerAddCookie): Added.
(testCookieManagerGetCookies): Added.
(testCookieManagerDeleteCookie): Added.
(serverCallback): Small update to avoid hardcoding strings we reuse.
(beforeAll): Added the new test cases to the test suite.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (225053 => 225054)


--- trunk/Source/WebCore/ChangeLog	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebCore/ChangeLog	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,3 +1,28 @@
+2017-11-20  Mario Sanchez Prada  <[email protected]>
+
+        [GTK] New API to add, retrieve and delete cookies via WebKitCookieManager
+        https://bugs.webkit.org/show_bug.cgi?id=177932
+
+        Reviewed by Carlos Garcia Campos.
+
+        Implemented setCookie(), getCookies() and deleteCookie() in the Soup
+        backend, and refactored some utility functions and conversions out of
+        NetworkStorageSessionSoup into a new CookieSoup.cpp file, so
+        that we now can convert between SoupCookie* and WebCore::Cookie
+        easily from anywhere (this is now needed from the UI Process).
+
+        * platform/Cookie.h: Add declarations for the new conversions.
+        * platform/SourcesSoup.txt: Add CookieSoup.cpp.
+        * platform/network/soup/CookieSoup.cpp: Added.
+        (WebCore::Cookie::Cookie): New constructor, creates a WebCore::Cookie out of a SoupCookie*.
+        (WebCore::msToSoupDate): Moved from NetworkStorageSessionSoup.cpp.
+        (WebCore::Cookie::toSoupCookie): New, based on toSoupCookie() from NetworkStorageSessionSoup.cpp.
+        * platform/network/soup/NetworkStorageSessionSoup.cpp:
+        (WebCore::NetworkStorageSession::setCookies): Used the new implicit conversion.
+        (WebCore::NetworkStorageSession::setCookie): Newly implemented.
+        (WebCore::NetworkStorageSession::deleteCookie): Newly implemented.
+        (WebCore::NetworkStorageSession::getCookies): Newly implemented.
+
 2017-11-20  Zalan Bujtas  <[email protected]>
 
         Remove slow repaint object from FrameView when style changes.

Modified: trunk/Source/WebCore/platform/Cookie.h (225053 => 225054)


--- trunk/Source/WebCore/platform/Cookie.h	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebCore/platform/Cookie.h	2017-11-20 22:02:46 UTC (rev 225054)
@@ -67,6 +67,9 @@
 #ifdef __OBJC__
     WEBCORE_EXPORT Cookie(NSHTTPCookie *);
     WEBCORE_EXPORT operator NSHTTPCookie *() const;
+#elif USE(SOUP)
+    explicit Cookie(SoupCookie*);
+    SoupCookie* toSoupCookie() const;
 #endif
 
     bool isNull() const

Modified: trunk/Source/WebCore/platform/SourcesSoup.txt (225053 => 225054)


--- trunk/Source/WebCore/platform/SourcesSoup.txt	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebCore/platform/SourcesSoup.txt	2017-11-20 22:02:46 UTC (rev 225054)
@@ -24,6 +24,7 @@
 platform/network/soup/AuthenticationChallengeSoup.cpp
 platform/network/soup/CertificateInfo.cpp
 platform/network/soup/CookieJarSoup.cpp
+platform/network/soup/CookieSoup.cpp
 platform/network/soup/CookieStorageSoup.cpp
 platform/network/soup/CredentialStorageSoup.cpp
 platform/network/soup/DNSSoup.cpp

Added: trunk/Source/WebCore/platform/network/soup/CookieSoup.cpp (0 => 225054)


--- trunk/Source/WebCore/platform/network/soup/CookieSoup.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/soup/CookieSoup.cpp	2017-11-20 22:02:46 UTC (rev 225054)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ * Copyright (C) 2017 Endless Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Cookie.h"
+
+#include <wtf/DateMath.h>
+
+namespace WebCore {
+
+Cookie::Cookie(SoupCookie* cookie)
+    : name(String::fromUTF8(cookie->name))
+    , value(String::fromUTF8(cookie->value))
+    , domain(String::fromUTF8(cookie->domain))
+    , path(String::fromUTF8(cookie->path))
+    , expires(cookie->expires ? static_cast<double>(soup_date_to_time_t(cookie->expires)) * 1000 : 0)
+    , httpOnly(cookie->http_only)
+    , secure(cookie->secure)
+    , session(!cookie->expires)
+
+{
+}
+
+static SoupDate* msToSoupDate(double ms)
+{
+    int year = msToYear(ms);
+    int dayOfYear = dayInYear(ms, year);
+    bool leapYear = isLeapYear(year);
+
+    // monthFromDayInYear() returns a value in the [0,11] range, while soup_date_new() expects
+    // a value in the [1,12] range, meaning we have to manually adjust the month value.
+    return soup_date_new(year, monthFromDayInYear(dayOfYear, leapYear) + 1, dayInMonthFromDayInYear(dayOfYear, leapYear), msToHours(ms), msToMinutes(ms), static_cast<int>(ms / 1000) % 60);
+}
+
+SoupCookie* Cookie::toSoupCookie() const
+{
+    if (name.isNull() || value.isNull() || domain.isNull() || path.isNull())
+        return nullptr;
+
+    SoupCookie* soupCookie = soup_cookie_new(name.utf8().data(), value.utf8().data(),
+        domain.utf8().data(), path.utf8().data(), -1);
+
+    soup_cookie_set_http_only(soupCookie, httpOnly);
+    soup_cookie_set_secure(soupCookie, secure);
+
+    if (!session) {
+        SoupDate* date = msToSoupDate(expires);
+        soup_cookie_set_expires(soupCookie, date);
+        soup_date_free(date);
+    }
+
+    return soupCookie;
+}
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp (225053 => 225054)


--- trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp	2017-11-20 22:02:46 UTC (rev 225054)
@@ -2,6 +2,7 @@
  * Copyright (C) 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2013 University of Szeged. All rights reserved.
  * Copyright (C) 2016 Igalia S.L.
+ * Copyright (C) 2017 Endless Mobile, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +34,7 @@
 #include "Cookie.h"
 #include "ResourceHandle.h"
 #include "SoupNetworkSession.h"
+#include <WebCore/GUniquePtrSoup.h>
 #include <libsoup/soup.h>
 #include <wtf/DateMath.h>
 #include <wtf/MainThread.h>
@@ -283,45 +285,21 @@
 #endif
 }
 
-static SoupDate* msToSoupDate(double ms)
-{
-    int year = msToYear(ms);
-    int dayOfYear = dayInYear(ms, year);
-    bool leapYear = isLeapYear(year);
-
-    // monthFromDayInYear() returns a value in the [0,11] range, while soup_date_new() expects
-    // a value in the [1,12] range, meaning we have to manually adjust the month value.
-    return soup_date_new(year, monthFromDayInYear(dayOfYear, leapYear) + 1, dayInMonthFromDayInYear(dayOfYear, leapYear), msToHours(ms), msToMinutes(ms), static_cast<int>(ms / 1000) % 60);
-}
-
-static SoupCookie* toSoupCookie(const Cookie& cookie)
-{
-    SoupCookie* soupCookie = soup_cookie_new(cookie.name.utf8().data(), cookie.value.utf8().data(),
-        cookie.domain.utf8().data(), cookie.path.utf8().data(), -1);
-    soup_cookie_set_http_only(soupCookie, cookie.httpOnly);
-    soup_cookie_set_secure(soupCookie, cookie.secure);
-    if (!cookie.session) {
-        SoupDate* date = msToSoupDate(cookie.expires);
-        soup_cookie_set_expires(soupCookie, date);
-        soup_date_free(date);
-    }
-    return soupCookie;
-}
-
 void NetworkStorageSession::setCookies(const Vector<Cookie>& cookies, const URL&, const URL&)
 {
     for (auto cookie : cookies)
-        soup_cookie_jar_add_cookie(cookieStorage(), toSoupCookie(cookie));
+        soup_cookie_jar_add_cookie(cookieStorage(), cookie.toSoupCookie());
 }
 
-void NetworkStorageSession::setCookie(const Cookie&)
+void NetworkStorageSession::setCookie(const Cookie& cookie)
 {
-    // FIXME: Implement for WK2 to use.
+    soup_cookie_jar_add_cookie(cookieStorage(), cookie.toSoupCookie());
 }
 
-void NetworkStorageSession::deleteCookie(const Cookie&)
+void NetworkStorageSession::deleteCookie(const Cookie& cookie)
 {
-    // FIXME: Implement for WK2 to use.
+    GUniquePtr<SoupCookie> targetCookie(cookie.toSoupCookie());
+    soup_cookie_jar_delete_cookie(cookieStorage(), targetCookie.get());
 }
 
 Vector<Cookie> NetworkStorageSession::getAllCookies()
@@ -330,10 +308,17 @@
     return { };
 }
 
-Vector<Cookie> NetworkStorageSession::getCookies(const URL&)
+Vector<Cookie> NetworkStorageSession::getCookies(const URL& url)
 {
-    // FIXME: Implement for WK2 to use.
-    return { };
+    Vector<Cookie> cookies;
+    GUniquePtr<SoupURI> uri = url.createSoupURI();
+    GUniquePtr<GSList> cookiesList(soup_cookie_jar_get_cookie_list(cookieStorage(), uri.get(), TRUE));
+    for (GSList* item = cookiesList.get(); item; item = g_slist_next(item)) {
+        GUniquePtr<SoupCookie> soupCookie(static_cast<SoupCookie*>(item->data));
+        cookies.append(WebCore::Cookie(soupCookie.get()));
+    }
+
+    return cookies;
 }
 
 void NetworkStorageSession::flushCookieStore()

Modified: trunk/Source/WebKit/ChangeLog (225053 => 225054)


--- trunk/Source/WebKit/ChangeLog	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebKit/ChangeLog	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,3 +1,24 @@
+2017-11-20  Mario Sanchez Prada  <[email protected]>
+
+        [GTK] New API to add, retrieve and delete cookies via WebKitCookieManager
+        https://bugs.webkit.org/show_bug.cgi?id=177932
+
+        Reviewed by Carlos Garcia Campos.
+
+        Added new API to WebKitCookieManager to add, retrieve and delete complete
+        cookies into/out-of a running session, and updated documentation sections.
+
+        * UIProcess/API/glib/WebKitCookieManager.cpp:
+        (webkit_cookie_manager_add_cookie): New function.
+        (webkit_cookie_manager_add_cookie_finish): Ditto.
+        (webkit_cookie_manager_get_cookies): Ditto.
+        (webkit_cookie_manager_get_cookies_finish): Ditto.
+        (webkit_cookie_manager_delete_cookie): Ditto.
+        (webkit_cookie_manager_delete_cookie_finish): Ditto.
+        * UIProcess/API/gtk/WebKitCookieManager.h: Added new functions.
+        * UIProcess/API/wpe/WebKitCookieManager.h: Ditto.
+        * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt: Ditto.
+
 2017-11-20  Carlos Garcia Campos  <[email protected]>
 
         [WPE] webkit_web_view_new() should enable specifying wpe_view_backend object

Modified: trunk/Source/WebKit/UIProcess/API/glib/WebKitCookieManager.cpp (225053 => 225054)


--- trunk/Source/WebKit/UIProcess/API/glib/WebKitCookieManager.cpp	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebKit/UIProcess/API/glib/WebKitCookieManager.cpp	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2017 Endless Mobile, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,6 +28,7 @@
 #include "WebKitWebsiteDataManagerPrivate.h"
 #include "WebKitWebsiteDataPrivate.h"
 #include "WebsiteDataRecord.h"
+#include <glib/gi18n-lib.h>
 #include <pal/SessionID.h>
 #include <wtf/glib/GRefPtr.h>
 #include <wtf/glib/WTFGType.h>
@@ -233,6 +235,192 @@
 }
 
 /**
+ * webkit_cookie_manager_add_cookie:
+ * @cookie_manager: a #WebKitCookieManager
+ * @cookie: the #SoupCookie to be added
+ * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously add a #SoupCookie to the underlying storage.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * webkit_cookie_manager_add_cookie_finish() to get the result of the operation.
+ *
+ * Since: 2.20
+ */
+void webkit_cookie_manager_add_cookie(WebKitCookieManager* manager, SoupCookie* cookie, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+    g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
+    g_return_if_fail(cookie);
+
+    GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
+
+    auto sessionID = webkitWebsiteDataManagerGetDataStore(manager->priv->dataManager).websiteDataStore().sessionID();
+    const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
+
+    // Cookies are read/written from/to the same SQLite database on disk regardless
+    // of the process we access them from, so just use the first process pool.
+    processPools[0]->supplement<WebCookieManagerProxy>()->setCookie(sessionID, WebCore::Cookie(cookie), [task = WTFMove(task)](CallbackBase::Error error) {
+        if (error != CallbackBase::Error::None) {
+            // This can only happen in cases where the web process is not available,
+            // consider the operation "cancelled" from the point of view of the client.
+            g_task_return_new_error(task.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"));
+            return;
+        }
+
+        g_task_return_boolean(task.get(), TRUE);
+    });
+}
+
+/**
+ * webkit_cookie_manager_add_cookie_finish:
+ * @cookie_manager: a #WebKitCookieManager
+ * @result: a #GAsyncResult
+ * @error: return location for error or %NULL to ignore
+ *
+ * Finish an asynchronous operation started with webkit_cookie_manager_add_cookie().
+ *
+ * Returns: %TRUE if the cookie was added or %FALSE in case of error.
+ *
+ * Since: 2.20
+ */
+gboolean webkit_cookie_manager_add_cookie_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
+{
+    g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), FALSE);
+    g_return_val_if_fail(g_task_is_valid(result, manager), FALSE);
+
+    return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+/**
+ * webkit_cookie_manager_get_cookies:
+ * @cookie_manager: a #WebKitCookieManager
+ * @uri: the URI associated to the cookies to be retrieved
+ * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously get a list of #SoupCookie from @cookie_manager associated with @uri, which
+ * must be either an HTTP or an HTTPS URL.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * webkit_cookie_manager_get_cookies_finish() to get the result of the operation.
+ *
+ * Since: 2.20
+ */
+void webkit_cookie_manager_get_cookies(WebKitCookieManager* manager, const gchar* uri, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+    g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
+    g_return_if_fail(uri);
+
+    GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
+
+    auto sessionID = webkitWebsiteDataManagerGetDataStore(manager->priv->dataManager).websiteDataStore().sessionID();
+    const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
+
+    // Cookies are read/written from/to the same SQLite database on disk regardless
+    // of the process we access them from, so just use the first process pool.
+    processPools[0]->supplement<WebCookieManagerProxy>()->getCookies(sessionID, WebCore::URL(WebCore::URL(), String::fromUTF8(uri)), [task = WTFMove(task)](const Vector<WebCore::Cookie>& cookies, CallbackBase::Error error) {
+        if (error != CallbackBase::Error::None) {
+            // This can only happen in cases where the web process is not available,
+            // consider the operation "cancelled" from the point of view of the client.
+            g_task_return_new_error(task.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"));
+            return;
+        }
+
+        GList* cookiesList = nullptr;
+        for (auto& cookie : cookies)
+            cookiesList = g_list_prepend(cookiesList, cookie.toSoupCookie());
+
+        g_task_return_pointer(task.get(), g_list_reverse(cookiesList), [](gpointer data) {
+            g_list_free_full(static_cast<GList*>(data), reinterpret_cast<GDestroyNotify>(soup_cookie_free));
+        });
+    });
+}
+
+/**
+ * webkit_cookie_manager_get_cookies_finish:
+ * @cookie_manager: a #WebKitCookieManager
+ * @result: a #GAsyncResult
+ * @error: return location for error or %NULL to ignore
+ *
+ * Finish an asynchronous operation started with webkit_cookie_manager_get_cookies().
+ * The return value is a #GSList of #SoupCookie instances which should be released
+ * with g_list_free_full() and soup_cookie_free().
+ *
+ * Returns: (element-type SoupCookie) (transfer full): A #GList of #SoupCookie instances.
+ *
+ * Since: 2.20
+ */
+GList* webkit_cookie_manager_get_cookies_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
+{
+    g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), nullptr);
+    g_return_val_if_fail(g_task_is_valid(result, manager), nullptr);
+
+    return reinterpret_cast<GList*>(g_task_propagate_pointer(G_TASK(result), error));
+}
+
+/**
+ * webkit_cookie_manager_delete_cookie:
+ * @cookie_manager: a #WebKitCookieManager
+ * @cookie: the #SoupCookie to be deleted
+ * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously delete a #SoupCookie from the current session.
+ *
+ * When the operation is finished, @callback will be called. You can then call
+ * webkit_cookie_manager_delete_cookie_finish() to get the result of the operation.
+ *
+ * Since: 2.20
+ */
+void webkit_cookie_manager_delete_cookie(WebKitCookieManager* manager, SoupCookie* cookie, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+    g_return_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager));
+    g_return_if_fail(cookie);
+
+    GRefPtr<GTask> task = adoptGRef(g_task_new(manager, cancellable, callback, userData));
+
+    auto sessionID = webkitWebsiteDataManagerGetDataStore(manager->priv->dataManager).websiteDataStore().sessionID();
+    const auto& processPools = webkitWebsiteDataManagerGetProcessPools(manager->priv->dataManager);
+
+    // Cookies are read/written from/to the same SQLite database on disk regardless
+    // of the process we access them from, so just use the first process pool.
+    processPools[0]->supplement<WebCookieManagerProxy>()->deleteCookie(sessionID, WebCore::Cookie(cookie), [task = WTFMove(task)](CallbackBase::Error error) {
+        if (error != CallbackBase::Error::None) {
+            // This can only happen in cases where the web process is not available,
+            // consider the operation "cancelled" from the point of view of the client.
+            g_task_return_new_error(task.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"));
+            return;
+        }
+
+        g_task_return_boolean(task.get(), TRUE);
+    });
+}
+
+/**
+ * webkit_cookie_manager_delete_cookie_finish:
+ * @cookie_manager: a #WebKitCookieManager
+ * @result: a #GAsyncResult
+ * @error: return location for error or %NULL to ignore
+ *
+ * Finish an asynchronous operation started with webkit_cookie_manager_delete_cookie().
+ *
+ * Returns: %TRUE if the cookie was deleted or %FALSE in case of error.
+ *
+ * Since: 2.20
+ */
+gboolean webkit_cookie_manager_delete_cookie_finish(WebKitCookieManager* manager, GAsyncResult* result, GError** error)
+{
+    g_return_val_if_fail(WEBKIT_IS_COOKIE_MANAGER(manager), FALSE);
+    g_return_val_if_fail(g_task_is_valid(result, manager), FALSE);
+
+    return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+/**
  * webkit_cookie_manager_get_domains_with_cookies:
  * @cookie_manager: a #WebKitCookieManager
  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore

Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitCookieManager.h (225053 => 225054)


--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitCookieManager.h	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitCookieManager.h	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2017 Endless Mobile, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,7 @@
 
 #include <gio/gio.h>
 #include <glib-object.h>
+#include <libsoup/soup.h>
 #include <webkit2/WebKitDefines.h>
 
 G_BEGIN_DECLS
@@ -107,6 +109,42 @@
                                                        GAsyncResult                 *result,
                                                        GError                      **error);
 
+WEBKIT_API void
+webkit_cookie_manager_add_cookie                      (WebKitCookieManager          *cookie_manager,
+                                                       SoupCookie                   *cookie,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+
+WEBKIT_API gboolean
+webkit_cookie_manager_add_cookie_finish               (WebKitCookieManager          *cookie_manager,
+                                                       GAsyncResult                 *result,
+                                                       GError                      **error);
+
+WEBKIT_API void
+webkit_cookie_manager_get_cookies                     (WebKitCookieManager          *cookie_manager,
+                                                       const gchar                  *uri,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+
+WEBKIT_API GList *
+webkit_cookie_manager_get_cookies_finish              (WebKitCookieManager          *cookie_manager,
+                                                       GAsyncResult                 *result,
+                                                       GError                      **error);
+
+WEBKIT_API void
+webkit_cookie_manager_delete_cookie                   (WebKitCookieManager          *cookie_manager,
+                                                       SoupCookie                   *cookie,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+
+WEBKIT_API gboolean
+webkit_cookie_manager_delete_cookie_finish            (WebKitCookieManager          *cookie_manager,
+                                                       GAsyncResult                 *result,
+                                                       GError                      **error);
+
 WEBKIT_DEPRECATED_FOR(webkit_website_data_manager_fetch) void
 webkit_cookie_manager_get_domains_with_cookies        (WebKitCookieManager          *cookie_manager,
                                                        GCancellable                 *cancellable,

Modified: trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt (225053 => 225054)


--- trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1006,6 +1006,12 @@
 webkit_cookie_manager_get_accept_policy_finish
 webkit_cookie_manager_get_domains_with_cookies
 webkit_cookie_manager_get_domains_with_cookies_finish
+webkit_cookie_manager_add_cookie
+webkit_cookie_manager_add_cookie_finish
+webkit_cookie_manager_get_cookies
+webkit_cookie_manager_get_cookies_finish
+webkit_cookie_manager_delete_cookie
+webkit_cookie_manager_delete_cookie_finish
 webkit_cookie_manager_delete_cookies_for_domain
 webkit_cookie_manager_delete_all_cookies
 

Modified: trunk/Source/WebKit/UIProcess/API/wpe/WebKitCookieManager.h (225053 => 225054)


--- trunk/Source/WebKit/UIProcess/API/wpe/WebKitCookieManager.h	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Source/WebKit/UIProcess/API/wpe/WebKitCookieManager.h	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2017 Endless Mobile, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,7 @@
 
 #include <gio/gio.h>
 #include <glib-object.h>
+#include <libsoup/soup.h>
 #include <wpe/WebKitDefines.h>
 
 G_BEGIN_DECLS
@@ -107,6 +109,42 @@
                                                        GAsyncResult                 *result,
                                                        GError                      **error);
 
+WEBKIT_API void
+webkit_cookie_manager_add_cookie                      (WebKitCookieManager          *cookie_manager,
+                                                       SoupCookie                   *cookie,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+
+WEBKIT_API gboolean
+webkit_cookie_manager_add_cookie_finish               (WebKitCookieManager          *cookie_manager,
+                                                       GAsyncResult                 *result,
+                                                       GError                      **error);
+
+WEBKIT_API void
+webkit_cookie_manager_get_cookies                     (WebKitCookieManager          *cookie_manager,
+                                                       const gchar                  *uri,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+
+WEBKIT_API GList *
+webkit_cookie_manager_get_cookies_finish              (WebKitCookieManager          *cookie_manager,
+                                                       GAsyncResult                 *result,
+                                                       GError                      **error);
+
+WEBKIT_API void
+webkit_cookie_manager_delete_cookie                   (WebKitCookieManager          *cookie_manager,
+                                                       SoupCookie                   *cookie,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+
+WEBKIT_API gboolean
+webkit_cookie_manager_delete_cookie_finish            (WebKitCookieManager          *cookie_manager,
+                                                       GAsyncResult                 *result,
+                                                       GError                      **error);
+
 WEBKIT_DEPRECATED_FOR(webkit_website_data_manager_fetch) void
 webkit_cookie_manager_get_domains_with_cookies        (WebKitCookieManager          *cookie_manager,
                                                        GCancellable                 *cancellable,

Modified: trunk/Tools/ChangeLog (225053 => 225054)


--- trunk/Tools/ChangeLog	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Tools/ChangeLog	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,3 +1,21 @@
+2017-11-20  Mario Sanchez Prada  <[email protected]>
+
+        [GTK] New API to add, retrieve and delete cookies via WebKitCookieManager
+        https://bugs.webkit.org/show_bug.cgi?id=177932
+
+        Reviewed by Carlos Garcia Campos.
+
+        Added new test cases to cover the newly added API for WebKitCookieManager:
+        webkit_cookie_manager_add_cookie, webkit_cookie_manager_get_cookies and
+        webkit_cookie_manager_delete_cookie.
+
+        * TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp:
+        (testCookieManagerAddCookie): Added.
+        (testCookieManagerGetCookies): Added.
+        (testCookieManagerDeleteCookie): Added.
+        (serverCallback): Small update to avoid hardcoding strings we reuse.
+        (beforeAll): Added the new test cases to the test suite.
+
 2017-11-20  Stephan Szabo  <[email protected]>
 
         [Win] Update ruby JSC test writer for gigacage changes

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp (225053 => 225054)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp	2017-11-20 21:20:15 UTC (rev 225053)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp	2017-11-20 22:02:46 UTC (rev 225054)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2017 Endless Mobile, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -21,6 +22,7 @@
 
 #include "WebKitTestServer.h"
 #include "WebViewTest.h"
+#include <WebCore/GUniquePtrSoup.h>
 #include <glib/gstdio.h>
 
 static WebKitTestServer* kServer;
@@ -27,6 +29,14 @@
 
 static const char* kFirstPartyDomain = "127.0.0.1";
 static const char* kThirdPartyDomain = "localhost";
+
+static const char* kCookieName = "foo";
+static const char* kCookieValue = "bar";
+static const char* kCookiePath = "/";
+
+static const char* kCookiePathNew = "/new";
+static const char* kCookieValueNew = "new-value";
+
 static const char* kIndexHtmlFormat =
     "<html><body>"
     " <p>WebKitGTK+ Cookie Manager test</p>"
@@ -55,6 +65,8 @@
     ~CookieManagerTest()
     {
         g_strfreev(m_domains);
+        g_list_free_full(m_cookies, reinterpret_cast<GDestroyNotify>(soup_cookie_free));
+
         g_signal_handlers_disconnect_matched(m_cookieManager, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
         if (m_cookiesTextFile)
             g_unlink(m_cookiesTextFile.get());
@@ -102,6 +114,61 @@
         return m_acceptPolicy;
     }
 
+    static void addCookieReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
+    {
+        GUniqueOutPtr<GError> error;
+        bool added = webkit_cookie_manager_add_cookie_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
+        g_assert(!error.get());
+        g_assert(added);
+
+        CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
+        g_main_loop_quit(test->m_mainLoop);
+    }
+
+    void addCookie(SoupCookie* cookie)
+    {
+        webkit_cookie_manager_add_cookie(m_cookieManager, cookie, 0, addCookieReadyCallback, this);
+        g_main_loop_run(m_mainLoop);
+    }
+
+    static void getCookiesReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
+    {
+        GUniqueOutPtr<GError> error;
+        GList* cookies = webkit_cookie_manager_get_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
+        g_assert(!error.get());
+
+        CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
+        test->m_cookies = cookies;
+        g_main_loop_quit(test->m_mainLoop);
+    }
+
+    GList* getCookies(const char* uri)
+    {
+        g_list_free_full(m_cookies, reinterpret_cast<GDestroyNotify>(soup_cookie_free));
+        m_cookies = nullptr;
+        webkit_cookie_manager_get_cookies(m_cookieManager, uri, 0, getCookiesReadyCallback, this);
+        g_main_loop_run(m_mainLoop);
+
+        return m_cookies;
+    }
+
+    static void deleteCookieReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
+    {
+        GUniqueOutPtr<GError> error;
+        bool deleted = webkit_cookie_manager_delete_cookie_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
+        g_assert(!error.get());
+        g_assert(deleted);
+
+        CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
+        g_main_loop_quit(test->m_mainLoop);
+    }
+
+    void deleteCookie(SoupCookie* cookie)
+    {
+        webkit_cookie_manager_delete_cookie(m_cookieManager, cookie, 0, deleteCookieReadyCallback, this);
+        g_main_loop_run(m_mainLoop);
+    }
+
     void setAcceptPolicy(WebKitCookieAcceptPolicy policy)
     {
         webkit_cookie_manager_set_accept_policy(m_cookieManager, policy);
@@ -170,6 +237,7 @@
     WebKitCookieManager* m_cookieManager { nullptr };
     WebKitCookieAcceptPolicy m_acceptPolicy { WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY };
     char** m_domains { nullptr };
+    GList* m_cookies { nullptr };
     bool m_cookiesChanged { false };
     int m_cookiesExpectedToChangeCount { 0 };
     bool m_finishLoopWhenCookiesChange { false };
@@ -209,6 +277,223 @@
     g_assert_cmpint(g_strv_length(domains), ==, 0);
 }
 
+static void testCookieManagerAddCookie(CookieManagerTest* test, gconstpointer)
+{
+    // Load the html content, with the default NO_THIRD_PARTY accept policy,
+    // which will automatically add one cookie.
+    test->loadURI(kServer->getURIForPath("/index.html").data());
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+
+    // Check the cookies that have been added for the domain.
+    GUniquePtr<char> uri(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
+    GList* foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    SoupCookie* foundCookie = static_cast<SoupCookie*>(foundCookies->data);
+    g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+    g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
+    g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
+    g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
+
+    // Try to add now a cookie with same (name, domain, path) than the ones already added.
+    GUniquePtr<SoupCookie> firstCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePath, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
+    test->addCookie(firstCookie.get());
+
+    // Still one cookie, since (name, domain, path) are the same than the already existing
+    // one, but the new value is now stored as replaced by the recently added cookie.
+    foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    foundCookie = static_cast<SoupCookie*>(foundCookies->data);
+    g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+    g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
+    g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
+    g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValueNew);
+
+    // Now create another cookie with a different path and add it.
+    GUniquePtr<SoupCookie> secondCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
+    test->addCookie(secondCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+
+    // Retrieve the list of cookies for the same domain and path again now and check.
+    uri.reset(g_strdup_printf("%s://%s%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain, kCookiePathNew));
+    foundCookies = test->getCookies(uri.get());
+
+    // We have now two cookies that would apply to the passed URL, one is the cookie initially
+    // loaded with the web content and the other cookie the one we manually added.
+    g_assert_cmpint(g_list_length(foundCookies), ==, 2);
+
+    // Add a third new cookie for a different domain than the previous ones.
+    GUniquePtr<SoupCookie> thirdCookie(soup_cookie_new(kCookieName, kCookieValueNew, kThirdPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
+    test->addCookie(thirdCookie.get());
+
+    // Only one cookie now, since the domain is different.
+    uri.reset(g_strdup_printf("%s://%s%s", SOUP_URI_SCHEME_HTTP, kThirdPartyDomain, kCookiePathNew));
+    foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
+
+    foundCookie = static_cast<SoupCookie*>(foundCookies->data);
+    g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+    g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kThirdPartyDomain);
+    g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePathNew);
+    g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValueNew);
+
+    // Finally, delete all cookies and check they are all gone.
+    test->deleteAllCookies();
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
+}
+
+static void testCookieManagerGetCookies(CookieManagerTest* test, gconstpointer)
+{
+    // Load the html content and retrieve the two cookies automatically added with ALWAYS policy.
+    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
+    test->loadURI(kServer->getURIForPath("/index.html").data());
+    test->waitUntilLoadFinished();
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
+
+    // Retrieve the first cookie using a HTTP scheme.
+    GUniquePtr<char> uri(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
+    GList* foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    SoupCookie* foundCookie = static_cast<SoupCookie*>(foundCookies->data);
+    g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+    g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
+    g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
+    g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
+
+    // Retrieve the second cookie using a HTTPS scheme.
+    uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTPS, kThirdPartyDomain));
+    foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    foundCookie = static_cast<SoupCookie*>(foundCookies->data);
+    g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+    g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kThirdPartyDomain);
+    g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
+    g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
+
+    // Create a new cookie and add it to the first domain.
+    GUniquePtr<SoupCookie> newCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
+    test->addCookie(newCookie.get());
+
+    // We should get two cookies that would apply to the same URL passed, since
+    // http://127.0.0.1/new is a subset of the http://127.0.0.1/ URL.
+    uri.reset(g_strdup_printf("%s://%s%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain, kCookiePathNew));
+    foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 2);
+
+    // We have now two cookies that would apply to the passed URL, one is the cookie initially
+    // loaded with the web content and the other cookie the one we manually added.
+    g_assert_cmpint(g_list_length(foundCookies), ==, 2);
+
+    bool newPathChecked = false;
+    const char* pathFound = nullptr;
+    const char* valueFound = nullptr;
+    for (uint i = 0; i < 2; i++) {
+        foundCookie = static_cast<SoupCookie*>(g_list_nth_data(foundCookies, i));
+        g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+        g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
+
+        // Cookies will have different values for 'value' and 'path', so make sure that
+        // we check for both possibilities, but different ones for each cookie found.
+        pathFound = soup_cookie_get_path(foundCookie);
+        valueFound = soup_cookie_get_value(foundCookie);
+        if (i > 0) {
+            if (newPathChecked) {
+                g_assert_cmpstr(pathFound, ==, kCookiePath);
+                g_assert_cmpstr(valueFound, ==, kCookieValue);
+            } else {
+                g_assert_cmpstr(pathFound, ==, kCookiePathNew);
+                g_assert_cmpstr(valueFound, ==, kCookieValueNew);
+            }
+        } else {
+            if (g_strcmp0(pathFound, kCookiePath)) {
+                g_assert_cmpstr(pathFound, ==, kCookiePathNew);
+                g_assert_cmpstr(valueFound, ==, kCookieValueNew);
+                newPathChecked = true;
+            }
+
+            if (g_strcmp0(pathFound, kCookiePathNew)) {
+                g_assert_cmpstr(pathFound, ==, kCookiePath);
+                g_assert_cmpstr(valueFound, ==, kCookieValue);
+                newPathChecked = false;
+            }
+        }
+    }
+
+    // We should get 1 cookie only if we specify http://127.0.0.1/, though.
+    uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
+    foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    foundCookie = static_cast<SoupCookie*>(foundCookies->data);
+    g_assert_cmpstr(soup_cookie_get_name(foundCookie), ==, kCookieName);
+    g_assert_cmpstr(soup_cookie_get_domain(foundCookie), ==, kFirstPartyDomain);
+    g_assert_cmpstr(soup_cookie_get_path(foundCookie), ==, kCookiePath);
+    g_assert_cmpstr(soup_cookie_get_value(foundCookie), ==, kCookieValue);
+
+    // Finally, delete all cookies and try to retrieve them again, one by one.
+    test->deleteAllCookies();
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
+
+    uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
+    foundCookies = test->getCookies(uri.get());
+    g_assert_null(foundCookies);
+}
+
+static void testCookieManagerDeleteCookie(CookieManagerTest* test, gconstpointer)
+{
+    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
+    test->loadURI(kServer->getURIForPath("/index.html").data());
+    test->waitUntilLoadFinished();
+
+    // Initially, there should be two cookies available.
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
+
+    // Delete the cookie for the first party domain.
+    GUniquePtr<char> uri(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kFirstPartyDomain));
+    GList* foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    GUniquePtr<SoupCookie> firstPartyCookie(soup_cookie_copy(static_cast<SoupCookie*>(foundCookies->data)));
+    test->deleteCookie(firstPartyCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+
+    // Try deleting a non-existent cookie (wrong name).
+    GUniquePtr<SoupCookie> wrongCookie(soup_cookie_new("wrong-name", kCookieValue, kThirdPartyDomain, kCookiePath, -1));
+    test->deleteCookie(wrongCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+
+    // Try deleting a non-existent cookie (wrong domain).
+    wrongCookie.reset(soup_cookie_new(kCookieName, kCookieValue, "wrong-domain", kCookiePath, -1));
+    test->deleteCookie(wrongCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+
+    // Try deleting a non-existent cookie (wrong path).
+    wrongCookie.reset(soup_cookie_new(kCookieName, kCookieValue, kThirdPartyDomain, "wrong-path", -1));
+    test->deleteCookie(wrongCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+
+    // Delete the cookie for the third party domain.
+    uri.reset(g_strdup_printf("%s://%s", SOUP_URI_SCHEME_HTTP, kThirdPartyDomain));
+    foundCookies = test->getCookies(uri.get());
+    g_assert_cmpint(g_list_length(foundCookies), ==, 1);
+
+    GUniquePtr<SoupCookie> thirdPartyCookie(soup_cookie_copy(static_cast<SoupCookie*>(foundCookies->data)));
+    test->deleteCookie(thirdPartyCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
+
+    // Finally, add a new cookie now we don't have any and delete it afterwards.
+    GUniquePtr<SoupCookie> newCookie(soup_cookie_new(kCookieName, kCookieValueNew, kFirstPartyDomain, kCookiePathNew, SOUP_COOKIE_MAX_AGE_ONE_HOUR));
+    test->addCookie(newCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
+    test->deleteCookie(newCookie.get());
+    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
+}
+
 static void testCookieManagerDeleteCookies(CookieManagerTest* test, gconstpointer)
 {
     test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
@@ -386,12 +671,14 @@
     }
 
     soup_message_set_status(message, SOUP_STATUS_OK);
+    gchar* header_str = g_strdup_printf("%s=%s; Max-Age=60", kCookieName, kCookieValue);
+
     if (g_str_equal(path, "/index.html")) {
         char* indexHtml = g_strdup_printf(kIndexHtmlFormat, soup_server_get_port(server));
-        soup_message_headers_replace(message->response_headers, "Set-Cookie", "foo=bar; Max-Age=60");
+        soup_message_headers_replace(message->response_headers, "Set-Cookie", header_str);
         soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, indexHtml, strlen(indexHtml));
     } else if (g_str_equal(path, "/image.png"))
-        soup_message_headers_replace(message->response_headers, "Set-Cookie", "baz=qux; Max-Age=60");
+        soup_message_headers_replace(message->response_headers, "Set-Cookie", header_str);
     else if (g_str_equal(path, "/no-cookies.html")) {
         static const char* indexHtml = "<html><body><p>No cookies</p></body></html>";
         soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, indexHtml, strlen(indexHtml));
@@ -406,6 +693,9 @@
     kServer->run(serverCallback);
 
     CookieManagerTest::add("WebKitCookieManager", "accept-policy", testCookieManagerAcceptPolicy);
+    CookieManagerTest::add("WebKitCookieManager", "add-cookie", testCookieManagerAddCookie);
+    CookieManagerTest::add("WebKitCookieManager", "get-cookies", testCookieManagerGetCookies);
+    CookieManagerTest::add("WebKitCookieManager", "delete-cookie", testCookieManagerDeleteCookie);
     CookieManagerTest::add("WebKitCookieManager", "delete-cookies", testCookieManagerDeleteCookies);
     CookieManagerTest::add("WebKitCookieManager", "cookies-changed", testCookieManagerCookiesChanged);
     CookieManagerTest::add("WebKitCookieManager", "persistent-storage", testCookieManagerPersistentStorage);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to