[libsoup/carlosgc/thread-safe: 12/19] cookies: make SoupCookieJar thread safe
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/carlosgc/thread-safe: 12/19] cookies: make SoupCookieJar thread safe
- Date: Tue, 3 May 2022 10:07:19 +0000 (UTC)
commit 178932c6c8e96c3c00ee55fd32d69463bbf81fc3
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]