Update mojo surfaces bindings and mojo/cc/ glue
[chromium-blink-merge.git] / chrome / browser / safe_browsing / client_side_detection_host_unittest.cc
blob20590b5966bb5f2788c8891815f50ed01b34c09a
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::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 virtual void SetUp() {
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 virtual void TearDown() {
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 virtual 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() {
249 csd_host_->DidStopLoading(pending_rvh());
252 void UpdateIPUrlMap(const std::string& ip, const std::string& host) {
253 csd_host_->UpdateIPUrlMap(ip, host, "", "", content::RESOURCE_TYPE_OBJECT);
256 BrowseInfo* GetBrowseInfo() {
257 return csd_host_->browse_info_.get();
260 void ExpectPreClassificationChecks(const GURL& url,
261 const bool* is_private,
262 const bool* is_incognito,
263 const bool* match_csd_whitelist,
264 const bool* malware_killswitch,
265 const bool* get_valid_cached_result,
266 const bool* is_in_cache,
267 const bool* over_phishing_report_limit,
268 const bool* over_malware_report_limit) {
269 if (is_private) {
270 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
271 .WillOnce(Return(*is_private));
273 if (is_incognito) {
274 EXPECT_CALL(*mock_profile_, IsOffTheRecord())
275 .WillRepeatedly(Return(*is_incognito));
277 if (match_csd_whitelist) {
278 EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(url))
279 .WillOnce(Return(*match_csd_whitelist));
281 if (malware_killswitch) {
282 EXPECT_CALL(*database_manager_.get(), IsMalwareKillSwitchOn())
283 .WillRepeatedly(Return(*malware_killswitch));
285 if (get_valid_cached_result) {
286 EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull()))
287 .WillOnce(DoAll(SetArgumentPointee<1>(true),
288 Return(*get_valid_cached_result)));
290 if (is_in_cache) {
291 EXPECT_CALL(*csd_service_, IsInCache(url)).WillOnce(Return(*is_in_cache));
293 if (over_phishing_report_limit) {
294 EXPECT_CALL(*csd_service_, OverPhishingReportLimit())
295 .WillOnce(Return(*over_phishing_report_limit));
297 if (over_malware_report_limit) {
298 EXPECT_CALL(*csd_service_, OverMalwareReportLimit())
299 .WillOnce(Return(*over_malware_report_limit));
303 void WaitAndCheckPreClassificationChecks() {
304 // Wait for CheckCsdWhitelist and CheckCache() to be called if at all.
305 base::RunLoop().RunUntilIdle();
306 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
307 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
308 EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get()));
309 EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
312 void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
313 csd_host_->feature_extractor_.reset(extractor);
316 void SetRedirectChain(const std::vector<GURL>& redirect_chain) {
317 csd_host_->browse_info_->url_redirects = redirect_chain;
320 void SetReferrer(const GURL& referrer) {
321 csd_host_->browse_info_->referrer = referrer;
324 void ExpectShouldClassifyForMalwareResult(bool should_classify) {
325 EXPECT_EQ(should_classify, csd_host_->should_classify_for_malware_);
328 void ExpectStartPhishingDetection(const GURL* url) {
329 const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
330 SafeBrowsingMsg_StartPhishingDetection::ID);
331 if (url) {
332 ASSERT_TRUE(msg);
333 Tuple1<GURL> actual_url;
334 SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
335 EXPECT_EQ(*url, actual_url.a);
336 EXPECT_EQ(rvh()->GetRoutingID(), msg->routing_id());
337 process()->sink().ClearMessages();
338 } else {
339 ASSERT_FALSE(msg);
343 void TestUnsafeResourceCopied(const UnsafeResource& resource) {
344 ASSERT_TRUE(csd_host_->unsafe_resource_.get());
345 // Test that the resource from OnSafeBrowsingHit notification was copied
346 // into the CSDH.
347 EXPECT_EQ(resource.url, csd_host_->unsafe_resource_->url);
348 EXPECT_EQ(resource.original_url, csd_host_->unsafe_resource_->original_url);
349 EXPECT_EQ(resource.is_subresource,
350 csd_host_->unsafe_resource_->is_subresource);
351 EXPECT_EQ(resource.threat_type, csd_host_->unsafe_resource_->threat_type);
352 EXPECT_TRUE(csd_host_->unsafe_resource_->callback.is_null());
353 EXPECT_EQ(resource.render_process_host_id,
354 csd_host_->unsafe_resource_->render_process_host_id);
355 EXPECT_EQ(resource.render_view_id,
356 csd_host_->unsafe_resource_->render_view_id);
359 void SetUnsafeSubResourceForCurrent() {
360 UnsafeResource resource;
361 resource.url = GURL("http://www.malware.com/");
362 resource.original_url = web_contents()->GetURL();
363 resource.is_subresource = true;
364 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
365 resource.callback = base::Bind(&EmptyUrlCheckCallback);
366 resource.render_process_host_id = web_contents()->GetRenderProcessHost()->
367 GetID();
368 resource.render_view_id =
369 web_contents()->GetRenderViewHost()->GetRoutingID();
370 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
371 csd_host_->OnSafeBrowsingMatch(resource);
372 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
373 csd_host_->OnSafeBrowsingHit(resource);
374 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
375 resource.callback.Reset();
376 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
377 TestUnsafeResourceCopied(resource);
380 void NavigateWithSBHitAndCommit(const GURL& url) {
381 // Create a pending navigation.
382 controller().LoadURL(
383 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
385 ASSERT_TRUE(pending_rvh());
386 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
387 pending_rvh()->GetProcess()->GetID()) {
388 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
389 pending_rvh()->GetRoutingID());
392 // Simulate a safebrowsing hit before navigation completes.
393 UnsafeResource resource;
394 resource.url = url;
395 resource.original_url = url;
396 resource.is_subresource = false;
397 resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
398 resource.callback = base::Bind(&EmptyUrlCheckCallback);
399 resource.render_process_host_id = pending_rvh()->GetProcess()->GetID();
400 resource.render_view_id = pending_rvh()->GetRoutingID();
401 csd_host_->OnSafeBrowsingMatch(resource);
402 csd_host_->OnSafeBrowsingHit(resource);
403 resource.callback.Reset();
405 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
407 // LoadURL created a navigation entry, now simulate the RenderView sending
408 // a notification that it actually navigated.
409 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
411 ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
412 ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
413 TestUnsafeResourceCopied(resource);
416 void NavigateWithoutSBHitAndCommit(const GURL& safe_url) {
417 controller().LoadURL(
418 safe_url, content::Referrer(), content::PAGE_TRANSITION_LINK,
419 std::string());
421 ASSERT_TRUE(pending_rvh());
422 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
423 pending_rvh()->GetProcess()->GetID()) {
424 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
425 pending_rvh()->GetRoutingID());
427 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
428 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
430 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
431 ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
432 ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
435 void CheckIPUrlEqual(const std::vector<IPUrlInfo>& expect,
436 const std::vector<IPUrlInfo>& result) {
437 ASSERT_EQ(expect.size(), result.size());
439 for (unsigned int i = 0; i < expect.size(); ++i) {
440 EXPECT_EQ(expect[i].url, result[i].url);
441 EXPECT_EQ(expect[i].method, result[i].method);
442 EXPECT_EQ(expect[i].referrer, result[i].referrer);
443 EXPECT_EQ(expect[i].resource_type, result[i].resource_type);
447 protected:
448 scoped_ptr<ClientSideDetectionHost> csd_host_;
449 scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
450 scoped_refptr<StrictMock<MockSafeBrowsingUIManager> > ui_manager_;
451 scoped_refptr<StrictMock<MockSafeBrowsingDatabaseManager> > database_manager_;
452 MockTestingProfile* mock_profile_; // We don't own this object
455 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneInvalidVerdict) {
456 // Case 0: renderer sends an invalid verdict string that we're unable to
457 // parse.
458 MockBrowserFeatureExtractor* mock_extractor =
459 new StrictMock<MockBrowserFeatureExtractor>(
460 web_contents(),
461 csd_host_.get());
462 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
463 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
464 OnPhishingDetectionDone("Invalid Protocol Buffer");
465 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
468 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneNotPhishing) {
469 // Case 1: client thinks the page is phishing. The server does not agree.
470 // No interstitial is shown.
471 MockBrowserFeatureExtractor* mock_extractor =
472 new StrictMock<MockBrowserFeatureExtractor>(
473 web_contents(),
474 csd_host_.get());
475 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
477 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
478 ClientPhishingRequest verdict;
479 verdict.set_url("http://phishingurl.com/");
480 verdict.set_client_score(1.0f);
481 verdict.set_is_phishing(true);
483 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
484 .WillOnce(InvokeDoneCallback(&verdict));
485 EXPECT_CALL(*csd_service_,
486 SendClientReportPhishingRequest(
487 Pointee(PartiallyEqualVerdict(verdict)), _))
488 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
489 OnPhishingDetectionDone(verdict.SerializeAsString());
490 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
491 ASSERT_FALSE(cb.is_null());
493 // Make sure DisplayBlockingPage is not going to be called.
494 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
495 cb.Run(GURL(verdict.url()), false);
496 base::RunLoop().RunUntilIdle();
497 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
500 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneDisabled) {
501 // Case 2: client thinks the page is phishing and so does the server but
502 // showing the interstitial is disabled => no interstitial is shown.
503 MockBrowserFeatureExtractor* mock_extractor =
504 new StrictMock<MockBrowserFeatureExtractor>(
505 web_contents(),
506 csd_host_.get());
507 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
509 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
510 ClientPhishingRequest verdict;
511 verdict.set_url("http://phishingurl.com/");
512 verdict.set_client_score(1.0f);
513 verdict.set_is_phishing(true);
515 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
516 .WillOnce(InvokeDoneCallback(&verdict));
517 EXPECT_CALL(*csd_service_,
518 SendClientReportPhishingRequest(
519 Pointee(PartiallyEqualVerdict(verdict)), _))
520 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
521 OnPhishingDetectionDone(verdict.SerializeAsString());
522 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
523 ASSERT_FALSE(cb.is_null());
525 // Make sure DisplayBlockingPage is not going to be called.
526 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
527 cb.Run(GURL(verdict.url()), false);
528 base::RunLoop().RunUntilIdle();
529 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
532 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneShowInterstitial) {
533 // Case 3: client thinks the page is phishing and so does the server.
534 // We show an interstitial.
535 MockBrowserFeatureExtractor* mock_extractor =
536 new StrictMock<MockBrowserFeatureExtractor>(
537 web_contents(),
538 csd_host_.get());
539 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
541 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
542 GURL phishing_url("http://phishingurl.com/");
543 ClientPhishingRequest verdict;
544 verdict.set_url(phishing_url.spec());
545 verdict.set_client_score(1.0f);
546 verdict.set_is_phishing(true);
548 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
549 .WillOnce(InvokeDoneCallback(&verdict));
550 EXPECT_CALL(*csd_service_,
551 SendClientReportPhishingRequest(
552 Pointee(PartiallyEqualVerdict(verdict)), _))
553 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
554 OnPhishingDetectionDone(verdict.SerializeAsString());
555 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
556 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
557 ASSERT_FALSE(cb.is_null());
559 UnsafeResource resource;
560 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
561 .WillOnce(SaveArg<0>(&resource));
562 cb.Run(phishing_url, true);
564 base::RunLoop().RunUntilIdle();
565 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
566 EXPECT_EQ(phishing_url, resource.url);
567 EXPECT_EQ(phishing_url, resource.original_url);
568 EXPECT_FALSE(resource.is_subresource);
569 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
570 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
571 resource.render_process_host_id);
572 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
573 resource.render_view_id);
575 // Make sure the client object will be deleted.
576 BrowserThread::PostTask(
577 BrowserThread::IO,
578 FROM_HERE,
579 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
580 ui_manager_, resource.callback));
583 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneMultiplePings) {
584 // Case 4 & 5: client thinks a page is phishing then navigates to
585 // another page which is also considered phishing by the client
586 // before the server responds with a verdict. After a while the
587 // server responds for both requests with a phishing verdict. Only
588 // a single interstitial is shown for the second URL.
589 MockBrowserFeatureExtractor* mock_extractor =
590 new StrictMock<MockBrowserFeatureExtractor>(
591 web_contents(),
592 csd_host_.get());
593 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
595 ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
596 GURL phishing_url("http://phishingurl.com/");
597 ClientPhishingRequest verdict;
598 verdict.set_url(phishing_url.spec());
599 verdict.set_client_score(1.0f);
600 verdict.set_is_phishing(true);
602 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
603 .WillOnce(InvokeDoneCallback(&verdict));
604 EXPECT_CALL(*csd_service_,
605 SendClientReportPhishingRequest(
606 Pointee(PartiallyEqualVerdict(verdict)), _))
607 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
608 OnPhishingDetectionDone(verdict.SerializeAsString());
609 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
610 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
611 ASSERT_FALSE(cb.is_null());
613 // Set this back to a normal browser feature extractor since we're using
614 // NavigateAndCommit() and it's easier to use the real thing than setting up
615 // mock expectations.
616 SetFeatureExtractor(new BrowserFeatureExtractor(web_contents(),
617 csd_host_.get()));
618 GURL other_phishing_url("http://other_phishing_url.com/bla");
619 ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
620 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse);
621 // We navigate away. The callback cb should be revoked.
622 NavigateAndCommit(other_phishing_url);
623 // Wait for the pre-classification checks to finish for other_phishing_url.
624 WaitAndCheckPreClassificationChecks();
626 ClientSideDetectionService::ClientReportPhishingRequestCallback cb_other;
627 verdict.set_url(other_phishing_url.spec());
628 verdict.set_client_score(0.8f);
629 EXPECT_CALL(*csd_service_,
630 SendClientReportPhishingRequest(
631 Pointee(PartiallyEqualVerdict(verdict)), _))
632 .WillOnce(DoAll(DeleteArg<0>(),
633 SaveArg<1>(&cb_other),
634 QuitUIMessageLoop()));
635 std::vector<GURL> redirect_chain;
636 redirect_chain.push_back(other_phishing_url);
637 SetRedirectChain(redirect_chain);
638 OnPhishingDetectionDone(verdict.SerializeAsString());
639 base::MessageLoop::current()->Run();
640 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
641 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
642 ASSERT_FALSE(cb_other.is_null());
644 // We expect that the interstitial is shown for the second phishing URL and
645 // not for the first phishing URL.
646 UnsafeResource resource;
647 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
648 .WillOnce(SaveArg<0>(&resource));
650 cb.Run(phishing_url, true); // Should have no effect.
651 cb_other.Run(other_phishing_url, true); // Should show interstitial.
653 base::RunLoop().RunUntilIdle();
654 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
655 EXPECT_EQ(other_phishing_url, resource.url);
656 EXPECT_EQ(other_phishing_url, resource.original_url);
657 EXPECT_FALSE(resource.is_subresource);
658 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
659 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
660 resource.render_process_host_id);
661 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
662 resource.render_view_id);
664 // Make sure the client object will be deleted.
665 BrowserThread::PostTask(
666 BrowserThread::IO,
667 FROM_HERE,
668 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
669 ui_manager_, resource.callback));
672 TEST_F(ClientSideDetectionHostTest,
673 OnPhishingDetectionDoneVerdictNotPhishing) {
674 // Case 6: renderer sends a verdict string that isn't phishing.
675 MockBrowserFeatureExtractor* mock_extractor =
676 new StrictMock<MockBrowserFeatureExtractor>(
677 web_contents(),
678 csd_host_.get());
679 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
681 ClientPhishingRequest verdict;
682 verdict.set_url("http://not-phishing.com/");
683 verdict.set_client_score(0.1f);
684 verdict.set_is_phishing(false);
686 EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
687 OnPhishingDetectionDone(verdict.SerializeAsString());
688 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
691 TEST_F(ClientSideDetectionHostTest,
692 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchSubResource) {
693 // Case 7: renderer sends a verdict string that isn't phishing but the URL
694 // of a subresource was on the regular phishing or malware lists.
695 GURL url("http://not-phishing.com/");
696 ClientPhishingRequest verdict;
697 verdict.set_url(url.spec());
698 verdict.set_client_score(0.1f);
699 verdict.set_is_phishing(false);
701 // First we have to navigate to the URL to set the unique page ID.
702 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
703 &kFalse, &kFalse, &kFalse, &kFalse);
704 NavigateAndCommit(url);
705 WaitAndCheckPreClassificationChecks();
706 SetUnsafeSubResourceForCurrent();
708 EXPECT_CALL(*csd_service_,
709 SendClientReportPhishingRequest(
710 Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
711 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
712 std::vector<GURL> redirect_chain;
713 redirect_chain.push_back(url);
714 SetRedirectChain(redirect_chain);
715 OnPhishingDetectionDone(verdict.SerializeAsString());
716 base::MessageLoop::current()->Run();
717 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
720 TEST_F(ClientSideDetectionHostTest,
721 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchOnNewRVH) {
722 // When navigating to a different host (thus creating a pending RVH) which
723 // matches regular malware list, and after navigation the renderer sends a
724 // verdict string that isn't phishing, we should still send the report.
726 // Do an initial navigation to a safe host.
727 GURL start_url("http://safe.example.com/");
728 ExpectPreClassificationChecks(
729 start_url, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
730 &kFalse);
731 NavigateAndCommit(start_url);
732 WaitAndCheckPreClassificationChecks();
734 // Now navigate to a different host which will have a malware hit before the
735 // navigation commits.
736 GURL url("http://malware-but-not-phishing.com/");
737 ClientPhishingRequest verdict;
738 verdict.set_url(url.spec());
739 verdict.set_client_score(0.1f);
740 verdict.set_is_phishing(false);
742 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
743 &kFalse, &kFalse, &kFalse, &kFalse);
744 NavigateWithSBHitAndCommit(url);
745 WaitAndCheckPreClassificationChecks();
747 EXPECT_CALL(*csd_service_,
748 SendClientReportPhishingRequest(
749 Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
750 .WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
751 std::vector<GURL> redirect_chain;
752 redirect_chain.push_back(url);
753 SetRedirectChain(redirect_chain);
754 OnPhishingDetectionDone(verdict.SerializeAsString());
755 base::MessageLoop::current()->Run();
756 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
758 ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse,
759 &kFalse, &kFalse, &kFalse, &kFalse);
760 NavigateWithoutSBHitAndCommit(start_url);
761 WaitAndCheckPreClassificationChecks();
764 TEST_F(ClientSideDetectionHostTest,
765 DidStopLoadingShowMalwareInterstitial) {
766 // Case 9: client thinks the page match malware IP and so does the server.
767 // We show an sub-resource malware interstitial.
768 MockBrowserFeatureExtractor* mock_extractor =
769 new StrictMock<MockBrowserFeatureExtractor>(
770 web_contents(),
771 csd_host_.get());
772 SetFeatureExtractor(mock_extractor); // The host class takes ownership.
774 GURL malware_landing_url("http://malware.com/");
775 GURL malware_ip_url("http://badip.com");
776 ClientMalwareRequest malware_verdict;
777 malware_verdict.set_url("http://malware.com/");
778 ClientMalwareRequest::UrlInfo* badipurl =
779 malware_verdict.add_bad_ip_url_info();
780 badipurl->set_ip("1.2.3.4");
781 badipurl->set_url("http://badip.com");
783 ExpectPreClassificationChecks(GURL(malware_verdict.url()), &kFalse, &kFalse,
784 &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
785 &kFalse);
786 NavigateAndCommit(GURL(malware_verdict.url()));
787 WaitAndCheckPreClassificationChecks();
789 ClientSideDetectionService::ClientReportMalwareRequestCallback cb;
790 EXPECT_CALL(*mock_extractor, ExtractMalwareFeatures(_, _, _))
791 .WillOnce(InvokeMalwareCallback(&malware_verdict));
792 EXPECT_CALL(*csd_service_,
793 SendClientReportMalwareRequest(
794 Pointee(PartiallyEqualMalwareVerdict(malware_verdict)), _))
795 .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
796 DidStopLoading();
797 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
798 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
799 ASSERT_FALSE(cb.is_null());
801 UnsafeResource resource;
802 EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
803 .WillOnce(SaveArg<0>(&resource));
804 cb.Run(malware_landing_url, malware_ip_url, true);
806 base::RunLoop().RunUntilIdle();
807 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
808 EXPECT_EQ(malware_ip_url, resource.url);
809 EXPECT_EQ(malware_landing_url, resource.original_url);
810 EXPECT_TRUE(resource.is_subresource);
811 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL, resource.threat_type);
812 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
813 resource.render_process_host_id);
814 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
815 resource.render_view_id);
817 // Make sure the client object will be deleted.
818 BrowserThread::PostTask(
819 BrowserThread::IO,
820 FROM_HERE,
821 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
822 ui_manager_, resource.callback));
825 TEST_F(ClientSideDetectionHostTest, UpdateIPUrlMap) {
826 BrowseInfo* browse_info = GetBrowseInfo();
828 // Empty IP or host are skipped
829 UpdateIPUrlMap("250.10.10.10", std::string());
830 ASSERT_EQ(0U, browse_info->ips.size());
831 UpdateIPUrlMap(std::string(), "http://google.com/a");
832 ASSERT_EQ(0U, browse_info->ips.size());
833 UpdateIPUrlMap(std::string(), std::string());
834 ASSERT_EQ(0U, browse_info->ips.size());
836 std::vector<IPUrlInfo> expected_urls;
837 for (int i = 0; i < 20; i++) {
838 std::string url = base::StringPrintf("http://%d.com/", i);
839 expected_urls.push_back(
840 IPUrlInfo(url, "", "", content::RESOURCE_TYPE_OBJECT));
841 UpdateIPUrlMap("250.10.10.10", url);
843 ASSERT_EQ(1U, browse_info->ips.size());
844 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
845 CheckIPUrlEqual(expected_urls,
846 browse_info->ips["250.10.10.10"]);
848 // Add more urls for this ip, it exceeds max limit and won't be added
849 UpdateIPUrlMap("250.10.10.10", "http://21.com/");
850 ASSERT_EQ(1U, browse_info->ips.size());
851 ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
852 CheckIPUrlEqual(expected_urls,
853 browse_info->ips["250.10.10.10"]);
855 // Add 199 more IPs
856 for (int i = 0; i < 199; i++) {
857 std::string ip = base::StringPrintf("%d.%d.%d.256", i, i, i);
858 expected_urls.clear();
859 expected_urls.push_back(
860 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT));
861 UpdateIPUrlMap(ip, "test.com/");
862 ASSERT_EQ(1U, browse_info->ips[ip].size());
863 CheckIPUrlEqual(expected_urls,
864 browse_info->ips[ip]);
866 ASSERT_EQ(200U, browse_info->ips.size());
868 // Exceeding max ip limit 200, these won't be added
869 UpdateIPUrlMap("250.250.250.250", "goo.com/");
870 UpdateIPUrlMap("250.250.250.250", "bar.com/");
871 UpdateIPUrlMap("250.250.0.250", "foo.com/");
872 ASSERT_EQ(200U, browse_info->ips.size());
874 // Add url to existing IPs succeed
875 UpdateIPUrlMap("100.100.100.256", "more.com/");
876 ASSERT_EQ(2U, browse_info->ips["100.100.100.256"].size());
877 expected_urls.clear();
878 expected_urls.push_back(
879 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT));
880 expected_urls.push_back(
881 IPUrlInfo("more.com/", "", "", content::RESOURCE_TYPE_OBJECT));
882 CheckIPUrlEqual(expected_urls,
883 browse_info->ips["100.100.100.256"]);
886 TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
887 // Test that canceling pending should classify requests works as expected.
889 GURL first_url("http://first.phishy.url.com");
890 GURL second_url("http://second.url.com/");
891 // The first few checks are done synchronously so check that they have been
892 // done for the first URL, while the second URL has all the checks done. We
893 // need to manually set up the IsPrivateIPAddress mock since if the same mock
894 // expectation is specified twice, gmock will only use the last instance of
895 // it, meaning the first will never be matched.
896 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
897 .WillOnce(Return(false))
898 .WillOnce(Return(false));
899 ExpectPreClassificationChecks(first_url, NULL, &kFalse, &kFalse, &kFalse,
900 NULL, NULL, NULL, NULL);
901 ExpectPreClassificationChecks(second_url, NULL, &kFalse, &kFalse, &kFalse,
902 &kFalse, &kFalse, &kFalse, &kFalse);
904 NavigateAndCommit(first_url);
905 // Don't flush the message loop, as we want to navigate to a different
906 // url before the final pre-classification checks are run.
907 NavigateAndCommit(second_url);
908 WaitAndCheckPreClassificationChecks();
911 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckPass) {
912 // Navigate the tab to a page. We should see a StartPhishingDetection IPC.
913 GURL url("http://host.com/");
914 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
915 &kFalse, &kFalse, &kFalse, &kFalse);
916 NavigateAndCommit(url);
917 WaitAndCheckPreClassificationChecks();
919 ExpectStartPhishingDetection(&url);
920 ExpectShouldClassifyForMalwareResult(true);
923 TEST_F(ClientSideDetectionHostTest,
924 TestPreClassificationCheckInPageNavigation) {
925 GURL url("http://host.com/");
926 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
927 &kFalse, &kFalse, &kFalse, &kFalse);
928 NavigateAndCommit(url);
929 WaitAndCheckPreClassificationChecks();
931 ExpectStartPhishingDetection(&url);
932 ExpectShouldClassifyForMalwareResult(true);
934 // Now try an in-page navigation. This should not trigger an IPC.
935 EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0);
936 GURL inpage("http://host.com/#foo");
937 ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL,
938 NULL, NULL);
939 NavigateAndCommit(inpage);
940 WaitAndCheckPreClassificationChecks();
942 ExpectStartPhishingDetection(NULL);
943 ExpectShouldClassifyForMalwareResult(true);
946 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckXHTML) {
947 // Check that XHTML is supported, in addition to the default HTML type.
948 GURL url("http://host.com/xhtml");
949 rvh_tester()->SetContentsMimeType("application/xhtml+xml");
950 ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
951 &kFalse, &kFalse, &kFalse, &kFalse);
952 NavigateAndCommit(url);
953 WaitAndCheckPreClassificationChecks();
955 ExpectStartPhishingDetection(&url);
956 ExpectShouldClassifyForMalwareResult(true);
959 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckTwoNavigations) {
960 // Navigate to two hosts, which should cause two IPCs.
961 GURL url1("http://host1.com/");
962 ExpectPreClassificationChecks(url1, &kFalse, &kFalse, &kFalse, &kFalse,
963 &kFalse, &kFalse, &kFalse, &kFalse);
964 NavigateAndCommit(url1);
965 WaitAndCheckPreClassificationChecks();
967 ExpectStartPhishingDetection(&url1);
968 ExpectShouldClassifyForMalwareResult(true);
970 GURL url2("http://host2.com/");
971 ExpectPreClassificationChecks(url2, &kFalse, &kFalse, &kFalse, &kFalse,
972 &kFalse, &kFalse, &kFalse, &kFalse);
973 NavigateAndCommit(url2);
974 WaitAndCheckPreClassificationChecks();
976 ExpectStartPhishingDetection(&url2);
977 ExpectShouldClassifyForMalwareResult(true);
980 TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckMimeType) {
981 // If the mime type is not one that we support, no IPC should be triggered
982 // but all pre-classification checks should run because we might classify
983 // other mime types for malware.
984 // Note: for this test to work correctly, the new URL must be on the
985 // same domain as the previous URL, otherwise it will create a new
986 // RenderViewHost that won't have the mime type set.
987 GURL url("http://host2.com/image.jpg");
988 rvh_tester()->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