| // Copyright 2018 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/safe_browsing/triggers/suspicious_site_trigger.h" | 
 |  | 
 | #include "base/test/metrics/histogram_tester.h" | 
 | #include "base/test/test_simple_task_runner.h" | 
 | #include "components/prefs/testing_pref_service.h" | 
 | #include "components/safe_browsing/common/safe_browsing_prefs.h" | 
 | #include "components/safe_browsing/triggers/mock_trigger_manager.h" | 
 | #include "content/public/test/navigation_simulator.h" | 
 | #include "content/public/test/test_browser_thread_bundle.h" | 
 | #include "content/public/test/test_renderer_host.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | using content::NavigationSimulator; | 
 | using content::RenderFrameHost; | 
 | using content::RenderFrameHostTester; | 
 |  | 
 | using testing::_; | 
 | using testing::DoAll; | 
 | using testing::Return; | 
 | using testing::SetArgPointee; | 
 |  | 
 | namespace safe_browsing { | 
 |  | 
 | namespace { | 
 | const char kSuspiciousUrl[] = "https://suspicious.com/"; | 
 | const char kCleanUrl[] = "https://foo.com/"; | 
 | }  // namespace | 
 |  | 
 | class SuspiciousSiteTriggerTest : public content::RenderViewHostTestHarness { | 
 |  public: | 
 |   SuspiciousSiteTriggerTest() : task_runner_(new base::TestSimpleTaskRunner) {} | 
 |   ~SuspiciousSiteTriggerTest() override {} | 
 |  | 
 |   void SetUp() override { | 
 |     content::RenderViewHostTestHarness::SetUp(); | 
 |  | 
 |     // Enable any prefs required for the trigger to run. | 
 |     safe_browsing::RegisterProfilePrefs(prefs_.registry()); | 
 |     prefs_.SetBoolean(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true); | 
 |     prefs_.SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, true); | 
 |     prefs_.SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, true); | 
 |   } | 
 |  | 
 |   void CreateTrigger(bool monitor_mode) { | 
 |     safe_browsing::SuspiciousSiteTrigger::CreateForWebContents( | 
 |         web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr, | 
 |         monitor_mode); | 
 |     safe_browsing::SuspiciousSiteTrigger* trigger = | 
 |         safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents()); | 
 |     // Give the trigger a test task runner that we can synchronize on. | 
 |     trigger->SetTaskRunnerForTest(task_runner_); | 
 |   } | 
 |  | 
 |   // Returns the final RenderFrameHost after navigation commits. | 
 |   RenderFrameHost* NavigateFrame(const std::string& url, | 
 |                                  RenderFrameHost* frame) { | 
 |     GURL gurl(url); | 
 |     auto navigation_simulator = | 
 |         NavigationSimulator::CreateRendererInitiated(gurl, frame); | 
 |     navigation_simulator->Commit(); | 
 |     RenderFrameHost* final_frame_host = | 
 |         navigation_simulator->GetFinalRenderFrameHost(); | 
 |     return final_frame_host; | 
 |   } | 
 |  | 
 |   // Returns the final RenderFrameHost after navigation commits. | 
 |   RenderFrameHost* NavigateMainFrame(const std::string& url) { | 
 |     return NavigateFrame(url, web_contents()->GetMainFrame()); | 
 |   } | 
 |  | 
 |   // Returns the final RenderFrameHost after navigation commits. | 
 |   RenderFrameHost* CreateAndNavigateSubFrame(const std::string& url, | 
 |                                              RenderFrameHost* parent) { | 
 |     RenderFrameHost* subframe = | 
 |         RenderFrameHostTester::For(parent)->AppendChild("subframe"); | 
 |     return NavigateFrame(url, subframe); | 
 |   } | 
 |  | 
 |   void StartNewFakeLoad() { | 
 |     // This fakes a new LoadStart event in the trigger, since the navigation | 
 |     // simulator doesn't restart the load when we start a new navigation. | 
 |     safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents()) | 
 |         ->DidStartLoading(); | 
 |   } | 
 |  | 
 |   void FinishAllNavigations() { | 
 |     // Call the trigger's DidStopLoading event handler directly since it is not | 
 |     // called as part of the navigating individual frames. | 
 |     safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents()) | 
 |         ->DidStopLoading(); | 
 |   } | 
 |  | 
 |   void TriggerSuspiciousSite() { | 
 |     // Notify the trigger that a suspicious site was detected. | 
 |     safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents()) | 
 |         ->SuspiciousSiteDetected(); | 
 |   } | 
 |  | 
 |   void WaitForTaskRunnerIdle() { | 
 |     task_runner_->RunUntilIdle(); | 
 |     base::RunLoop().RunUntilIdle(); | 
 |   } | 
 |  | 
 |   // Checks the trigger event histogram and ensures that |event| happened | 
 |   // |count| times. | 
 |   void ExpectEventHistogramCount(const SuspiciousSiteTriggerEvent event, | 
 |                                  int count) { | 
 |     histograms_.ExpectBucketCount(kSuspiciousSiteTriggerEventMetricName, | 
 |                                   static_cast<int>(event), count); | 
 |   } | 
 |  | 
 |   // Checks the histogram that tracks what state the trigger was in when the | 
 |   // delay timer fired. Ensures that the trigger was in |state| and occured | 
 |   // |count| times. | 
 |   void ExpectDelayStateHistogramCount( | 
 |       const SuspiciousSiteTrigger::TriggerState state, | 
 |       int count) { | 
 |     histograms_.ExpectBucketCount( | 
 |         kSuspiciousSiteTriggerReportDelayStateMetricName, | 
 |         static_cast<int>(state), count); | 
 |   } | 
 |  | 
 |   // Checks the report rejection histogram and makes sure that |count| reports | 
 |   // were rejected for |reason|. | 
 |   void ExpectReportRejectionHistogramCount(const TriggerManagerReason reason, | 
 |                                            int count) { | 
 |     histograms_.ExpectBucketCount( | 
 |         kSuspiciousSiteTriggerReportRejectionMetricName, | 
 |         static_cast<int>(reason), count); | 
 |   } | 
 |  | 
 |   // Checks the report rejection histogram and makes sure it was empty, | 
 |   // indicating no errors occurred. | 
 |   void ExpectNoReportRejection() { | 
 |     histograms_.ExpectTotalCount( | 
 |         kSuspiciousSiteTriggerReportRejectionMetricName, 0); | 
 |   } | 
 |  | 
 |   MockTriggerManager* get_trigger_manager() { return &trigger_manager_; } | 
 |  | 
 |  private: | 
 |   TestingPrefServiceSimple prefs_; | 
 |   MockTriggerManager trigger_manager_; | 
 |   base::HistogramTester histograms_; | 
 |   scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | 
 | }; | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, RegularPageNonSuspicious) { | 
 |   // In a normal case where there are no suspicious URLs on the page, the | 
 |   // trigger should not fire. | 
 |   CreateTrigger(/*monitor_mode=*/false); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(0); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(0); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   // One page load start and finish. No suspicious sites and no reports sent. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0); | 
 |   ExpectNoReportRejection(); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitDuringLoad) { | 
 |   // When a suspicious site is detected in the middle of a page load, a report | 
 |   // is created after the page load has finished. | 
 |   CreateTrigger(/*monitor_mode=*/false); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(1) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(1) | 
 |       .WillOnce(Return(true)); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame); | 
 |   TriggerSuspiciousSite(); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   WaitForTaskRunnerIdle(); | 
 |  | 
 |   // One page load start and finish. One suspicious site detected and one | 
 |   // report started and sent after the page finished loading. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 1); | 
 |  | 
 |   // Ensure the delay timer fired and it happened in the REPORT_STARTED state | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 1); | 
 |   ExpectDelayStateHistogramCount( | 
 |       SuspiciousSiteTrigger::TriggerState::REPORT_STARTED, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 1); | 
 |   ExpectNoReportRejection(); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitAfterLoad) { | 
 |   // When a suspicious site is detected in after a page load, a report is | 
 |   // created immediately. | 
 |   CreateTrigger(/*monitor_mode=*/false); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(1) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(1) | 
 |       .WillOnce(Return(true)); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   FinishAllNavigations(); | 
 |   TriggerSuspiciousSite(); | 
 |  | 
 |   WaitForTaskRunnerIdle(); | 
 |  | 
 |   // One page load start and finish. One suspicious site detected and one | 
 |   // report started and sent. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 1); | 
 |  | 
 |   // Ensure the delay timer fired and it happened in the REPORT_STARTED state | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 1); | 
 |   ExpectDelayStateHistogramCount( | 
 |       SuspiciousSiteTrigger::TriggerState::REPORT_STARTED, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 1); | 
 |   ExpectNoReportRejection(); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, ReportRejectedByTriggerManager) { | 
 |   // If the trigger manager rejects the report then no report is sent. | 
 |   CreateTrigger(/*monitor_mode=*/false); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(1) | 
 |       .WillOnce( | 
 |           DoAll(SetArgPointee<6>(TriggerManagerReason::DAILY_QUOTA_EXCEEDED), | 
 |                 Return(false))); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(0); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame); | 
 |   TriggerSuspiciousSite(); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   WaitForTaskRunnerIdle(); | 
 |  | 
 |   // One page load start and finish. One suspicious site detected but no report | 
 |   // is sent because it's rejected. Error stats should reflect the rejection. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1); | 
 |  | 
 |   // Ensure no report was started or finished, and no delay timer fired. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 0); | 
 |  | 
 |   // Ensure that starting a report failed, and it was rejected for the | 
 |   // expected reason (quota). | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_START_FAILED, 1); | 
 |   ExpectReportRejectionHistogramCount( | 
 |       TriggerManagerReason::DAILY_QUOTA_EXCEEDED, 1); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, NewNavigationMidLoad_NotSuspicious) { | 
 |   // Exercise what happens when a new navigation begins in the middle of a page | 
 |   // load when no suspicious site is detected. | 
 |   CreateTrigger(/*monitor_mode=*/false); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(0); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(0); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   // Begin a brand new load before the first one is finished. | 
 |   StartNewFakeLoad(); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   // Two page load start events, but only one finish. No suspicious sites | 
 |   // detected and no reports sent. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 2); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0); | 
 |   ExpectNoReportRejection(); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, NewNavigationMidLoad_Suspicious) { | 
 |   // Exercise what happens when a new navigation begins in the middle of a page | 
 |   // load when a suspicious site was detected. The report of the first site | 
 |   // must be cancelled because we were waiting for the first load to finish | 
 |   // before beginning the report. | 
 |   CreateTrigger(/*monitor_mode=*/false); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(0); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(0); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   // Trigger a suspicious site. We wait for this page load to finish before | 
 |   // creating the report. | 
 |   TriggerSuspiciousSite(); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   // Begin a brand new load before the first one is finished. This will cancel | 
 |   // the report that is queued. | 
 |   StartNewFakeLoad(); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   // Two page load start events, but only one finish. One suspicious site | 
 |   // detected but no reports created because the report gets cancelled. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 2); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0); | 
 |   ExpectNoReportRejection(); | 
 |  | 
 |   // Ensure that the repot got cancelled by the second load. | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::PENDING_REPORT_CANCELLED_BY_LOAD, 1); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, MonitorMode_NotSuspicious) { | 
 |   // Testing the trigger in monitoring mode, it should never send reports. | 
 |   // In a normal case where there are no suspicious URLs on the page, the | 
 |   // trigger should not fire. | 
 |   CreateTrigger(/*monitor_mode=*/true); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(0); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(0); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   // One page load start and finish. No suspicious sites and no reports sent. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0); | 
 |   ExpectNoReportRejection(); | 
 | } | 
 |  | 
 | TEST_F(SuspiciousSiteTriggerTest, MonitorMode_SuspiciousHitDuringLoad) { | 
 |   // Testing the trigger in monitoring mode, it should never send reports. | 
 |   // When a suspicious site is detected in the middle of a page load, a report | 
 |   // is created after the page load has finished. | 
 |   CreateTrigger(/*monitor_mode=*/true); | 
 |  | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _)) | 
 |       .Times(0); | 
 |   EXPECT_CALL(*get_trigger_manager(), | 
 |               FinishCollectingThreatDetails(_, _, _, _, _, _)) | 
 |       .Times(0); | 
 |  | 
 |   RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl); | 
 |   CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame); | 
 |   TriggerSuspiciousSite(); | 
 |   CreateAndNavigateSubFrame(kCleanUrl, main_frame); | 
 |   FinishAllNavigations(); | 
 |  | 
 |   WaitForTaskRunnerIdle(); | 
 |  | 
 |   // One page load start and finish. One suspicious site detected and one | 
 |   // possible report that gets skipped. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1); | 
 |   ExpectEventHistogramCount( | 
 |       SuspiciousSiteTriggerEvent::REPORT_POSSIBLE_BUT_SKIPPED, 1); | 
 |  | 
 |   // No reports are started or finished, no delay timer fired. | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 0); | 
 |   ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 0); | 
 |   ExpectNoReportRejection(); | 
 | } | 
 | }  // namespace safe_browsing |