blob: edc11aa95c44eeb91a713f98b68706d7f15ff19e [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/browsing_data/registrable_domain_filter_builder.h"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "net/cookies/canonical_cookie.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace {
const char kGoogleDomain[] = "google.com";
// sp.nom.br is an eTLD, so this is a regular valid registrable domain, just
// like google.com.
const char kLongETLDDomain[] = "website.sp.nom.br";
// This domain will also not be found in registries, and since it has only
// one component, it will not be recognized as a valid registrable domain.
const char kInternalHostname[] = "fileserver";
// This domain will not be found in registries. It will be assumed that
// it belongs to an unknown registry, and since it has two components,
// they will be treated as the second level domain and TLD. Most importantly,
// it will NOT be treated as a subdomain of "fileserver".
const char kUnknownRegistryDomain[] = "second-level-domain.fileserver";
// IP addresses are supported.
const char kIPAddress[] = "192.168.1.1";
struct TestCase {
std::string url;
bool should_match;
};
void RunTestCase(TestCase test_case,
const base::Callback<bool(const GURL&)>& filter) {
GURL url(test_case.url);
EXPECT_TRUE(url.is_valid()) << test_case.url << " is not valid.";
EXPECT_EQ(test_case.should_match, filter.Run(GURL(test_case.url)))
<< test_case.url;
}
void RunTestCase(
TestCase test_case,
const base::Callback<bool(const ContentSettingsPattern&)>& filter) {
ContentSettingsPattern pattern =
ContentSettingsPattern::FromString(test_case.url);
EXPECT_TRUE(pattern.IsValid()) << test_case.url << " is not valid.";
EXPECT_EQ(test_case.should_match, filter.Run(pattern)) << pattern.ToString();
}
void RunTestCase(
TestCase test_case,
const base::Callback<bool(const net::CanonicalCookie&)>& filter) {
// Test with regular cookie, http only, domain, and secure.
std::string cookie_line = "A=2";
GURL test_url(test_case.url);
EXPECT_TRUE(test_url.is_valid()) << test_case.url;
std::unique_ptr<net::CanonicalCookie> cookie = net::CanonicalCookie::Create(
test_url, cookie_line, base::Time::Now(), net::CookieOptions());
EXPECT_TRUE(cookie) << cookie_line << " from " << test_case.url
<< " is not a valid cookie";
if (cookie)
EXPECT_EQ(test_case.should_match, filter.Run(*cookie))
<< cookie->DebugString();
cookie_line = std::string("A=2;domain=") + test_url.host();
cookie = net::CanonicalCookie::Create(
test_url, cookie_line, base::Time::Now(), net::CookieOptions());
if (cookie)
EXPECT_EQ(test_case.should_match, filter.Run(*cookie))
<< cookie->DebugString();
cookie_line = std::string("A=2; HttpOnly;") + test_url.host();
cookie = net::CanonicalCookie::Create(
test_url, cookie_line, base::Time::Now(), net::CookieOptions());
if (cookie)
EXPECT_EQ(test_case.should_match, filter.Run(*cookie))
<< cookie->DebugString();
cookie_line = std::string("A=2; HttpOnly; Secure;") + test_url.host();
cookie = net::CanonicalCookie::Create(
test_url, cookie_line, base::Time::Now(), net::CookieOptions());
if (cookie)
EXPECT_EQ(test_case.should_match, filter.Run(*cookie))
<< cookie->DebugString();
}
void RunTestCase(
TestCase test_case,
const base::Callback<bool(const std::string&)>& filter) {
std::string channel_id_server_id = test_case.url;
EXPECT_EQ(test_case.should_match, filter.Run(channel_id_server_id))
<< channel_id_server_id << " should "
<< (test_case.should_match ? "" : "NOT ") << "be matched by the filter.";
}
} // namespace
TEST(RegistrableDomainFilterBuilderTest, Noop) {
// An no-op filter matches everything.
base::Callback<bool(const GURL&)> filter =
RegistrableDomainFilterBuilder::BuildNoopFilter();
TestCase test_cases[] = {
{"https://www.google.com", true},
{"https://www.chrome.com", true},
{"http://www.google.com/foo/bar", true},
{"https://website.sp.nom.br", true},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, GURLWhitelist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::WHITELIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const GURL&)> filter = builder.BuildGeneralFilter();
TestCase test_cases[] = {
// We match any URL on the specified domains.
{"http://www.google.com/foo/bar", true},
{"https://www.sub.google.com/foo/bar", true},
{"https://sub.google.com", true},
{"http://www.sub.google.com:8000/foo/bar", true},
{"https://website.sp.nom.br", true},
{"https://www.website.sp.nom.br", true},
{"http://192.168.1.1", true},
{"http://192.168.1.1:80", true},
// Internal hostnames do not have subdomains.
{"http://fileserver", true },
{"http://fileserver/foo/bar", true },
{"http://website.fileserver/foo/bar", false },
// This is a valid registrable domain with the TLD "fileserver", which
// is unrelated to the internal hostname "fileserver".
{"http://second-level-domain.fileserver/foo", true},
{"http://www.second-level-domain.fileserver/index.html", true},
// Different domains.
{"https://www.youtube.com", false},
{"https://www.google.net", false},
{"http://192.168.1.2", false},
// Check both a bare eTLD.
{"https://sp.nom.br", false},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, GURLBlacklist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::BLACKLIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const GURL&)> filter = builder.BuildGeneralFilter();
TestCase test_cases[] = {
// We match any URL that are not on the specified domains.
{"http://www.google.com/foo/bar", false},
{"https://www.sub.google.com/foo/bar", false},
{"https://sub.google.com", false},
{"http://www.sub.google.com:8000/foo/bar", false},
{"https://website.sp.nom.br", false},
{"https://www.website.sp.nom.br", false},
{"http://192.168.1.1", false},
{"http://192.168.1.1:80", false},
// Internal hostnames do not have subdomains.
{"http://fileserver", false },
{"http://fileserver/foo/bar", false },
{"http://website.fileserver/foo/bar", true },
// This is a valid registrable domain with the TLD "fileserver", which
// is unrelated to the internal hostname "fileserver".
{"http://second-level-domain.fileserver/foo", false},
{"http://www.second-level-domain.fileserver/index.html", false},
// Different domains.
{"https://www.youtube.com", true},
{"https://www.google.net", true},
{"http://192.168.1.2", true},
// Check our bare eTLD.
{"https://sp.nom.br", true},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, WhitelistContentSettings) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::WHITELIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const ContentSettingsPattern&)> filter =
builder.BuildWebsiteSettingsPatternMatchesFilter();
TestCase test_cases[] = {
// Whitelist matches any patterns that include the whitelisted
// registerable domains.
{"https://www.google.com", true},
{"http://www.google.com", true},
{"http://www.google.com/index.html", true},
{"http://www.google.com/foo/bar", true},
{"www.sub.google.com/bar", true},
{"http://www.sub.google.com:8000/foo/bar", true},
{"https://[*.]google.com", true},
{"https://[*.]google.com:443", true},
{"[*.]google.com", true},
{"[*.]google.com/foo/bar", true},
{"[*.]google.com:80", true},
{"www.google.com/?q=test", true},
{"192.168.1.1", true},
{"192.168.1.1:80", true},
// We check that we treat the eTLDs correctly.
{"https://website.sp.nom.br", true},
{"https://www.website.sp.nom.br", true},
// Different eTLDs, and a bare eTLD.
{"[*.]google", false},
{"[*.]google.net", false},
{"https://[*.]google.org", false},
{"https://[*.]foo.bar.com", false},
{"https://sp.nom.br", false},
{"http://192.168.1.2", false},
// Internal hostnames do not have subdomains.
{"http://fileserver", true },
{"http://[*.]fileserver", false },
{"http://website.fileserver", false },
// This is a valid registrable domain with the TLD "fileserver", which
// is unrelated to the internal hostname "fileserver".
{"http://second-level-domain.fileserver", true},
{"http://[*.]second-level-domain.fileserver", true},
{"http://www.second-level-domain.fileserver", true},
{"http://[*.]www.second-level-domain.fileserver", true},
// These patterns are more general than our registerable domain filter,
// as they apply to more sites. So we don't match them. The content
// settings categories that we'll be seeing from browsing_data_remover
// aren't going to have these, but I test for it anyways.
{"*", false},
{"*:80", false}
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, BlacklistContentSettings) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::BLACKLIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const ContentSettingsPattern&)> filter =
builder.BuildWebsiteSettingsPatternMatchesFilter();
TestCase test_cases[] = {
// Blacklist matches any patterns that isn't in the blacklist
// registerable domains.
{"https://www.google.com", false},
{"http://www.google.com", false},
{"http://www.google.com/index.html", false},
{"http://www.google.com/foo/bar", false},
{"www.sub.google.com/bar", false},
{"http://www.sub.google.com:8000/foo/bar", false},
{"https://[*.]google.com", false},
{"https://[*.]google.com:443", false},
{"[*.]google.com", false},
{"[*.]google.com/foo/bar", false},
{"[*.]google.com:80", false},
{"www.google.com/?q=test", false},
{"192.168.1.1", false},
{"192.168.1.1:80", false},
// We check that we treat the eTLDs correctly.
{"https://website.sp.nom.br", false},
{"https://www.website.sp.nom.br", false},
// Different eTLDs, and a bare eTLD.
{"[*.]google", true},
{"[*.]google.net", true},
{"https://[*.]google.org", true},
{"https://[*.]foo.bar.com", true},
{"https://sp.nom.br", true},
{"http://192.168.1.2", true},
// Internal hostnames do not have subdomains.
{"fileserver", false },
{"http://[*.]fileserver", true },
{"website.fileserver", true },
// This is a valid registrable domain with the TLD "fileserver", which
// is unrelated to the internal hostname "fileserver".
{"http://second-level-domain.fileserver", false},
{"http://[*.]second-level-domain.fileserver", false},
{"http://www.second-level-domain.fileserver", false},
{"http://[*.]www.second-level-domain.fileserver", false},
// These patterns are more general than our registerable domain filter,
// as they apply to more sites. So we don't match them. The content
// settings categories that we'll be seeing from browsing_data_remover
// aren't going to have these, but I test for it anyways.
{"*", true},
{"*:80", true}
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, MatchesCookiesWhitelist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::WHITELIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const net::CanonicalCookie&)> filter =
builder.BuildCookieFilter();
TestCase test_cases[] = {
// Any cookie with the same registerable domain as the origins is matched.
{"https://www.google.com", true},
{"http://www.google.com", true},
{"http://www.google.com:300", true},
{"https://mail.google.com", true},
{"http://mail.google.com", true},
{"http://google.com", true},
{"https://website.sp.nom.br", true},
{"https://sub.website.sp.nom.br", true},
{"http://192.168.1.1", true},
{"http://192.168.1.1:10", true},
// Different eTLDs.
{"https://www.google.org", false},
{"https://www.google.co.uk", false},
// We treat eTLD+1 and bare eTLDs as different domains.
{"https://www.sp.nom.br", false},
{"https://sp.nom.br", false},
// Different hosts in general.
{"https://www.chrome.com", false},
{"http://192.168.2.1", false},
// Internal hostnames do not have subdomains.
{"https://fileserver", true },
{"http://fileserver/foo/bar", true },
{"http://website.fileserver", false },
// This is a valid registrable domain with the TLD "fileserver", which
// is unrelated to the internal hostname "fileserver".
{"http://second-level-domain.fileserver", true},
{"https://subdomain.second-level-domain.fileserver", true},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, MatchesCookiesBlacklist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::BLACKLIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const net::CanonicalCookie&)> filter =
builder.BuildCookieFilter();
TestCase test_cases[] = {
// Any cookie that doesn't have the same registerable domain is matched.
{"https://www.google.com", false},
{"http://www.google.com", false},
{"http://www.google.com:300", false},
{"https://mail.google.com", false},
{"http://mail.google.com", false},
{"http://google.com", false},
{"https://website.sp.nom.br", false},
{"https://sub.website.sp.nom.br", false},
{"http://192.168.1.1", false},
{"http://192.168.1.1:10", false},
// Different eTLDs.
{"https://www.google.org", true},
{"https://www.google.co.uk", true},
// We treat eTLD+1 and bare eTLDs as different domains.
{"https://www.sp.nom.br", true},
{"https://sp.nom.br", true},
// Different hosts in general.
{"https://www.chrome.com", true},
{"http://192.168.2.1", true},
// Internal hostnames do not have subdomains.
{"https://fileserver", false },
{"http://fileserver/foo/bar", false },
{"http://website.fileserver", true },
// This is a valid registrable domain with the TLD "fileserver", which
// is unrelated to the internal hostname "fileserver".
{"http://second-level-domain.fileserver", false},
{"https://subdomain.second-level-domain.fileserver", false},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, MatchesChannelIDsWhitelist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::WHITELIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const std::string&)> filter =
builder.BuildChannelIDFilter();
TestCase test_cases[] = {
// Channel ID server identifiers can be second level domains, ...
{"google.com", true},
{"website.sp.nom.br", true},
{"second-level-domain.fileserver", true},
// ... IP addresses, or internal hostnames.
{"192.168.1.1", true},
{"fileserver", true},
// Channel IDs not in the whitelist are not matched.
{"example.com", false},
{"192.168.1.2", false},
{"website.fileserver", false},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, MatchesChannelIDsBlacklist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::BLACKLIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const std::string&)> filter =
builder.BuildChannelIDFilter();
TestCase test_cases[] = {
// Channel ID server identifiers can be second level domains, ...
{"google.com", false},
{"website.sp.nom.br", false},
{"second-level-domain.fileserver", false},
// ...IP addresses, or internal hostnames.
{"192.168.1.1", false},
{"fileserver", false},
// Channel IDs that are not blacklisted are matched.
{"example.com", true},
{"192.168.1.2", true},
{"website.fileserver", true},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, MatchesPluginSitesWhitelist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::WHITELIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const std::string&)> filter =
builder.BuildPluginFilter();
TestCase test_cases[] = {
// Plugin sites can be domains, ...
{"google.com", true},
{"www.google.com", true},
{"website.sp.nom.br", true},
{"www.website.sp.nom.br", true},
{"second-level-domain.fileserver", true},
{"foo.bar.second-level-domain.fileserver", true},
// ... IP addresses, or internal hostnames.
{"192.168.1.1", true},
{"fileserver", true},
// Sites not in the whitelist are not matched.
{"example.com", false},
{"192.168.1.2", false},
{"website.fileserver", false},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}
TEST(RegistrableDomainFilterBuilderTest, MatchesPluginSitesBlacklist) {
RegistrableDomainFilterBuilder builder(
RegistrableDomainFilterBuilder::BLACKLIST);
builder.AddRegisterableDomain(std::string(kGoogleDomain));
builder.AddRegisterableDomain(std::string(kLongETLDDomain));
builder.AddRegisterableDomain(std::string(kIPAddress));
builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
builder.AddRegisterableDomain(std::string(kInternalHostname));
base::Callback<bool(const std::string&)> filter =
builder.BuildPluginFilter();
TestCase test_cases[] = {
// Plugin sites can be domains, ...
{"google.com", false},
{"www.google.com", false},
{"website.sp.nom.br", false},
{"www.website.sp.nom.br", false},
{"second-level-domain.fileserver", false},
{"foo.bar.second-level-domain.fileserver", false},
// ... IP addresses, or internal hostnames.
{"192.168.1.1", false},
{"fileserver", false},
// Sites not in the blacklist are matched.
{"example.com", true},
{"192.168.1.2", true},
{"website.fileserver", true},
};
for (TestCase test_case : test_cases)
RunTestCase(test_case, filter);
}