Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / client_side_detection_host_unittest.cc
blobd6f20d68449d145f9cffd6097e16d607732134aa
1 // Copyright (c) 2012 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.
5 #include "base/files/file_path.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "chrome/browser/safe_browsing/browser_feature_extractor.h"
12 #include "chrome/browser/safe_browsing/client_side_detection_host.h"
13 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
14 #include "chrome/browser/safe_browsing/database_manager.h"
15 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
16 #include "chrome/browser/safe_browsing/ui_manager.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/safe_browsing/csd.pb.h"
19 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
20 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/mock_render_process_host.h"
25 #include "content/public/test/test_browser_thread.h"
26 #include "content/public/test/test_renderer_host.h"
27 #include "content/public/test/web_contents_tester.h"
28 #include "ipc/ipc_test_sink.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "url/gurl.h"
33 using ::testing::_;
34 using ::testing::DeleteArg;
35 using ::testing::DoAll;
36 using ::testing::Eq;
37 using ::testing::IsNull;
38 using ::testing::Mock;
39 using ::testing::NiceMock;
40 using ::testing::NotNull;
41 using ::testing::Pointee;
42 using ::testing::Return;
43 using ::testing::SaveArg;
44 using ::testing::SetArgumentPointee;
45 using ::testing::StrictMock;
46 using content::BrowserThread;
47 using content::RenderFrameHostTester;
48 using content::ResourceType;
49 using content::WebContents;
51 namespace {
53 const bool kFalse = false;
54 const bool kTrue = true;
56 } // namespace
58 namespace safe_browsing {
59 namespace {
60 // This matcher verifies that the client computed verdict
61 // (ClientPhishingRequest) which is passed to SendClientReportPhishingRequest
62 // has the expected fields set. Note: we can't simply compare the protocol
63 // buffer strings because the BrowserFeatureExtractor might add features to the
64 // verdict object before calling SendClientReportPhishingRequest.
65 MATCHER_P(PartiallyEqualVerdict, other, "") {
66 return (other.url() == arg.url() &&
67 other.client_score() == arg.client_score() &&
68 other.is_phishing() == arg.is_phishing());
71 MATCHER_P(PartiallyEqualMalwareVerdict, other, "") {
72 if (other.url() != arg.url() ||
73 other.referrer_url() != arg.referrer_url() ||
74 other.bad_ip_url_info_size() != arg.bad_ip_url_info_size())
75 return false;
77 for (int i = 0; i < other.bad_ip_url_info_size(); ++i) {
78 if (other.bad_ip_url_info(i).ip() != arg.bad_ip_url_info(i).ip() ||
79 other.bad_ip_url_info(i).url() != arg.bad_ip_url_info(i).url())
80 return false;
82 return true;
85 // Test that the callback is NULL when the verdict is not phishing.
86 MATCHER(CallbackIsNull, "") {
87 return arg.is_null();
90 ACTION(QuitUIMessageLoop) {
91 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
92 base::MessageLoopForUI::current()->Quit();
95 ACTION_P(InvokeDoneCallback, verdict) {
96 scoped_ptr<ClientPhishingRequest> request(::std::tr1::get<1>(args));
97 request->CopyFrom(*verdict);
98 ::std::tr1::get<2>(args).Run(true, request.Pass());
101 ACTION_P(InvokeMalwareCallback, verdict) {
102 scoped_ptr<ClientMalwareRequest> request(::std::tr1::get<1>(args));
103 request->CopyFrom(*verdict);
104 ::std::tr1::get<2>(args).Run(true, request.Pass());
107 void EmptyUrlCheckCallback(bool processed) {
110 class MockClientSideDetectionService : public ClientSideDetectionService {
111 public:
112 MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
113 virtual ~MockClientSideDetectionService() {}
115 MOCK_METHOD2(SendClientReportPhishingRequest,
116 void(ClientPhishingRequest*,
117 const ClientReportPhishingRequestCallback&));
118 MOCK_METHOD2(SendClientReportMalwareRequest,
119 void(ClientMalwareRequest*,
120 const ClientReportMalwareRequestCallback&));
121 MOCK_CONST_METHOD1(IsPrivateIPAddress, bool(const std::string&));
122 MOCK_METHOD2(GetValidCachedResult, bool(const GURL&, bool*));
123 MOCK_METHOD1(IsInCache, bool(const GURL&));
124 MOCK_METHOD0(OverPhishingReportLimit, bool());
125 MOCK_METHOD0(OverMalwareReportLimit, bool());
127 private:
128 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
131 class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
132 public:
133 explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
134 : SafeBrowsingUIManager(service) { }
136 MOCK_METHOD1(DisplayBlockingPage, void(const UnsafeResource& resource));
138 // Helper function which calls OnBlockingPageComplete for this client
139 // object.
140 void InvokeOnBlockingPageComplete(const UrlCheckCallback& callback) {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142 // Note: this will delete the client object in the case of the CsdClient
143 // implementation.
144 if (!callback.is_null())
145 callback.Run(false);
148 protected:
149 virtual ~MockSafeBrowsingUIManager() { }
151 private:
152 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
155 class MockSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
156 public:
157 explicit MockSafeBrowsingDatabaseManager(SafeBrowsingService* service)
158 : SafeBrowsingDatabaseManager(service) { }
160 MOCK_METHOD1(MatchCsdWhitelistUrl, bool(const GURL&));
161 MOCK_METHOD1(MatchMalwareIP, bool(const std::string& ip_address));
162 MOCK_METHOD0(IsMalwareKillSwitchOn, bool());
164 protected:
165 virtual ~MockSafeBrowsingDatabaseManager() {}
167 private:
168 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
171 class MockTestingProfile : public TestingProfile {
172 public:
173 MockTestingProfile() {}
174 virtual ~MockTestingProfile() {}
176 MOCK_CONST_METHOD0(IsOffTheRecord, bool());
179 class MockBrowserFeatureExtractor : public BrowserFeatureExtractor {
180 public:
181 explicit MockBrowserFeatureExtractor(
182 WebContents* tab,
183 ClientSideDetectionHost* host)
184 : BrowserFeatureExtractor(tab, host) {}
185 virtual ~MockBrowserFeatureExtractor() {}
187 MOCK_METHOD3(ExtractFeatures,
188 void(const BrowseInfo*,
189 ClientPhishingRequest*,
190 const BrowserFeatureExtractor::DoneCallback&));
192 MOCK_METHOD3(ExtractMalwareFeatures,
193 void(BrowseInfo*,
194 ClientMalwareRequest*,
195 const BrowserFeatureExtractor::MalwareDoneCallback&));
198 } // namespace
200 class ClientSideDetectionHostTest : public ChromeRenderViewHostTestHarness {
201 public:
202 typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
204 void SetUp() override {
205 ChromeRenderViewHostTestHarness::SetUp();
207 // Inject service classes.
208 csd_service_.reset(new StrictMock<MockClientSideDetectionService>());
209 // Only used for initializing mock objects.
210 SafeBrowsingService* sb_service =
211 SafeBrowsingService::CreateSafeBrowsingService();
212 database_manager_ =
213 new StrictMock<MockSafeBrowsingDatabaseManager>(sb_service);
214 ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>(sb_service);
215 csd_host_.reset(safe_browsing::ClientSideDetectionHost::Create(
216 web_contents()));
217 csd_host_->set_client_side_detection_service(csd_service_.get());
218 csd_host_->set_safe_browsing_managers(ui_manager_.get(),
219 database_manager_.get());
220 // We need to create this here since we don't call DidStopLanding in
221 // this test.
222 csd_host_->browse_info_.reset(new BrowseInfo);
225 void TearDown() override {
226 // Delete the host object on the UI thread and release the
227 // SafeBrowsingService.
228 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
229 csd_host_.release());
230 database_manager_ = NULL;
231 ui_manager_ = NULL;
232 base::RunLoop().RunUntilIdle();
233 ChromeRenderViewHostTestHarness::TearDown();
236 content::BrowserContext* CreateBrowserContext() override {
237 // Set custom profile object so that we can mock calls to IsOffTheRecord.
238 // This needs to happen before we call the parent SetUp() function. We use
239 // a nice mock because other parts of the code are calling IsOffTheRecord.
240 mock_profile_ = new NiceMock<MockTestingProfile>();
241 return mock_profile_;
244 void OnPhishingDetectionDone(const std::string& verdict_str) {
245 csd_host_->OnPhishingDetectionDone(verdict_str);
248 void DidStopLoading() { csd_host_->DidStopLoading(); }
250 void UpdateIPUrlMap(const std::string& ip, const std::string& host) {
251 csd_host_->UpdateIPUrlMap(ip, host, "", "", content::RESOURCE_TYPE_OBJECT);
254 BrowseInfo* GetBrowseInfo() {
255 return csd_host_->browse_info_.get();
258 void ExpectPreClassificationChecks(const GURL& url,
259 const bool* is_private,
260 const bool* is_incognito,
261 const bool* match_csd_whitelist,
262 const bool* malware_killswitch,
263 const bool* get_valid_cached_result,
264 const bool* is_in_cache,
265 const bool* over_phishing_report_limit,
266 const bool* over_malware_report_limit) {
267 if (is_private) {
268 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
269 .WillOnce(Return(*is_private));
271 if (is_incognito) {
272 EXPECT_CALL(*mock_profile_, IsOffTheRecord())
273 .WillRepeatedly(Return(*is_incognito));
275 if (match_csd_whitelist) {
276 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(url))
277 .WillOnce(Return(*match_csd_whitelist));
279 if (malware_killswitch) {
280 EXPECT_CALL(*database_manager_.get(), IsMalwareKillSwitchOn())
281 .WillRepeatedly(Return(*malware_killswitch));
283 if (get_valid_cached_result) {
284 EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull()))
285 .WillOnce(DoAll(SetArgumentPointee<1>(true),
286 Return(*get_valid_cached_result)));
288 if (is_in_cache) {
289 EXPECT_CALL(*csd_service_, IsInCache(url)).WillOnce(Return(*is_in_cache));
291 if (over_phishing_report_limit) {
292 EXPECT_CALL(*csd_service_, OverPhishingReportLimit())
293 .WillOnce(Return(*over_phishing_report_limit));
295 if (over_malware_report_limit) {
296 EXPECT_CALL(*csd_service_, OverMalwareReportLimit())
297 .WillOnce(Return(*over_malware_report_limit));
301 void WaitAndCheckPreClassificationChecks() {
302 // Wait for CheckCsdWhitelist and CheckCache() to be called if at all.
303 base::RunLoop().RunUntilIdle();
304 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
305 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
306 EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get()));
307 EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
310 void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
311 csd_host_->feature_extractor_.reset(extractor);
314 void SetRedirectChain(const std::vector<GURL>& redirect_chain) {
315 csd_host_->browse_info_->url_redirects = redirect_chain;
318 void SetReferrer(const GURL& referrer) {
319 csd_host_->browse_info_->referrer = referrer;
322 void ExpectShouldClassifyForMalwareResult(bool should_classify) {
323 EXPECT_EQ(should_classify, csd_host_->should_classify_for_malware_);
326 void ExpectStartPhishingDetection(const GURL* url) {
327 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
328 SafeBrowsingMsg_StartPhishingDetection::ID);
329 if (url) {
330 ASSERT_TRUE(msg);
331 Tuple<GURL> actual_url;
332 SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
333 EXPECT_EQ(*url, get<0>(actual_url));
334 EXPECT_EQ(rvh()->GetRoutingID(), msg->routing_id());
335 process()->sink().ClearMessages();
336 } else {
337 ASSERT_FALSE(msg);
341 void TestUnsafeResourceCopied(const UnsafeResource& resource) {
342 ASSERT_TRUE(csd_host_->unsafe_resource_.get());
343 // Test that the resource from OnSafeBrowsingHit notification was copied
344 // into the CSDH.
345 EXPECT_EQ(resource.url, csd_host_->unsafe_resource_->url);
346 EXPECT_EQ(resource.original_url, csd_host_->unsafe_resource_->original_url);
347 EXPECT_EQ(resource.is_subresource,
348 csd_host_->unsafe_resource_->is_subresource);
349 EXPECT_EQ(resource.threat_type, csd_host_->unsafe_resource_->threat_type);
350 EXPECT_TRUE(csd_host_->unsafe_resource_->callback.is_null());
351 EXPECT_EQ(resource.render_process_host_id,
352 csd_host_->unsafe_resource_->render_process_host_id);
353 EXPECT_EQ(resource.render_view_id,
354 csd_host_->unsafe_resource_->render_view_id);
357 void SetUnsafeSubResourceForCurrent() {
358 UnsafeResource resource;
359 resource.url = GURL("http://www.malware.com/");
360 resource.original_url = web_contents()->GetURL();
361 resource.is_subresource = true;
362 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
363 resource.callback = base::Bind(&EmptyUrlCheckCallback);
364 resource.render_process_host_id = web_contents()->GetRenderProcessHost()->
365 GetID();
366 resource.render_view_id =
367 web_contents()->GetRenderViewHost()->GetRoutingID();
368 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
369 csd_host_->OnSafeBrowsingMatch(resource);
370 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
371 csd_host_->OnSafeBrowsingHit(resource);
372 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
373 resource.callback.Reset();
374 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
375 TestUnsafeResourceCopied(resource);
378 void NavigateWithSBHitAndCommit(const GURL& url) {
379 // Create a pending navigation.
380 controller().LoadURL(
381 url, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
383 ASSERT_TRUE(pending_rvh());
384 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
385 pending_rvh()->GetProcess()->GetID()) {
386 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
387 pending_rvh()->GetRoutingID());
390 // Simulate a safebrowsing hit before navigation completes.
391 UnsafeResource resource;
392 resource.url = url;
393 resource.original_url = url;
394 resource.is_subresource = false;
395 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
396 resource.callback = base::Bind(&EmptyUrlCheckCallback);
397 resource.render_process_host_id = pending_rvh()->GetProcess()->GetID();
398 resource.render_view_id = pending_rvh()->GetRoutingID();
399 csd_host_->OnSafeBrowsingMatch(resource);
400 csd_host_->OnSafeBrowsingHit(resource);
401 resource.callback.Reset();
403 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
405 // LoadURL created a navigation entry, now simulate the RenderView sending
406 // a notification that it actually navigated.
407 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
409 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
410 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
411 TestUnsafeResourceCopied(resource);
414 void NavigateWithoutSBHitAndCommit(const GURL& safe_url) {
415 controller().LoadURL(
416 safe_url, content::Referrer(), ui::PAGE_TRANSITION_LINK,
417 std::string());
419 ASSERT_TRUE(pending_rvh());
420 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
421 pending_rvh()->GetProcess()->GetID()) {
422 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
423 pending_rvh()->GetRoutingID());
425 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
426 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
428 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
429 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
430 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
433 void CheckIPUrlEqual(const std::vector<IPUrlInfo>& expect,
434 const std::vector<IPUrlInfo>& result) {
435 ASSERT_EQ(expect.size(), result.size());
437 for (unsigned int i = 0; i < expect.size(); ++i) {
438 EXPECT_EQ(expect[i].url, result[i].url);
439 EXPECT_EQ(expect[i].method, result[i].method);
440 EXPECT_EQ(expect[i].referrer, result[i].referrer);
441 EXPECT_EQ(expect[i].resource_type, result[i].resource_type);
445 protected:
446 scoped_ptr<ClientSideDetectionHost> csd_host_;
447 scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
448 scoped_refptr<StrictMock<MockSafeBrowsingUIManager> > ui_manager_;
449 scoped_refptr<StrictMock<MockSafeBrowsingDatabaseManager> > database_manager_;
450 MockTestingProfile* mock_profile_; // We don't own this object
453 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneInvalidVerdict) {
454 // Case 0: renderer sends an invalid verdict string that we're unable to
455 // parse.
456 MockBrowserFeatureExtractor* mock_extractor =
457 new StrictMock<MockBrowserFeatureExtractor>(
458 web_contents(),
459 csd_host_.get());
460 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
461 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
462 OnPhishingDetectionDone("Invalid Protocol Buffer");
463 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
466 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneNotPhishing) {
467 // Case 1: client thinks the page is phishing. The server does not agree.
468 // No interstitial is shown.
469 MockBrowserFeatureExtractor* mock_extractor =
470 new StrictMock<MockBrowserFeatureExtractor>(
471 web_contents(),
472 csd_host_.get());
473 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
475 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
476 ClientPhishingRequest verdict;
477 verdict.set_url("http://phishingurl.com/");
478 verdict.set_client_score(1.0f);
479 verdict.set_is_phishing(true);
481 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
482 .WillOnce(InvokeDoneCallback(&verdict));
483 EXPECT_CALL(*csd_service_,
484 SendClientReportPhishingRequest(
485 Pointee(PartiallyEqualVerdict(verdict)), _))
486 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
487 OnPhishingDetectionDone(verdict.SerializeAsString());
488 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
489 ASSERT_FALSE(cb.is_null());
491 // Make sure DisplayBlockingPage is not going to be called.
492 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
493 cb.Run(GURL(verdict.url()), false);
494 base::RunLoop().RunUntilIdle();
495 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
498 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneDisabled) {
499 // Case 2: client thinks the page is phishing and so does the server but
500 // showing the interstitial is disabled => no interstitial is shown.
501 MockBrowserFeatureExtractor* mock_extractor =
502 new StrictMock<MockBrowserFeatureExtractor>(
503 web_contents(),
504 csd_host_.get());
505 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
507 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
508 ClientPhishingRequest verdict;
509 verdict.set_url("http://phishingurl.com/");
510 verdict.set_client_score(1.0f);
511 verdict.set_is_phishing(true);
513 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
514 .WillOnce(InvokeDoneCallback(&verdict));
515 EXPECT_CALL(*csd_service_,
516 SendClientReportPhishingRequest(
517 Pointee(PartiallyEqualVerdict(verdict)), _))
518 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
519 OnPhishingDetectionDone(verdict.SerializeAsString());
520 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
521 ASSERT_FALSE(cb.is_null());
523 // Make sure DisplayBlockingPage is not going to be called.
524 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
525 cb.Run(GURL(verdict.url()), false);
526 base::RunLoop().RunUntilIdle();
527 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
530 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneShowInterstitial) {
531 // Case 3: client thinks the page is phishing and so does the server.
532 // We show an interstitial.
533 MockBrowserFeatureExtractor* mock_extractor =
534 new StrictMock<MockBrowserFeatureExtractor>(
535 web_contents(),
536 csd_host_.get());
537 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
539 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
540 GURL phishing_url("http://phishingurl.com/");
541 ClientPhishingRequest verdict;
542 verdict.set_url(phishing_url.spec());
543 verdict.set_client_score(1.0f);
544 verdict.set_is_phishing(true);
546 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
547 .WillOnce(InvokeDoneCallback(&verdict));
548 EXPECT_CALL(*csd_service_,
549 SendClientReportPhishingRequest(
550 Pointee(PartiallyEqualVerdict(verdict)), _))
551 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
552 OnPhishingDetectionDone(verdict.SerializeAsString());
553 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
554 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
555 ASSERT_FALSE(cb.is_null());
557 UnsafeResource resource;
558 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
559 .WillOnce(SaveArg<0>(&resource));
560 cb.Run(phishing_url, true);
562 base::RunLoop().RunUntilIdle();
563 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
564 EXPECT_EQ(phishing_url, resource.url);
565 EXPECT_EQ(phishing_url, resource.original_url);
566 EXPECT_FALSE(resource.is_subresource);
567 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
568 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
569 resource.render_process_host_id);
570 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
571 resource.render_view_id);
573 // Make sure the client object will be deleted.
574 BrowserThread::PostTask(
575 BrowserThread::IO,
576 FROM_HERE,
577 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
578 ui_manager_, resource.callback));
581 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneMultiplePings) {
582 // Case 4 & 5: client thinks a page is phishing then navigates to
583 // another page which is also considered phishing by the client
584 // before the server responds with a verdict. After a while the
585 // server responds for both requests with a phishing verdict. Only
586 // a single interstitial is shown for the second URL.
587 MockBrowserFeatureExtractor* mock_extractor =
588 new StrictMock<MockBrowserFeatureExtractor>(
589 web_contents(),
590 csd_host_.get());
591 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
593 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
594 GURL phishing_url("http://phishingurl.com/");
595 ClientPhishingRequest verdict;
596 verdict.set_url(phishing_url.spec());
597 verdict.set_client_score(1.0f);
598 verdict.set_is_phishing(true);
600 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
601 .WillOnce(InvokeDoneCallback(&verdict));
602 EXPECT_CALL(*csd_service_,
603 SendClientReportPhishingRequest(
604 Pointee(PartiallyEqualVerdict(verdict)), _))
605 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
606 OnPhishingDetectionDone(verdict.SerializeAsString());
607 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
608 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
609 ASSERT_FALSE(cb.is_null());
611 // Set this back to a normal browser feature extractor since we're using
612 // NavigateAndCommit() and it's easier to use the real thing than setting up
613 // mock expectations.
614 SetFeatureExtractor(new BrowserFeatureExtractor(web_contents(),
615 csd_host_.get()));
616 GURL other_phishing_url("http://other_phishing_url.com/bla");
617 ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
618 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse);
619 // We navigate away. The callback cb should be revoked.
620 NavigateAndCommit(other_phishing_url);
621 // Wait for the pre-classification checks to finish for other_phishing_url.
622 WaitAndCheckPreClassificationChecks();
624 ClientSideDetectionService::ClientReportPhishingRequestCallback cb_other;
625 verdict.set_url(other_phishing_url.spec());
626 verdict.set_client_score(0.8f);
627 EXPECT_CALL(*csd_service_,
628 SendClientReportPhishingRequest(
629 Pointee(PartiallyEqualVerdict(verdict)), _))
630 .WillOnce(DoAll(DeleteArg<0>(),
631 SaveArg<1>(&cb_other),
632 QuitUIMessageLoop()));
633 std::vector<GURL> redirect_chain;
634 redirect_chain.push_back(other_phishing_url);
635 SetRedirectChain(redirect_chain);
636 OnPhishingDetectionDone(verdict.SerializeAsString());
637 base::MessageLoop::current()->Run();
638 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
639 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
640 ASSERT_FALSE(cb_other.is_null());
642 // We expect that the interstitial is shown for the second phishing URL and
643 // not for the first phishing URL.
644 UnsafeResource resource;
645 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
646 .WillOnce(SaveArg<0>(&resource));
648 cb.Run(phishing_url, true); // Should have no effect.
649 cb_other.Run(other_phishing_url, true); // Should show interstitial.
651 base::RunLoop().RunUntilIdle();
652 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
653 EXPECT_EQ(other_phishing_url, resource.url);
654 EXPECT_EQ(other_phishing_url, resource.original_url);
655 EXPECT_FALSE(resource.is_subresource);
656 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
657 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
658 resource.render_process_host_id);
659 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
660 resource.render_view_id);
662 // Make sure the client object will be deleted.
663 BrowserThread::PostTask(
664 BrowserThread::IO,
665 FROM_HERE,
666 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
667 ui_manager_, resource.callback));
670 TEST_F(ClientSideDetectionHostTest,
671 OnPhishingDetectionDoneVerdictNotPhishing) {
672 // Case 6: renderer sends a verdict string that isn't phishing.
673 MockBrowserFeatureExtractor* mock_extractor =
674 new StrictMock<MockBrowserFeatureExtractor>(
675 web_contents(),
676 csd_host_.get());
677 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
679 ClientPhishingRequest verdict;
680 verdict.set_url("http://not-phishing.com/");
681 verdict.set_client_score(0.1f);
682 verdict.set_is_phishing(false);
684 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
685 OnPhishingDetectionDone(verdict.SerializeAsString());
686 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
689 TEST_F(ClientSideDetectionHostTest,
690 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchSubResource) {
691 // Case 7: renderer sends a verdict string that isn't phishing but the URL
692 // of a subresource was on the regular phishing or malware lists.
693 GURL url("http://not-phishing.com/");
694 ClientPhishingRequest verdict;
695 verdict.set_url(url.spec());
696 verdict.set_client_score(0.1f);
697 verdict.set_is_phishing(false);
699 // First we have to navigate to the URL to set the unique page ID.
700 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
701 &kFalse, &kFalse, &kFalse, &kFalse);
702 NavigateAndCommit(url);
703 WaitAndCheckPreClassificationChecks();
704 SetUnsafeSubResourceForCurrent();
706 EXPECT_CALL(*csd_service_,
707 SendClientReportPhishingRequest(
708 Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
709 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
710 std::vector<GURL> redirect_chain;
711 redirect_chain.push_back(url);
712 SetRedirectChain(redirect_chain);
713 OnPhishingDetectionDone(verdict.SerializeAsString());
714 base::MessageLoop::current()->Run();
715 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
718 TEST_F(ClientSideDetectionHostTest,
719 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchOnNewRVH) {
720 // When navigating to a different host (thus creating a pending RVH) which
721 // matches regular malware list, and after navigation the renderer sends a
722 // verdict string that isn't phishing, we should still send the report.
724 // Do an initial navigation to a safe host.
725 GURL start_url("http://safe.example.com/");
726 ExpectPreClassificationChecks(
727 start_url, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
728 &kFalse);
729 NavigateAndCommit(start_url);
730 WaitAndCheckPreClassificationChecks();
732 // Now navigate to a different host which will have a malware hit before the
733 // navigation commits.
734 GURL url("http://malware-but-not-phishing.com/");
735 ClientPhishingRequest verdict;
736 verdict.set_url(url.spec());
737 verdict.set_client_score(0.1f);
738 verdict.set_is_phishing(false);
740 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
741 &kFalse, &kFalse, &kFalse, &kFalse);
742 NavigateWithSBHitAndCommit(url);
743 WaitAndCheckPreClassificationChecks();
745 EXPECT_CALL(*csd_service_,
746 SendClientReportPhishingRequest(
747 Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
748 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
749 std::vector<GURL> redirect_chain;
750 redirect_chain.push_back(url);
751 SetRedirectChain(redirect_chain);
752 OnPhishingDetectionDone(verdict.SerializeAsString());
753 base::MessageLoop::current()->Run();
754 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
756 ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse,
757 &kFalse, &kFalse, &kFalse, &kFalse);
758 NavigateWithoutSBHitAndCommit(start_url);
759 WaitAndCheckPreClassificationChecks();
762 TEST_F(ClientSideDetectionHostTest,
763 DidStopLoadingShowMalwareInterstitial) {
764 // Case 9: client thinks the page match malware IP and so does the server.
765 // We show an sub-resource malware interstitial.
766 MockBrowserFeatureExtractor* mock_extractor =
767 new StrictMock<MockBrowserFeatureExtractor>(
768 web_contents(),
769 csd_host_.get());
770 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
772 GURL malware_landing_url("http://malware.com/");
773 GURL malware_ip_url("http://badip.com");
774 ClientMalwareRequest malware_verdict;
775 malware_verdict.set_url("http://malware.com/");
776 ClientMalwareRequest::UrlInfo* badipurl =
777 malware_verdict.add_bad_ip_url_info();
778 badipurl->set_ip("1.2.3.4");
779 badipurl->set_url("http://badip.com");
781 ExpectPreClassificationChecks(GURL(malware_verdict.url()), &kFalse, &kFalse,
782 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
783 &kFalse);
784 NavigateAndCommit(GURL(malware_verdict.url()));
785 WaitAndCheckPreClassificationChecks();
787 ClientSideDetectionService::ClientReportMalwareRequestCallback cb;
788 EXPECT_CALL(*mock_extractor, ExtractMalwareFeatures(_, _, _))
789 .WillOnce(InvokeMalwareCallback(&malware_verdict));
790 EXPECT_CALL(*csd_service_,
791 SendClientReportMalwareRequest(
792 Pointee(PartiallyEqualMalwareVerdict(malware_verdict)), _))
793 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
794 DidStopLoading();
795 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
796 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
797 ASSERT_FALSE(cb.is_null());
799 UnsafeResource resource;
800 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
801 .WillOnce(SaveArg<0>(&resource));
802 cb.Run(malware_landing_url, malware_ip_url, true);
804 base::RunLoop().RunUntilIdle();
805 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
806 EXPECT_EQ(malware_ip_url, resource.url);
807 EXPECT_EQ(malware_landing_url, resource.original_url);
808 EXPECT_TRUE(resource.is_subresource);
809 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL, resource.threat_type);
810 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
811 resource.render_process_host_id);
812 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
813 resource.render_view_id);
815 // Make sure the client object will be deleted.
816 BrowserThread::PostTask(
817 BrowserThread::IO,
818 FROM_HERE,
819 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
820 ui_manager_, resource.callback));
823 TEST_F(ClientSideDetectionHostTest, UpdateIPUrlMap) {
824 BrowseInfo* browse_info = GetBrowseInfo();
826 // Empty IP or host are skipped
827 UpdateIPUrlMap("250.10.10.10", std::string());
828 ASSERT_EQ(0U, browse_info->ips.size());
829 UpdateIPUrlMap(std::string(), "http://google.com/a");
830 ASSERT_EQ(0U, browse_info->ips.size());
831 UpdateIPUrlMap(std::string(), std::string());
832 ASSERT_EQ(0U, browse_info->ips.size());
834 std::vector<IPUrlInfo> expected_urls;
835 for (int i = 0; i < 20; i++) {
836 std::string url = base::StringPrintf("http://%d.com/", i);
837 expected_urls.push_back(
838 IPUrlInfo(url, "", "", content::RESOURCE_TYPE_OBJECT));
839 UpdateIPUrlMap("250.10.10.10", url);
841 ASSERT_EQ(1U, browse_info->ips.size());
842 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
843 CheckIPUrlEqual(expected_urls,
844 browse_info->ips["250.10.10.10"]);
846 // Add more urls for this ip, it exceeds max limit and won't be added
847 UpdateIPUrlMap("250.10.10.10", "http://21.com/");
848 ASSERT_EQ(1U, browse_info->ips.size());
849 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
850 CheckIPUrlEqual(expected_urls,
851 browse_info->ips["250.10.10.10"]);
853 // Add 199 more IPs
854 for (int i = 0; i < 199; i++) {
855 std::string ip = base::StringPrintf("%d.%d.%d.256", i, i, i);
856 expected_urls.clear();
857 expected_urls.push_back(
858 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT));
859 UpdateIPUrlMap(ip, "test.com/");
860 ASSERT_EQ(1U, browse_info->ips[ip].size());
861 CheckIPUrlEqual(expected_urls,
862 browse_info->ips[ip]);
864 ASSERT_EQ(200U, browse_info->ips.size());
866 // Exceeding max ip limit 200, these won't be added
867 UpdateIPUrlMap("250.250.250.250", "goo.com/");
868 UpdateIPUrlMap("250.250.250.250", "bar.com/");
869 UpdateIPUrlMap("250.250.0.250", "foo.com/");
870 ASSERT_EQ(200U, browse_info->ips.size());
872 // Add url to existing IPs succeed
873 UpdateIPUrlMap("100.100.100.256", "more.com/");
874 ASSERT_EQ(2U, browse_info->ips["100.100.100.256"].size());
875 expected_urls.clear();
876 expected_urls.push_back(
877 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT));
878 expected_urls.push_back(
879 IPUrlInfo("more.com/", "", "", content::RESOURCE_TYPE_OBJECT));
880 CheckIPUrlEqual(expected_urls,
881 browse_info->ips["100.100.100.256"]);
884 TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
885 // Test that canceling pending should classify requests works as expected.
887 GURL first_url("http://first.phishy.url.com");
888 GURL second_url("http://second.url.com/");
889 // The first few checks are done synchronously so check that they have been
890 // done for the first URL, while the second URL has all the checks done. We
891 // need to manually set up the IsPrivateIPAddress mock since if the same mock
892 // expectation is specified twice, gmock will only use the last instance of
893 // it, meaning the first will never be matched.
894 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
895 .WillOnce(Return(false))
896 .WillOnce(Return(false));
897 ExpectPreClassificationChecks(first_url, NULL, &kFalse, &kFalse, &kFalse,
898 NULL, NULL, NULL, NULL);
899 ExpectPreClassificationChecks(second_url, NULL, &kFalse, &kFalse, &kFalse,
900 &kFalse, &kFalse, &kFalse, &kFalse);
902 NavigateAndCommit(first_url);
903 // Don't flush the message loop, as we want to navigate to a different
904 // url before the final pre-classification checks are run.
905 NavigateAndCommit(second_url);
906 WaitAndCheckPreClassificationChecks();
909 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckPass) {
910 // Navigate the tab to a page. We should see a StartPhishingDetection IPC.
911 GURL url("http://host.com/");
912 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
913 &kFalse, &kFalse, &kFalse, &kFalse);
914 NavigateAndCommit(url);
915 WaitAndCheckPreClassificationChecks();
917 ExpectStartPhishingDetection(&url);
918 ExpectShouldClassifyForMalwareResult(true);
921 TEST_F(ClientSideDetectionHostTest,
922 TestPreClassificationCheckInPageNavigation) {
923 GURL url("http://host.com/");
924 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
925 &kFalse, &kFalse, &kFalse, &kFalse);
926 NavigateAndCommit(url);
927 WaitAndCheckPreClassificationChecks();
929 ExpectStartPhishingDetection(&url);
930 ExpectShouldClassifyForMalwareResult(true);
932 // Now try an in-page navigation. This should not trigger an IPC.
933 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0);
934 GURL inpage("http://host.com/#foo");
935 ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL,
936 NULL, NULL);
937 NavigateAndCommit(inpage);
938 WaitAndCheckPreClassificationChecks();
940 ExpectStartPhishingDetection(NULL);
941 ExpectShouldClassifyForMalwareResult(true);
944 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckXHTML) {
945 // Check that XHTML is supported, in addition to the default HTML type.
946 GURL url("http://host.com/xhtml");
947 RenderFrameHostTester::For(web_contents()->GetMainFrame())->
948 SetContentsMimeType("application/xhtml+xml");
949 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
950 &kFalse, &kFalse, &kFalse, &kFalse);
951 NavigateAndCommit(url);
952 WaitAndCheckPreClassificationChecks();
954 ExpectStartPhishingDetection(&url);
955 ExpectShouldClassifyForMalwareResult(true);
958 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckTwoNavigations) {
959 // Navigate to two hosts, which should cause two IPCs.
960 GURL url1("http://host1.com/");
961 ExpectPreClassificationChecks(url1, &kFalse, &kFalse, &kFalse, &kFalse,
962 &kFalse, &kFalse, &kFalse, &kFalse);
963 NavigateAndCommit(url1);
964 WaitAndCheckPreClassificationChecks();
966 ExpectStartPhishingDetection(&url1);
967 ExpectShouldClassifyForMalwareResult(true);
969 GURL url2("http://host2.com/");
970 ExpectPreClassificationChecks(url2, &kFalse, &kFalse, &kFalse, &kFalse,
971 &kFalse, &kFalse, &kFalse, &kFalse);
972 NavigateAndCommit(url2);
973 WaitAndCheckPreClassificationChecks();
975 ExpectStartPhishingDetection(&url2);
976 ExpectShouldClassifyForMalwareResult(true);
979 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckMimeType) {
980 // If the mime type is not one that we support, no IPC should be triggered
981 // but all pre-classification checks should run because we might classify
982 // other mime types for malware.
983 // Note: for this test to work correctly, the new URL must be on the
984 // same domain as the previous URL, otherwise it will create a new
985 // RenderViewHost that won't have the mime type set.
986 GURL url("http://host2.com/image.jpg");
987 RenderFrameHostTester::For(web_contents()->GetMainFrame())->
988 SetContentsMimeType("image/jpeg");
989 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
990 &kFalse, &kFalse, &kFalse, &kFalse);
991 NavigateAndCommit(url);
992 WaitAndCheckPreClassificationChecks();
994 ExpectStartPhishingDetection(NULL);
995 ExpectShouldClassifyForMalwareResult(true);
998 TEST_F(ClientSideDetectionHostTest,
999 TestPreClassificationCheckPrivateIpAddress) {
1000 // If IsPrivateIPAddress returns true, no IPC should be triggered.
1001 GURL url("http://host3.com/");
1002 ExpectPreClassificationChecks(url, &kTrue, &kFalse, NULL, NULL, NULL, NULL,
1003 NULL, NULL);
1004 NavigateAndCommit(url);
1005 WaitAndCheckPreClassificationChecks();
1006 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
1007 SafeBrowsingMsg_StartPhishingDetection::ID);
1008 ASSERT_FALSE(msg);
1009 ExpectShouldClassifyForMalwareResult(false);
1012 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckIncognito) {
1013 // If the tab is incognito there should be no IPC. Also, we shouldn't
1014 // even check the csd-whitelist.
1015 GURL url("http://host4.com/");
1016 ExpectPreClassificationChecks(url, &kFalse, &kTrue, NULL, NULL, NULL, NULL,
1017 NULL, NULL);
1018 NavigateAndCommit(url);
1019 WaitAndCheckPreClassificationChecks();
1021 ExpectStartPhishingDetection(NULL);
1022 ExpectShouldClassifyForMalwareResult(false);
1025 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckCsdWhitelist) {
1026 // If the URL is on the csd whitelist no phishing IPC should be sent
1027 // but we should classify the URL for malware.
1028 GURL url("http://host5.com/");
1029 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kFalse, &kFalse,
1030 &kFalse, &kFalse, &kFalse);
1031 NavigateAndCommit(url);
1032 WaitAndCheckPreClassificationChecks();
1034 ExpectStartPhishingDetection(NULL);
1035 ExpectShouldClassifyForMalwareResult(true);
1038 TEST_F(ClientSideDetectionHostTest,
1039 TestPreClassificationCheckMalwareKillSwitch) {
1040 // If the malware killswitch is on we shouldn't classify the page for malware.
1041 GURL url("http://host5.com/kill-switch");
1042 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, &kFalse,
1043 &kFalse, &kFalse, &kFalse);
1044 NavigateAndCommit(url);
1045 WaitAndCheckPreClassificationChecks();
1047 ExpectStartPhishingDetection(&url);
1048 ExpectShouldClassifyForMalwareResult(false);
1051 TEST_F(ClientSideDetectionHostTest,
1052 TestPreClassificationCheckKillswitchAndCsdWhitelist) {
1053 // If both the malware kill-swtich is on and the URL is on the csd whitelist,
1054 // we will leave pre-classification checks early.
1055 GURL url("http://host5.com/kill-switch-and-whitelisted");
1056 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kTrue, NULL,
1057 NULL, NULL, NULL);
1058 NavigateAndCommit(url);
1059 WaitAndCheckPreClassificationChecks();
1061 ExpectStartPhishingDetection(NULL);
1062 ExpectShouldClassifyForMalwareResult(false);
1065 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckInvalidCache) {
1066 // If item is in the cache but it isn't valid, we will classify regardless
1067 // of whether we are over the reporting limit.
1068 GURL url("http://host6.com/");
1069 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1070 &kFalse, &kTrue, NULL, &kFalse);
1072 NavigateAndCommit(url);
1073 WaitAndCheckPreClassificationChecks();
1075 ExpectStartPhishingDetection(&url);
1076 ExpectShouldClassifyForMalwareResult(true);
1079 TEST_F(ClientSideDetectionHostTest,
1080 TestPreClassificationCheckOverPhishingReportingLimit) {
1081 // If the url isn't in the cache and we are over the reporting limit, we
1082 // don't do classification.
1083 GURL url("http://host7.com/");
1084 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1085 &kFalse, &kFalse, &kTrue, &kFalse);
1086 NavigateAndCommit(url);
1087 WaitAndCheckPreClassificationChecks();
1089 ExpectStartPhishingDetection(NULL);
1090 ExpectShouldClassifyForMalwareResult(true);
1093 TEST_F(ClientSideDetectionHostTest,
1094 TestPreClassificationCheckOverMalwareReportingLimit) {
1095 GURL url("http://host.com/");
1096 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1097 &kFalse, &kFalse, &kFalse, &kTrue);
1098 NavigateAndCommit(url);
1099 WaitAndCheckPreClassificationChecks();
1101 ExpectStartPhishingDetection(&url);
1102 ExpectShouldClassifyForMalwareResult(false);
1105 TEST_F(ClientSideDetectionHostTest,
1106 TestPreClassificationCheckOverBothReportingLimits) {
1107 GURL url("http://host.com/");
1108 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1109 &kFalse, &kFalse, &kTrue, &kTrue);
1110 NavigateAndCommit(url);
1111 WaitAndCheckPreClassificationChecks();
1113 ExpectStartPhishingDetection(NULL);
1114 ExpectShouldClassifyForMalwareResult(false);
1117 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckHttpsUrl) {
1118 GURL url("https://host.com/");
1119 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1120 &kFalse, &kFalse, &kFalse, &kFalse);
1121 NavigateAndCommit(url);
1122 WaitAndCheckPreClassificationChecks();
1124 ExpectStartPhishingDetection(NULL);
1125 ExpectShouldClassifyForMalwareResult(true);
1128 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckValidCached) {
1129 // If result is cached, we will try and display the blocking page directly
1130 // with no start classification message.
1131 GURL url("http://host8.com/");
1132 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue,
1133 &kFalse, &kFalse, &kFalse);
1135 UnsafeResource resource;
1136 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
1137 .WillOnce(SaveArg<0>(&resource));
1139 NavigateAndCommit(url);
1140 WaitAndCheckPreClassificationChecks();
1141 EXPECT_EQ(url, resource.url);
1142 EXPECT_EQ(url, resource.original_url);
1144 ExpectStartPhishingDetection(NULL);
1146 // Showing a phishing warning will invalidate all the weak pointers which
1147 // means we will not extract malware features.
1148 ExpectShouldClassifyForMalwareResult(false);
1150 } // namespace safe_browsing