232 lines
7.8 KiB
Diff
232 lines
7.8 KiB
Diff
From 845e198402377f8644e9ae5200f1715df1ddfc08 Mon Sep 17 00:00:00 2001
|
|
From: Patrick Griffis <pgriffis@igalia.com>
|
|
Date: Thu, 27 Mar 2025 14:43:26 -0500
|
|
Subject: [PATCH 1/3] cookie: Always normalize domain value
|
|
|
|
In order for libpsl to give accurate results the domain must be lowercased.
|
|
|
|
To make it easiest we normalize it at construction time of the cookie.
|
|
---
|
|
libsoup/cookies/soup-cookie-jar.c | 11 ++++++++---
|
|
libsoup/cookies/soup-cookie.c | 22 +++++++++++++++++++---
|
|
libsoup/soup-tld.c | 11 ++++++++++-
|
|
libsoup/soup-uri-utils-private.h | 2 ++
|
|
libsoup/soup-uri-utils.c | 18 ++++++++++++++++++
|
|
tests/cookies-test.c | 19 +++++++++++++++++++
|
|
6 files changed, 76 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c
|
|
index fac53a5f9..7f92ace1f 100644
|
|
--- a/libsoup/cookies/soup-cookie-jar.c
|
|
+++ b/libsoup/cookies/soup-cookie-jar.c
|
|
@@ -519,6 +519,7 @@ incoming_cookie_is_third_party (SoupCookieJar *jar,
|
|
{
|
|
SoupCookieJarPrivate *priv;
|
|
const char *normalized_cookie_domain;
|
|
+ char *normalized_first_party_host;
|
|
const char *cookie_base_domain;
|
|
const char *first_party_base_domain;
|
|
const char *first_party_host;
|
|
@@ -540,12 +541,16 @@ incoming_cookie_is_third_party (SoupCookieJar *jar,
|
|
if (cookie_base_domain == NULL)
|
|
cookie_base_domain = soup_cookie_get_domain (cookie);
|
|
|
|
- first_party_base_domain = soup_tld_get_base_domain (first_party_host, NULL);
|
|
+ normalized_first_party_host = soup_uri_normalize_domain (first_party_host);
|
|
+ first_party_base_domain = soup_tld_get_base_domain (normalized_first_party_host, NULL);
|
|
if (first_party_base_domain == NULL)
|
|
- first_party_base_domain = first_party_host;
|
|
+ first_party_base_domain = normalized_first_party_host;
|
|
|
|
- if (soup_host_matches_host (cookie_base_domain, first_party_base_domain))
|
|
+ if (soup_host_matches_host (cookie_base_domain, first_party_base_domain)) {
|
|
+ g_free (normalized_first_party_host);
|
|
return FALSE;
|
|
+ }
|
|
+ g_free (normalized_first_party_host);
|
|
|
|
if (policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY)
|
|
return TRUE;
|
|
diff --git a/libsoup/cookies/soup-cookie.c b/libsoup/cookies/soup-cookie.c
|
|
index cc80d001f..b6d771646 100644
|
|
--- a/libsoup/cookies/soup-cookie.c
|
|
+++ b/libsoup/cookies/soup-cookie.c
|
|
@@ -168,6 +168,16 @@ parse_date (const char **val_p)
|
|
return date;
|
|
}
|
|
|
|
+static gboolean
|
|
+is_lowercase_ascii_string (const char *str)
|
|
+{
|
|
+ for (; *str; str++) {
|
|
+ if (!g_ascii_islower (*str))
|
|
+ return FALSE;
|
|
+ }
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
#define MAX_AGE_CAP_IN_SECONDS 31536000 // 1 year
|
|
#define MAX_ATTRIBUTE_SIZE 1024
|
|
|
|
@@ -311,6 +321,12 @@ parse_one_cookie (const char *header, GUri *origin)
|
|
g_free (cookie->domain);
|
|
cookie->domain = tmp;
|
|
}
|
|
+
|
|
+ if (!is_lowercase_ascii_string (cookie->domain)) {
|
|
+ char *tmp = soup_uri_normalize_domain (cookie->domain);
|
|
+ g_free (cookie->domain);
|
|
+ cookie->domain = tmp;
|
|
+ }
|
|
}
|
|
|
|
if (origin) {
|
|
@@ -321,7 +337,7 @@ parse_one_cookie (const char *header, GUri *origin)
|
|
return NULL;
|
|
}
|
|
} else
|
|
- cookie->domain = g_strdup (g_uri_get_host (origin));
|
|
+ cookie->domain = soup_uri_normalize_domain (g_uri_get_host (origin));
|
|
|
|
/* The original cookie spec didn't say that pages
|
|
* could only set cookies for paths they were under.
|
|
@@ -364,7 +380,7 @@ cookie_new_internal (const char *name, const char *value,
|
|
cookie = g_slice_new0 (SoupCookie);
|
|
cookie->name = g_strdup (name);
|
|
cookie->value = g_strdup (value);
|
|
- cookie->domain = g_strdup (domain);
|
|
+ cookie->domain = soup_uri_normalize_domain (domain);
|
|
cookie->path = g_strdup (path);
|
|
soup_cookie_set_max_age (cookie, max_age);
|
|
cookie->same_site_policy = SOUP_SAME_SITE_POLICY_LAX;
|
|
@@ -537,7 +553,7 @@ void
|
|
soup_cookie_set_domain (SoupCookie *cookie, const char *domain)
|
|
{
|
|
g_free (cookie->domain);
|
|
- cookie->domain = g_strdup (domain);
|
|
+ cookie->domain = soup_uri_normalize_domain (domain);
|
|
}
|
|
|
|
/**
|
|
diff --git a/libsoup/soup-tld.c b/libsoup/soup-tld.c
|
|
index 2d8151662..71fac5749 100644
|
|
--- a/libsoup/soup-tld.c
|
|
+++ b/libsoup/soup-tld.c
|
|
@@ -15,6 +15,7 @@
|
|
#include <libpsl.h>
|
|
|
|
#include "soup-tld.h"
|
|
+#include "soup-uri-utils-private.h"
|
|
#include "soup.h"
|
|
|
|
static const char *soup_tld_get_base_domain_internal (const char *hostname,
|
|
@@ -41,6 +42,8 @@ static const char *soup_tld_get_base_domain_internal (const char *hostname,
|
|
* UTF-8 or ASCII format (and the return value will be in the same
|
|
* format).
|
|
*
|
|
+ * For accurate results @hostname must be lowercase.
|
|
+ *
|
|
* Returns: a pointer to the start of the base domain in @hostname. If
|
|
* an error occurs, %NULL will be returned and @error set.
|
|
**/
|
|
@@ -80,6 +83,8 @@ gboolean
|
|
soup_tld_domain_is_public_suffix (const char *domain)
|
|
{
|
|
const psl_ctx_t* psl = soup_psl_context ();
|
|
+ char *normalized;
|
|
+ gboolean is_public_suffix;
|
|
|
|
g_return_val_if_fail (domain, FALSE);
|
|
|
|
@@ -88,7 +93,11 @@ soup_tld_domain_is_public_suffix (const char *domain)
|
|
return FALSE;
|
|
}
|
|
|
|
- return psl_is_public_suffix2 (psl, domain, PSL_TYPE_ANY | PSL_TYPE_NO_STAR_RULE);
|
|
+ normalized = soup_uri_normalize_domain (domain);
|
|
+ is_public_suffix = psl_is_public_suffix2 (psl, normalized, PSL_TYPE_ANY | PSL_TYPE_NO_STAR_RULE);
|
|
+ g_free (normalized);
|
|
+
|
|
+ return is_public_suffix;
|
|
}
|
|
|
|
/**
|
|
diff --git a/libsoup/soup-uri-utils-private.h b/libsoup/soup-uri-utils-private.h
|
|
index 0119f0814..c2f984f86 100644
|
|
--- a/libsoup/soup-uri-utils-private.h
|
|
+++ b/libsoup/soup-uri-utils-private.h
|
|
@@ -28,6 +28,8 @@ GUri *soup_uri_copy_with_normalized_flags (GUri *uri);
|
|
|
|
char *soup_uri_get_host_for_headers (GUri *uri);
|
|
|
|
+char *soup_uri_normalize_domain (const char *domain);
|
|
+
|
|
#define SOUP_URI_IS_VALID(x) ((x) && g_uri_get_host(x) && g_uri_get_host(x)[0])
|
|
|
|
G_END_DECLS
|
|
diff --git a/libsoup/soup-uri-utils.c b/libsoup/soup-uri-utils.c
|
|
index 0963a1143..1f65faede 100644
|
|
--- a/libsoup/soup-uri-utils.c
|
|
+++ b/libsoup/soup-uri-utils.c
|
|
@@ -506,3 +506,21 @@ soup_uri_get_host_for_headers (GUri *uri)
|
|
|
|
return g_strdup (host);
|
|
}
|
|
+
|
|
+char *
|
|
+soup_uri_normalize_domain (const char *domain)
|
|
+{
|
|
+ char *lower;
|
|
+ char *normalized;
|
|
+
|
|
+ g_assert (domain);
|
|
+
|
|
+ if (g_str_is_ascii (domain))
|
|
+ return g_ascii_strdown (domain, -1);
|
|
+
|
|
+ lower = g_utf8_casefold (domain, -1);
|
|
+ normalized = g_utf8_normalize (lower, -1, G_NORMALIZE_NFKC);
|
|
+ g_free (lower);
|
|
+
|
|
+ return normalized;
|
|
+}
|
|
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
|
|
index 1d2d45630..7007aaf59 100644
|
|
--- a/tests/cookies-test.c
|
|
+++ b/tests/cookies-test.c
|
|
@@ -695,6 +695,24 @@ do_cookies_threads_test (void)
|
|
soup_test_session_abort_unref (session);
|
|
}
|
|
|
|
+static void
|
|
+do_cookies_public_suffix_test (void)
|
|
+{
|
|
+ SoupCookieJar *jar = soup_cookie_jar_new ();
|
|
+ GUri *uri = g_uri_parse ("http://example.CO.uk", SOUP_HTTP_URI_FLAGS, NULL);
|
|
+ GSList *cookies;
|
|
+
|
|
+ soup_cookie_jar_set_cookie (jar, uri, "value=1; domain=.co.uk");
|
|
+ soup_cookie_jar_set_cookie (jar, uri, "value=1; domain=.CO.uk");
|
|
+ soup_cookie_jar_set_cookie (jar, uri, "value=1; domain=.CO.UK");
|
|
+
|
|
+ cookies = soup_cookie_jar_all_cookies (jar);
|
|
+ g_assert_cmpint (g_slist_length (cookies), ==, 0);
|
|
+
|
|
+ g_uri_unref (uri);
|
|
+ g_object_unref (jar);
|
|
+}
|
|
+
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
@@ -726,6 +744,7 @@ main (int argc, char **argv)
|
|
g_test_add_func ("/cookies/secure-cookies", do_cookies_strict_secure_test);
|
|
g_test_add_func ("/cookies/prefix", do_cookies_prefix_test);
|
|
g_test_add_func ("/cookies/threads", do_cookies_threads_test);
|
|
+ g_test_add_func ("/cookies/public-suffix", do_cookies_public_suffix_test);
|
|
|
|
ret = g_test_run ();
|
|
|
|
--
|
|
GitLab
|