LibURL: Reverse host labels before searching the public suffix table

The generated public suffix table stores each entry with it's labels
reversed, but the lookup we were using didn't reverse its input before
searching. This led to multi-label public suffixes not matching when
they should have.
This commit is contained in:
Tim Ledbetter 2026-06-07 12:29:11 +01:00 committed by Shannon Booth
parent 3771bd5d4a
commit 2a5f239d11
2 changed files with 23 additions and 3 deletions

View file

@ -81,9 +81,21 @@ PublicSuffixData::PublicSuffixData()
{
}
static bool is_reversed_public_suffix(StringView reversed_host)
{
return binary_search(s_public_suffixes, reversed_host);
}
bool PublicSuffixData::is_public_suffix(StringView host)
{
return binary_search(s_public_suffixes, host);
// Empty labels are kept so that inputs such as "com." do not match the bare "com" entry.
auto labels = host.split_view('.', SplitBehavior::KeepEmpty);
labels.reverse();
StringBuilder reversed_host;
reversed_host.join('.', labels);
return is_reversed_public_suffix(reversed_host.string_view());
}
Optional<String> PublicSuffixData::get_public_suffix(StringView string)
@ -98,7 +110,7 @@ Optional<String> PublicSuffixData::get_public_suffix(StringView string)
search_string.append(overall_search_string.string_view());
search_string.append(part);
if (is_public_suffix(search_string.string_view())) {
if (is_reversed_public_suffix(search_string.string_view())) {
overall_search_string.append(part);
overall_search_string.append('.');
continue;
@ -108,7 +120,7 @@ Optional<String> PublicSuffixData::get_public_suffix(StringView string)
search_string.append(overall_search_string.string_view());
search_string.append('.');
if (is_public_suffix(search_string.string_view())) {
if (is_reversed_public_suffix(search_string.string_view())) {
overall_search_string.append(part);
overall_search_string.append('.');
continue;

View file

@ -14,6 +14,11 @@ TEST_CASE(is_public_suffix)
EXPECT(public_suffix_data->is_public_suffix("com"sv));
EXPECT(public_suffix_data->is_public_suffix("com.br"sv));
EXPECT(public_suffix_data->is_public_suffix("co.uk"sv));
EXPECT(public_suffix_data->is_public_suffix("ac.uk"sv));
EXPECT(public_suffix_data->is_public_suffix("gov.uk"sv));
EXPECT(public_suffix_data->is_public_suffix("com.au"sv));
EXPECT(public_suffix_data->is_public_suffix("co.jp"sv));
EXPECT(!public_suffix_data->is_public_suffix(""sv));
EXPECT(!public_suffix_data->is_public_suffix("."sv));
@ -46,4 +51,7 @@ TEST_CASE(get_public_suffix)
EXPECT_EQ(public_suffix_data->get_public_suffix("..com."sv), "com"sv);
EXPECT_EQ(public_suffix_data->get_public_suffix("com.br"sv), "com.br"sv);
EXPECT_EQ(public_suffix_data->get_public_suffix("not-a-public-suffix.com.br"sv), "com.br"sv);
EXPECT_EQ(public_suffix_data->get_public_suffix("co.uk"sv), "co.uk"sv);
EXPECT_EQ(public_suffix_data->get_public_suffix("bbc.co.uk"sv), "co.uk"sv);
EXPECT_EQ(public_suffix_data->get_public_suffix("www.bbc.co.uk"sv), "co.uk"sv);
}