Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / client_side_detection_host_unittest.cc
blob132bb84c96d14b7848feafcd29bf731c1b2c1ae2
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::RenderViewHostTester;
48 using content::WebContents;
50 namespace {
52 const bool kFalse = false;
53 const bool kTrue = true;
55 } // namespace
57 namespace safe_browsing {
58 namespace {
59 // This matcher verifies that the client computed verdict
60 // (ClientPhishingRequest) which is passed to SendClientReportPhishingRequest
61 // has the expected fields set. Note: we can't simply compare the protocol
62 // buffer strings because the BrowserFeatureExtractor might add features to the
63 // verdict object before calling SendClientReportPhishingRequest.
64 MATCHER_P(PartiallyEqualVerdict, other, "") {
65 return (other.url() == arg.url() &&
66 other.client_score() == arg.client_score() &&
67 other.is_phishing() == arg.is_phishing());
70 MATCHER_P(PartiallyEqualMalwareVerdict, other, "") {
71 if (other.url() != arg.url() ||
72 other.referrer_url() != arg.referrer_url() ||
73 other.bad_ip_url_info_size() != arg.bad_ip_url_info_size())
74 return false;
76 for (int i = 0; i < other.bad_ip_url_info_size(); ++i) {
77 if (other.bad_ip_url_info(i).ip() != arg.bad_ip_url_info(i).ip() ||
78 other.bad_ip_url_info(i).url() != arg.bad_ip_url_info(i).url())
79 return false;
81 return true;
84 // Test that the callback is NULL when the verdict is not phishing.
85 MATCHER(CallbackIsNull, "") {
86 return arg.is_null();
89 ACTION(QuitUIMessageLoop) {
90 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
91 base::MessageLoopForUI::current()->Quit();
94 // It's kind of insane that InvokeArgument doesn't work with callbacks, but it
95 // doesn't seem like it.
96 ACTION_TEMPLATE(InvokeCallbackArgument,
97 HAS_1_TEMPLATE_PARAMS(int, k),
98 AND_2_VALUE_PARAMS(p0, p1)) {
99 ::std::tr1::get<k>(args).Run(p0, p1);
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_METHOD2(SendClientReportPhishingRequest,
117 void(ClientPhishingRequest*,
118 const ClientReportPhishingRequestCallback&));
119 MOCK_METHOD2(SendClientReportMalwareRequest,
120 void(ClientMalwareRequest*,
121 const ClientReportMalwareRequestCallback&));
122 MOCK_CONST_METHOD1(IsPrivateIPAddress, bool(const std::string&));
123 MOCK_METHOD2(GetValidCachedResult, bool(const GURL&, bool*));
124 MOCK_METHOD1(IsInCache, bool(const GURL&));
125 MOCK_METHOD0(OverPhishingReportLimit, bool());
126 MOCK_METHOD0(OverMalwareReportLimit, bool());
128 private:
129 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
132 class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
133 public:
134 explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
135 : SafeBrowsingUIManager(service) { }
137 MOCK_METHOD1(DisplayBlockingPage, void(const UnsafeResource& resource));
139 // Helper function which calls OnBlockingPageComplete for this client
140 // object.
141 void InvokeOnBlockingPageComplete(const UrlCheckCallback& callback) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
143 // Note: this will delete the client object in the case of the CsdClient
144 // implementation.
145 if (!callback.is_null())
146 callback.Run(false);
149 protected:
150 virtual ~MockSafeBrowsingUIManager() { }
152 private:
153 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
156 class MockSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
157 public:
158 explicit MockSafeBrowsingDatabaseManager(SafeBrowsingService* service)
159 : SafeBrowsingDatabaseManager(service) { }
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 virtual void SetUp() {
206 ChromeRenderViewHostTestHarness::SetUp();
208 // Inject service classes.
209 csd_service_.reset(new StrictMock<MockClientSideDetectionService>());
210 // Only used for initializing mock objects.
211 SafeBrowsingService* sb_service =
212 SafeBrowsingService::CreateSafeBrowsingService();
213 database_manager_ =
214 new StrictMock<MockSafeBrowsingDatabaseManager>(sb_service);
215 ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>(sb_service);
216 csd_host_.reset(safe_browsing::ClientSideDetectionHost::Create(
217 web_contents()));
218 csd_host_->set_client_side_detection_service(csd_service_.get());
219 csd_host_->set_safe_browsing_managers(ui_manager_.get(),
220 database_manager_.get());
221 // We need to create this here since we don't call DidStopLanding in
222 // this test.
223 csd_host_->browse_info_.reset(new BrowseInfo);
226 virtual void TearDown() {
227 // Delete the host object on the UI thread and release the
228 // SafeBrowsingService.
229 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
230 csd_host_.release());
231 database_manager_ = NULL;
232 ui_manager_ = NULL;
233 base::RunLoop().RunUntilIdle();
234 ChromeRenderViewHostTestHarness::TearDown();
237 virtual content::BrowserContext* CreateBrowserContext() OVERRIDE {
238 // Set custom profile object so that we can mock calls to IsOffTheRecord.
239 // This needs to happen before we call the parent SetUp() function. We use
240 // a nice mock because other parts of the code are calling IsOffTheRecord.
241 mock_profile_ = new NiceMock<MockTestingProfile>();
242 return mock_profile_;
245 void OnPhishingDetectionDone(const std::string& verdict_str) {
246 csd_host_->OnPhishingDetectionDone(verdict_str);
249 void DidStopLoading() {
250 csd_host_->DidStopLoading(pending_rvh());
253 void UpdateIPUrlMap(const std::string& ip, const std::string& host) {
254 csd_host_->UpdateIPUrlMap(ip, host, "", "", ResourceType::OBJECT);
257 BrowseInfo* GetBrowseInfo() {
258 return csd_host_->browse_info_.get();
261 void ExpectPreClassificationChecks(const GURL& url,
262 const bool* is_private,
263 const bool* is_incognito,
264 const bool* match_csd_whitelist,
265 const bool* malware_killswitch,
266 const bool* get_valid_cached_result,
267 const bool* is_in_cache,
268 const bool* over_phishing_report_limit,
269 const bool* over_malware_report_limit) {
270 if (is_private) {
271 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
272 .WillOnce(Return(*is_private));
274 if (is_incognito) {
275 EXPECT_CALL(*mock_profile_, IsOffTheRecord())
276 .WillRepeatedly(Return(*is_incognito));
278 if (match_csd_whitelist) {
279 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(url))
280 .WillOnce(Return(*match_csd_whitelist));
282 if (malware_killswitch) {
283 EXPECT_CALL(*database_manager_.get(), IsMalwareKillSwitchOn())
284 .WillRepeatedly(Return(*malware_killswitch));
286 if (get_valid_cached_result) {
287 EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull()))
288 .WillOnce(DoAll(SetArgumentPointee<1>(true),
289 Return(*get_valid_cached_result)));
291 if (is_in_cache) {
292 EXPECT_CALL(*csd_service_, IsInCache(url)).WillOnce(Return(*is_in_cache));
294 if (over_phishing_report_limit) {
295 EXPECT_CALL(*csd_service_, OverPhishingReportLimit())
296 .WillOnce(Return(*over_phishing_report_limit));
298 if (over_malware_report_limit) {
299 EXPECT_CALL(*csd_service_, OverMalwareReportLimit())
300 .WillOnce(Return(*over_malware_report_limit));
304 void WaitAndCheckPreClassificationChecks() {
305 // Wait for CheckCsdWhitelist and CheckCache() to be called if at all.
306 base::RunLoop().RunUntilIdle();
307 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
308 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
309 EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get()));
310 EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
313 void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
314 csd_host_->feature_extractor_.reset(extractor);
317 void SetRedirectChain(const std::vector<GURL>& redirect_chain) {
318 csd_host_->browse_info_->url_redirects = redirect_chain;
321 void SetReferrer(const GURL& referrer) {
322 csd_host_->browse_info_->referrer = referrer;
325 void ExpectShouldClassifyForMalwareResult(bool should_classify) {
326 EXPECT_EQ(should_classify, csd_host_->should_classify_for_malware_);
329 void ExpectStartPhishingDetection(const GURL* url) {
330 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
331 SafeBrowsingMsg_StartPhishingDetection::ID);
332 if (url) {
333 ASSERT_TRUE(msg);
334 Tuple1<GURL> actual_url;
335 SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
336 EXPECT_EQ(*url, actual_url.a);
337 EXPECT_EQ(rvh()->GetRoutingID(), msg->routing_id());
338 process()->sink().ClearMessages();
339 } else {
340 ASSERT_FALSE(msg);
344 void TestUnsafeResourceCopied(const UnsafeResource& resource) {
345 ASSERT_TRUE(csd_host_->unsafe_resource_.get());
346 // Test that the resource from OnSafeBrowsingHit notification was copied
347 // into the CSDH.
348 EXPECT_EQ(resource.url, csd_host_->unsafe_resource_->url);
349 EXPECT_EQ(resource.original_url, csd_host_->unsafe_resource_->original_url);
350 EXPECT_EQ(resource.is_subresource,
351 csd_host_->unsafe_resource_->is_subresource);
352 EXPECT_EQ(resource.threat_type, csd_host_->unsafe_resource_->threat_type);
353 EXPECT_TRUE(csd_host_->unsafe_resource_->callback.is_null());
354 EXPECT_EQ(resource.render_process_host_id,
355 csd_host_->unsafe_resource_->render_process_host_id);
356 EXPECT_EQ(resource.render_view_id,
357 csd_host_->unsafe_resource_->render_view_id);
360 void SetUnsafeSubResourceForCurrent() {
361 UnsafeResource resource;
362 resource.url = GURL("http://www.malware.com/");
363 resource.original_url = web_contents()->GetURL();
364 resource.is_subresource = true;
365 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
366 resource.callback = base::Bind(&EmptyUrlCheckCallback);
367 resource.render_process_host_id = web_contents()->GetRenderProcessHost()->
368 GetID();
369 resource.render_view_id =
370 web_contents()->GetRenderViewHost()->GetRoutingID();
371 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
372 csd_host_->OnSafeBrowsingMatch(resource);
373 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
374 csd_host_->OnSafeBrowsingHit(resource);
375 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
376 resource.callback.Reset();
377 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
378 TestUnsafeResourceCopied(resource);
381 void NavigateWithSBHitAndCommit(const GURL& url) {
382 // Create a pending navigation.
383 controller().LoadURL(
384 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
386 ASSERT_TRUE(pending_rvh());
387 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
388 pending_rvh()->GetProcess()->GetID()) {
389 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
390 pending_rvh()->GetRoutingID());
393 // Simulate a safebrowsing hit before navigation completes.
394 UnsafeResource resource;
395 resource.url = url;
396 resource.original_url = url;
397 resource.is_subresource = false;
398 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
399 resource.callback = base::Bind(&EmptyUrlCheckCallback);
400 resource.render_process_host_id = pending_rvh()->GetProcess()->GetID();
401 resource.render_view_id = pending_rvh()->GetRoutingID();
402 csd_host_->OnSafeBrowsingMatch(resource);
403 csd_host_->OnSafeBrowsingHit(resource);
404 resource.callback.Reset();
406 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
408 // LoadURL created a navigation entry, now simulate the RenderView sending
409 // a notification that it actually navigated.
410 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
412 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
413 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
414 TestUnsafeResourceCopied(resource);
417 void NavigateWithoutSBHitAndCommit(const GURL& safe_url) {
418 controller().LoadURL(
419 safe_url, content::Referrer(), content::PAGE_TRANSITION_LINK,
420 std::string());
422 ASSERT_TRUE(pending_rvh());
423 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
424 pending_rvh()->GetProcess()->GetID()) {
425 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
426 pending_rvh()->GetRoutingID());
428 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
429 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
431 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
432 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
433 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
436 void CheckIPUrlEqual(const std::vector<IPUrlInfo>& expect,
437 const std::vector<IPUrlInfo>& result) {
438 ASSERT_EQ(expect.size(), result.size());
440 for (unsigned int i = 0; i < expect.size(); ++i) {
441 EXPECT_EQ(expect[i].url, result[i].url);
442 EXPECT_EQ(expect[i].method, result[i].method);
443 EXPECT_EQ(expect[i].referrer, result[i].referrer);
444 EXPECT_EQ(expect[i].resource_type, result[i].resource_type);
448 protected:
449 scoped_ptr<ClientSideDetectionHost> csd_host_;
450 scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
451 scoped_refptr<StrictMock<MockSafeBrowsingUIManager> > ui_manager_;
452 scoped_refptr<StrictMock<MockSafeBrowsingDatabaseManager> > database_manager_;
453 MockTestingProfile* mock_profile_; // We don't own this object
456 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneInvalidVerdict) {
457 // Case 0: renderer sends an invalid verdict string that we're unable to
458 // parse.
459 MockBrowserFeatureExtractor* mock_extractor =
460 new StrictMock<MockBrowserFeatureExtractor>(
461 web_contents(),
462 csd_host_.get());
463 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
464 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
465 OnPhishingDetectionDone("Invalid Protocol Buffer");
466 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
469 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneNotPhishing) {
470 // Case 1: client thinks the page is phishing. The server does not agree.
471 // No interstitial is shown.
472 MockBrowserFeatureExtractor* mock_extractor =
473 new StrictMock<MockBrowserFeatureExtractor>(
474 web_contents(),
475 csd_host_.get());
476 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
478 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
479 ClientPhishingRequest verdict;
480 verdict.set_url("http://phishingurl.com/");
481 verdict.set_client_score(1.0f);
482 verdict.set_is_phishing(true);
484 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
485 .WillOnce(DoAll(DeleteArg<1>(),
486 InvokeCallbackArgument<2>(true, &verdict)));
487 EXPECT_CALL(*csd_service_,
488 SendClientReportPhishingRequest(
489 Pointee(PartiallyEqualVerdict(verdict)), _))
490 .WillOnce(SaveArg<1>(&cb));
491 OnPhishingDetectionDone(verdict.SerializeAsString());
492 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
493 ASSERT_FALSE(cb.is_null());
495 // Make sure DisplayBlockingPage is not going to be called.
496 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
497 cb.Run(GURL(verdict.url()), false);
498 base::RunLoop().RunUntilIdle();
499 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
502 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneDisabled) {
503 // Case 2: client thinks the page is phishing and so does the server but
504 // showing the interstitial is disabled => no interstitial is shown.
505 MockBrowserFeatureExtractor* mock_extractor =
506 new StrictMock<MockBrowserFeatureExtractor>(
507 web_contents(),
508 csd_host_.get());
509 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
511 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
512 ClientPhishingRequest verdict;
513 verdict.set_url("http://phishingurl.com/");
514 verdict.set_client_score(1.0f);
515 verdict.set_is_phishing(true);
517 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
518 .WillOnce(DoAll(DeleteArg<1>(),
519 InvokeCallbackArgument<2>(true, &verdict)));
520 EXPECT_CALL(*csd_service_,
521 SendClientReportPhishingRequest(
522 Pointee(PartiallyEqualVerdict(verdict)), _))
523 .WillOnce(SaveArg<1>(&cb));
524 OnPhishingDetectionDone(verdict.SerializeAsString());
525 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
526 ASSERT_FALSE(cb.is_null());
528 // Make sure DisplayBlockingPage is not going to be called.
529 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
530 cb.Run(GURL(verdict.url()), false);
531 base::RunLoop().RunUntilIdle();
532 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
535 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneShowInterstitial) {
536 // Case 3: client thinks the page is phishing and so does the server.
537 // We show an interstitial.
538 MockBrowserFeatureExtractor* mock_extractor =
539 new StrictMock<MockBrowserFeatureExtractor>(
540 web_contents(),
541 csd_host_.get());
542 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
544 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
545 GURL phishing_url("http://phishingurl.com/");
546 ClientPhishingRequest verdict;
547 verdict.set_url(phishing_url.spec());
548 verdict.set_client_score(1.0f);
549 verdict.set_is_phishing(true);
551 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
552 .WillOnce(DoAll(DeleteArg<1>(),
553 InvokeCallbackArgument<2>(true, &verdict)));
554 EXPECT_CALL(*csd_service_,
555 SendClientReportPhishingRequest(
556 Pointee(PartiallyEqualVerdict(verdict)), _))
557 .WillOnce(SaveArg<1>(&cb));
558 OnPhishingDetectionDone(verdict.SerializeAsString());
559 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
560 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
561 ASSERT_FALSE(cb.is_null());
563 UnsafeResource resource;
564 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
565 .WillOnce(SaveArg<0>(&resource));
566 cb.Run(phishing_url, true);
568 base::RunLoop().RunUntilIdle();
569 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
570 EXPECT_EQ(phishing_url, resource.url);
571 EXPECT_EQ(phishing_url, resource.original_url);
572 EXPECT_FALSE(resource.is_subresource);
573 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
574 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
575 resource.render_process_host_id);
576 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
577 resource.render_view_id);
579 // Make sure the client object will be deleted.
580 BrowserThread::PostTask(
581 BrowserThread::IO,
582 FROM_HERE,
583 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
584 ui_manager_, resource.callback));
587 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneMultiplePings) {
588 // Case 4 & 5: client thinks a page is phishing then navigates to
589 // another page which is also considered phishing by the client
590 // before the server responds with a verdict. After a while the
591 // server responds for both requests with a phishing verdict. Only
592 // a single interstitial is shown for the second URL.
593 MockBrowserFeatureExtractor* mock_extractor =
594 new StrictMock<MockBrowserFeatureExtractor>(
595 web_contents(),
596 csd_host_.get());
597 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
599 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
600 GURL phishing_url("http://phishingurl.com/");
601 ClientPhishingRequest verdict;
602 verdict.set_url(phishing_url.spec());
603 verdict.set_client_score(1.0f);
604 verdict.set_is_phishing(true);
606 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
607 .WillOnce(DoAll(DeleteArg<1>(),
608 InvokeCallbackArgument<2>(true, &verdict)));
609 EXPECT_CALL(*csd_service_,
610 SendClientReportPhishingRequest(
611 Pointee(PartiallyEqualVerdict(verdict)), _))
612 .WillOnce(SaveArg<1>(&cb));
613 OnPhishingDetectionDone(verdict.SerializeAsString());
614 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
615 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
616 ASSERT_FALSE(cb.is_null());
618 // Set this back to a normal browser feature extractor since we're using
619 // NavigateAndCommit() and it's easier to use the real thing than setting up
620 // mock expectations.
621 SetFeatureExtractor(new BrowserFeatureExtractor(web_contents(),
622 csd_host_.get()));
623 GURL other_phishing_url("http://other_phishing_url.com/bla");
624 ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
625 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse);
626 // We navigate away. The callback cb should be revoked.
627 NavigateAndCommit(other_phishing_url);
628 // Wait for the pre-classification checks to finish for other_phishing_url.
629 WaitAndCheckPreClassificationChecks();
631 ClientSideDetectionService::ClientReportPhishingRequestCallback cb_other;
632 verdict.set_url(other_phishing_url.spec());
633 verdict.set_client_score(0.8f);
634 EXPECT_CALL(*csd_service_,
635 SendClientReportPhishingRequest(
636 Pointee(PartiallyEqualVerdict(verdict)), _))
637 .WillOnce(DoAll(DeleteArg<0>(),
638 SaveArg<1>(&cb_other),
639 QuitUIMessageLoop()));
640 std::vector<GURL> redirect_chain;
641 redirect_chain.push_back(other_phishing_url);
642 SetRedirectChain(redirect_chain);
643 OnPhishingDetectionDone(verdict.SerializeAsString());
644 base::MessageLoop::current()->Run();
645 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
646 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
647 ASSERT_FALSE(cb_other.is_null());
649 // We expect that the interstitial is shown for the second phishing URL and
650 // not for the first phishing URL.
651 UnsafeResource resource;
652 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
653 .WillOnce(SaveArg<0>(&resource));
655 cb.Run(phishing_url, true); // Should have no effect.
656 cb_other.Run(other_phishing_url, true); // Should show interstitial.
658 base::RunLoop().RunUntilIdle();
659 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
660 EXPECT_EQ(other_phishing_url, resource.url);
661 EXPECT_EQ(other_phishing_url, resource.original_url);
662 EXPECT_FALSE(resource.is_subresource);
663 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
664 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
665 resource.render_process_host_id);
666 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
667 resource.render_view_id);
669 // Make sure the client object will be deleted.
670 BrowserThread::PostTask(
671 BrowserThread::IO,
672 FROM_HERE,
673 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
674 ui_manager_, resource.callback));
677 TEST_F(ClientSideDetectionHostTest,
678 OnPhishingDetectionDoneVerdictNotPhishing) {
679 // Case 6: renderer sends a verdict string that isn't phishing.
680 MockBrowserFeatureExtractor* mock_extractor =
681 new StrictMock<MockBrowserFeatureExtractor>(
682 web_contents(),
683 csd_host_.get());
684 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
686 ClientPhishingRequest verdict;
687 verdict.set_url("http://not-phishing.com/");
688 verdict.set_client_score(0.1f);
689 verdict.set_is_phishing(false);
691 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
692 OnPhishingDetectionDone(verdict.SerializeAsString());
693 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
696 TEST_F(ClientSideDetectionHostTest,
697 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchSubResource) {
698 // Case 7: renderer sends a verdict string that isn't phishing but the URL
699 // of a subresource was on the regular phishing or malware lists.
700 GURL url("http://not-phishing.com/");
701 ClientPhishingRequest verdict;
702 verdict.set_url(url.spec());
703 verdict.set_client_score(0.1f);
704 verdict.set_is_phishing(false);
706 // First we have to navigate to the URL to set the unique page ID.
707 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
708 &kFalse, &kFalse, &kFalse, &kFalse);
709 NavigateAndCommit(url);
710 WaitAndCheckPreClassificationChecks();
711 SetUnsafeSubResourceForCurrent();
713 EXPECT_CALL(*csd_service_,
714 SendClientReportPhishingRequest(
715 Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
716 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
717 std::vector<GURL> redirect_chain;
718 redirect_chain.push_back(url);
719 SetRedirectChain(redirect_chain);
720 OnPhishingDetectionDone(verdict.SerializeAsString());
721 base::MessageLoop::current()->Run();
722 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
725 TEST_F(ClientSideDetectionHostTest,
726 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchOnNewRVH) {
727 // When navigating to a different host (thus creating a pending RVH) which
728 // matches regular malware list, and after navigation the renderer sends a
729 // verdict string that isn't phishing, we should still send the report.
731 // Do an initial navigation to a safe host.
732 GURL start_url("http://safe.example.com/");
733 ExpectPreClassificationChecks(
734 start_url, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
735 &kFalse);
736 NavigateAndCommit(start_url);
737 WaitAndCheckPreClassificationChecks();
739 // Now navigate to a different host which will have a malware hit before the
740 // navigation commits.
741 GURL url("http://malware-but-not-phishing.com/");
742 ClientPhishingRequest verdict;
743 verdict.set_url(url.spec());
744 verdict.set_client_score(0.1f);
745 verdict.set_is_phishing(false);
747 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
748 &kFalse, &kFalse, &kFalse, &kFalse);
749 NavigateWithSBHitAndCommit(url);
750 WaitAndCheckPreClassificationChecks();
752 EXPECT_CALL(*csd_service_,
753 SendClientReportPhishingRequest(
754 Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
755 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
756 std::vector<GURL> redirect_chain;
757 redirect_chain.push_back(url);
758 SetRedirectChain(redirect_chain);
759 OnPhishingDetectionDone(verdict.SerializeAsString());
760 base::MessageLoop::current()->Run();
761 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
763 ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse,
764 &kFalse, &kFalse, &kFalse, &kFalse);
765 NavigateWithoutSBHitAndCommit(start_url);
766 WaitAndCheckPreClassificationChecks();
769 TEST_F(ClientSideDetectionHostTest,
770 DidStopLoadingShowMalwareInterstitial) {
771 // Case 9: client thinks the page match malware IP and so does the server.
772 // We show an sub-resource malware interstitial.
773 MockBrowserFeatureExtractor* mock_extractor =
774 new StrictMock<MockBrowserFeatureExtractor>(
775 web_contents(),
776 csd_host_.get());
777 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
779 GURL malware_landing_url("http://malware.com/");
780 GURL malware_ip_url("http://badip.com");
781 ClientMalwareRequest malware_verdict;
782 malware_verdict.set_url("http://malware.com/");
783 ClientMalwareRequest::UrlInfo* badipurl =
784 malware_verdict.add_bad_ip_url_info();
785 badipurl->set_ip("1.2.3.4");
786 badipurl->set_url("http://badip.com");
788 ExpectPreClassificationChecks(GURL(malware_verdict.url()), &kFalse, &kFalse,
789 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
790 &kFalse);
791 NavigateAndCommit(GURL(malware_verdict.url()));
792 WaitAndCheckPreClassificationChecks();
794 ClientSideDetectionService::ClientReportMalwareRequestCallback cb;
795 EXPECT_CALL(*mock_extractor, ExtractMalwareFeatures(_, _, _))
796 .WillOnce(InvokeMalwareCallback(&malware_verdict));
797 EXPECT_CALL(*csd_service_,
798 SendClientReportMalwareRequest(
799 Pointee(PartiallyEqualMalwareVerdict(malware_verdict)), _))
800 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
801 DidStopLoading();
802 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
803 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
804 ASSERT_FALSE(cb.is_null());
806 UnsafeResource resource;
807 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
808 .WillOnce(SaveArg<0>(&resource));
809 cb.Run(malware_landing_url, malware_ip_url, true);
811 base::RunLoop().RunUntilIdle();
812 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
813 EXPECT_EQ(malware_ip_url, resource.url);
814 EXPECT_EQ(malware_landing_url, resource.original_url);
815 EXPECT_TRUE(resource.is_subresource);
816 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL, resource.threat_type);
817 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
818 resource.render_process_host_id);
819 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
820 resource.render_view_id);
822 // Make sure the client object will be deleted.
823 BrowserThread::PostTask(
824 BrowserThread::IO,
825 FROM_HERE,
826 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
827 ui_manager_, resource.callback));
830 TEST_F(ClientSideDetectionHostTest, UpdateIPUrlMap) {
831 BrowseInfo* browse_info = GetBrowseInfo();
833 // Empty IP or host are skipped
834 UpdateIPUrlMap("250.10.10.10", std::string());
835 ASSERT_EQ(0U, browse_info->ips.size());
836 UpdateIPUrlMap(std::string(), "http://google.com/a");
837 ASSERT_EQ(0U, browse_info->ips.size());
838 UpdateIPUrlMap(std::string(), std::string());
839 ASSERT_EQ(0U, browse_info->ips.size());
841 std::vector<IPUrlInfo> expected_urls;
842 for (int i = 0; i < 20; i++) {
843 std::string url = base::StringPrintf("http://%d.com/", i);
844 expected_urls.push_back(IPUrlInfo(url, "", "", ResourceType::OBJECT));
845 UpdateIPUrlMap("250.10.10.10", url);
847 ASSERT_EQ(1U, browse_info->ips.size());
848 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
849 CheckIPUrlEqual(expected_urls,
850 browse_info->ips["250.10.10.10"]);
852 // Add more urls for this ip, it exceeds max limit and won't be added
853 UpdateIPUrlMap("250.10.10.10", "http://21.com/");
854 ASSERT_EQ(1U, browse_info->ips.size());
855 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
856 CheckIPUrlEqual(expected_urls,
857 browse_info->ips["250.10.10.10"]);
859 // Add 199 more IPs
860 for (int i = 0; i < 199; i++) {
861 std::string ip = base::StringPrintf("%d.%d.%d.256", i, i, i);
862 expected_urls.clear();
863 expected_urls.push_back(IPUrlInfo("test.com/", "", "",
864 ResourceType::OBJECT));
865 UpdateIPUrlMap(ip, "test.com/");
866 ASSERT_EQ(1U, browse_info->ips[ip].size());
867 CheckIPUrlEqual(expected_urls,
868 browse_info->ips[ip]);
870 ASSERT_EQ(200U, browse_info->ips.size());
872 // Exceeding max ip limit 200, these won't be added
873 UpdateIPUrlMap("250.250.250.250", "goo.com/");
874 UpdateIPUrlMap("250.250.250.250", "bar.com/");
875 UpdateIPUrlMap("250.250.0.250", "foo.com/");
876 ASSERT_EQ(200U, browse_info->ips.size());
878 // Add url to existing IPs succeed
879 UpdateIPUrlMap("100.100.100.256", "more.com/");
880 ASSERT_EQ(2U, browse_info->ips["100.100.100.256"].size());
881 expected_urls.clear();
882 expected_urls.push_back(IPUrlInfo("test.com/", "", "", ResourceType::OBJECT));
883 expected_urls.push_back(IPUrlInfo("more.com/", "", "", ResourceType::OBJECT));
884 CheckIPUrlEqual(expected_urls,
885 browse_info->ips["100.100.100.256"]);
888 TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
889 // Test that canceling pending should classify requests works as expected.
891 GURL first_url("http://first.phishy.url.com");
892 GURL second_url("http://second.url.com/");
893 // The first few checks are done synchronously so check that they have been
894 // done for the first URL, while the second URL has all the checks done. We
895 // need to manually set up the IsPrivateIPAddress mock since if the same mock
896 // expectation is specified twice, gmock will only use the last instance of
897 // it, meaning the first will never be matched.
898 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
899 .WillOnce(Return(false))
900 .WillOnce(Return(false));
901 ExpectPreClassificationChecks(first_url, NULL, &kFalse, &kFalse, &kFalse,
902 NULL, NULL, NULL, NULL);
903 ExpectPreClassificationChecks(second_url, NULL, &kFalse, &kFalse, &kFalse,
904 &kFalse, &kFalse, &kFalse, &kFalse);
906 NavigateAndCommit(first_url);
907 // Don't flush the message loop, as we want to navigate to a different
908 // url before the final pre-classification checks are run.
909 NavigateAndCommit(second_url);
910 WaitAndCheckPreClassificationChecks();
913 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckPass) {
914 // Navigate the tab to a page. We should see a StartPhishingDetection IPC.
915 GURL url("http://host.com/");
916 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
917 &kFalse, &kFalse, &kFalse, &kFalse);
918 NavigateAndCommit(url);
919 WaitAndCheckPreClassificationChecks();
921 ExpectStartPhishingDetection(&url);
922 ExpectShouldClassifyForMalwareResult(true);
925 TEST_F(ClientSideDetectionHostTest,
926 TestPreClassificationCheckInPageNavigation) {
927 GURL url("http://host.com/");
928 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
929 &kFalse, &kFalse, &kFalse, &kFalse);
930 NavigateAndCommit(url);
931 WaitAndCheckPreClassificationChecks();
933 ExpectStartPhishingDetection(&url);
934 ExpectShouldClassifyForMalwareResult(true);
936 // Now try an in-page navigation. This should not trigger an IPC.
937 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0);
938 GURL inpage("http://host.com/#foo");
939 ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL,
940 NULL, NULL);
941 NavigateAndCommit(inpage);
942 WaitAndCheckPreClassificationChecks();
944 ExpectStartPhishingDetection(NULL);
945 ExpectShouldClassifyForMalwareResult(true);
948 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckXHTML) {
949 // Check that XHTML is supported, in addition to the default HTML type.
950 GURL url("http://host.com/xhtml");
951 rvh_tester()->SetContentsMimeType("application/xhtml+xml");
952 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
953 &kFalse, &kFalse, &kFalse, &kFalse);
954 NavigateAndCommit(url);
955 WaitAndCheckPreClassificationChecks();
957 ExpectStartPhishingDetection(&url);
958 ExpectShouldClassifyForMalwareResult(true);
961 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckTwoNavigations) {
962 // Navigate to two hosts, which should cause two IPCs.
963 GURL url1("http://host1.com/");
964 ExpectPreClassificationChecks(url1, &kFalse, &kFalse, &kFalse, &kFalse,
965 &kFalse, &kFalse, &kFalse, &kFalse);
966 NavigateAndCommit(url1);
967 WaitAndCheckPreClassificationChecks();
969 ExpectStartPhishingDetection(&url1);
970 ExpectShouldClassifyForMalwareResult(true);
972 GURL url2("http://host2.com/");
973 ExpectPreClassificationChecks(url2, &kFalse, &kFalse, &kFalse, &kFalse,
974 &kFalse, &kFalse, &kFalse, &kFalse);
975 NavigateAndCommit(url2);
976 WaitAndCheckPreClassificationChecks();
978 ExpectStartPhishingDetection(&url2);
979 ExpectShouldClassifyForMalwareResult(true);
982 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckMimeType) {
983 // If the mime type is not one that we support, no IPC should be triggered
984 // but all pre-classification checks should run because we might classify
985 // other mime types for malware.
986 // Note: for this test to work correctly, the new URL must be on the
987 // same domain as the previous URL, otherwise it will create a new
988 // RenderViewHost that won't have the mime type set.
989 GURL url("http://host2.com/image.jpg");
990 rvh_tester()->SetContentsMimeType("image/jpeg");
991 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
992 &kFalse, &kFalse,&kFalse, &kFalse);
993 NavigateAndCommit(url);
994 WaitAndCheckPreClassificationChecks();
996 ExpectStartPhishingDetection(NULL);
997 ExpectShouldClassifyForMalwareResult(true);
1000 TEST_F(ClientSideDetectionHostTest,
1001 TestPreClassificationCheckPrivateIpAddress) {
1002 // If IsPrivateIPAddress returns true, no IPC should be triggered.
1003 GURL url("http://host3.com/");
1004 ExpectPreClassificationChecks(url, &kTrue, &kFalse, NULL, NULL, NULL, NULL,
1005 NULL, NULL);
1006 NavigateAndCommit(url);
1007 WaitAndCheckPreClassificationChecks();
1008 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
1009 SafeBrowsingMsg_StartPhishingDetection::ID);
1010 ASSERT_FALSE(msg);
1011 ExpectShouldClassifyForMalwareResult(false);
1014 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckIncognito) {
1015 // If the tab is incognito there should be no IPC. Also, we shouldn't
1016 // even check the csd-whitelist.
1017 GURL url("http://host4.com/");
1018 ExpectPreClassificationChecks(url, &kFalse, &kTrue, NULL, NULL, NULL, NULL,
1019 NULL, NULL);
1020 NavigateAndCommit(url);
1021 WaitAndCheckPreClassificationChecks();
1023 ExpectStartPhishingDetection(NULL);
1024 ExpectShouldClassifyForMalwareResult(false);
1027 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckCsdWhitelist) {
1028 // If the URL is on the csd whitelist no phishing IPC should be sent
1029 // but we should classify the URL for malware.
1030 GURL url("http://host5.com/");
1031 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kFalse, &kFalse,
1032 &kFalse, &kFalse, &kFalse);
1033 NavigateAndCommit(url);
1034 WaitAndCheckPreClassificationChecks();
1036 ExpectStartPhishingDetection(NULL);
1037 ExpectShouldClassifyForMalwareResult(true);
1040 TEST_F(ClientSideDetectionHostTest,
1041 TestPreClassificationCheckMalwareKillSwitch) {
1042 // If the malware killswitch is on we shouldn't classify the page for malware.
1043 GURL url("http://host5.com/kill-switch");
1044 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, &kFalse,
1045 &kFalse, &kFalse, &kFalse);
1046 NavigateAndCommit(url);
1047 WaitAndCheckPreClassificationChecks();
1049 ExpectStartPhishingDetection(&url);
1050 ExpectShouldClassifyForMalwareResult(false);
1053 TEST_F(ClientSideDetectionHostTest,
1054 TestPreClassificationCheckKillswitchAndCsdWhitelist) {
1055 // If both the malware kill-swtich is on and the URL is on the csd whitelist,
1056 // we will leave pre-classification checks early.
1057 GURL url("http://host5.com/kill-switch-and-whitelisted");
1058 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kTrue, NULL,
1059 NULL, NULL, NULL);
1060 NavigateAndCommit(url);
1061 WaitAndCheckPreClassificationChecks();
1063 ExpectStartPhishingDetection(NULL);
1064 ExpectShouldClassifyForMalwareResult(false);
1067 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckInvalidCache) {
1068 // If item is in the cache but it isn't valid, we will classify regardless
1069 // of whether we are over the reporting limit.
1070 GURL url("http://host6.com/");
1071 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1072 &kFalse, &kTrue, NULL, &kFalse);
1074 NavigateAndCommit(url);
1075 WaitAndCheckPreClassificationChecks();
1077 ExpectStartPhishingDetection(&url);
1078 ExpectShouldClassifyForMalwareResult(true);
1081 TEST_F(ClientSideDetectionHostTest,
1082 TestPreClassificationCheckOverPhishingReportingLimit) {
1083 // If the url isn't in the cache and we are over the reporting limit, we
1084 // don't do classification.
1085 GURL url("http://host7.com/");
1086 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1087 &kFalse, &kFalse, &kTrue, &kFalse);
1088 NavigateAndCommit(url);
1089 WaitAndCheckPreClassificationChecks();
1091 ExpectStartPhishingDetection(NULL);
1092 ExpectShouldClassifyForMalwareResult(true);
1095 TEST_F(ClientSideDetectionHostTest,
1096 TestPreClassificationCheckOverMalwareReportingLimit) {
1097 GURL url("http://host.com/");
1098 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1099 &kFalse, &kFalse, &kFalse, &kTrue);
1100 NavigateAndCommit(url);
1101 WaitAndCheckPreClassificationChecks();
1103 ExpectStartPhishingDetection(&url);
1104 ExpectShouldClassifyForMalwareResult(false);
1107 TEST_F(ClientSideDetectionHostTest,
1108 TestPreClassificationCheckOverBothReportingLimits) {
1109 GURL url("http://host.com/");
1110 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1111 &kFalse, &kFalse, &kTrue, &kTrue);
1112 NavigateAndCommit(url);
1113 WaitAndCheckPreClassificationChecks();
1115 ExpectStartPhishingDetection(NULL);
1116 ExpectShouldClassifyForMalwareResult(false);
1119 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckHttpsUrl) {
1120 GURL url("https://host.com/");
1121 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
1122 &kFalse, &kFalse, &kFalse, &kFalse);
1123 NavigateAndCommit(url);
1124 WaitAndCheckPreClassificationChecks();
1126 ExpectStartPhishingDetection(NULL);
1127 ExpectShouldClassifyForMalwareResult(true);
1130 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckValidCached) {
1131 // If result is cached, we will try and display the blocking page directly
1132 // with no start classification message.
1133 GURL url("http://host8.com/");
1134 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue,
1135 &kFalse, &kFalse, &kFalse);
1137 UnsafeResource resource;
1138 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
1139 .WillOnce(SaveArg<0>(&resource));
1141 NavigateAndCommit(url);
1142 WaitAndCheckPreClassificationChecks();
1143 EXPECT_EQ(url, resource.url);
1144 EXPECT_EQ(url, resource.original_url);
1146 ExpectStartPhishingDetection(NULL);
1148 // Showing a phishing warning will invalidate all the weak pointers which
1149 // means we will not extract malware features.
1150 ExpectShouldClassifyForMalwareResult(false);
1152 } // namespace safe_browsing