diff --git a/Libraries/LibHTTP/Cookie/Cookie.cpp b/Libraries/LibHTTP/Cookie/Cookie.cpp index 377a9374f7..9acb51fb95 100644 --- a/Libraries/LibHTTP/Cookie/Cookie.cpp +++ b/Libraries/LibHTTP/Cookie/Cookie.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace HTTP::Cookie { @@ -161,7 +162,7 @@ bool cookie_matches_url(Cookie const& cookie, URL::URL const& url, String const& // the cookie's domain. // - The cookie's domain is not a public suffix, for user agents configured to reject "public suffixes". bool is_not_host_only_and_domain_matches = (!cookie.host_only && domain_matches(retrieval_host_canonical, cookie.domain)) - && !URL::is_public_suffix(cookie.domain); + && !URL::PublicSuffixData::the()->is_matching_public_suffix(cookie.domain); if (!is_host_only_and_has_identical_domain && !is_not_host_only_and_domain_matches) return false; diff --git a/Libraries/LibURL/Host.cpp b/Libraries/LibURL/Host.cpp index d30a5c090b..fa8d7e91b6 100644 --- a/Libraries/LibURL/Host.cpp +++ b/Libraries/LibURL/Host.cpp @@ -238,7 +238,7 @@ Optional Host::registrable_domain() const host_without_trailing_dot = host_without_trailing_dot.substring_view(0, host_without_trailing_dot.length() - 1); // NB: If we do not find a registrable domain via the PSL, use everything after the second to last dot. - auto registrable_domain = get_registrable_domain(host_without_trailing_dot); + auto registrable_domain = PublicSuffixData::the()->find_matching_registrable_domain(host_without_trailing_dot); if (!registrable_domain.has_value()) { auto last_dot = host_without_trailing_dot.find_last('.'); if (last_dot.has_value()) { diff --git a/Libraries/LibURL/URL.cpp b/Libraries/LibURL/URL.cpp index c9d9107f59..7cfa380e5c 100644 --- a/Libraries/LibURL/URL.cpp +++ b/Libraries/LibURL/URL.cpp @@ -15,7 +15,6 @@ #include #include #include -#include namespace URL { @@ -505,33 +504,4 @@ ByteString percent_decode(StringView input) return builder.to_byte_string(); } -bool is_public_suffix(StringView host) -{ - return PublicSuffixData::the()->is_matching_public_suffix(host); -} - -// https://github.com/publicsuffix/list/wiki/Format#algorithm -Optional get_registrable_domain(StringView host) -{ - // The registered or registrable domain is the public suffix plus one additional label. - auto public_suffix = PublicSuffixData::the()->find_matching_public_suffix(host); - if (!public_suffix.has_value() || !host.ends_with(*public_suffix)) - return {}; - - if (host == *public_suffix) - return {}; - - auto subhost = host.substring_view(0, host.length() - public_suffix->bytes_as_string_view().length()); - subhost = subhost.trim("."sv, TrimMode::Right); - - if (subhost.is_empty()) - return {}; - - size_t start_index = 0; - if (auto index = subhost.find_last('.'); index.has_value()) - start_index = *index + 1; - - return MUST(String::from_utf8(host.substring_view(start_index))); -} - } diff --git a/Libraries/LibURL/URL.h b/Libraries/LibURL/URL.h index c9779086ab..46cf46d77e 100644 --- a/Libraries/LibURL/URL.h +++ b/Libraries/LibURL/URL.h @@ -210,9 +210,6 @@ Optional create_with_url_or_path(ByteString const&); Optional create_with_file_scheme(ByteString const& path, ByteString const& fragment = {}, ByteString const& hostname = {}); URL create_with_data(StringView mime_type, StringView payload, bool is_base64 = false); -bool is_public_suffix(StringView host); -Optional get_registrable_domain(StringView host); - inline URL about_blank() { return URL::about("blank"_string); } inline URL about_srcdoc() { return URL::about("srcdoc"_string); } diff --git a/Libraries/LibWebView/CookieJar.cpp b/Libraries/LibWebView/CookieJar.cpp index 5e6ef6e084..e4a3d295be 100644 --- a/Libraries/LibWebView/CookieJar.cpp +++ b/Libraries/LibWebView/CookieJar.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -198,7 +199,7 @@ void CookieJar::set_cookie(URL::URL const& url, HTTP::Cookie::ParsedCookie const return; // 9. If the user agent is configured to reject "public suffixes" and the domain-attribute is a public suffix: - if (URL::is_public_suffix(domain_attribute)) { + if (URL::PublicSuffixData::the()->is_matching_public_suffix(domain_attribute)) { // 1. Let request-host-canonical be the canonicalized request-host. // 2. If request-host fails to be canonicalized then abort this algorithm and ignore the cookie entirely. diff --git a/Meta/Generators/generate_public_suffix_data.py b/Meta/Generators/generate_public_suffix_data.py index b41173b7b3..c861c4f806 100644 --- a/Meta/Generators/generate_public_suffix_data.py +++ b/Meta/Generators/generate_public_suffix_data.py @@ -37,6 +37,7 @@ public: bool is_matching_public_suffix(StringView host); Optional find_matching_public_suffix(StringView string); + Optional find_matching_registrable_domain(StringView string); }; @@ -139,6 +140,30 @@ Optional PublicSuffixData::find_matching_public_suffix(StringView string return MUST(return_string_builder.to_string()); } +// https://github.com/publicsuffix/list/wiki/Format#algorithm +Optional PublicSuffixData::find_matching_registrable_domain(StringView host) +{ + // The registered or registrable domain is the public suffix plus one additional label. + auto public_suffix = find_matching_public_suffix(host); + if (!public_suffix.has_value() || !host.ends_with(*public_suffix)) + return {}; + + if (host == *public_suffix) + return {}; + + auto subhost = host.substring_view(0, host.length() - public_suffix->bytes_as_string_view().length()); + subhost = subhost.trim("."sv, TrimMode::Right); + + if (subhost.is_empty()) + return {}; + + size_t start_index = 0; + if (auto index = subhost.find_last('.'); index.has_value()) + start_index = *index + 1; + + return MUST(String::from_utf8(host.substring_view(start_index))); +} + } """ diff --git a/Tests/LibURL/TestURL.cpp b/Tests/LibURL/TestURL.cpp index e56edc8d12..8387703806 100644 --- a/Tests/LibURL/TestURL.cpp +++ b/Tests/LibURL/TestURL.cpp @@ -9,6 +9,7 @@ #include #include +#include #include TEST_CASE(basic) @@ -633,47 +634,47 @@ TEST_CASE(invalid_domain_code_points) TEST_CASE(get_registrable_domain) { { - auto domain = URL::get_registrable_domain({}); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain({}); EXPECT(!domain.has_value()); } { - auto domain = URL::get_registrable_domain("foobar"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("foobar"sv); EXPECT(!domain.has_value()); } { - auto domain = URL::get_registrable_domain("com"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("com"sv); EXPECT(!domain.has_value()); } { - auto domain = URL::get_registrable_domain(".com"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain(".com"sv); EXPECT(!domain.has_value()); } { - auto domain = URL::get_registrable_domain("example.com"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("example.com"sv); VERIFY(domain.has_value()); EXPECT_EQ(*domain, "example.com"sv); } { - auto domain = URL::get_registrable_domain(".example.com"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain(".example.com"sv); VERIFY(domain.has_value()); EXPECT_EQ(*domain, "example.com"sv); } { - auto domain = URL::get_registrable_domain("www.example.com"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("www.example.com"sv); VERIFY(domain.has_value()); EXPECT_EQ(*domain, "example.com"sv); } { - auto domain = URL::get_registrable_domain("sub.www.example.com"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("sub.www.example.com"sv); VERIFY(domain.has_value()); EXPECT_EQ(*domain, "example.com"sv); } { - auto domain = URL::get_registrable_domain("github.io"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("github.io"sv); EXPECT(!domain.has_value()); } { - auto domain = URL::get_registrable_domain("ladybird.github.io"sv); + auto domain = URL::PublicSuffixData::the()->find_matching_registrable_domain("ladybird.github.io"sv); VERIFY(domain.has_value()); EXPECT_EQ(*domain, "ladybird.github.io"sv); }