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"
34 using ::testing::DeleteArg
;
35 using ::testing::DoAll
;
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
;
53 const bool kFalse
= false;
54 const bool kTrue
= true;
58 namespace safe_browsing
{
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())
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())
85 // Test that the callback is NULL when the verdict is not phishing.
86 MATCHER(CallbackIsNull
, "") {
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
{
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());
128 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService
);
131 class MockSafeBrowsingUIManager
: public SafeBrowsingUIManager
{
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
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
144 if (!callback
.is_null())
149 virtual ~MockSafeBrowsingUIManager() { }
152 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager
);
155 class MockSafeBrowsingDatabaseManager
: public SafeBrowsingDatabaseManager
{
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());
165 virtual ~MockSafeBrowsingDatabaseManager() {}
168 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager
);
171 class MockTestingProfile
: public TestingProfile
{
173 MockTestingProfile() {}
174 virtual ~MockTestingProfile() {}
176 MOCK_CONST_METHOD0(IsOffTheRecord
, bool());
179 class MockBrowserFeatureExtractor
: public BrowserFeatureExtractor
{
181 explicit MockBrowserFeatureExtractor(
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
,
194 ClientMalwareRequest
*,
195 const BrowserFeatureExtractor::MalwareDoneCallback
&));
200 class ClientSideDetectionHostTest
: public ChromeRenderViewHostTestHarness
{
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();
213 new StrictMock
<MockSafeBrowsingDatabaseManager
>(sb_service
);
214 ui_manager_
= new StrictMock
<MockSafeBrowsingUIManager
>(sb_service
);
215 csd_host_
.reset(safe_browsing::ClientSideDetectionHost::Create(
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
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
;
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
) {
270 EXPECT_CALL(*csd_service_
, IsPrivateIPAddress(_
))
271 .WillOnce(Return(*is_private
));
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
)));
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
);
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();
343 void TestUnsafeResourceCopied(const UnsafeResource
& resource
) {
344 ASSERT_TRUE(csd_host_
->unsafe_resource_
.get());
345 // Test that the resource from OnSafeBrowsingHit notification was copied
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()->
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
;
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
,
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
);
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
458 MockBrowserFeatureExtractor
* mock_extractor
=
459 new StrictMock
<MockBrowserFeatureExtractor
>(
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
>(
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
>(
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
>(
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(
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
>(
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(),
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(
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
>(
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
,
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
>(
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
,
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
)));
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(
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"]);
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
,
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
,
1004 NavigateAndCommit(url
);
1005 WaitAndCheckPreClassificationChecks();
1006 const IPC::Message
* msg
= process()->sink().GetFirstMessageMatching(
1007 SafeBrowsingMsg_StartPhishingDetection::ID
);
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
,
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
,
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