| Index: chrome/browser/subresource_filter/subresource_filter_browsertest.cc
|
| diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
|
| index 6aefb51b109d6367a9cd84ecaaabafc64352975d..93f7d85684981b65917f11dd072f40b843395e38 100644
|
| --- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
|
| +++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
|
| @@ -15,6 +15,7 @@
|
| #include "base/memory/ptr_util.h"
|
| #include "base/path_service.h"
|
| #include "base/strings/string_piece.h"
|
| +#include "base/strings/string_util.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/test/histogram_tester.h"
|
| #include "chrome/browser/browser_process.h"
|
| @@ -22,6 +23,7 @@
|
| #include "chrome/browser/metrics/subprocess_metrics_provider.h"
|
| #include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
|
| #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
|
| +#include "chrome/browser/safe_browsing/v4_test_utils.h"
|
| #include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/browser/ui/browser_commands.h"
|
| @@ -34,6 +36,7 @@
|
| #include "components/content_settings/core/common/content_settings.h"
|
| #include "components/safe_browsing_db/test_database_manager.h"
|
| #include "components/safe_browsing_db/util.h"
|
| +#include "components/safe_browsing_db/v4_database.h"
|
| #include "components/security_interstitials/content/unsafe_resource.h"
|
| #include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
|
| #include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
|
| @@ -67,7 +70,7 @@ namespace {
|
|
|
| // The path to a multi-frame document used for tests.
|
| static constexpr const char kTestFrameSetPath[] =
|
| - "subresource_filter/frame_set.html";
|
| + "/subresource_filter/frame_set.html";
|
|
|
| // Names of DocumentLoad histograms.
|
| constexpr const char kDocumentLoadActivationLevel[] =
|
| @@ -108,61 +111,34 @@ constexpr const char kEvaluationWallDuration[] =
|
| constexpr const char kEvaluationCPUDuration[] =
|
| "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration";
|
|
|
| +#if defined(GOOGLE_CHROME_BUILD)
|
| +// Names of navigation chain patterns histogram.
|
| +const char kMatchesPatternHistogramName[] =
|
| + "SubresourceFilter.PageLoad.RedirectChainMatchPattern";
|
| +const char kNavigationChainSize[] =
|
| + "SubresourceFilter.PageLoad.RedirectChainLength";
|
| +const char kSubresourceFilterOnlySuffix[] = ".SubresourceFilterOnly";
|
| +#endif
|
| +
|
| // Other histograms.
|
| const char kSubresourceFilterPromptHistogram[] =
|
| "SubresourceFilter.Prompt.NumVisibility";
|
|
|
| -// Database manager that allows any URL to be configured as blacklisted for
|
| -// testing.
|
| -class FakeSafeBrowsingDatabaseManager
|
| - : public safe_browsing::TestSafeBrowsingDatabaseManager {
|
| - public:
|
| - FakeSafeBrowsingDatabaseManager() {}
|
| -
|
| - void AddBlacklistedURL(const GURL& url,
|
| - safe_browsing::SBThreatType threat_type) {
|
| - url_to_threat_type_[url] = threat_type;
|
| - }
|
| -
|
| - protected:
|
| - ~FakeSafeBrowsingDatabaseManager() override {}
|
| -
|
| - bool CheckBrowseUrl(const GURL& url, Client* client) override {
|
| - if (!url_to_threat_type_.count(url))
|
| - return true;
|
| -
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&Client::OnCheckBrowseUrlResult, base::Unretained(client),
|
| - url, url_to_threat_type_[url],
|
| - safe_browsing::ThreatMetadata()));
|
| - return false;
|
| - }
|
| -
|
| - bool CheckResourceUrl(const GURL& url, Client* client) override {
|
| - return true;
|
| - }
|
| -
|
| - bool IsSupported() const override { return true; }
|
| - bool ChecksAreAlwaysAsync() const override { return false; }
|
| - bool CanCheckResourceType(
|
| - content::ResourceType /* resource_type */) const override {
|
| - return true;
|
| - }
|
| -
|
| - safe_browsing::ThreatSource GetThreatSource() const override {
|
| - return safe_browsing::ThreatSource::LOCAL_PVER4;
|
| - }
|
| -
|
| - bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
|
| - Client* client) override {
|
| - return true;
|
| - }
|
| -
|
| - private:
|
| - std::map<GURL, safe_browsing::SBThreatType> url_to_threat_type_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
|
| +// Human readable representation of expected redirect chain match patterns.
|
| +// The explanations for the buckets given for the following redirect chain:
|
| +// A->B->C->D, where A is initial URL and D is a final URL.
|
| +enum RedirectChainMatchPattern {
|
| + EMPTY, // No histograms were recorded.
|
| + F0M0L1, // D is a Safe Browsing match.
|
| + F0M1L0, // B or C, or both are Safe Browsing matches.
|
| + F0M1L1, // B or C, or both and D are Safe Browsing matches.
|
| + F1M0L0, // A is Safe Browsing match
|
| + F1M0L1, // A and D are Safe Browsing matches.
|
| + F1M1L0, // B and/or C and A are Safe Browsing matches.
|
| + F1M1L1, // B and/or C and A and D are Safe Browsing matches.
|
| + NO_REDIRECTS_HIT, // Redirect chain consists of single URL, aka no redirects
|
| + // has happened, and this URL was a Safe Browsing hit.
|
| + NUM_HIT_PATTERNS,
|
| };
|
|
|
| // UI manager that never actually shows any interstitials, but emulates as if
|
| @@ -190,12 +166,6 @@ GURL GetURLWithFragment(const GURL& url, base::StringPiece fragment) {
|
| return url.ReplaceComponents(replacements);
|
| }
|
|
|
| -GURL GetURLWithQuery(const GURL& url, base::StringPiece query) {
|
| - GURL::Replacements replacements;
|
| - replacements.SetQueryStr(query);
|
| - return url.ReplaceComponents(replacements);
|
| -}
|
| -
|
| } // namespace
|
|
|
| namespace subresource_filter {
|
| @@ -239,26 +209,47 @@ class SubresourceFilterBrowserTestImpl : public InProcessBrowserTest {
|
| // As a workaround, enable the feature here, then enable the feature once
|
| // again + set up the field trials later.
|
| void SetUpCommandLine(base::CommandLine* command_line) override {
|
| - command_line->AppendSwitchASCII(switches::kEnableFeatures,
|
| - kSafeBrowsingSubresourceFilter.name);
|
| + command_line->AppendSwitchASCII(
|
| + switches::kEnableFeatures,
|
| + base::JoinString(
|
| + {kSafeBrowsingSubresourceFilter.name, "SafeBrowsingV4OnlyEnabled",
|
| + kSubresourceFilterSafeBrowsingActivationThrottle.name},
|
| + ","));
|
| }
|
|
|
| - void SetUpInProcessBrowserTestFixture() override {
|
| - fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
|
| - test_safe_browsing_factory_.SetTestDatabaseManager(
|
| - fake_safe_browsing_database_.get());
|
| - test_safe_browsing_factory_.SetTestUIManager(new FakeSafeBrowsingUIManager);
|
| - safe_browsing::SafeBrowsingService::RegisterFactory(
|
| - &test_safe_browsing_factory_);
|
| + void SetUp() override {
|
| + sb_factory_ =
|
| + base::MakeUnique<safe_browsing::TestSafeBrowsingServiceFactory>(
|
| + safe_browsing::V4FeatureList::V4UsageStatus::V4_ONLY);
|
| + sb_factory_->SetTestUIManager(new FakeSafeBrowsingUIManager());
|
| + safe_browsing::SafeBrowsingService::RegisterFactory(sb_factory_.get());
|
| +
|
| + safe_browsing::V4Database::RegisterStoreFactoryForTest(
|
| + base::WrapUnique(new safe_browsing::TestV4StoreFactory()));
|
| +
|
| + v4_db_factory_ = new safe_browsing::TestV4DatabaseFactory();
|
| + safe_browsing::V4Database::RegisterDatabaseFactoryForTest(
|
| + base::WrapUnique(v4_db_factory_));
|
| +
|
| + v4_get_hash_factory_ =
|
| + new safe_browsing::TestV4GetHashProtocolManagerFactory();
|
| + safe_browsing::V4GetHashProtocolManager::RegisterFactory(
|
| + base::WrapUnique(v4_get_hash_factory_));
|
| + InProcessBrowserTest::SetUp();
|
| }
|
|
|
| - void SetUpOnMainThread() override {
|
| - scoped_feature_toggle_.reset(new ScopedSubresourceFilterFeatureToggle(
|
| - base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
|
| - kActivationScopeActivationList, kActivationListPhishingInterstitial,
|
| - measure_performance_ ? "1" : "0", "" /* suppress_notifications */,
|
| - whitelist_site_on_reload_ ? "true" : "false"));
|
| + void TearDown() override {
|
| + InProcessBrowserTest::TearDown();
|
| + // Unregister test factories after InProcessBrowserTest::TearDown
|
| + // (which destructs SafeBrowsingService).
|
| + safe_browsing::V4GetHashProtocolManager::RegisterFactory(nullptr);
|
| + safe_browsing::V4Database::RegisterDatabaseFactoryForTest(nullptr);
|
| + safe_browsing::V4Database::RegisterStoreFactoryForTest(nullptr);
|
| + safe_browsing::SafeBrowsingService::RegisterFactory(nullptr);
|
| + }
|
|
|
| + void SetUpOnMainThread() override {
|
| + SetUpActivationFeature();
|
| base::FilePath test_data_dir;
|
| PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
|
| embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
|
| @@ -268,13 +259,36 @@ class SubresourceFilterBrowserTestImpl : public InProcessBrowserTest {
|
| ASSERT_TRUE(embedded_test_server()->Start());
|
| }
|
|
|
| + virtual void SetUpActivationFeature() {
|
| + scoped_feature_toggle_.reset(new ScopedSubresourceFilterFeatureToggle(
|
| + base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
|
| + kActivationScopeActivationList, kActivationListPhishingInterstitial,
|
| + measure_performance_ ? "1" : "0", "" /* suppress_notifications */,
|
| + whitelist_site_on_reload_ ? "true" : "false"));
|
| + }
|
| +
|
| GURL GetTestUrl(const std::string& relative_url) {
|
| return embedded_test_server()->base_url().Resolve(relative_url);
|
| }
|
|
|
| + void MarkUrlAsMatchingListWithId(
|
| + const GURL& bad_url,
|
| + const safe_browsing::ListIdentifier& list_id,
|
| + safe_browsing::ThreatPatternType threat_pattern_type) {
|
| + safe_browsing::FullHashInfo full_hash_info =
|
| + GetFullHashInfoWithMetadata(bad_url, list_id, threat_pattern_type);
|
| + v4_db_factory_->MarkPrefixAsBad(list_id, full_hash_info.full_hash);
|
| + v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
|
| + }
|
| +
|
| void ConfigureAsPhishingURL(const GURL& url) {
|
| - fake_safe_browsing_database_->AddBlacklistedURL(
|
| - url, safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
|
| + MarkUrlAsMatchingListWithId(url, safe_browsing::GetUrlSocEngId(),
|
| + safe_browsing::ThreatPatternType::NONE);
|
| + }
|
| +
|
| + void ConfigureAsSubresourceFilterOnlyURL(const GURL& url) {
|
| + MarkUrlAsMatchingListWithId(url, safe_browsing::GetUrlSubresourceFilterId(),
|
| + safe_browsing::ThreatPatternType::NONE);
|
| }
|
|
|
| content::WebContents* web_contents() {
|
| @@ -348,16 +362,24 @@ class SubresourceFilterBrowserTestImpl : public InProcessBrowserTest {
|
| test_ruleset_publisher_.SetRuleset(test_ruleset_pair.unindexed));
|
| }
|
|
|
| + void set_scoped_feature_toggle(ScopedSubresourceFilterFeatureToggle* toggle) {
|
| + scoped_feature_toggle_.reset(toggle);
|
| + }
|
| +
|
| private:
|
| TestRulesetCreator ruleset_creator_;
|
| - safe_browsing::TestSafeBrowsingServiceFactory test_safe_browsing_factory_;
|
| - scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
|
|
|
| std::unique_ptr<ScopedSubresourceFilterFeatureToggle> scoped_feature_toggle_;
|
| TestRulesetPublisher test_ruleset_publisher_;
|
| const bool measure_performance_;
|
| const bool whitelist_site_on_reload_;
|
|
|
| + std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory> sb_factory_;
|
| + // Owned by the V4Database.
|
| + safe_browsing::TestV4DatabaseFactory* v4_db_factory_;
|
| + // Owned by the V4GetHashProtocolManager.
|
| + safe_browsing::TestV4GetHashProtocolManagerFactory* v4_get_hash_factory_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(SubresourceFilterBrowserTestImpl);
|
| };
|
|
|
| @@ -429,6 +451,22 @@ class SubresourceFilterWebSocketBrowserTest
|
| std::unique_ptr<net::SpawnedTestServer> websocket_test_server_;
|
| };
|
|
|
| +#if defined(GOOGLE_CHROME_BUILD)
|
| +class SubresourceFilterListBrowserTest
|
| + : public SubresourceFilterBrowserTestImpl {
|
| + public:
|
| + SubresourceFilterListBrowserTest()
|
| + : SubresourceFilterBrowserTestImpl(false, false) {}
|
| +
|
| + void SetUpActivationFeature() override {
|
| + set_scoped_feature_toggle(new ScopedSubresourceFilterFeatureToggle(
|
| + base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
|
| + kActivationScopeActivationList, kActivationListSubresourceFilter, "0",
|
| + "" /* suppress_notifications */, "false"));
|
| + }
|
| +};
|
| +#endif
|
| +
|
| // Tests -----------------------------------------------------------------------
|
|
|
| IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, MainFrameActivation) {
|
| @@ -450,6 +488,27 @@ IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, MainFrameActivation) {
|
| EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
|
| }
|
|
|
| +#if defined(GOOGLE_CHROME_BUILD)
|
| +IN_PROC_BROWSER_TEST_F(SubresourceFilterListBrowserTest, MainFrameActivation) {
|
| + GURL url(GetTestUrl("subresource_filter/frame_with_included_script.html"));
|
| + ConfigureAsSubresourceFilterOnlyURL(url);
|
| + ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix(
|
| + "suffix-that-does-not-match-anything"));
|
| + ui_test_utils::NavigateToURL(browser(), url);
|
| + EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
|
| +
|
| + ASSERT_NO_FATAL_FAILURE(
|
| + SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
|
| + ui_test_utils::NavigateToURL(browser(), url);
|
| + EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
|
| +
|
| + // The main frame document should never be filtered.
|
| + SetRulesetToDisallowURLsWithPathSuffix("frame_with_included_script.html");
|
| + ui_test_utils::NavigateToURL(browser(), url);
|
| + EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
|
| +}
|
| +#endif
|
| +
|
| // There should be no document-level de-/reactivation happening on the renderer
|
| // side as a result of an in-page navigation.
|
| IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
|
| @@ -489,9 +548,9 @@ IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, SubFrameActivation) {
|
|
|
| IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
|
| HistoryNavigationActivation) {
|
| - GURL url_without_activation(GetTestUrl(kTestFrameSetPath));
|
| - GURL url_with_activation(
|
| - GetURLWithQuery(url_without_activation, "activation"));
|
| + GURL url_with_activation(GetTestUrl(kTestFrameSetPath));
|
| + GURL url_without_activation(
|
| + embedded_test_server()->GetURL("a.com", kTestFrameSetPath));
|
| ConfigureAsPhishingURL(url_with_activation);
|
| ASSERT_NO_FATAL_FAILURE(
|
| SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
|
| @@ -1128,4 +1187,53 @@ IN_PROC_BROWSER_TEST_F(SubresourceFilterWhitelistSiteOnReloadBrowserTest,
|
| static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
|
| }
|
|
|
| +#if defined(GOOGLE_CHROME_BUILD)
|
| +// This test is only enabled when GOOGLE_CHROME_BUILD is true because the store
|
| +// that this test uses is only populated on GOOGLE_CHROME_BUILD builds.
|
| +IN_PROC_BROWSER_TEST_F(
|
| + SubresourceFilterBrowserTest,
|
| + ExpectRedirectPatternHistogramsAreRecordedForSubresourceFilterOnlyMatch) {
|
| + ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix(
|
| + "suffix-that-does-not-match-anything"));
|
| +
|
| + GURL url(GetTestUrl("subresource_filter/frame_with_included_script.html"));
|
| + ConfigureAsSubresourceFilterOnlyURL(url);
|
| +
|
| + base::HistogramTester tester;
|
| + ui_test_utils::NavigateToURL(browser(), url);
|
| +
|
| + EXPECT_THAT(tester.GetAllSamples(std::string(kMatchesPatternHistogramName) +
|
| + std::string(kSubresourceFilterOnlySuffix)),
|
| + ::testing::ElementsAre(base::Bucket(NO_REDIRECTS_HIT, 1)));
|
| + EXPECT_THAT(tester.GetAllSamples(std::string(kNavigationChainSize) +
|
| + std::string(kSubresourceFilterOnlySuffix)),
|
| + ::testing::ElementsAre(base::Bucket(1, 1)));
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(
|
| + SubresourceFilterBrowserTest,
|
| + ExpectRedirectPatternHistogramsAreRecordedForSubresourceFilterOnlyRedirectMatch) {
|
| + ASSERT_NO_FATAL_FAILURE(
|
| + SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
|
| + const std::string initial_host("a.com");
|
| + const std::string redirected_host("b.com");
|
| +
|
| + GURL redirect_url(embedded_test_server()->GetURL(
|
| + redirected_host, "/subresource_filter/frame_with_included_script.html"));
|
| + GURL url(embedded_test_server()->GetURL(
|
| + initial_host, "/server-redirect?" + redirect_url.spec()));
|
| +
|
| + ConfigureAsSubresourceFilterOnlyURL(url.GetOrigin());
|
| + base::HistogramTester tester;
|
| + ui_test_utils::NavigateToURL(browser(), url);
|
| + EXPECT_THAT(tester.GetAllSamples(std::string(kMatchesPatternHistogramName) +
|
| + std::string(kSubresourceFilterOnlySuffix)),
|
| + ::testing::IsEmpty());
|
| +
|
| + EXPECT_THAT(tester.GetAllSamples(std::string(kNavigationChainSize) +
|
| + std::string(kSubresourceFilterOnlySuffix)),
|
| + ::testing::IsEmpty());
|
| +}
|
| +#endif
|
| +
|
| } // namespace subresource_filter
|
|
|