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"
35 using ::testing::DeleteArg
;
36 using ::testing::DoAll
;
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
;
54 const bool kFalse
= false;
55 const bool kTrue
= true;
59 namespace safe_browsing
{
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())
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())
86 // Test that the callback is NULL when the verdict is not phishing.
87 MATCHER(CallbackIsNull
, "") {
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
{
113 MockClientSideDetectionService() : ClientSideDetectionService(NULL
) {}
114 virtual ~MockClientSideDetectionService() {}
116 MOCK_METHOD3(SendClientReportPhishingRequest
,
117 void(ClientPhishingRequest
*,
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());
130 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService
);
133 class MockSafeBrowsingUIManager
: public SafeBrowsingUIManager
{
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
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
146 if (!callback
.is_null())
151 virtual ~MockSafeBrowsingUIManager() { }
154 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager
);
157 class MockSafeBrowsingDatabaseManager
: public TestSafeBrowsingDatabaseManager
{
159 MockSafeBrowsingDatabaseManager() {}
161 MOCK_METHOD1(MatchCsdWhitelistUrl
, bool(const GURL
&));
162 MOCK_METHOD1(MatchMalwareIP
, bool(const std::string
& ip_address
));
163 MOCK_METHOD0(IsMalwareKillSwitchOn
, bool());
166 virtual ~MockSafeBrowsingDatabaseManager() {}
169 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager
);
172 class MockTestingProfile
: public TestingProfile
{
174 MockTestingProfile() {}
175 virtual ~MockTestingProfile() {}
177 MOCK_CONST_METHOD0(IsOffTheRecord
, bool());
180 class MockBrowserFeatureExtractor
: public BrowserFeatureExtractor
{
182 explicit MockBrowserFeatureExtractor(
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
,
195 ClientMalwareRequest
*,
196 const BrowserFeatureExtractor::MalwareDoneCallback
&));
201 class ClientSideDetectionHostTest
: public ChromeRenderViewHostTestHarness
{
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(
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
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
;
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
) {
266 EXPECT_CALL(*csd_service_
, IsPrivateIPAddress(_
))
267 .WillOnce(Return(*is_private
));
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
)));
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
);
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();
339 void TestUnsafeResourceCopied(const UnsafeResource
& resource
) {
340 ASSERT_TRUE(csd_host_
->unsafe_resource_
.get());
341 // Test that the resource from OnSafeBrowsingHit notification was copied
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()->
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
;
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
,
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
);
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
454 MockBrowserFeatureExtractor
* mock_extractor
=
455 new StrictMock
<MockBrowserFeatureExtractor
>(
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
>(
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
>(
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
>(
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(
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
>(
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(),
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(
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
>(
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
,
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
>(
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
,
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
)));
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(
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"]);
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
,
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
,
1002 NavigateAndCommit(url
);
1003 WaitAndCheckPreClassificationChecks();
1004 const IPC::Message
* msg
= process()->sink().GetFirstMessageMatching(
1005 SafeBrowsingMsg_StartPhishingDetection::ID
);
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
,
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
,
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