diff options
Diffstat (limited to 'chromium/components/policy/core/browser/url_blocklist_manager_unittest.cc')
-rw-r--r-- | chromium/components/policy/core/browser/url_blocklist_manager_unittest.cc | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/chromium/components/policy/core/browser/url_blocklist_manager_unittest.cc b/chromium/components/policy/core/browser/url_blocklist_manager_unittest.cc new file mode 100644 index 00000000000..52cc1851228 --- /dev/null +++ b/chromium/components/policy/core/browser/url_blocklist_manager_unittest.cc @@ -0,0 +1,649 @@ +// Copyright (c) 2012 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 "components/policy/core/browser/url_blocklist_manager.h" + +#include <stdint.h> +#include <memory> +#include <ostream> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/run_loop.h" +#include "base/test/task_environment.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/values.h" +#include "build/build_config.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "components/url_formatter/url_fixer.h" +#include "google_apis/gaia/gaia_urls.h" +#include "net/base/load_flags.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace policy { + +namespace { + +class TestingURLBlocklistManager : public URLBlocklistManager { + public: + explicit TestingURLBlocklistManager(PrefService* pref_service) + : URLBlocklistManager(pref_service, + policy_prefs::kUrlBlocklist, + policy_prefs::kUrlAllowlist), + update_called_(0), + set_blocklist_called_(false) {} + TestingURLBlocklistManager(const TestingURLBlocklistManager&) = delete; + TestingURLBlocklistManager& operator=(const TestingURLBlocklistManager&) = + delete; + + ~TestingURLBlocklistManager() override = default; + + // Make this method public for testing. + using URLBlocklistManager::ScheduleUpdate; + + // URLBlocklistManager overrides: + void SetBlocklist(std::unique_ptr<URLBlocklist> blocklist) override { + set_blocklist_called_ = true; + URLBlocklistManager::SetBlocklist(std::move(blocklist)); + } + + void Update() override { + update_called_++; + URLBlocklistManager::Update(); + } + + int update_called() const { return update_called_; } + bool set_blocklist_called() const { return set_blocklist_called_; } + + private: + int update_called_; + bool set_blocklist_called_; +}; + +class URLBlocklistManagerTest : public testing::Test { + protected: + URLBlocklistManagerTest() = default; + + void SetUp() override { + pref_service_.registry()->RegisterListPref(policy_prefs::kUrlBlocklist); + pref_service_.registry()->RegisterListPref(policy_prefs::kUrlAllowlist); + blocklist_manager_ = + std::make_unique<TestingURLBlocklistManager>(&pref_service_); + task_environment_.RunUntilIdle(); + } + + void TearDown() override { + if (blocklist_manager_) + task_environment_.RunUntilIdle(); + blocklist_manager_.reset(); + } + + TestingPrefServiceSimple pref_service_; + std::unique_ptr<TestingURLBlocklistManager> blocklist_manager_; + + base::test::TaskEnvironment task_environment_; +}; + +} // namespace + +// Returns whether |url| matches the |pattern|. +bool IsMatch(const std::string& pattern, const std::string& url) { + URLBlocklist blocklist; + + // Add the pattern to blocklist. + base::Value blocked(base::Value::Type::LIST); + blocked.Append(pattern); + blocklist.Block(&base::Value::AsListValue(blocked)); + + return blocklist.IsURLBlocked(GURL(url)); +} + +// Returns the state from blocklist after adding |pattern| to be blocked or +// allowed depending on |use_allowlist| and checking |url|. +policy::URLBlocklist::URLBlocklistState GetMatch(const std::string& pattern, + const std::string& url, + const bool use_allowlist) { + URLBlocklist blocklist; + + // Add the pattern to list. + base::Value blocked(base::Value::Type::LIST); + blocked.Append(pattern); + + if (use_allowlist) { + blocklist.Allow(&base::Value::AsListValue(blocked)); + } else { + blocklist.Block(&base::Value::AsListValue(blocked)); + } + + return blocklist.GetURLBlocklistState(GURL(url)); +} + +TEST_F(URLBlocklistManagerTest, LoadBlocklistOnCreate) { + base::Value list(base::Value::Type::LIST); + list.Append("example.com"); + pref_service_.SetManagedPref(policy_prefs::kUrlBlocklist, + base::Value::ToUniquePtrValue(std::move(list))); + auto manager = std::make_unique<URLBlocklistManager>( + &pref_service_, policy_prefs::kUrlBlocklist, policy_prefs::kUrlAllowlist); + task_environment_.RunUntilIdle(); + EXPECT_EQ(URLBlocklist::URL_IN_BLOCKLIST, + manager->GetURLBlocklistState(GURL("http://example.com"))); +} + +TEST_F(URLBlocklistManagerTest, LoadAllowlistOnCreate) { + base::Value list(base::Value::Type::LIST); + list.Append("example.com"); + pref_service_.SetManagedPref(policy_prefs::kUrlAllowlist, + base::Value::ToUniquePtrValue(std::move(list))); + auto manager = std::make_unique<URLBlocklistManager>( + &pref_service_, policy_prefs::kUrlBlocklist, policy_prefs::kUrlAllowlist); + task_environment_.RunUntilIdle(); + EXPECT_EQ(URLBlocklist::URL_IN_ALLOWLIST, + manager->GetURLBlocklistState(GURL("http://example.com"))); +} + +TEST_F(URLBlocklistManagerTest, SingleUpdateForTwoPrefChanges) { + base::Value blocklist(base::Value::Type::LIST); + blocklist.Append("*.google.com"); + base::Value allowlist(base::Value::Type::LIST); + allowlist.Append("mail.google.com"); + pref_service_.SetManagedPref( + policy_prefs::kUrlBlocklist, + base::Value::ToUniquePtrValue(std::move(blocklist))); + pref_service_.SetManagedPref( + policy_prefs::kUrlBlocklist, + base::Value::ToUniquePtrValue(std::move(allowlist))); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(1, blocklist_manager_->update_called()); +} + +TEST_F(URLBlocklistManagerTest, Filtering) { + URLBlocklist blocklist; + + // Block domain and all subdomains, for any filtered scheme. + EXPECT_TRUE(IsMatch("google.com", "http://google.com")); + EXPECT_TRUE(IsMatch("google.com", "http://google.com/")); + EXPECT_TRUE(IsMatch("google.com", "http://google.com/whatever")); + EXPECT_TRUE(IsMatch("google.com", "https://google.com/")); + EXPECT_FALSE(IsMatch("google.com", "bogus://google.com/")); + EXPECT_FALSE(IsMatch("google.com", "http://notgoogle.com/")); + EXPECT_TRUE(IsMatch("google.com", "http://mail.google.com")); + EXPECT_TRUE(IsMatch("google.com", "http://x.mail.google.com")); + EXPECT_TRUE(IsMatch("google.com", "https://x.mail.google.com/")); + EXPECT_TRUE(IsMatch("google.com", "http://x.y.google.com/a/b")); + EXPECT_FALSE(IsMatch("google.com", "http://youtube.com/")); + + // Filter only http, ftp and ws schemes. + EXPECT_TRUE(IsMatch("http://secure.com", "http://secure.com")); + EXPECT_TRUE(IsMatch("http://secure.com", "http://secure.com/whatever")); + EXPECT_TRUE(IsMatch("ftp://secure.com", "ftp://secure.com/")); + EXPECT_TRUE(IsMatch("ws://secure.com", "ws://secure.com")); + EXPECT_FALSE(IsMatch("http://secure.com", "https://secure.com/")); + EXPECT_FALSE(IsMatch("ws://secure.com", "wss://secure.com")); + EXPECT_TRUE(IsMatch("http://secure.com", "http://www.secure.com")); + EXPECT_FALSE(IsMatch("http://secure.com", "https://www.secure.com")); + EXPECT_FALSE(IsMatch("ws://secure.com", "wss://www.secure.com")); + + // Filter only a certain path prefix. + EXPECT_TRUE(IsMatch("path.to/ruin", "http://path.to/ruin")); + EXPECT_TRUE(IsMatch("path.to/ruin", "https://path.to/ruin")); + EXPECT_TRUE(IsMatch("path.to/ruin", "http://path.to/ruins")); + EXPECT_TRUE(IsMatch("path.to/ruin", "http://path.to/ruin/signup")); + EXPECT_TRUE(IsMatch("path.to/ruin", "http://www.path.to/ruin")); + EXPECT_FALSE(IsMatch("path.to/ruin", "http://path.to/fortune")); + + // Filter only a certain path prefix and scheme. + EXPECT_TRUE(IsMatch("https://s.aaa.com/path", "https://s.aaa.com/path")); + EXPECT_TRUE(IsMatch("https://s.aaa.com/path", "https://s.aaa.com/path/bbb")); + EXPECT_FALSE(IsMatch("https://s.aaa.com/path", "http://s.aaa.com/path")); + EXPECT_FALSE(IsMatch("https://s.aaa.com/path", "https://aaa.com/path")); + EXPECT_FALSE(IsMatch("https://s.aaa.com/path", "https://x.aaa.com/path")); + EXPECT_FALSE(IsMatch("https://s.aaa.com/path", "https://s.aaa.com/bbb")); + EXPECT_FALSE(IsMatch("https://s.aaa.com/path", "https://s.aaa.com/")); + + // Filter only ws and wss schemes. + EXPECT_TRUE(IsMatch("ws://ws.aaa.com", "ws://ws.aaa.com")); + EXPECT_TRUE(IsMatch("wss://ws.aaa.com", "wss://ws.aaa.com")); + EXPECT_FALSE(IsMatch("ws://ws.aaa.com", "http://ws.aaa.com")); + EXPECT_FALSE(IsMatch("ws://ws.aaa.com", "https://ws.aaa.com")); + EXPECT_FALSE(IsMatch("ws://ws.aaa.com", "ftp://ws.aaa.com")); + + // Block an ip address. + EXPECT_TRUE(IsMatch("123.123.123.123", "http://123.123.123.123/")); + EXPECT_FALSE(IsMatch("123.123.123.123", "http://123.123.123.124/")); + + // Test exceptions to path prefixes, and most specific matches. + base::Value blocked(base::Value::Type::LIST); + base::Value allowed(base::Value::Type::LIST); + blocked.Append("s.xxx.com/a"); + allowed.Append("s.xxx.com/a/b"); + blocked.Append("https://s.xxx.com/a/b/c"); + allowed.Append("https://s.xxx.com/a/b/c/d"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a/x"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://s.xxx.com/a/x"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a/b"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://s.xxx.com/a/b"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/x"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/c"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/x"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/d"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/c/d"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/d/x"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/c/d/x"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://xxx.com/a"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://xxx.com/a/b"))); + + // Open an exception. + blocked.ClearList(); + blocked.Append("google.com"); + allowed.ClearList(); + allowed.Append("plus.google.com"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://google.com/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.google.com/"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://plus.google.com/"))); + + // Open an exception only when using https for mail. + allowed.ClearList(); + allowed.Append("https://mail.google.com"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://google.com/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://mail.google.com/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.google.com/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://www.google.com/"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://mail.google.com/"))); + + // Match exactly "google.com", only for http. Subdomains without exceptions + // are still blocked. + allowed.ClearList(); + allowed.Append("http://.google.com"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://google.com/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://google.com/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.google.com/"))); + + // A smaller path match in an exact host overrides a longer path for hosts + // that also match subdomains. + blocked.ClearList(); + blocked.Append("yyy.com/aaa"); + blocklist.Block(&base::Value::AsListValue(blocked)); + allowed.ClearList(); + allowed.Append(".yyy.com/a"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://yyy.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://yyy.com/aaa"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://yyy.com/aaa2"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://www.yyy.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.yyy.com/aaa"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.yyy.com/aaa2"))); + + // If the exact entry is both allowed and blocked, allowing takes precedence. + blocked.ClearList(); + blocked.Append("example.com"); + blocklist.Block(&base::Value::AsListValue(blocked)); + allowed.ClearList(); + allowed.Append("example.com"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://example.com"))); + + // Devtools should not be blocked. + blocked.ClearList(); + blocked.Append("*"); + blocklist.Block(&base::Value::AsListValue(blocked)); + allowed.ClearList(); + allowed.Append("devtools://*"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("devtools://something.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://something.com"))); +} + +TEST_F(URLBlocklistManagerTest, QueryParameters) { + URLBlocklist blocklist; + base::Value blocked(base::Value::Type::LIST); + base::Value allowed(base::Value::Type::LIST); + + // Block domain and all subdomains, for any filtered scheme. + blocked.Append("youtube.com"); + allowed.Append("youtube.com/watch?v=XYZ"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com/watch?v=123"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?v=123&v=XYZ"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?v=XYZ&v=123"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube.com/watch?v=XYZ"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?v=XYZ&foo=bar"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?foo=bar&v=XYZ"))); + + allowed.ClearList(); + allowed.Append("youtube.com/watch?av=XYZ&ag=123"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com/watch?av=123"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com/watch?av=XYZ"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?av=123&ag=XYZ"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?ag=XYZ&av=123"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?av=XYZ&ag=123"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?ag=123&av=XYZ"))); + EXPECT_TRUE(blocklist.IsURLBlocked( + GURL("http://youtube.com/watch?av=XYZ&ag=123&av=123"))); + EXPECT_TRUE(blocklist.IsURLBlocked( + GURL("http://youtube.com/watch?av=XYZ&ag=123&ag=1234"))); + + allowed.ClearList(); + allowed.Append("youtube.com/watch?foo=bar*&vid=2*"); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com/watch?vid=2"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube.com/watch?foo=bar"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?vid=2&foo=bar"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?vid=2&foo=bar1"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube.com/watch?vid=234&foo=bar"))); + EXPECT_FALSE(blocklist.IsURLBlocked( + GURL("http://youtube.com/watch?vid=234&foo=bar23"))); + + blocked.ClearList(); + blocked.Append("youtube1.com/disallow?v=44678"); + blocklist.Block(&base::Value::AsListValue(blocked)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube1.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube1.com?v=123"))); + // Path does not match + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube1.com?v=44678"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube1.com/disallow?v=44678"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube1.com/disallow?v=4467"))); + EXPECT_FALSE(blocklist.IsURLBlocked( + GURL("http://youtube1.com/disallow?v=4467&v=123"))); + EXPECT_TRUE(blocklist.IsURLBlocked( + GURL("http://youtube1.com/disallow?v=4467&v=123&v=44678"))); + + blocked.ClearList(); + blocked.Append("youtube1.com/disallow?g=*"); + blocklist.Block(&base::Value::AsListValue(blocked)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube1.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube1.com?ag=123"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube1.com/disallow?g=123"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube1.com/disallow?ag=13&g=123"))); + + blocked.ClearList(); + blocked.Append("youtube2.com/disallow?a*"); + blocklist.Block(&base::Value::AsListValue(blocked)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube2.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked( + GURL("http://youtube2.com/disallow?b=123&a21=467"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube2.com/disallow?abba=true"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube2.com/disallow?baba=true"))); + + allowed.ClearList(); + blocked.ClearList(); + blocked.Append("youtube3.com"); + allowed.Append("youtube3.com/watch?fo*"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube3.com"))); + EXPECT_TRUE( + blocklist.IsURLBlocked(GURL("http://youtube3.com/watch?b=123&a21=467"))); + EXPECT_FALSE(blocklist.IsURLBlocked( + GURL("http://youtube3.com/watch?b=123&a21=467&foo1"))); + EXPECT_FALSE(blocklist.IsURLBlocked( + GURL("http://youtube3.com/watch?b=123&a21=467&foo=bar"))); + EXPECT_FALSE(blocklist.IsURLBlocked( + GURL("http://youtube3.com/watch?b=123&a21=467&fo=ba"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("http://youtube3.com/watch?foreign=true"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube3.com/watch?fold"))); + + allowed.ClearList(); + blocked.ClearList(); + blocked.Append("youtube4.com"); + allowed.Append("youtube4.com?*"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube4.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube4.com/?hello"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube4.com/?foo"))); + + allowed.ClearList(); + blocked.ClearList(); + blocked.Append("youtube5.com?foo=bar"); + allowed.Append("youtube5.com?foo1=bar1&foo2=bar2&"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://youtube5.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://youtube5.com/?foo=bar&a=b"))); + // More specific filter is given precedence. + EXPECT_FALSE(blocklist.IsURLBlocked( + GURL("http://youtube5.com/?a=b&foo=bar&foo1=bar1&foo2=bar2"))); +} + +TEST_F(URLBlocklistManagerTest, BlockAllWithExceptions) { + URLBlocklist blocklist; + + base::Value blocked(base::Value::Type::LIST); + base::Value allowed(base::Value::Type::LIST); + blocked.Append("*"); + allowed.Append(".www.google.com"); + allowed.Append("plus.google.com"); + allowed.Append("https://mail.google.com"); + allowed.Append("https://very.safe/path"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://random.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://google.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://s.www.google.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://www.google.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://plus.google.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("http://s.plus.google.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://mail.google.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://mail.google.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://s.mail.google.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("https://very.safe/"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://very.safe/path"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("https://very.safe/path"))); +} + +TEST_F(URLBlocklistManagerTest, DefaultBlocklistExceptions) { + URLBlocklist blocklist; + base::Value blocked(base::Value::Type::LIST); + + // Blocklist everything: + blocked.Append("*"); + blocklist.Block(&base::Value::AsListValue(blocked)); + + // Internal NTP and extension URLs are not blocked by the "*": + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.google.com"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("chrome-extension://xyz"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("chrome-search://most-visited/title.html"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("chrome-native://ntp"))); +#if BUILDFLAG(IS_IOS) + // Ensure that the NTP is not blocked on iOS by "*". + // TODO(crbug.com/1073291): On iOS, the NTP can not be blocked even by + // explicitly listing it as a blocked URL. This is due to the usage of + // "about:newtab" as its URL which is not recognized and filtered by the + // URLBlocklist code. + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("about:newtab"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("about://newtab/"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("chrome://newtab"))); +#endif + + // Unless they are explicitly on the blocklist: + blocked.Append("chrome-extension://*"); + base::Value allowed(base::Value::Type::LIST); + allowed.Append("chrome-extension://abc"); + blocklist.Block(&base::Value::AsListValue(blocked)); + blocklist.Allow(&base::Value::AsListValue(allowed)); + + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("http://www.google.com"))); + EXPECT_TRUE(blocklist.IsURLBlocked(GURL("chrome-extension://xyz"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("chrome-extension://abc"))); + EXPECT_FALSE( + blocklist.IsURLBlocked(GURL("chrome-search://most-visited/title.html"))); + EXPECT_FALSE(blocklist.IsURLBlocked(GURL("chrome-native://ntp"))); +} + +TEST_F(URLBlocklistManagerTest, BlocklistBasicCoverage) { + // Tests to cover the documentation from + // http://www.chromium.org/administrators/url-blocklist-filter-format + + // [scheme://][.]host[:port][/path][@query] + // Scheme can be http, https, ftp, chrome, etc. This field is optional, and + // must be followed by '://'. + EXPECT_TRUE(IsMatch("file://*", "file:///abc.txt")); + EXPECT_TRUE(IsMatch("file:*", "file:///usr/local/boot.txt")); + EXPECT_TRUE(IsMatch("https://*", "https:///abc.txt")); + EXPECT_TRUE(IsMatch("ftp://*", "ftp://ftp.txt")); + EXPECT_TRUE(IsMatch("chrome://*", "chrome:policy")); + EXPECT_TRUE(IsMatch("noscheme", "http://noscheme")); + // Filter custom schemes. + EXPECT_TRUE(IsMatch("custom://*", "custom://example_app")); + EXPECT_TRUE(IsMatch("custom:*", "custom:example2_app")); + EXPECT_FALSE(IsMatch("custom://*", "customs://example_apps")); + EXPECT_FALSE(IsMatch("custom://*", "cust*://example_ap")); + EXPECT_FALSE(IsMatch("custom://*", "ecustom:example_app")); + EXPECT_TRUE(IsMatch("custom://*", "custom:///abc.txt")); + // Tests for custom scheme patterns that are not supported. + EXPECT_FALSE(IsMatch("wrong://app", "wrong://app")); + EXPECT_FALSE(IsMatch("wrong ://*", "wrong ://app")); + EXPECT_FALSE(IsMatch(" wrong:*", " wrong://app")); + + // Ommitting the scheme matches most standard schemes. + EXPECT_TRUE(IsMatch("example.com", "chrome:example.com")); + EXPECT_TRUE(IsMatch("example.com", "chrome://example.com")); + EXPECT_TRUE(IsMatch("example.com", "file://example.com/")); + EXPECT_TRUE(IsMatch("example.com", "ftp://example.com")); + EXPECT_TRUE(IsMatch("example.com", "http://example.com")); + EXPECT_TRUE(IsMatch("example.com", "https://example.com")); + EXPECT_TRUE(IsMatch("example.com", "ws://example.com")); + EXPECT_TRUE(IsMatch("example.com", "wss://example.com")); + + // Some schemes are not matched when the scheme is ommitted. + EXPECT_FALSE(IsMatch("example.com", "about://example.com")); + EXPECT_FALSE(IsMatch("example.com", "about:example.com")); + EXPECT_FALSE(IsMatch("example.com/*", "filesystem:///something")); + EXPECT_FALSE(IsMatch("example.com", "custom://example.com")); + EXPECT_FALSE(IsMatch("example", "custom://example")); + EXPECT_FALSE(IsMatch("example.com", "gopher://example.com")); + + // An optional '.' (dot) can prefix the host field to disable subdomain + // matching, see below for details. + EXPECT_TRUE(IsMatch(".example.com", "http://example.com/path")); + EXPECT_FALSE(IsMatch(".example.com", "http://mail.example.com/path")); + EXPECT_TRUE(IsMatch("example.com", "http://mail.example.com/path")); + EXPECT_TRUE(IsMatch("ftp://.ftp.file", "ftp://ftp.file")); + EXPECT_FALSE(IsMatch("ftp://.ftp.file", "ftp://sub.ftp.file")); + + // The host field is required, and is a valid hostname or an IP address. It + // can also take the special '*' value, see below for details. + EXPECT_TRUE(IsMatch("*", "http://anything")); + EXPECT_TRUE(IsMatch("*", "ftp://anything")); + EXPECT_TRUE(IsMatch("*", "custom://anything")); + EXPECT_TRUE(IsMatch("host", "http://host:8080")); + EXPECT_FALSE(IsMatch("host", "file:///host")); + EXPECT_TRUE(IsMatch("10.1.2.3", "http://10.1.2.3:8080/path")); + // No host, will match nothing. + EXPECT_FALSE(IsMatch(":8080", "http://host:8080")); + EXPECT_FALSE(IsMatch(":8080", "http://:8080")); + + // An optional port can come after the host. It must be a valid port value + // from 1 to 65535. + EXPECT_TRUE(IsMatch("host:8080", "http://host:8080/path")); + EXPECT_TRUE(IsMatch("host:1", "http://host:1/path")); + // Out of range port. + EXPECT_FALSE(IsMatch("host:65536", "http://host:65536/path")); + // Star is not allowed in port numbers. + EXPECT_FALSE(IsMatch("example.com:*", "http://example.com")); + EXPECT_FALSE(IsMatch("example.com:*", "http://example.com:8888")); + + // An optional path can come after port. + EXPECT_TRUE(IsMatch("host/path", "http://host:8080/path")); + EXPECT_TRUE(IsMatch("host/path/path2", "http://host/path/path2")); + EXPECT_TRUE(IsMatch("host/path", "http://host/path/path2")); + + // An optional query can come in the end, which is a set of key-value and + // key-only tokens delimited by '&'. The key-value tokens are separated + // by '='. A query token can optionally end with a '*' to indicate prefix + // match. Token order is ignored during matching. + EXPECT_TRUE(IsMatch("host?q1=1&q2=2", "http://host?q2=2&q1=1")); + EXPECT_FALSE(IsMatch("host?q1=1&q2=2", "http://host?q2=1&q1=2")); + EXPECT_FALSE(IsMatch("host?q1=1&q2=2", "http://host?Q2=2&Q1=1")); + EXPECT_TRUE(IsMatch("host?q1=1&q2=2", "http://host?q2=2&q1=1&q3=3")); + EXPECT_TRUE(IsMatch("host?q1=1&q2=2*", "http://host?q2=21&q1=1&q3=3")); + + // user:pass fields can be included but will be ignored + // (e.g. http://user:pass@ftp.example.com/pub/bigfile.iso). + EXPECT_TRUE(IsMatch("host.com/path", "http://user:pass@host.com:8080/path")); + EXPECT_TRUE( + IsMatch("ftp://host.com/path", "ftp://user:pass@host.com:8080/path")); + + // Case sensitivity. + // Scheme is case insensitive. + EXPECT_TRUE(IsMatch("suPPort://*", "support:example")); + EXPECT_TRUE(IsMatch("FILE://*", "file:example")); + EXPECT_TRUE(IsMatch("FILE://*", "FILE://example")); + EXPECT_TRUE(IsMatch("FtP:*", "ftp://example")); + EXPECT_TRUE(IsMatch("http://example.com", "HTTP://example.com")); + EXPECT_TRUE(IsMatch("HTTP://example.com", "http://example.com")); + // Host is case insensitive. + EXPECT_TRUE(IsMatch("http://EXAMPLE.COM", "http://example.com")); + EXPECT_TRUE(IsMatch("Example.com", "http://examplE.com/Path?Query=1")); + // Path is case sensitive. + EXPECT_FALSE(IsMatch("example.com/Path", "http://example.com/path")); + EXPECT_TRUE(IsMatch("http://example.com/aB", "http://example.com/aB")); + EXPECT_FALSE(IsMatch("http://example.com/aB", "http://example.com/Ab")); + EXPECT_FALSE(IsMatch("http://example.com/aB", "http://example.com/ab")); + EXPECT_FALSE(IsMatch("http://example.com/aB", "http://example.com/AB")); + // Query is case sensitive. + EXPECT_FALSE(IsMatch("host/path?Query=1", "http://host/path?query=1")); +} + +// Test for GetURLBlocklistState method. +TEST_F(URLBlocklistManagerTest, UseBlocklistState) { + const policy::URLBlocklist::URLBlocklistState in_blocklist = + policy::URLBlocklist::URLBlocklistState::URL_IN_BLOCKLIST; + const policy::URLBlocklist::URLBlocklistState in_allowlist = + policy::URLBlocklist::URLBlocklistState::URL_IN_ALLOWLIST; + const policy::URLBlocklist::URLBlocklistState neutral_state = + policy::URLBlocklist::URLBlocklistState::URL_NEUTRAL_STATE; + + // Test allowlist states. + EXPECT_EQ(in_allowlist, GetMatch("example.com", "http://example.com", true)); + EXPECT_EQ(in_allowlist, GetMatch("http://*", "http://example.com", true)); + EXPECT_EQ(in_allowlist, GetMatch("custom://*", "custom://app", true)); + EXPECT_EQ(in_allowlist, GetMatch("custom:*", "custom://app/play", true)); + EXPECT_EQ(in_allowlist, GetMatch("custom:*", "custom://app:8080", true)); + // Test blocklist states. + EXPECT_EQ(in_blocklist, GetMatch("ftp:*", "ftp://server", false)); + // Test neutral states. + EXPECT_EQ(neutral_state, GetMatch("file:*", "http://example.com", true)); + EXPECT_EQ(neutral_state, GetMatch("https://*", "http://example.com", false)); +} +} // namespace policy |