Home | History | Annotate | Download | only in safe_browsing
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/command_line.h"
      6 #include "base/file_path.h"
      7 #include "base/memory/ref_counted.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/memory/scoped_temp_dir.h"
     10 #include "base/task.h"
     11 #include "chrome/browser/safe_browsing/client_side_detection_host.h"
     12 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
     13 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     14 #include "chrome/common/chrome_switches.h"
     15 #include "chrome/common/safe_browsing/csd.pb.h"
     16 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
     17 #include "chrome/test/testing_profile.h"
     18 #include "chrome/test/ui_test_utils.h"
     19 #include "content/browser/browser_thread.h"
     20 #include "content/browser/renderer_host/test_render_view_host.h"
     21 #include "content/browser/tab_contents/test_tab_contents.h"
     22 #include "googleurl/src/gurl.h"
     23 #include "ipc/ipc_test_sink.h"
     24 #include "testing/gmock/include/gmock/gmock.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 
     27 using ::testing::_;
     28 using ::testing::DeleteArg;
     29 using ::testing::DoAll;
     30 using ::testing::Eq;
     31 using ::testing::Mock;
     32 using ::testing::NiceMock;
     33 using ::testing::NotNull;
     34 using ::testing::Pointee;
     35 using ::testing::Return;
     36 using ::testing::SaveArg;
     37 using ::testing::SetArgumentPointee;
     38 using ::testing::StrictMock;
     39 
     40 namespace {
     41 const bool kFalse = false;
     42 const bool kTrue = true;
     43 }
     44 
     45 namespace safe_browsing {
     46 
     47 MATCHER_P(EqualsProto, other, "") {
     48   return other.SerializeAsString() == arg.SerializeAsString();
     49 }
     50 
     51 class MockClientSideDetectionService : public ClientSideDetectionService {
     52  public:
     53   explicit MockClientSideDetectionService(const FilePath& model_path)
     54       : ClientSideDetectionService(model_path, NULL) {}
     55   virtual ~MockClientSideDetectionService() {};
     56 
     57   MOCK_METHOD2(SendClientReportPhishingRequest,
     58                void(ClientPhishingRequest*,
     59                     ClientReportPhishingRequestCallback*));
     60   MOCK_CONST_METHOD1(IsPrivateIPAddress, bool(const std::string&));
     61   MOCK_METHOD2(GetValidCachedResult, bool(const GURL&, bool*));
     62   MOCK_METHOD1(IsInCache, bool(const GURL&));
     63   MOCK_METHOD0(OverReportLimit, bool());
     64 
     65  private:
     66   DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
     67 };
     68 
     69 class MockSafeBrowsingService : public SafeBrowsingService {
     70  public:
     71   MockSafeBrowsingService() {}
     72   virtual ~MockSafeBrowsingService() {}
     73 
     74   MOCK_METHOD8(DisplayBlockingPage,
     75                void(const GURL&, const GURL&, const std::vector<GURL>&,
     76                     ResourceType::Type, UrlCheckResult, Client*, int, int));
     77   MOCK_METHOD1(MatchCsdWhitelistUrl, bool(const GURL&));
     78 
     79   // Helper function which calls OnBlockingPageComplete for this client
     80   // object.
     81   void InvokeOnBlockingPageComplete(SafeBrowsingService::Client* client) {
     82     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     83     DCHECK(client);
     84     // Note: this will delete the client object in the case of the CsdClient
     85     // implementation.
     86     client->OnBlockingPageComplete(false);
     87   }
     88 
     89  private:
     90   DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService);
     91 };
     92 
     93 class MockTestingProfile : public TestingProfile {
     94  public:
     95   MockTestingProfile() {}
     96   virtual ~MockTestingProfile() {}
     97 
     98   MOCK_METHOD0(IsOffTheRecord, bool());
     99 };
    100 
    101 // Helper function which quits the UI message loop from the IO message loop.
    102 void QuitUIMessageLoop() {
    103   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    104   BrowserThread::PostTask(BrowserThread::UI,
    105                           FROM_HERE,
    106                           new MessageLoop::QuitTask());
    107 }
    108 
    109 class ClientSideDetectionHostTest : public RenderViewHostTestHarness {
    110  public:
    111   virtual void SetUp() {
    112     // Set custom profile object so that we can mock calls to IsOffTheRecord.
    113     // This needs to happen before we call the parent SetUp() function.  We use
    114     // a nice mock because other parts of the code are calling IsOffTheRecord.
    115     mock_profile_ = new NiceMock<MockTestingProfile>();
    116     profile_.reset(mock_profile_);
    117 
    118     RenderViewHostTestHarness::SetUp();
    119     ui_thread_.reset(new BrowserThread(BrowserThread::UI, &message_loop_));
    120     // Note: we're starting a real IO thread to make sure our DCHECKs that
    121     // verify which thread is running are actually tested.
    122     io_thread_.reset(new BrowserThread(BrowserThread::IO));
    123     ASSERT_TRUE(io_thread_->Start());
    124 
    125     // Inject service classes.
    126     ScopedTempDir tmp_dir;
    127     ASSERT_TRUE(tmp_dir.CreateUniqueTempDir());
    128     FilePath model_path = tmp_dir.path().AppendASCII("model");
    129 
    130     csd_service_.reset(new StrictMock<MockClientSideDetectionService>(
    131         model_path));
    132     sb_service_ = new StrictMock<MockSafeBrowsingService>();
    133     csd_host_ = contents()->safebrowsing_detection_host();
    134     csd_host_->set_client_side_detection_service(csd_service_.get());
    135     csd_host_->set_safe_browsing_service(sb_service_.get());
    136 
    137     // Save command-line so that it can be restored for every test.
    138     original_cmd_line_.reset(
    139         new CommandLine(*CommandLine::ForCurrentProcess()));
    140   }
    141 
    142   virtual void TearDown() {
    143     io_thread_.reset();
    144     ui_thread_.reset();
    145     RenderViewHostTestHarness::TearDown();
    146     // Restore the command-line like it was before we ran the test.
    147     *CommandLine::ForCurrentProcess() = *original_cmd_line_;
    148   }
    149 
    150   void OnDetectedPhishingSite(const std::string& verdict_str) {
    151     csd_host_->OnDetectedPhishingSite(verdict_str);
    152   }
    153 
    154   void FlushIOMessageLoop() {
    155     // If there was a message posted on the IO thread to display the
    156     // interstitial page we know that it would have been posted before
    157     // we put the quit message there.
    158     BrowserThread::PostTask(BrowserThread::IO,
    159                             FROM_HERE,
    160                             NewRunnableFunction(&QuitUIMessageLoop));
    161     MessageLoop::current()->Run();
    162   }
    163 
    164   void ExpectPreClassificationChecks(const GURL& url,
    165                                      const bool* is_private,
    166                                      const bool* is_incognito,
    167                                      const bool* match_csd_whitelist,
    168                                      const bool* get_valid_cached_result,
    169                                      const bool* is_in_cache,
    170                                      const bool* over_report_limit) {
    171     if (is_private) {
    172       EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
    173           .WillOnce(Return(*is_private));
    174     }
    175     if (is_incognito) {
    176       EXPECT_CALL(*mock_profile_, IsOffTheRecord())
    177           .WillRepeatedly(Return(*is_incognito));
    178     }
    179     if (match_csd_whitelist) {
    180       EXPECT_CALL(*sb_service_, MatchCsdWhitelistUrl(url))
    181           .WillOnce(Return(*match_csd_whitelist));
    182     }
    183     if (get_valid_cached_result) {
    184       EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull()))
    185           .WillOnce(DoAll(SetArgumentPointee<1>(true),
    186                           Return(*get_valid_cached_result)));
    187     }
    188     if (is_in_cache) {
    189       EXPECT_CALL(*csd_service_, IsInCache(url)).WillOnce(Return(*is_in_cache));
    190     }
    191     if (over_report_limit) {
    192       EXPECT_CALL(*csd_service_, OverReportLimit())
    193           .WillOnce(Return(*over_report_limit));
    194     }
    195   }
    196 
    197   void WaitAndCheckPreClassificationChecks() {
    198     // Wait for CheckCsdWhitelist to be called if at all.
    199     FlushIOMessageLoop();
    200     // Checks for CheckCache() to be called if at all.
    201     MessageLoop::current()->RunAllPending();
    202     EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    203     EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
    204     EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
    205   }
    206 
    207  protected:
    208   ClientSideDetectionHost* csd_host_;
    209   scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
    210   scoped_refptr<StrictMock<MockSafeBrowsingService> > sb_service_;
    211   MockTestingProfile* mock_profile_;  // We don't own this object
    212 
    213  private:
    214   scoped_ptr<BrowserThread> ui_thread_;
    215   scoped_ptr<BrowserThread> io_thread_;
    216   scoped_ptr<CommandLine> original_cmd_line_;
    217 };
    218 
    219 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteInvalidVerdict) {
    220   // Case 0: renderer sends an invalid verdict string that we're unable to
    221   // parse.
    222   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _)).Times(0);
    223   OnDetectedPhishingSite("Invalid Protocol Buffer");
    224   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    225 }
    226 
    227 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteNotPhishing) {
    228   // Case 1: client thinks the page is phishing.  The server does not agree.
    229   // No interstitial is shown.
    230   ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
    231   ClientPhishingRequest verdict;
    232   verdict.set_url("http://phishingurl.com/");
    233   verdict.set_client_score(1.0f);
    234   verdict.set_is_phishing(true);
    235 
    236   EXPECT_CALL(*csd_service_,
    237               SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
    238       .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
    239   OnDetectedPhishingSite(verdict.SerializeAsString());
    240   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    241   ASSERT_TRUE(cb);
    242 
    243   // Make sure DisplayBlockingPage is not going to be called.
    244   EXPECT_CALL(*sb_service_,
    245               DisplayBlockingPage(_, _, _, _, _, _, _, _)).Times(0);
    246   cb->Run(GURL(verdict.url()), false);
    247   delete cb;
    248   // If there was a message posted on the IO thread to display the
    249   // interstitial page we know that it would have been posted before
    250   // we put the quit message there.
    251   BrowserThread::PostTask(BrowserThread::IO,
    252                           FROM_HERE,
    253                           NewRunnableFunction(&QuitUIMessageLoop));
    254   MessageLoop::current()->Run();
    255   EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
    256 }
    257 
    258 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteDisabled) {
    259   // Case 2: client thinks the page is phishing and so does the server but
    260   // showing the interstitial is disabled => no interstitial is shown.
    261   ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
    262   ClientPhishingRequest verdict;
    263   verdict.set_url("http://phishingurl.com/");
    264   verdict.set_client_score(1.0f);
    265   verdict.set_is_phishing(true);
    266 
    267   EXPECT_CALL(*csd_service_,
    268               SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
    269       .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
    270   OnDetectedPhishingSite(verdict.SerializeAsString());
    271   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    272   ASSERT_TRUE(cb);
    273 
    274   // Make sure DisplayBlockingPage is not going to be called.
    275   EXPECT_CALL(*sb_service_,
    276               DisplayBlockingPage(_, _, _, _, _, _, _, _)).Times(0);
    277   cb->Run(GURL(verdict.url()), false);
    278   delete cb;
    279 
    280   FlushIOMessageLoop();
    281   EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
    282 }
    283 
    284 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteShowInterstitial) {
    285   // Case 3: client thinks the page is phishing and so does the server.
    286   // We show an interstitial.
    287   ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
    288   GURL phishing_url("http://phishingurl.com/");
    289   ClientPhishingRequest verdict;
    290   verdict.set_url(phishing_url.spec());
    291   verdict.set_client_score(1.0f);
    292   verdict.set_is_phishing(true);
    293 
    294   CommandLine::ForCurrentProcess()->AppendSwitch(
    295       switches::kEnableClientSidePhishingInterstitial);
    296 
    297   EXPECT_CALL(*csd_service_,
    298               SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
    299       .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
    300   OnDetectedPhishingSite(verdict.SerializeAsString());
    301   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    302   ASSERT_TRUE(cb);
    303 
    304   SafeBrowsingService::Client* client;
    305   EXPECT_CALL(*sb_service_,
    306               DisplayBlockingPage(
    307                   phishing_url,
    308                   phishing_url,
    309                   _,
    310                   ResourceType::MAIN_FRAME,
    311                   SafeBrowsingService::URL_PHISHING,
    312                   _ /* a CsdClient object */,
    313                   contents()->GetRenderProcessHost()->id(),
    314                   contents()->render_view_host()->routing_id()))
    315       .WillOnce(SaveArg<5>(&client));
    316 
    317   cb->Run(phishing_url, true);
    318   delete cb;
    319 
    320   FlushIOMessageLoop();
    321   EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
    322 
    323   // Make sure the client object will be deleted.
    324   BrowserThread::PostTask(
    325       BrowserThread::IO,
    326       FROM_HERE,
    327       NewRunnableMethod(
    328           sb_service_.get(),
    329           &MockSafeBrowsingService::InvokeOnBlockingPageComplete,
    330           client));
    331   // Since the CsdClient object will be deleted on the UI thread I need
    332   // to run the UI message loop.  Post a task to stop the UI message loop
    333   // after the client object destructor is called.
    334   FlushIOMessageLoop();
    335 }
    336 
    337 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteMultiplePings) {
    338   // Case 4 & 5: client thinks a page is phishing then navigates to
    339   // another page which is also considered phishing by the client
    340   // before the server responds with a verdict.  After a while the
    341   // server responds for both requests with a phishing verdict.  Only
    342   // a single interstitial is shown for the second URL.
    343   ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
    344   GURL phishing_url("http://phishingurl.com/");
    345   ClientPhishingRequest verdict;
    346   verdict.set_url(phishing_url.spec());
    347   verdict.set_client_score(1.0f);
    348   verdict.set_is_phishing(true);
    349 
    350   CommandLine::ForCurrentProcess()->AppendSwitch(
    351       switches::kEnableClientSidePhishingInterstitial);
    352 
    353   EXPECT_CALL(*csd_service_,
    354               SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
    355       .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
    356   OnDetectedPhishingSite(verdict.SerializeAsString());
    357   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    358   ASSERT_TRUE(cb);
    359   GURL other_phishing_url("http://other_phishing_url.com/bla");
    360   ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
    361                                 &kFalse, &kFalse, &kFalse);
    362   // We navigate away.  The callback cb should be revoked.
    363   NavigateAndCommit(other_phishing_url);
    364   // Wait for the pre-classification checks to finish for other_phishing_url.
    365   WaitAndCheckPreClassificationChecks();
    366 
    367   ClientSideDetectionService::ClientReportPhishingRequestCallback* cb_other;
    368   verdict.set_url(other_phishing_url.spec());
    369   verdict.set_client_score(0.8f);
    370   EXPECT_CALL(*csd_service_,
    371               SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
    372       .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb_other)));
    373   OnDetectedPhishingSite(verdict.SerializeAsString());
    374   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    375   ASSERT_TRUE(cb_other);
    376 
    377   // We expect that the interstitial is shown for the second phishing URL and
    378   // not for the first phishing URL.
    379   EXPECT_CALL(*sb_service_,
    380               DisplayBlockingPage(phishing_url, phishing_url,_, _, _, _, _, _))
    381       .Times(0);
    382   SafeBrowsingService::Client* client;
    383   EXPECT_CALL(*sb_service_,
    384               DisplayBlockingPage(
    385                   other_phishing_url,
    386                   other_phishing_url,
    387                   _,
    388                   ResourceType::MAIN_FRAME,
    389                   SafeBrowsingService::URL_PHISHING,
    390                   _ /* a CsdClient object */,
    391                   contents()->GetRenderProcessHost()->id(),
    392                   contents()->render_view_host()->routing_id()))
    393       .WillOnce(SaveArg<5>(&client));
    394 
    395   cb->Run(phishing_url, true);  // Should have no effect.
    396   delete cb;
    397   cb_other->Run(other_phishing_url, true);  // Should show interstitial.
    398   delete cb_other;
    399 
    400   FlushIOMessageLoop();
    401   EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
    402 
    403   // Make sure the client object will be deleted.
    404   BrowserThread::PostTask(
    405       BrowserThread::IO,
    406       FROM_HERE,
    407       NewRunnableMethod(
    408           sb_service_.get(),
    409           &MockSafeBrowsingService::InvokeOnBlockingPageComplete,
    410           client));
    411   // Since the CsdClient object will be deleted on the UI thread I need
    412   // to run the UI message loop.  Post a task to stop the UI message loop
    413   // after the client object destructor is called.
    414   FlushIOMessageLoop();
    415 }
    416 
    417 TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
    418   // Test that canceling pending should classify requests works as expected.
    419 
    420   GURL first_url("http://first.phishy.url.com");
    421   // The proxy checks is done synchronously so check that it has been done
    422   // for the first URL.
    423   ExpectPreClassificationChecks(first_url, &kFalse, &kFalse, &kFalse, NULL,
    424                                 NULL, NULL);
    425   NavigateAndCommit(first_url);
    426 
    427   // Don't flush the message loop, as we want to navigate to a different
    428   // url before the final pre-classification checks are run.
    429   GURL second_url("http://second.url.com/");
    430   ExpectPreClassificationChecks(second_url, &kFalse, &kFalse, &kFalse, &kFalse,
    431                                 &kFalse, &kFalse);
    432   NavigateAndCommit(second_url);
    433   WaitAndCheckPreClassificationChecks();
    434 }
    435 
    436 TEST_F(ClientSideDetectionHostTest, ShouldClassifyUrl) {
    437   // Navigate the tab to a page.  We should see a StartPhishingDetection IPC.
    438   GURL url("http://host.com/");
    439   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
    440                                 &kFalse, &kFalse);
    441   NavigateAndCommit(url);
    442   WaitAndCheckPreClassificationChecks();
    443 
    444   const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
    445       SafeBrowsingMsg_StartPhishingDetection::ID);
    446   ASSERT_TRUE(msg);
    447   Tuple1<GURL> actual_url;
    448   SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
    449   EXPECT_EQ(url, actual_url.a);
    450   EXPECT_EQ(rvh()->routing_id(), msg->routing_id());
    451   process()->sink().ClearMessages();
    452 
    453   // Now try an in-page navigation.  This should not trigger an IPC.
    454   EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0);
    455   url = GURL("http://host.com/#foo");
    456   ExpectPreClassificationChecks(url, NULL, NULL, NULL, NULL, NULL, NULL);
    457   NavigateAndCommit(url);
    458   WaitAndCheckPreClassificationChecks();
    459 
    460   msg = process()->sink().GetFirstMessageMatching(
    461       SafeBrowsingMsg_StartPhishingDetection::ID);
    462   ASSERT_FALSE(msg);
    463 
    464   // Check that XHTML is supported, in addition to the default HTML type.
    465   // Note: for this test to work correctly, the new URL must be on the
    466   // same domain as the previous URL, otherwise it will create a new
    467   // RenderViewHost that won't have the mime type set.
    468   url = GURL("http://host.com/xhtml");
    469   rvh()->set_contents_mime_type("application/xhtml+xml");
    470   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
    471                                 &kFalse, &kFalse);
    472   NavigateAndCommit(url);
    473   WaitAndCheckPreClassificationChecks();
    474   msg = process()->sink().GetFirstMessageMatching(
    475       SafeBrowsingMsg_StartPhishingDetection::ID);
    476   ASSERT_TRUE(msg);
    477   SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
    478   EXPECT_EQ(url, actual_url.a);
    479   EXPECT_EQ(rvh()->routing_id(), msg->routing_id());
    480   process()->sink().ClearMessages();
    481 
    482   // Navigate to a new host, which should cause another IPC.
    483   url = GURL("http://host2.com/");
    484   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
    485                                 &kFalse, &kFalse);
    486   NavigateAndCommit(url);
    487   WaitAndCheckPreClassificationChecks();
    488   msg = process()->sink().GetFirstMessageMatching(
    489       SafeBrowsingMsg_StartPhishingDetection::ID);
    490   ASSERT_TRUE(msg);
    491   SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
    492   EXPECT_EQ(url, actual_url.a);
    493   EXPECT_EQ(rvh()->routing_id(), msg->routing_id());
    494   process()->sink().ClearMessages();
    495 
    496   // If the mime type is not one that we support, no IPC should be triggered.
    497   // Note: for this test to work correctly, the new URL must be on the
    498   // same domain as the previous URL, otherwise it will create a new
    499   // RenderViewHost that won't have the mime type set.
    500   url = GURL("http://host2.com/image.jpg");
    501   rvh()->set_contents_mime_type("image/jpeg");
    502   ExpectPreClassificationChecks(url, NULL, NULL, NULL, NULL, NULL, NULL);
    503   NavigateAndCommit(url);
    504   WaitAndCheckPreClassificationChecks();
    505   msg = process()->sink().GetFirstMessageMatching(
    506       SafeBrowsingMsg_StartPhishingDetection::ID);
    507   ASSERT_FALSE(msg);
    508 
    509   // If IsPrivateIPAddress returns true, no IPC should be triggered.
    510   url = GURL("http://host3.com/");
    511   ExpectPreClassificationChecks(url, &kTrue, NULL, NULL, NULL, NULL, NULL);
    512   NavigateAndCommit(url);
    513   WaitAndCheckPreClassificationChecks();
    514   msg = process()->sink().GetFirstMessageMatching(
    515       SafeBrowsingMsg_StartPhishingDetection::ID);
    516   ASSERT_FALSE(msg);
    517 
    518   // If the connection is proxied, no IPC should be triggered.
    519   // Note: for this test to work correctly, the new URL must be on the
    520   // same domain as the previous URL, otherwise it will create a new
    521   // RenderViewHost that won't have simulate_fetch_via_proxy set.
    522   url = GURL("http://host3.com/abc");
    523   rvh()->set_simulate_fetch_via_proxy(true);
    524   ExpectPreClassificationChecks(url, NULL, NULL, NULL, NULL, NULL, NULL);
    525   NavigateAndCommit(url);
    526   WaitAndCheckPreClassificationChecks();
    527   msg = process()->sink().GetFirstMessageMatching(
    528       SafeBrowsingMsg_StartPhishingDetection::ID);
    529   ASSERT_FALSE(msg);
    530 
    531   // If the tab is incognito there should be no IPC.  Also, we shouldn't
    532   // even check the csd-whitelist.
    533   url = GURL("http://host4.com/");
    534   ExpectPreClassificationChecks(url, &kFalse, &kTrue, NULL, NULL, NULL, NULL);
    535   NavigateAndCommit(url);
    536   WaitAndCheckPreClassificationChecks();
    537   msg = process()->sink().GetFirstMessageMatching(
    538       SafeBrowsingMsg_StartPhishingDetection::ID);
    539   ASSERT_FALSE(msg);
    540 
    541   // If the URL is on the csd whitelist, no IPC should be triggered.
    542   url = GURL("http://host5.com/");
    543   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, NULL, NULL,
    544                                 NULL);
    545   NavigateAndCommit(url);
    546   WaitAndCheckPreClassificationChecks();
    547   msg = process()->sink().GetFirstMessageMatching(
    548       SafeBrowsingMsg_StartPhishingDetection::ID);
    549   ASSERT_FALSE(msg);
    550 
    551   // If item is in the cache but it isn't valid, we will classify regardless
    552   // of whether we are over the reporting limit.
    553   url = GURL("http://host6.com/");
    554   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue,
    555                                 NULL);
    556   NavigateAndCommit(url);
    557   WaitAndCheckPreClassificationChecks();
    558   msg = process()->sink().GetFirstMessageMatching(
    559       SafeBrowsingMsg_StartPhishingDetection::ID);
    560   ASSERT_TRUE(msg);
    561   SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
    562   EXPECT_EQ(url, actual_url.a);
    563   EXPECT_EQ(rvh()->routing_id(), msg->routing_id());
    564   process()->sink().ClearMessages();
    565 
    566   // If the url isn't in the cache and we are over the reporting limit, we
    567   // don't do classification.
    568   url = GURL("http://host7.com/");
    569   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
    570                                 &kFalse, &kTrue);
    571   NavigateAndCommit(url);
    572   WaitAndCheckPreClassificationChecks();
    573   msg = process()->sink().GetFirstMessageMatching(
    574       SafeBrowsingMsg_StartPhishingDetection::ID);
    575   ASSERT_FALSE(msg);
    576 
    577   // If result is cached, we will try and display the blocking page directly
    578   // with no start classification message.
    579   CommandLine::ForCurrentProcess()->AppendSwitch(
    580       switches::kEnableClientSidePhishingInterstitial);
    581   url = GURL("http://host8.com/");
    582   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, NULL,
    583                                 NULL);
    584   EXPECT_CALL(*sb_service_,
    585               DisplayBlockingPage(Eq(url), Eq(url), _, _, _, _, _, _))
    586       .WillOnce(DeleteArg<5>());
    587   NavigateAndCommit(url);
    588   // Wait for CheckCsdWhitelist to be called on the IO thread.
    589   FlushIOMessageLoop();
    590   // Wait for CheckCache() to be called on the UI thread.
    591   MessageLoop::current()->RunAllPending();
    592   // Wait for DisplayBlockingPage to be called on the IO thread.
    593   FlushIOMessageLoop();
    594   // Now we check that all expected functions were indeed called on the two
    595   // service objects.
    596   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
    597   EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
    598   msg = process()->sink().GetFirstMessageMatching(
    599       SafeBrowsingMsg_StartPhishingDetection::ID);
    600   ASSERT_FALSE(msg);
    601 }
    602 
    603 }  // namespace safe_browsing
    604