[libsoup/carlosgc/thread-safe: 12/21] cookies: make SoupCookieJar thread safe




commit 49cf0cddd20b0becae2053a32e87928657cef037
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Tue Apr 19 15:17:46 2022 +0200

    cookies: make SoupCookieJar thread safe

 libsoup/cookies/soup-cookie-jar.c | 34 ++++++++++++++-
 tests/cookies-test.c              | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+), 2 deletions(-)
---
diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c
index c14f90ab..35c1d7b3 100644
--- a/libsoup/cookies/soup-cookie-jar.c
+++ b/libsoup/cookies/soup-cookie-jar.c
@@ -53,6 +53,7 @@ enum {
 static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
 
 typedef struct {
+        GMutex mutex;
        gboolean constructed, read_only;
        GHashTable *domains, *serials;
        guint serial;
@@ -76,6 +77,7 @@ soup_cookie_jar_init (SoupCookieJar *jar)
                                               g_free, NULL);
        priv->serials = g_hash_table_new (NULL, NULL);
        priv->accept_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
+        g_mutex_init (&priv->mutex);
 }
 
 static void
@@ -100,6 +102,7 @@ soup_cookie_jar_finalize (GObject *object)
                soup_cookies_free (value);
        g_hash_table_destroy (priv->domains);
        g_hash_table_destroy (priv->serials);
+        g_mutex_clear (&priv->mutex);
 
        G_OBJECT_CLASS (soup_cookie_jar_parent_class)->finalize (object);
 }
@@ -342,6 +345,8 @@ get_cookies (SoupCookieJar *jar,
                 next_domain = NULL;
         }
 
