Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / client_side_detection_host_unittest.cc
blobbb744ccce6fce63dd47ef99c464bbd9cf2da8805
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/test_database_manager.h"
17 #include "chrome/browser/safe_browsing/ui_manager.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/safe_browsing/csd.pb.h"
20 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
21 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/test/mock_render_process_host.h"
26 #include "content/public/test/test_browser_thread.h"
27 #include "content/public/test/test_renderer_host.h"
28 #include "content/public/test/web_contents_tester.h"
29 #include "ipc/ipc_test_sink.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "url/gurl.h"
34 using ::testing::_;
35 using ::testing::DeleteArg;
36 using ::testing::DoAll;
37 using ::testing::Eq;
38 using ::testing::IsNull;
39 using ::testing::Mock;
40 using ::testing::NiceMock;
41 using ::testing::NotNull;
42 using ::testing::Pointee;
43 using ::testing::Return;
44 using ::testing::SaveArg;
45 using ::testing::SetArgumentPointee;
46 using ::testing::StrictMock;
47 using content::BrowserThread;
48 using content::RenderFrameHostTester;
49 using content::ResourceType;
50 using content::WebContents;
52 namespace {
54 const bool kFalse = false;
55 const bool kTrue = true;
57 } // namespace
59 namespace safe_browsing {
60 namespace {
61 // This matcher verifies that the client computed verdict
62 // (ClientPhishingRequest) which is passed to SendClientReportPhishingRequest
63 // has the expected fields set. Note: we can't simply compare the protocol
64 // buffer strings because the BrowserFeatureExtractor might add features to the
65 // verdict object before calling SendClientReportPhishingRequest.
66 MATCHER_P(PartiallyEqualVerdict, other, "") {
67 return (other.url() == arg.url() &&
68 other.client_score() == arg.client_score() &&
69 other.is_phishing() == arg.is_phishing());
72 MATCHER_P(PartiallyEqualMalwareVerdict, other, "") {
73 if (other.url() != arg.url() ||
74 other.referrer_url() != arg.referrer_url() ||
75 other.bad_ip_url_info_size() != arg.bad_ip_url_info_size())
76 return false;
78 for (int i = 0; i < other.bad_ip_url_info_size(); ++i) {
79 if (other.bad_ip_url_info(i).ip() != arg.bad_ip_url_info(i).ip() ||
80 other.bad_ip_url_info(i).url() != arg.bad_ip_url_info(i).url())
81 return false;
83 return true;
86 // Test that the callback is NULL when the verdict is not phishing.
87 MATCHER(CallbackIsNull, "") {
88 return arg.is_null();
91 ACTION(QuitUIMessageLoop) {
92 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
93 base::MessageLoopForUI::current()->Quit();
96 ACTION_P(InvokeDoneCallback, verdict) {
97 scoped_ptr<ClientPhishingRequest> request(::std::tr1::get<1>(args));
98 request->CopyFrom(*verdict);
99 ::std::tr1::get<2>(args).Run(true, request.Pass());
102 ACTION_P(InvokeMalwareCallback, verdict) {
103 scoped_ptr<ClientMalwareRequest> request(::std::tr1::get<1>(args));
104 request->CopyFrom(*verdict);
105 ::std::tr1::get<2>(args).Run(true, request.Pass());
108 void EmptyUrlCheckCallback(bool processed) {
111 class MockClientSideDetectionService : public ClientSideDetectionService {
112 public:
113 MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
114 virtual ~MockClientSideDetectionService() {}
116 MOCK_METHOD3(SendClientReportPhishingRequest,
117 void(ClientPhishingRequest*,
118 bool,
119 const ClientReportPhishingRequestCallback&));
120 MOCK_METHOD2(SendClientReportMalwareRequest,
121 void(ClientMalwareRequest*,
122 const ClientReportMalwareRequestCallback&));
123 MOCK_CONST_METHOD1(IsPrivateIPAddress, bool(const std::string&));
124 MOCK_METHOD2(GetValidCachedResult, bool(const GURL&, bool*));
125 MOCK_METHOD1(IsInCache, bool(const GURL&));
126 MOCK_METHOD0(OverPhishingReportLimit, bool());
127 MOCK_METHOD0(OverMalwareReportLimit, bool());
129 private:
130 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
133 class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
134 public:
135 explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
136 : SafeBrowsingUIManager(service) { }
138 MOCK_METHOD1(DisplayBlockingPage, void(const UnsafeResource& resource));
140 // Helper function which calls OnBlockingPageComplete for this client
141 // object.
142 void InvokeOnBlockingPageComplete(const UrlCheckCallback& callback) {
143 DCHECK_CURRENTLY_ON(BrowserThread::IO);
144 // Note: this will delete the client object in the case of the CsdClient
145 // implementation.
146 if (!callback.is_null())
147 callback.Run(false);
150 protected:
151 virtual ~MockSafeBrowsingUIManager() { }
153 private:
154 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
157 class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
158 public:
159 MockSafeBrowsingDatabaseManager() {}
161 MOCK_METHOD1(MatchCsdWhitelistUrl, bool(const GURL&));
162 MOCK_METHOD1(MatchMalwareIP, bool(const std::string& ip_address));
163 MOCK_METHOD0(IsMalwareKillSwitchOn, bool());
165 protected:
166 virtual ~MockSafeBrowsingDatabaseManager() {}
168 private:
169 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
172 class MockTestingProfile : public TestingProfile {
173 public:
174 MockTestingProfile() {}
175 virtual ~MockTestingProfile() {}
177 MOCK_CONST_METHOD0(IsOffTheRecord, bool());
180 class MockBrowserFeatureExtractor : public BrowserFeatureExtractor {
181 public:
182 explicit MockBrowserFeatureExtractor(
183 WebContents* tab,
184 ClientSideDetectionHost* host)
185 : BrowserFeatureExtractor(tab, host) {}
186 virtual ~MockBrowserFeatureExtractor() {}
188 MOCK_METHOD3(ExtractFeatures,
189 void(const BrowseInfo*,
190 ClientPhishingRequest*,
191 const BrowserFeatureExtractor::DoneCallback&));
193 MOCK_METHOD3(ExtractMalwareFeatures,
194 void(BrowseInfo*,
195 ClientMalwareRequest*,
196 const BrowserFeatureExtractor::MalwareDoneCallback&));
199 } // namespace
201 class ClientSideDetectionHostTest : public ChromeRenderViewHostTestHarness {
202 public:
203 typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
205 void SetUp() override {
206 ChromeRenderViewHostTestHarness::SetUp();
208 // Inject service classes.
209 csd_service_.reset(new StrictMock<MockClientSideDetectionService>());
210 database_manager_ = new StrictMock<MockSafeBrowsingDatabaseManager>();
211 ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>(
212 SafeBrowsingService::CreateSafeBrowsingService());
213 csd_host_.reset(safe_browsing::ClientSideDetectionHost::Create(
214 web_contents()));
215 csd_host_->set_client_side_detection_service(csd_service_.get());
216 csd_host_->set_safe_browsing_managers(ui_manager_.get(),
217 database_manager_.get());
218 // We need to create this here since we don't call DidStopLanding in
219 // this test.
220 csd_host_->browse_info_.reset(new BrowseInfo);
223 void TearDown() override {
224 // Delete the host object on the UI thread and release the
225 // SafeBrowsingService.
226 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
227 csd_host_.release());
228 database_manager_ = NULL;
229 ui_manager_ = NULL;
230 base::RunLoop().RunUntilIdle();
231 ChromeRenderViewHostTestHarness::TearDown();
234 content::BrowserContext* CreateBrowserContext() override {
235 // Set custom profile object so that we can mock calls to IsOffTheRecord.
236 // This needs to happen before we call the parent SetUp() function. We use
237 // a nice mock because other parts of the code are calling IsOffTheRecord.
238 mock_profile_ = new NiceMock<MockTestingProfile>();
239 return mock_profile_;
242 void OnPhishingDetectionDone(const std::string& verdict_str) {
243 csd_host_->OnPhishingDetectionDone(verdict_str);
246 void DidStopLoading() { csd_host_->DidStopLoading(); }
248 void UpdateIPUrlMap(const std::string& ip, const std::string& host) {
249 csd_host_->UpdateIPUrlMap(ip, host, "", "", content::RESOURCE_TYPE_OBJECT);
252 BrowseInfo* GetBrowseInfo() {
253 return csd_host_->browse_info_.get();
256 void ExpectPreClassificationChecks(const GURL& url,
257 const bool* is_private,
258 const bool* is_incognito,
259 const bool* match_csd_whitelist,
260 const bool* malware_killswitch,
261 const bool* get_valid_cached_result,
262 const bool* is_in_cache,
263 const bool* over_phishing_report_limit,
264 const bool* over_malware_report_limit) {
265 if (is_private) {
266 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
267 .WillOnce(Return(*is_private));
269 if (is_incognito) {
270 EXPECT_CALL(*mock_profile_, IsOffTheRecord())
271 .WillRepeatedly(Return(*is_incognito));
273 if (match_csd_whitelist) {
274 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(url))
275 .WillOnce(Return(*match_csd_whitelist));
277 if (malware_killswitch) {
278 EXPECT_CALL(*database_manager_.get(), IsMalwareKillSwitchOn())
279 .WillRepeatedly(Return(*malware_killswitch));
281 if (get_valid_cached_result) {
282 EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull()))
283 .WillOnce(DoAll(SetArgumentPointee<1>(true),
284 Return(*get_valid_cached_result)));
286 if (is_in_cache) {
287 EXPECT_CALL(*csd_service_, IsInCache(url)).WillOnce(Return(*is_in_cache));
289 if (over_phishing_report_limit) {
290 EXPECT_CALL(*csd_service_, OverPhishingReportLimit())
291 .WillOnce(Return(*over_phishing_report_limit));
293 if (over_malware_report_limit) {
294 EXPECT_CALL(*csd_service_, OverMalwareReportLimit())
295 .WillOnce(Return(*over_malware_report_limit));
299 void WaitAndCheckPreClassificationChecks() {
300 // Wait for CheckCsdWhitelist and CheckCache() to be called if at all.
301 base::RunLoop().RunUntilIdle();
302 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
303 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
304 EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get()));
305 EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
308 void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
309 csd_host_->feature_extractor_.reset(extractor);
312 void SetRedirectChain(const std::vector<GURL>& redirect_chain) {
313 csd_host_->browse_info_->url_redirects = redirect_chain;
316 void SetReferrer(const GURL& referrer) {
317 csd_host_->browse_info_->referrer = referrer;
320 void ExpectShouldClassifyForMalwareResult(bool should_classify) {
321 EXPECT_EQ(should_classify, csd_host_->should_classify_for_malware_);
324 void ExpectStartPhishingDetection(const GURL* url) {
325 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
326 SafeBrowsingMsg_StartPhishingDetection::ID);
327 if (url) {
328 ASSERT_TRUE(msg);
329 base::Tuple<GURL> actual_url;
330 SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
331 EXPECT_EQ(*url, base::get<0>(actual_url));
332 EXPECT_EQ(rvh()->GetRoutingID(), msg->routing_id());
333 process()->sink().ClearMessages();
334 } else {
335 ASSERT_FALSE(msg);
339 void TestUnsafeResourceCopied(const UnsafeResource& resource) {
340 ASSERT_TRUE(csd_host_->unsafe_resource_.get());
341 // Test that the resource from OnSafeBrowsingHit notification was copied
342 // into the CSDH.
343 EXPECT_EQ(resource.url, csd_host_->unsafe_resource_->url);
344 EXPECT_EQ(resource.original_url, csd_host_->unsafe_resource_->original_url);
345 EXPECT_EQ(resource.is_subresource,
346 csd_host_->unsafe_resource_->is_subresource);
347 EXPECT_EQ(resource.threat_type, csd_host_->unsafe_resource_->threat_type);
348 EXPECT_TRUE(csd_host_->unsafe_resource_->callback.is_null());
349 EXPECT_EQ(resource.render_process_host_id,
350 csd_host_->unsafe_resource_->render_process_host_id);
351 EXPECT_EQ(resource.render_view_id,
352 csd_host_->unsafe_resource_->render_view_id);
355 void SetUnsafeSubResourceForCurrent() {
356 UnsafeResource resource;
357 resource.url = GURL("http://www.malware.com/");
358 resource.original_url = web_contents()->GetURL();
359 resource.is_subresource = true;
360 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
361 resource.callback = base::Bind(&EmptyUrlCheckCallback);
362 resource.render_process_host_id = web_contents()->GetRenderProcessHost()->
363 GetID();
364 resource.render_view_id =
365 web_contents()->GetRenderViewHost()->GetRoutingID();
366 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
367 csd_host_->OnSafeBrowsingMatch(resource);
368 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
369 csd_host_->OnSafeBrowsingHit(resource);
370 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
371 resource.callback.Reset();
372 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
373 TestUnsafeResourceCopied(resource);
376 void NavigateWithSBHitAndCommit(const GURL& url) {
377 // Create a pending navigation.
378 controller().LoadURL(
379 url, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
381 ASSERT_TRUE(pending_rvh());
382 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
383 pending_rvh()->GetProcess()->GetID()) {
384 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
385 pending_rvh()->GetRoutingID());
388 // Simulate a safebrowsing hit before navigation completes.
389 UnsafeResource resource;
390 resource.url = url;
391 resource.original_url = url;
392 resource.is_subresource = false;
393 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
394 resource.callback = base::Bind(&EmptyUrlCheckCallback);
395 resource.render_process_host_id = pending_rvh()->GetProcess()->GetID();
396 resource.render_view_id = pending_rvh()->GetRoutingID();
397 csd_host_->OnSafeBrowsingMatch(resource);
398 csd_host_->OnSafeBrowsingHit(resource);
399 resource.callback.Reset();
401 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
403 // LoadURL created a navigation entry, now simulate the RenderView sending
404 // a notification that it actually navigated.
405 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
407 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
408 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
409 TestUnsafeResourceCopied(resource);
412 void NavigateWithoutSBHitAndCommit(const GURL& safe_url) {
413 controller().LoadURL(
414 safe_url, content::Referrer(), ui::PAGE_TRANSITION_LINK,
415 std::string());
417 ASSERT_TRUE(pending_rvh());
418 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
419 pending_rvh()->GetProcess()->GetID()) {
420 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
421 pending_rvh()->GetRoutingID());
423 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
424 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
426 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
427 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
428 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
431 void CheckIPUrlEqual(const std::vector<IPUrlInfo>& expect,
432 const std::vector<IPUrlInfo>& result) {
433 ASSERT_EQ(expect.size(), result.size());
435 for (unsigned int i = 0; i < expect.size(); ++i) {
436 EXPECT_EQ(expect[i].url, result[i].url);
437 EXPECT_EQ(expect[i].method, result[i].method);
438 EXPECT_EQ(expect[i].referrer, result[i].referrer);
439 EXPECT_EQ(expect[i].resource_type, result[i].resource_type);
443 protected:
444 scoped_ptr<ClientSideDetectionHost> csd_host_;
445 scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
446 scoped_refptr<StrictMock<MockSafeBrowsingUIManager> > ui_manager_;
447 scoped_refptr<StrictMock<MockSafeBrowsingDatabaseManager> > database_manager_;
448 MockTestingProfile* mock_profile_; // We don't own this object
451 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneInvalidVerdict) {
452 // Case 0: renderer sends an invalid verdict string that we're unable to
453 // parse.
454 MockBrowserFeatureExtractor* mock_extractor =
455 new StrictMock<MockBrowserFeatureExtractor>(
456 web_contents(),
457 csd_host_.get());
458 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
459 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
460 OnPhishingDetectionDone("Invalid Protocol Buffer");
461 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
464 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneNotPhishing) {
465 // Case 1: client thinks the page is phishing. The server does not agree.
466 // No interstitial is shown.
467 MockBrowserFeatureExtractor* mock_extractor =
468 new StrictMock<MockBrowserFeatureExtractor>(
469 web_contents(),
470 csd_host_.get());
471 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
473 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
474 ClientPhishingRequest verdict;
475 verdict.set_url("http://phishingurl.com/");
476 verdict.set_client_score(1.0f);
477 verdict.set_is_phishing(true);
479 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
480 .WillOnce(InvokeDoneCallback(&verdict));
481 EXPECT_CALL(*csd_service_,
482 SendClientReportPhishingRequest(
483 Pointee(PartiallyEqualVerdict(verdict)), _, _))
484 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<2>(&cb)));
485 OnPhishingDetectionDone(verdict.SerializeAsString());
486 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
487 ASSERT_FALSE(cb.is_null());
489 // Make sure DisplayBlockingPage is not going to be called.
490 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
491 cb.Run(GURL(verdict.url()), false);
492 base::RunLoop().RunUntilIdle();
493 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
496 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneDisabled) {
497 // Case 2: client thinks the page is phishing and so does the server but
498 // showing the interstitial is disabled => no interstitial is shown.
499 MockBrowserFeatureExtractor* mock_extractor =
500 new StrictMock<MockBrowserFeatureExtractor>(
501 web_contents(),
502 csd_host_.get());
503 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
505 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
506 ClientPhishingRequest verdict;
507 verdict.set_url("http://phishingurl.com/");
508 verdict.set_client_score(1.0f);
509 verdict.set_is_phishing(true);
511 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
512 .WillOnce(InvokeDoneCallback(&verdict));
513 EXPECT_CALL(*csd_service_,
514 SendClientReportPhishingRequest(
515 Pointee(PartiallyEqualVerdict(verdict)), _, _))
516 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<2>(&cb)));
517 OnPhishingDetectionDone(verdict.SerializeAsString());
518 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
519 ASSERT_FALSE(cb.is_null());
521 // Make sure DisplayBlockingPage is not going to be called.
522 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
523 cb.Run(GURL(verdict.url()), false);
524 base::RunLoop().RunUntilIdle();
525 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
528 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneShowInterstitial) {
529 // Case 3: client thinks the page is phishing and so does the server.
530 // We show an interstitial.
531 MockBrowserFeatureExtractor* mock_extractor =
532 new StrictMock<MockBrowserFeatureExtractor>(
533 web_contents(),
534 csd_host_.get());
535 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
537 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
538 GURL phishing_url("http://phishingurl.com/");
539 ClientPhishingRequest verdict;
540 verdict.set_url(phishing_url.spec());
541 verdict.set_client_score(1.0f);
542 verdict.set_is_phishing(true);
544 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
545 .WillOnce(InvokeDoneCallback(&verdict));
546 EXPECT_CALL(*csd_service_,
547 SendClientReportPhishingRequest(
548 Pointee(PartiallyEqualVerdict(verdict)), _, _))
549 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<2>(&cb)));
550 OnPhishingDetectionDone(verdict.SerializeAsString());
551 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
552 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
553 ASSERT_FALSE(cb.is_null());
555 UnsafeResource resource;
556 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
557 .WillOnce(SaveArg<0>(&resource));
558 cb.Run(phishing_url, true);
560 base::RunLoop().RunUntilIdle();
561 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
562 EXPECT_EQ(phishing_url, resource.url);
563 EXPECT_EQ(phishing_url, resource.original_url);
564 EXPECT_FALSE(resource.is_subresource);
565 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
566 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
567 resource.render_process_host_id);
568 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
569 resource.render_view_id);
571 // Make sure the client object will be deleted.
572 BrowserThread::PostTask(
573 BrowserThread::IO,
574 FROM_HERE,
575 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
576 ui_manager_, resource.callback));
579 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneMultiplePings) {
580 // Case 4 & 5: client thinks a page is phishing then navigates to
581 // another page which is also considered phishing by the client
582 // before the server responds with a verdict. After a while the
583 // server responds for both requests with a phishing verdict. Only
584 // a single interstitial is shown for the second URL.
585 MockBrowserFeatureExtractor* mock_extractor =
586 new StrictMock<MockBrowserFeatureExtractor>(
587 web_contents(),
588 csd_host_.get());
589 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
591 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
592 GURL phishing_url("http://phishingurl.com/");
593 ClientPhishingRequest verdict;
594 verdict.set_url(phishing_url.spec());
595 verdict.set_client_score(1.0f);
596 verdict.set_is_phishing(true);
598 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
599 .WillOnce(InvokeDoneCallback(&verdict));
600 EXPECT_CALL(*csd_service_,
601 SendClientReportPhishingRequest(
602 Pointee(PartiallyEqualVerdict(verdict)), _, _))
603 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<2>(&cb)));
604 OnPhishingDetectionDone(verdict.SerializeAsString());
605 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
606 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
607 ASSERT_FALSE(cb.is_null());
609 // Set this back to a normal browser feature extractor since we're using
610 // NavigateAndCommit() and it's easier to use the real thing than setting up
611 // mock expectations.
612 SetFeatureExtractor(new BrowserFeatureExtractor(web_contents(),
613 csd_host_.get()));
614 GURL other_phishing_url("http://other_phishing_url.com/bla");
615 ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
616 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse);
617 // We navigate away. The callback cb should be revoked.
618 NavigateAndCommit(other_phishing_url);
619 // Wait for the pre-classification checks to finish for other_phishing_url.
620 WaitAndCheckPreClassificationChecks();
622 ClientSideDetectionService::ClientReportPhishingRequestCallback cb_other;
623 verdict.set_url(other_phishing_url.spec());
624 verdict.set_client_score(0.8f);
625 EXPECT_CALL(*csd_service_,
626 SendClientReportPhishingRequest(
627 Pointee(PartiallyEqualVerdict(verdict)), _, _))
628 .WillOnce(DoAll(DeleteArg<0>(),
629 SaveArg<2>(&cb_other),
630 QuitUIMessageLoop()));
631 std::vector<GURL> redirect_chain;
632 redirect_chain.push_back(other_phishing_url);
633 SetRedirectChain(redirect_chain);
634 OnPhishingDetectionDone(verdict.SerializeAsString());
635 base::MessageLoop::current()->Run();
636 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
637 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
638 ASSERT_FALSE(cb_other.is_null());
640 // We expect that the interstitial is shown for the second phishing URL and
641 // not for the first phishing URL.
642 UnsafeResource resource;
643 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
644 .WillOnce(SaveArg<0>(&resource));
646 cb.Run(phishing_url, true); // Should have no effect.
647 cb_other.Run(other_phishing_url, true); // Should show interstitial.
649 base::RunLoop().RunUntilIdle();
650 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
651 EXPECT_EQ(other_phishing_url, resource.url);
652 EXPECT_EQ(other_phishing_url, resource.original_url);
653 EXPECT_FALSE(resource.is_subresource);
654 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
655 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
656 resource.render_process_host_id);
657 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
658 resource.render_view_id);
660 // Make sure the client object will be deleted.
661 BrowserThread::PostTask(
662 BrowserThread::IO,
663 FROM_HERE,
664 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
665 ui_manager_, resource.callback));
668 TEST_F(ClientSideDetectionHostTest,
669 OnPhishingDetectionDoneVerdictNotPhishing) {
670 // Case 6: renderer sends a verdict string that isn't phishing.
671 MockBrowserFeatureExtractor* mock_extractor =
672 new StrictMock<MockBrowserFeatureExtractor>(
673 web_contents(),
674 csd_host_.get());
675 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
677 ClientPhishingRequest verdict;
678 verdict.set_url("http://not-phishing.com/");
679 verdict.set_client_score(0.1f);
680 verdict.set_is_phishing(false);
682 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
683 OnPhishingDetectionDone(verdict.SerializeAsString());
684 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
687 TEST_F(ClientSideDetectionHostTest,
688 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchSubResource) {
689 // Case 7: renderer sends a verdict string that isn't phishing but the URL
690 // of a subresource was on the regular phishing or malware lists.
691 GURL url("http://not-phishing.com/");
692 ClientPhishingRequest verdict;
693 verdict.set_url(url.spec());
694 verdict.set_client_score(0.1f);
695 verdict.set_is_phishing(false);
697 // First we have to navigate to the URL to set the unique page ID.
698 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
699 &kFalse, &kFalse, &kFalse, &kFalse);
700 NavigateAndCommit(url);
701 WaitAndCheckPreClassificationChecks();
702 SetUnsafeSubResourceForCurrent();
704 EXPECT_CALL(*csd_service_,
705 SendClientReportPhishingRequest(
706 Pointee(PartiallyEqualVerdict(verdict)), _, CallbackIsNull()))
707 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
708 std::vector<GURL> redirect_chain;
709 redirect_chain.push_back(url);
710 SetRedirectChain(redirect_chain);
711 OnPhishingDetectionDone(verdict.SerializeAsString());
712 base::MessageLoop::current()->Run();
713 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
716 TEST_F(ClientSideDetectionHostTest,
717 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchOnNewRVH) {
718 // When navigating to a different host (thus creating a pending RVH) which
719 // matches regular malware list, and after navigation the renderer sends a
720 // verdict string that isn't phishing, we should still send the report.
722 // Do an initial navigation to a safe host.
723 GURL start_url("http://safe.example.com/");
724 ExpectPreClassificationChecks(
725 start_url, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
726 &kFalse);
727 NavigateAndCommit(start_url);
728 WaitAndCheckPreClassificationChecks();
730 // Now navigate to a different host which will have a malware hit before the
731 // navigation commits.
732 GURL url("http://malware-but-not-phishing.com/");
733 ClientPhishingRequest verdict;
734 verdict.set_url(url.spec());
735 verdict.set_client_score(0.1f);
736 verdict.set_is_phishing(false);
738 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
739 &kFalse, &kFalse, &kFalse, &kFalse);
740 NavigateWithSBHitAndCommit(url);
741 WaitAndCheckPreClassificationChecks();
743 EXPECT_CALL(*csd_service_,
744 SendClientReportPhishingRequest(
745 Pointee(PartiallyEqualVerdict(verdict)), _, CallbackIsNull()))
746 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
747 std::vector<GURL> redirect_chain;
748 redirect_chain.push_back(url);
749 SetRedirectChain(redirect_chain);
750 OnPhishingDetectionDone(verdict.SerializeAsString());
751 base::MessageLoop::current()->Run();
752 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
754 ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse,
755 &kFalse, &kFalse, &kFalse, &kFalse);
756 NavigateWithoutSBHitAndCommit(start_url);
757 WaitAndCheckPreClassificationChecks();
760 TEST_F(ClientSideDetectionHostTest,
761 DidStopLoadingShowMalwareInterstitial) {
762 // Case 9: client thinks the page match malware IP and so does the server.
763 // We show an sub-resource malware interstitial.
764 MockBrowserFeatureExtractor* mock_extractor =
765 new StrictMock<MockBrowserFeatureExtractor>(
766 web_contents(),
767 csd_host_.get());
768 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
770 GURL malware_landing_url("http://malware.com/");
771 GURL malware_ip_url("http://badip.com");
772 ClientMalwareRequest malware_verdict;
773 malware_verdict.set_url("http://malware.com/");
774 ClientMalwareRequest::UrlInfo* badipurl =
775 malware_verdict.add_bad_ip_url_info();
776 badipurl->set_ip("1.2.3.4");
777 badipurl->set_url("http://badip.com");
779 ExpectPreClassificationChecks(GURL(malware_verdict.url()), &kFalse, &kFalse,
780 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
781 &kFalse);
782 NavigateAndCommit(GURL(malware_verdict.url()));
783 WaitAndCheckPreClassificationChecks();
785 ClientSideDetectionService::ClientReportMalwareRequestCallback cb;
786 EXPECT_CALL(*mock_extractor, ExtractMalwareFeatures(_, _, _))
787 .WillOnce(InvokeMalwareCallback(&malware_verdict));
788 EXPECT_CALL(*csd_service_,
789 SendClientReportMalwareRequest(
790 Pointee(PartiallyEqualMalwareVerdict(malware_verdict)), _))
791 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
792 DidStopLoading();
793 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
794 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
795 ASSERT_FALSE(cb.is_null());
797 UnsafeResource resource;
798 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
799 .WillOnce(SaveArg<0>(&resource));
800 cb.Run(malware_landing_url, malware_ip_url, true);
802 base::RunLoop().RunUntilIdle();
803 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
804 EXPECT_EQ(malware_ip_url, resource.url);
805 EXPECT_EQ(malware_landing_url, resource.original_url);
806 EXPECT_TRUE(resource.is_subresource);
807 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL, resource.threat_type);
808 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
809 resource.render_process_host_id);
810 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
811 resource.render_view_id);
813 // Make sure the client object will be deleted.
814 BrowserThread::PostTask(
815 BrowserThread::IO,
816 FROM_HERE,
817 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
818 ui_manager_, resource.callback));
821 TEST_F(ClientSideDetectionHostTest, UpdateIPUrlMap) {
822 BrowseInfo* browse_info = GetBrowseInfo();
824 // Empty IP or host are skipped
825 UpdateIPUrlMap("250.10.10.10", std::string());
826 ASSERT_EQ(0U, browse_info->ips.size());
827 UpdateIPUrlMap(std::string(), "http://google.com/a");
828 ASSERT_EQ(0U, browse_info->ips.size());
829 UpdateIPUrlMap(std::string(), std::string());
830 ASSERT_EQ(0U, browse_info->ips.size());
832 std::vector<IPUrlInfo> expected_urls;
833 for (int i = 0; i < 20; i++) {
834 std::string url = base::StringPrintf("http://%d.com/", i);
835 expected_urls.push_back(
836 IPUrlInfo(url, "", "", content::RESOURCE_TYPE_OBJECT));
837 UpdateIPUrlMap("250.10.10.10", url);
839 ASSERT_EQ(1U, browse_info->ips.size());
840 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
841 CheckIPUrlEqual(expected_urls,
842 browse_info->ips["250.10.10.10"]);
844 // Add more urls for this ip, it exceeds max limit and won't be added
845 UpdateIPUrlMap("250.10.10.10", "http://21.com/");
846 ASSERT_EQ(1U, browse_info->ips.size());
847 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
848 CheckIPUrlEqual(expected_urls,
849 browse_info->ips["250.10.10.10"]);
851 // Add 199 more IPs
852 for (int i = 0; i < 199; i++) {
853 std::string ip = base::StringPrintf("%d.%d.%d.256", i, i, i);
854 expected_urls.clear();
855 expected_urls.push_back(
856 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT));
857 UpdateIPUrlMap(ip, "test.com/");
858 ASSERT_EQ(1U, browse_info->ips[ip].size());
859 CheckIPUrlEqual(expected_urls,
860 browse_info->ips[ip]);
862 ASSERT_EQ(200U, browse_info->ips.size());
864 // Exceeding max ip limit 200, these won't be added
865 UpdateIPUrlMap("250.250.250.250", "goo.com/");
866 UpdateIPUrlMap("250.250.250.250", "bar.com/");
867 UpdateIPUrlMap("250.250.0.250", "foo.com/");
868 ASSERT_EQ(200U, browse_info->ips.size());
870 // Add url to existing IPs succeed
871 UpdateIPUrlMap("100.100.100.256", "more.com/");
872 ASSERT_EQ(2U, browse_info->ips["100.100.100.256"].size());
873 expected_urls.clear();
874 expected_urls.push_back(
875 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT));
876 expected_urls.push_back(
877 IPUrlInfo("more.com/", "", "", content::RESOURCE_TYPE_OBJECT));
878 CheckIPUrlEqual(expected_urls,
879 browse_info->ips["100.100.100.256"]);
882 TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
883 // Test that canceling pending should classify requests works as expected.
885 GURL first_url("http://first.phishy.url.com");
886 GURL second_url("http://second.url.com/");
887 // The first few checks are done synchronously so check that they have been
888 // done for the first URL, while the second URL has all the checks done. We
889 // need to manually set up the IsPrivateIPAddress mock since if the same mock
890 // expectation is specified twice, gmock will only use the last instance of
891 // it, meaning the first will never be matched.
892 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
893 .WillOnce(Return(false))
894 .WillOnce(Return(false));
895 ExpectPreClassificationChecks(first_url, NULL, &kFalse, &kFalse, &kFalse,
896 NULL, NULL, NULL, NULL);
897 ExpectPreClassificationChecks(second_url, NULL, &kFalse, &kFalse, &kFalse,
898 &kFalse, &kFalse, &kFalse, &kFalse);
900 NavigateAndCommit(first_url);
901 // Don't flush the message loop, as we want to navigate to a different
902 // url before the final pre-classification checks are run.
903 NavigateAndCommit(second_url);
904 WaitAndCheckPreClassificationChecks();
907 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckPass) {
908 // Navigate the tab to a page. We should see a StartPhishingDetection IPC.
909 GURL url("http://host.com/");
910 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
911 &kFalse, &kFalse, &kFalse, &kFalse);
912 NavigateAndCommit(url);
913 WaitAndCheckPreClassificationChecks();
915 ExpectStartPhishingDetection(&url);
916 ExpectShouldClassifyForMalwareResult(true);
919 TEST_F(ClientSideDetectionHostTest,
920 TestPreClassificationCheckInPageNavigation) {
921 GURL url("http://host.com/");
922 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
923 &kFalse, &kFalse, &kFalse, &kFalse);
924 NavigateAndCommit(url);
925 WaitAndCheckPreClassificationChecks();
927 ExpectStartPhishingDetection(&url);
928 ExpectShouldClassifyForMalwareResult(true);
930 // Now try an in-page navigation. This should not trigger an IPC.
931 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0);
932 GURL inpage("http://host.com/#foo");
933 ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL,
934 NULL, NULL);
935 NavigateAndCommit(inpage);
936 WaitAndCheckPreClassificationChecks();
938 ExpectStartPhishingDetection(NULL);
939 ExpectShouldClassifyForMalwareResult(true);
942 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckXHTML) {
943 // Check that XHTML is supported, in addition to the default HTML type.
944 GURL url("http://host.com/xhtml");
945 RenderFrameHostTester::For(web_contents()->GetMainFrame())->
946 SetContentsMimeType("application/xhtml+xml");
947 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
948 &kFalse, &kFalse, &kFalse, &kFalse);
949 NavigateAndCommit(url);
950 WaitAndCheckPreClassificationChecks();
952 ExpectStartPhishingDetection(&url);
953 ExpectShouldClassifyForMalwareResult(true);
956 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckTwoNavigations) {
957 // Navigate to two hosts, which should cause two IPCs.
958 GURL url1("http://host1.com/");
959 ExpectPreClassificationChecks(url1, &kFalse, &kFalse, &kFalse, &kFalse,
960 &kFalse, &kFalse, &kFalse, &kFalse);
961 NavigateAndCommit(url1);
962 WaitAndCheckPreClassificationChecks();
964 ExpectStartPhishingDetection(&url1);
965 ExpectShouldClassifyForMalwareResult(true);
967 GURL url2("http://host2.com/");
968 ExpectPreClassificationChecks(url2, &kFalse, &kFalse, &kFalse, &kFalse,
969 &kFalse, &kFalse, &kFalse, &kFalse);
970 NavigateAndCommit(url2);
971 WaitAndCheckPreClassificationChecks();
973 ExpectStartPhishingDetection(&url2);
974 ExpectShouldClassifyForMalwareResult(true);
977 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckMimeType) {
978 // If the mime type is not one that we support, no IPC should be triggered
979 // but all pre-classification checks should run because we might classify
980 // other mime types for malware.
981 // Note: for this test to work correctly, the new URL must be on the
982 // same domain as the previous URL, otherwise it will create a new
983 // RenderViewHost that won't have the mime type set.
984 GURL url("http://host2.com/image.jpg");
985 RenderFrameHostTester::For(web_contents()->GetMainFrame())->
986 SetContentsMimeType("image/jpeg");
987 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
988 &kFalse, &kFalse, &kFalse, &kFalse);
989 NavigateAndCommit(url);
990 WaitAndCheckPreClassificationChecks();
992 ExpectStartPhishingDetection(NULL);
993 ExpectShouldClassifyForMalwareResult(true);
996 TEST_F(ClientSideDetectionHostTest,
997 TestPreClassificationCheckPrivateIpAddress) {
998 // If IsPrivateIPAddress returns true, no IPC should be triggered.
999 GURL url("http://host3.com/");
1000 ExpectPreClassificationChecks(url, &kTrue, &kFalse, NULL, NULL, NULL, NULL,
1001 NULL, NULL);
1002 NavigateAndCommit(url);
1003 WaitAndCheckPreClassificationChecks();
1004 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
1005 SafeBrowsingMsg_StartPhishingDetection::ID);
1006 ASSERT_FALSE(msg);
1007 ExpectShouldClassifyForMalwareResult(false);
1010 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckIncognito) {
1011 // If the tab is incognito there should be no IPC. Also, we shouldn't
1012 // even check the csd-whitelist.
1013 GURL url("http://host4.com/");
1014 ExpectPreClassificationChecks(url, &kFalse, &kTrue, NULL, NULL, NULL, NULL,
1015 NULL, NULL);
1016 NavigateAndCommit(url);
1017 WaitAndCheckPreClassificationChecks();
1019 ExpectStartPhishingDetection(NULL);
1020 ExpectShouldClassifyForMalwareResult(false);
1023 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckCsdWhitelist) {
1024 // If the URL is on the csd whitelist no phishing IPC should be sent
1025 // but we should classify the URL for malware.
1026 GURL url("http://host5.com/");
1027 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kFalse, &kFalse,
1028 &kFalse, &kFalse, &kFalse);
1029 NavigateAndCommit(url);
1030 WaitAndCheckPreClassificationChecks();
1032 ExpectStartPhishingDetection(NULL);
1033 ExpectShouldClassifyForMalwareResult(true);
1036 TEST_F(ClientSideDetectionHostTest,
1037 TestPreClassificationCheckMalwareKillSwitch) {
1038 // If the malware killswitch is on we shouldn't classify the page for malware.
1039 GURL url("http://host5.com/kill-switch");
1040 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, &kFalse,
1041 &kFalse, &kFalse, &kFalse);
1042 NavigateAndCommit(url);
1043 WaitAndCheckPreClassificationChecks();
1045 ExpectStartPhishingDetection(&url);
1046 ExpectShouldClassifyForMalwareResult(false);
1049 TEST_F(ClientSideDetectionHostTest,
1050 TestPreClassificationCheckKillswitchAndCsdWhitelist) {
1051 // If both the malware kill-swtich is on and the URL is on the csd whitelist,
1052 // we will leave pre-classification checks early.
1053 GURL url("http://host5.com/kill-switch-and-whitelisted");
1054 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kTrue, NULL,
1055 NULL, NULL, NULL);
1056 NavigateAndCommit(url);
1057 WaitAndCheckPreClassificationChecks();
1059 ExpectStartPhishingDetection(NULL);
1060 ExpectShouldClassifyForMalwareResult(false);
1063 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckInvalidCache) {
1064 // If item is in the cache but it isn't valid, we will classify regardless
1065 // of whether we are over the reporting limit.
1066 GURL url("http://host6.com/");
1067 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1068 &kFalse, &kTrue, NULL, &kFalse);
1070 NavigateAndCommit(url);
1071 WaitAndCheckPreClassificationChecks();
1073 ExpectStartPhishingDetection(&url);
1074 ExpectShouldClassifyForMalwareResult(true);
1077 TEST_F(ClientSideDetectionHostTest,
1078 TestPreClassificationCheckOverPhishingReportingLimit) {
1079 // If the url isn't in the cache and we are over the reporting limit, we
1080 // don't do classification.
1081 GURL url("http://host7.com/");
1082 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1083 &kFalse, &kFalse, &kTrue, &kFalse);
1084 NavigateAndCommit(url);
1085 WaitAndCheckPreClassificationChecks();
1087 ExpectStartPhishingDetection(NULL);
1088 ExpectShouldClassifyForMalwareResult(true);
1091 TEST_F(ClientSideDetectionHostTest,
1092 TestPreClassificationCheckOverMalwareReportingLimit) {
1093 GURL url("http://host.com/");
1094 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1095 &kFalse, &kFalse, &kFalse, &kTrue);
1096 NavigateAndCommit(url);
1097 WaitAndCheckPreClassificationChecks();
1099 ExpectStartPhishingDetection(&url);
1100 ExpectShouldClassifyForMalwareResult(false);
1103 TEST_F(ClientSideDetectionHostTest,
1104 TestPreClassificationCheckOverBothReportingLimits) {
1105 GURL url("http://host.com/");
1106 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1107 &kFalse, &kFalse, &kTrue, &kTrue);
1108 NavigateAndCommit(url);
1109 WaitAndCheckPreClassificationChecks();
1111 ExpectStartPhishingDetection(NULL);
1112 ExpectShouldClassifyForMalwareResult(false);
1115 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckHttpsUrl) {
1116 GURL url("https://host.com/");
1117 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1118 &kFalse, &kFalse, &kFalse, &kFalse);
1119 NavigateAndCommit(url);
1120 WaitAndCheckPreClassificationChecks();
1122 ExpectStartPhishingDetection(NULL);
1123 ExpectShouldClassifyForMalwareResult(true);
1126 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckValidCached) {
1127 // If result is cached, we will try and display the blocking page directly
1128 // with no start classification message.
1129 GURL url("http://host8.com/");
1130 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue,
1131 &kFalse, &kFalse, &kFalse);
1133 UnsafeResource resource;
1134 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
1135 .WillOnce(SaveArg<0>(&resource));
1137 NavigateAndCommit(url);
1138 WaitAndCheckPreClassificationChecks();
1139 EXPECT_EQ(url, resource.url);
1140 EXPECT_EQ(url, resource.original_url);
1142 ExpectStartPhishingDetection(NULL);
1144 // Showing a phishing warning will invalidate all the weak pointers which
1145 // means we will not extract malware features.
1146 ExpectShouldClassifyForMalwareResult(false);
1148 } // namespace safe_browsing