+        g_mutex_lock (&priv->mutex);
+
        do {
                new_head = domain_cookies = g_hash_table_lookup (priv->domains, cur);
                while (domain_cookies) {
@@ -378,6 +383,8 @@ get_cookies (SoupCookieJar *jar,
        }
        g_slist_free (cookies_to_remove);
 
+        g_mutex_unlock (&priv->mutex);
+
        return g_slist_sort_with_data (cookies, compare_cookies, jar);
 }
 
@@ -515,6 +522,7 @@ incoming_cookie_is_third_party (SoupCookieJar            *jar,
        const char *cookie_base_domain;
        const char *first_party_base_domain;
         const char *first_party_host;
+        gboolean retval;
 
        if (policy != SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY &&
            policy != SOUP_COOKIE_JAR_ACCEPT_GRANDFATHERED_THIRD_PARTY)
@@ -549,7 +557,11 @@ incoming_cookie_is_third_party (SoupCookieJar            *jar,
         * previously visited directly.
         */
        priv = soup_cookie_jar_get_instance_private (jar);
-       return !g_hash_table_lookup (priv->domains, soup_cookie_get_domain (cookie));
+        g_mutex_lock (&priv->mutex);
+       retval = !g_hash_table_lookup (priv->domains, soup_cookie_get_domain (cookie));
+        g_mutex_unlock (&priv->mutex);
+
+        return retval;
 }
 
 /**
@@ -606,6 +618,8 @@ soup_cookie_jar_add_cookie_full (SoupCookieJar *jar, SoupCookie *cookie, GUri *u
                return;
        }
 
+        g_mutex_lock (&priv->mutex);
+
        old_cookies = g_hash_table_lookup (priv->domains, soup_cookie_get_domain (cookie));
        for (oc = old_cookies; oc; oc = oc->next) {
                old_cookie = oc->data;
@@ -635,6 +649,8 @@ soup_cookie_jar_add_cookie_full (SoupCookieJar *jar, SoupCookie *cookie, GUri *u
                                soup_cookie_free (old_cookie);
                        }
 
+                        g_mutex_unlock (&priv->mutex);
+
                        return;
                }
                last = oc;
@@ -643,6 +659,7 @@ soup_cookie_jar_add_cookie_full (SoupCookieJar *jar, SoupCookie *cookie, GUri *u
        /* The new cookie is... a new cookie */
        if (soup_cookie_get_expires (cookie) && soup_date_time_is_past (soup_cookie_get_expires (cookie))) {
                soup_cookie_free (cookie);
+                g_mutex_unlock (&priv->mutex);
                return;
        }
 
@@ -655,6 +672,8 @@ soup_cookie_jar_add_cookie_full (SoupCookieJar *jar, SoupCookie *cookie, GUri *u
        }
 
        soup_cookie_jar_changed (jar, NULL, cookie);
+
+        g_mutex_unlock (&priv->mutex);
 }
 
 /**
@@ -882,6 +901,8 @@ soup_cookie_jar_all_cookies (SoupCookieJar *jar)
 
        priv = soup_cookie_jar_get_instance_private (jar);
 
+        g_mutex_lock (&priv->mutex);
+
        g_hash_table_iter_init (&iter, priv->domains);
 
        while (g_hash_table_iter_next (&iter, &key, &value)) {
@@ -890,6 +911,8 @@ soup_cookie_jar_all_cookies (SoupCookieJar *jar)
                        l = g_slist_prepend (l, soup_cookie_copy (p->data));
        }
 
+        g_mutex_unlock (&priv->mutex);
+
        return l;
 }
 
@@ -914,9 +937,13 @@ soup_cookie_jar_delete_cookie (SoupCookieJar *jar,
 
        priv = soup_cookie_jar_get_instance_private (jar);
 
+        g_mutex_lock (&priv->mutex);
+
        cookies = g_hash_table_lookup (priv->domains, soup_cookie_get_domain (cookie));
-       if (cookies == NULL)
+       if (cookies == NULL) {
+                g_mutex_unlock (&priv->mutex);
                return;
+        }
 
        for (p = cookies; p; p = p->next ) {
                SoupCookie *c = (SoupCookie*)p->data;
@@ -927,9 +954,12 @@ soup_cookie_jar_delete_cookie (SoupCookieJar *jar,
                                             cookies);
                        soup_cookie_jar_changed (jar, c, NULL);
                        soup_cookie_free (c);
+                        g_mutex_unlock (&priv->mutex);
                        return;
                }
        }
+
+        g_mutex_unlock (&priv->mutex);
 }
 
 /**
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
index 1c045343..0db2e44f 100644
--- a/tests/cookies-test.c
+++ b/tests/cookies-test.c
@@ -419,6 +419,92 @@ do_remove_feature_test (void)
        g_uri_unref (uri);
 }
 
+typedef struct {
+        SoupSession *session;
+        const char *cookie;
+} ThreadTestData;
+
+static void
+task_sync_function (GTask          *task,
+                    GObject        *source,
+                    ThreadTestData *data,
+                    GCancellable   *cancellable)
+{
+        SoupMessage *msg;
+        GBytes *body;
+
+        msg = soup_message_new_from_uri ("GET", first_party_uri);
+        soup_message_headers_append (soup_message_get_request_headers (msg),
+                                     "Echo-Set-Cookie", data->cookie);
+        body = soup_session_send_and_read (data->session, msg, NULL, NULL);
+        g_assert_nonnull (body);
+        g_bytes_unref (body);
+        g_object_unref (msg);
+
+        g_task_return_boolean (task, TRUE);
+}
+
+static void
+task_finished_cb (SoupSession  *session,
+                  GAsyncResult *result,
+                  guint        *finished_count)
+{
+        g_assert_true (g_task_propagate_boolean (G_TASK (result), NULL));
+        g_atomic_int_inc (finished_count);
+}
+
+static gint
+find_cookie (SoupCookie *cookie,
+             const char *name)
+{
+        return g_strcmp0 (soup_cookie_get_name (cookie), name);
+}
+
+static void
+do_cookies_threads_test (void)
+{
+        SoupSession *session;
+        SoupCookieJar *jar;
+        guint n_msgs = 4;
+        guint finished_count = 0;
+        guint i;
+        const char *values[4] = { "one=1", "two=2", "three=3", "four=4" };
+        GSList *cookies;
+
+        session = soup_test_session_new (NULL);
+        soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
+        jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR));
+
+        for (i = 0; i < n_msgs; i++) {
+                GTask *task;
+                ThreadTestData *data;
+
+                data = g_new (ThreadTestData, 1);
+                data->session = session;
+                data->cookie = values[i];
+
+                task = g_task_new (NULL, NULL, (GAsyncReadyCallback)task_finished_cb, &finished_count);
+                g_task_set_task_data (task, data, g_free);
+                g_task_run_in_thread (task, (GTaskThreadFunc)task_sync_function);
+                g_object_unref (task);
+        }
+
+        while (g_atomic_int_get (&finished_count) != n_msgs)
+                g_main_context_iteration (NULL, TRUE);
+
+        cookies = soup_cookie_jar_get_cookie_list (jar, first_party_uri, TRUE);
+        g_assert_cmpuint (g_slist_length (cookies), ==, 4);
+        g_assert_nonnull (g_slist_find_custom (cookies, "one", (GCompareFunc)find_cookie));
+        g_assert_nonnull (g_slist_find_custom (cookies, "two", (GCompareFunc)find_cookie));
+        g_assert_nonnull (g_slist_find_custom (cookies, "three", (GCompareFunc)find_cookie));
+        g_assert_nonnull (g_slist_find_custom (cookies, "four", (GCompareFunc)find_cookie));
+
+        while (g_main_context_pending (NULL))
+                g_main_context_iteration (NULL, FALSE);
+
+        soup_test_session_abort_unref (session);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -443,6 +529,7 @@ main (int argc, char **argv)
        g_test_add_func ("/cookies/get-cookies/empty-host", do_get_cookies_empty_host_test);
        g_test_add_func ("/cookies/remove-feature", do_remove_feature_test);
        g_test_add_func ("/cookies/secure-cookies", do_cookies_strict_secure_test);
+        g_test_add_func ("/cookies/threads", do_cookies_threads_test);
 
        ret = g_test_run ();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]