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::RenderFrameHostTester
;
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 void SetUp() override
{
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 void TearDown() override
{
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 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() { csd_host_
->DidStopLoading(); }
250 void UpdateIPUrlMap(const std::string
& ip
, const std::string
& host
) {
251 csd_host_
->UpdateIPUrlMap(ip
, host
, "", "", content::RESOURCE_TYPE_OBJECT
);
254 BrowseInfo
* GetBrowseInfo() {
255 return csd_host_
->browse_info_
.get();
258 void ExpectPreClassificationChecks(const GURL
& url
,
259 const bool* is_private
,
260 const bool* is_incognito
,
261 const bool* match_csd_whitelist
,
262 const bool* malware_killswitch
,
263 const bool* get_valid_cached_result
,
264 const bool* is_in_cache
,
265 const bool* over_phishing_report_limit
,
266 const bool* over_malware_report_limit
) {
268 EXPECT_CALL(*csd_service_
, IsPrivateIPAddress(_
))
269 .WillOnce(Return(*is_private
));
272 EXPECT_CALL(*mock_profile_
, IsOffTheRecord())
273 .WillRepeatedly(Return(*is_incognito
));
275 if (match_csd_whitelist
) {
276 EXPECT_CALL(*database_manager_
.get(), MatchCsdWhitelistUrl(url
))
277 .WillOnce(Return(*match_csd_whitelist
));
279 if (malware_killswitch
) {
280 EXPECT_CALL(*database_manager_
.get(), IsMalwareKillSwitchOn())
281 .WillRepeatedly(Return(*malware_killswitch
));
283 if (get_valid_cached_result
) {
284 EXPECT_CALL(*csd_service_
, GetValidCachedResult(url
, NotNull()))
285 .WillOnce(DoAll(SetArgumentPointee
<1>(true),
286 Return(*get_valid_cached_result
)));
289 EXPECT_CALL(*csd_service_
, IsInCache(url
)).WillOnce(Return(*is_in_cache
));
291 if (over_phishing_report_limit
) {
292 EXPECT_CALL(*csd_service_
, OverPhishingReportLimit())
293 .WillOnce(Return(*over_phishing_report_limit
));
295 if (over_malware_report_limit
) {
296 EXPECT_CALL(*csd_service_
, OverMalwareReportLimit())
297 .WillOnce(Return(*over_malware_report_limit
));
301 void WaitAndCheckPreClassificationChecks() {
302 // Wait for CheckCsdWhitelist and CheckCache() to be called if at all.
303 base::RunLoop().RunUntilIdle();
304 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_
.get()));
305 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_
.get()));
306 EXPECT_TRUE(Mock::VerifyAndClear(database_manager_
.get()));
307 EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_
));
310 void SetFeatureExtractor(BrowserFeatureExtractor
* extractor
) {
311 csd_host_
->feature_extractor_
.reset(extractor
);
314 void SetRedirectChain(const std::vector
<GURL
>& redirect_chain
) {
315 csd_host_
->browse_info_
->url_redirects
= redirect_chain
;
318 void SetReferrer(const GURL
& referrer
) {
319 csd_host_
->browse_info_
->referrer
= referrer
;
322 void ExpectShouldClassifyForMalwareResult(bool should_classify
) {
323 EXPECT_EQ(should_classify
, csd_host_
->should_classify_for_malware_
);
326 void ExpectStartPhishingDetection(const GURL
* url
) {
327 const IPC::Message
* msg
= process()->sink().GetFirstMessageMatching(
328 SafeBrowsingMsg_StartPhishingDetection::ID
);
331 Tuple
<GURL
> actual_url
;
332 SafeBrowsingMsg_StartPhishingDetection::Read(msg
, &actual_url
);
333 EXPECT_EQ(*url
, get
<0>(actual_url
));
334 EXPECT_EQ(rvh()->GetRoutingID(), msg
->routing_id());
335 process()->sink().ClearMessages();
341 void TestUnsafeResourceCopied(const UnsafeResource
& resource
) {
342 ASSERT_TRUE(csd_host_
->unsafe_resource_
.get());
343 // Test that the resource from OnSafeBrowsingHit notification was copied
345 EXPECT_EQ(resource
.url
, csd_host_
->unsafe_resource_
->url
);
346 EXPECT_EQ(resource
.original_url
, csd_host_
->unsafe_resource_
->original_url
);
347 EXPECT_EQ(resource
.is_subresource
,
348 csd_host_
->unsafe_resource_
->is_subresource
);
349 EXPECT_EQ(resource
.threat_type
, csd_host_
->unsafe_resource_
->threat_type
);
350 EXPECT_TRUE(csd_host_
->unsafe_resource_
->callback
.is_null());
351 EXPECT_EQ(resource
.render_process_host_id
,
352 csd_host_
->unsafe_resource_
->render_process_host_id
);
353 EXPECT_EQ(resource
.render_view_id
,
354 csd_host_
->unsafe_resource_
->render_view_id
);
357 void SetUnsafeSubResourceForCurrent() {
358 UnsafeResource resource
;
359 resource
.url
= GURL("http://www.malware.com/");
360 resource
.original_url
= web_contents()->GetURL();
361 resource
.is_subresource
= true;
362 resource
.threat_type
= SB_THREAT_TYPE_URL_MALWARE
;
363 resource
.callback
= base::Bind(&EmptyUrlCheckCallback
);
364 resource
.render_process_host_id
= web_contents()->GetRenderProcessHost()->
366 resource
.render_view_id
=
367 web_contents()->GetRenderViewHost()->GetRoutingID();
368 ASSERT_FALSE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
369 csd_host_
->OnSafeBrowsingMatch(resource
);
370 ASSERT_TRUE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
371 csd_host_
->OnSafeBrowsingHit(resource
);
372 ASSERT_TRUE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
373 resource
.callback
.Reset();
374 ASSERT_TRUE(csd_host_
->DidShowSBInterstitial());
375 TestUnsafeResourceCopied(resource
);
378 void NavigateWithSBHitAndCommit(const GURL
& url
) {
379 // Create a pending navigation.
380 controller().LoadURL(
381 url
, content::Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
383 ASSERT_TRUE(pending_rvh());
384 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
385 pending_rvh()->GetProcess()->GetID()) {
386 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
387 pending_rvh()->GetRoutingID());
390 // Simulate a safebrowsing hit before navigation completes.
391 UnsafeResource resource
;
393 resource
.original_url
= url
;
394 resource
.is_subresource
= false;
395 resource
.threat_type
= SB_THREAT_TYPE_URL_MALWARE
;
396 resource
.callback
= base::Bind(&EmptyUrlCheckCallback
);
397 resource
.render_process_host_id
= pending_rvh()->GetProcess()->GetID();
398 resource
.render_view_id
= pending_rvh()->GetRoutingID();
399 csd_host_
->OnSafeBrowsingMatch(resource
);
400 csd_host_
->OnSafeBrowsingHit(resource
);
401 resource
.callback
.Reset();
403 ASSERT_TRUE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
405 // LoadURL created a navigation entry, now simulate the RenderView sending
406 // a notification that it actually navigated.
407 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
409 ASSERT_TRUE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
410 ASSERT_TRUE(csd_host_
->DidShowSBInterstitial());
411 TestUnsafeResourceCopied(resource
);
414 void NavigateWithoutSBHitAndCommit(const GURL
& safe_url
) {
415 controller().LoadURL(
416 safe_url
, content::Referrer(), ui::PAGE_TRANSITION_LINK
,
419 ASSERT_TRUE(pending_rvh());
420 if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
421 pending_rvh()->GetProcess()->GetID()) {
422 EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
423 pending_rvh()->GetRoutingID());
425 ASSERT_FALSE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
426 ASSERT_FALSE(csd_host_
->DidShowSBInterstitial());
428 content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
429 ASSERT_FALSE(csd_host_
->DidPageReceiveSafeBrowsingMatch());
430 ASSERT_FALSE(csd_host_
->DidShowSBInterstitial());
433 void CheckIPUrlEqual(const std::vector
<IPUrlInfo
>& expect
,
434 const std::vector
<IPUrlInfo
>& result
) {
435 ASSERT_EQ(expect
.size(), result
.size());
437 for (unsigned int i
= 0; i
< expect
.size(); ++i
) {
438 EXPECT_EQ(expect
[i
].url
, result
[i
].url
);
439 EXPECT_EQ(expect
[i
].method
, result
[i
].method
);
440 EXPECT_EQ(expect
[i
].referrer
, result
[i
].referrer
);
441 EXPECT_EQ(expect
[i
].resource_type
, result
[i
].resource_type
);
446 scoped_ptr
<ClientSideDetectionHost
> csd_host_
;
447 scoped_ptr
<StrictMock
<MockClientSideDetectionService
> > csd_service_
;
448 scoped_refptr
<StrictMock
<MockSafeBrowsingUIManager
> > ui_manager_
;
449 scoped_refptr
<StrictMock
<MockSafeBrowsingDatabaseManager
> > database_manager_
;
450 MockTestingProfile
* mock_profile_
; // We don't own this object
453 TEST_F(ClientSideDetectionHostTest
, OnPhishingDetectionDoneInvalidVerdict
) {
454 // Case 0: renderer sends an invalid verdict string that we're unable to
456 MockBrowserFeatureExtractor
* mock_extractor
=
457 new StrictMock
<MockBrowserFeatureExtractor
>(
460 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
461 EXPECT_CALL(*mock_extractor
, ExtractFeatures(_
, _
, _
)).Times(0);
462 OnPhishingDetectionDone("Invalid Protocol Buffer");
463 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor
));
466 TEST_F(ClientSideDetectionHostTest
, OnPhishingDetectionDoneNotPhishing
) {
467 // Case 1: client thinks the page is phishing. The server does not agree.
468 // No interstitial is shown.
469 MockBrowserFeatureExtractor
* mock_extractor
=
470 new StrictMock
<MockBrowserFeatureExtractor
>(
473 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
475 ClientSideDetectionService::ClientReportPhishingRequestCallback cb
;
476 ClientPhishingRequest verdict
;
477 verdict
.set_url("http://phishingurl.com/");
478 verdict
.set_client_score(1.0f
);
479 verdict
.set_is_phishing(true);
481 EXPECT_CALL(*mock_extractor
, ExtractFeatures(_
, _
, _
))
482 .WillOnce(InvokeDoneCallback(&verdict
));
483 EXPECT_CALL(*csd_service_
,
484 SendClientReportPhishingRequest(
485 Pointee(PartiallyEqualVerdict(verdict
)), _
))
486 .WillOnce(DoAll(DeleteArg
<0>(), SaveArg
<1>(&cb
)));
487 OnPhishingDetectionDone(verdict
.SerializeAsString());
488 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
489 ASSERT_FALSE(cb
.is_null());
491 // Make sure DisplayBlockingPage is not going to be called.
492 EXPECT_CALL(*ui_manager_
.get(), DisplayBlockingPage(_
)).Times(0);
493 cb
.Run(GURL(verdict
.url()), false);
494 base::RunLoop().RunUntilIdle();
495 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_
.get()));
498 TEST_F(ClientSideDetectionHostTest
, OnPhishingDetectionDoneDisabled
) {
499 // Case 2: client thinks the page is phishing and so does the server but
500 // showing the interstitial is disabled => no interstitial is shown.
501 MockBrowserFeatureExtractor
* mock_extractor
=
502 new StrictMock
<MockBrowserFeatureExtractor
>(
505 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
507 ClientSideDetectionService::ClientReportPhishingRequestCallback cb
;
508 ClientPhishingRequest verdict
;
509 verdict
.set_url("http://phishingurl.com/");
510 verdict
.set_client_score(1.0f
);
511 verdict
.set_is_phishing(true);
513 EXPECT_CALL(*mock_extractor
, ExtractFeatures(_
, _
, _
))
514 .WillOnce(InvokeDoneCallback(&verdict
));
515 EXPECT_CALL(*csd_service_
,
516 SendClientReportPhishingRequest(
517 Pointee(PartiallyEqualVerdict(verdict
)), _
))
518 .WillOnce(DoAll(DeleteArg
<0>(), SaveArg
<1>(&cb
)));
519 OnPhishingDetectionDone(verdict
.SerializeAsString());
520 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
521 ASSERT_FALSE(cb
.is_null());
523 // Make sure DisplayBlockingPage is not going to be called.
524 EXPECT_CALL(*ui_manager_
.get(), DisplayBlockingPage(_
)).Times(0);
525 cb
.Run(GURL(verdict
.url()), false);
526 base::RunLoop().RunUntilIdle();
527 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_
.get()));
530 TEST_F(ClientSideDetectionHostTest
, OnPhishingDetectionDoneShowInterstitial
) {
531 // Case 3: client thinks the page is phishing and so does the server.
532 // We show an interstitial.
533 MockBrowserFeatureExtractor
* mock_extractor
=
534 new StrictMock
<MockBrowserFeatureExtractor
>(
537 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
539 ClientSideDetectionService::ClientReportPhishingRequestCallback cb
;
540 GURL
phishing_url("http://phishingurl.com/");
541 ClientPhishingRequest verdict
;
542 verdict
.set_url(phishing_url
.spec());
543 verdict
.set_client_score(1.0f
);
544 verdict
.set_is_phishing(true);
546 EXPECT_CALL(*mock_extractor
, ExtractFeatures(_
, _
, _
))
547 .WillOnce(InvokeDoneCallback(&verdict
));
548 EXPECT_CALL(*csd_service_
,
549 SendClientReportPhishingRequest(
550 Pointee(PartiallyEqualVerdict(verdict
)), _
))
551 .WillOnce(DoAll(DeleteArg
<0>(), SaveArg
<1>(&cb
)));
552 OnPhishingDetectionDone(verdict
.SerializeAsString());
553 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
554 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_
.get()));
555 ASSERT_FALSE(cb
.is_null());
557 UnsafeResource resource
;
558 EXPECT_CALL(*ui_manager_
.get(), DisplayBlockingPage(_
))
559 .WillOnce(SaveArg
<0>(&resource
));
560 cb
.Run(phishing_url
, true);
562 base::RunLoop().RunUntilIdle();
563 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_
.get()));
564 EXPECT_EQ(phishing_url
, resource
.url
);
565 EXPECT_EQ(phishing_url
, resource
.original_url
);
566 EXPECT_FALSE(resource
.is_subresource
);
567 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
, resource
.threat_type
);
568 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
569 resource
.render_process_host_id
);
570 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
571 resource
.render_view_id
);
573 // Make sure the client object will be deleted.
574 BrowserThread::PostTask(
577 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete
,
578 ui_manager_
, resource
.callback
));
581 TEST_F(ClientSideDetectionHostTest
, OnPhishingDetectionDoneMultiplePings
) {
582 // Case 4 & 5: client thinks a page is phishing then navigates to
583 // another page which is also considered phishing by the client
584 // before the server responds with a verdict. After a while the
585 // server responds for both requests with a phishing verdict. Only
586 // a single interstitial is shown for the second URL.
587 MockBrowserFeatureExtractor
* mock_extractor
=
588 new StrictMock
<MockBrowserFeatureExtractor
>(
591 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
593 ClientSideDetectionService::ClientReportPhishingRequestCallback cb
;
594 GURL
phishing_url("http://phishingurl.com/");
595 ClientPhishingRequest verdict
;
596 verdict
.set_url(phishing_url
.spec());
597 verdict
.set_client_score(1.0f
);
598 verdict
.set_is_phishing(true);
600 EXPECT_CALL(*mock_extractor
, ExtractFeatures(_
, _
, _
))
601 .WillOnce(InvokeDoneCallback(&verdict
));
602 EXPECT_CALL(*csd_service_
,
603 SendClientReportPhishingRequest(
604 Pointee(PartiallyEqualVerdict(verdict
)), _
))
605 .WillOnce(DoAll(DeleteArg
<0>(), SaveArg
<1>(&cb
)));
606 OnPhishingDetectionDone(verdict
.SerializeAsString());
607 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
608 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_
.get()));
609 ASSERT_FALSE(cb
.is_null());
611 // Set this back to a normal browser feature extractor since we're using
612 // NavigateAndCommit() and it's easier to use the real thing than setting up
613 // mock expectations.
614 SetFeatureExtractor(new BrowserFeatureExtractor(web_contents(),
616 GURL
other_phishing_url("http://other_phishing_url.com/bla");
617 ExpectPreClassificationChecks(other_phishing_url
, &kFalse
, &kFalse
, &kFalse
,
618 &kFalse
, &kFalse
, &kFalse
, &kFalse
, &kFalse
);
619 // We navigate away. The callback cb should be revoked.
620 NavigateAndCommit(other_phishing_url
);
621 // Wait for the pre-classification checks to finish for other_phishing_url.
622 WaitAndCheckPreClassificationChecks();
624 ClientSideDetectionService::ClientReportPhishingRequestCallback cb_other
;
625 verdict
.set_url(other_phishing_url
.spec());
626 verdict
.set_client_score(0.8f
);
627 EXPECT_CALL(*csd_service_
,
628 SendClientReportPhishingRequest(
629 Pointee(PartiallyEqualVerdict(verdict
)), _
))
630 .WillOnce(DoAll(DeleteArg
<0>(),
631 SaveArg
<1>(&cb_other
),
632 QuitUIMessageLoop()));
633 std::vector
<GURL
> redirect_chain
;
634 redirect_chain
.push_back(other_phishing_url
);
635 SetRedirectChain(redirect_chain
);
636 OnPhishingDetectionDone(verdict
.SerializeAsString());
637 base::MessageLoop::current()->Run();
638 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
639 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_
.get()));
640 ASSERT_FALSE(cb_other
.is_null());
642 // We expect that the interstitial is shown for the second phishing URL and
643 // not for the first phishing URL.
644 UnsafeResource resource
;
645 EXPECT_CALL(*ui_manager_
.get(), DisplayBlockingPage(_
))
646 .WillOnce(SaveArg
<0>(&resource
));
648 cb
.Run(phishing_url
, true); // Should have no effect.
649 cb_other
.Run(other_phishing_url
, true); // Should show interstitial.
651 base::RunLoop().RunUntilIdle();
652 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_
.get()));
653 EXPECT_EQ(other_phishing_url
, resource
.url
);
654 EXPECT_EQ(other_phishing_url
, resource
.original_url
);
655 EXPECT_FALSE(resource
.is_subresource
);
656 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
, resource
.threat_type
);
657 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
658 resource
.render_process_host_id
);
659 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
660 resource
.render_view_id
);
662 // Make sure the client object will be deleted.
663 BrowserThread::PostTask(
666 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete
,
667 ui_manager_
, resource
.callback
));
670 TEST_F(ClientSideDetectionHostTest
,
671 OnPhishingDetectionDoneVerdictNotPhishing
) {
672 // Case 6: renderer sends a verdict string that isn't phishing.
673 MockBrowserFeatureExtractor
* mock_extractor
=
674 new StrictMock
<MockBrowserFeatureExtractor
>(
677 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
679 ClientPhishingRequest verdict
;
680 verdict
.set_url("http://not-phishing.com/");
681 verdict
.set_client_score(0.1f
);
682 verdict
.set_is_phishing(false);
684 EXPECT_CALL(*mock_extractor
, ExtractFeatures(_
, _
, _
)).Times(0);
685 OnPhishingDetectionDone(verdict
.SerializeAsString());
686 EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor
));
689 TEST_F(ClientSideDetectionHostTest
,
690 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchSubResource
) {
691 // Case 7: renderer sends a verdict string that isn't phishing but the URL
692 // of a subresource was on the regular phishing or malware lists.
693 GURL
url("http://not-phishing.com/");
694 ClientPhishingRequest verdict
;
695 verdict
.set_url(url
.spec());
696 verdict
.set_client_score(0.1f
);
697 verdict
.set_is_phishing(false);
699 // First we have to navigate to the URL to set the unique page ID.
700 ExpectPreClassificationChecks(url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
701 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
702 NavigateAndCommit(url
);
703 WaitAndCheckPreClassificationChecks();
704 SetUnsafeSubResourceForCurrent();
706 EXPECT_CALL(*csd_service_
,
707 SendClientReportPhishingRequest(
708 Pointee(PartiallyEqualVerdict(verdict
)), CallbackIsNull()))
709 .WillOnce(DoAll(DeleteArg
<0>(), QuitUIMessageLoop()));
710 std::vector
<GURL
> redirect_chain
;
711 redirect_chain
.push_back(url
);
712 SetRedirectChain(redirect_chain
);
713 OnPhishingDetectionDone(verdict
.SerializeAsString());
714 base::MessageLoop::current()->Run();
715 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
718 TEST_F(ClientSideDetectionHostTest
,
719 OnPhishingDetectionDoneVerdictNotPhishingButSBMatchOnNewRVH
) {
720 // When navigating to a different host (thus creating a pending RVH) which
721 // matches regular malware list, and after navigation the renderer sends a
722 // verdict string that isn't phishing, we should still send the report.
724 // Do an initial navigation to a safe host.
725 GURL
start_url("http://safe.example.com/");
726 ExpectPreClassificationChecks(
727 start_url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
729 NavigateAndCommit(start_url
);
730 WaitAndCheckPreClassificationChecks();
732 // Now navigate to a different host which will have a malware hit before the
733 // navigation commits.
734 GURL
url("http://malware-but-not-phishing.com/");
735 ClientPhishingRequest verdict
;
736 verdict
.set_url(url
.spec());
737 verdict
.set_client_score(0.1f
);
738 verdict
.set_is_phishing(false);
740 ExpectPreClassificationChecks(url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
741 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
742 NavigateWithSBHitAndCommit(url
);
743 WaitAndCheckPreClassificationChecks();
745 EXPECT_CALL(*csd_service_
,
746 SendClientReportPhishingRequest(
747 Pointee(PartiallyEqualVerdict(verdict
)), CallbackIsNull()))
748 .WillOnce(DoAll(DeleteArg
<0>(), QuitUIMessageLoop()));
749 std::vector
<GURL
> redirect_chain
;
750 redirect_chain
.push_back(url
);
751 SetRedirectChain(redirect_chain
);
752 OnPhishingDetectionDone(verdict
.SerializeAsString());
753 base::MessageLoop::current()->Run();
754 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
756 ExpectPreClassificationChecks(start_url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
757 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
758 NavigateWithoutSBHitAndCommit(start_url
);
759 WaitAndCheckPreClassificationChecks();
762 TEST_F(ClientSideDetectionHostTest
,
763 DidStopLoadingShowMalwareInterstitial
) {
764 // Case 9: client thinks the page match malware IP and so does the server.
765 // We show an sub-resource malware interstitial.
766 MockBrowserFeatureExtractor
* mock_extractor
=
767 new StrictMock
<MockBrowserFeatureExtractor
>(
770 SetFeatureExtractor(mock_extractor
); // The host class takes ownership.
772 GURL
malware_landing_url("http://malware.com/");
773 GURL
malware_ip_url("http://badip.com");
774 ClientMalwareRequest malware_verdict
;
775 malware_verdict
.set_url("http://malware.com/");
776 ClientMalwareRequest::UrlInfo
* badipurl
=
777 malware_verdict
.add_bad_ip_url_info();
778 badipurl
->set_ip("1.2.3.4");
779 badipurl
->set_url("http://badip.com");
781 ExpectPreClassificationChecks(GURL(malware_verdict
.url()), &kFalse
, &kFalse
,
782 &kFalse
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
784 NavigateAndCommit(GURL(malware_verdict
.url()));
785 WaitAndCheckPreClassificationChecks();
787 ClientSideDetectionService::ClientReportMalwareRequestCallback cb
;
788 EXPECT_CALL(*mock_extractor
, ExtractMalwareFeatures(_
, _
, _
))
789 .WillOnce(InvokeMalwareCallback(&malware_verdict
));
790 EXPECT_CALL(*csd_service_
,
791 SendClientReportMalwareRequest(
792 Pointee(PartiallyEqualMalwareVerdict(malware_verdict
)), _
))
793 .WillOnce(DoAll(DeleteArg
<0>(), SaveArg
<1>(&cb
)));
795 EXPECT_TRUE(Mock::VerifyAndClear(csd_host_
.get()));
796 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_
.get()));
797 ASSERT_FALSE(cb
.is_null());
799 UnsafeResource resource
;
800 EXPECT_CALL(*ui_manager_
.get(), DisplayBlockingPage(_
))
801 .WillOnce(SaveArg
<0>(&resource
));
802 cb
.Run(malware_landing_url
, malware_ip_url
, true);
804 base::RunLoop().RunUntilIdle();
805 EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_
.get()));
806 EXPECT_EQ(malware_ip_url
, resource
.url
);
807 EXPECT_EQ(malware_landing_url
, resource
.original_url
);
808 EXPECT_TRUE(resource
.is_subresource
);
809 EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL
, resource
.threat_type
);
810 EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
811 resource
.render_process_host_id
);
812 EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
813 resource
.render_view_id
);
815 // Make sure the client object will be deleted.
816 BrowserThread::PostTask(
819 base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete
,
820 ui_manager_
, resource
.callback
));
823 TEST_F(ClientSideDetectionHostTest
, UpdateIPUrlMap
) {
824 BrowseInfo
* browse_info
= GetBrowseInfo();
826 // Empty IP or host are skipped
827 UpdateIPUrlMap("250.10.10.10", std::string());
828 ASSERT_EQ(0U, browse_info
->ips
.size());
829 UpdateIPUrlMap(std::string(), "http://google.com/a");
830 ASSERT_EQ(0U, browse_info
->ips
.size());
831 UpdateIPUrlMap(std::string(), std::string());
832 ASSERT_EQ(0U, browse_info
->ips
.size());
834 std::vector
<IPUrlInfo
> expected_urls
;
835 for (int i
= 0; i
< 20; i
++) {
836 std::string url
= base::StringPrintf("http://%d.com/", i
);
837 expected_urls
.push_back(
838 IPUrlInfo(url
, "", "", content::RESOURCE_TYPE_OBJECT
));
839 UpdateIPUrlMap("250.10.10.10", url
);
841 ASSERT_EQ(1U, browse_info
->ips
.size());
842 ASSERT_EQ(20U, browse_info
->ips
["250.10.10.10"].size());
843 CheckIPUrlEqual(expected_urls
,
844 browse_info
->ips
["250.10.10.10"]);
846 // Add more urls for this ip, it exceeds max limit and won't be added
847 UpdateIPUrlMap("250.10.10.10", "http://21.com/");
848 ASSERT_EQ(1U, browse_info
->ips
.size());
849 ASSERT_EQ(20U, browse_info
->ips
["250.10.10.10"].size());
850 CheckIPUrlEqual(expected_urls
,
851 browse_info
->ips
["250.10.10.10"]);
854 for (int i
= 0; i
< 199; i
++) {
855 std::string ip
= base::StringPrintf("%d.%d.%d.256", i
, i
, i
);
856 expected_urls
.clear();
857 expected_urls
.push_back(
858 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT
));
859 UpdateIPUrlMap(ip
, "test.com/");
860 ASSERT_EQ(1U, browse_info
->ips
[ip
].size());
861 CheckIPUrlEqual(expected_urls
,
862 browse_info
->ips
[ip
]);
864 ASSERT_EQ(200U, browse_info
->ips
.size());
866 // Exceeding max ip limit 200, these won't be added
867 UpdateIPUrlMap("250.250.250.250", "goo.com/");
868 UpdateIPUrlMap("250.250.250.250", "bar.com/");
869 UpdateIPUrlMap("250.250.0.250", "foo.com/");
870 ASSERT_EQ(200U, browse_info
->ips
.size());
872 // Add url to existing IPs succeed
873 UpdateIPUrlMap("100.100.100.256", "more.com/");
874 ASSERT_EQ(2U, browse_info
->ips
["100.100.100.256"].size());
875 expected_urls
.clear();
876 expected_urls
.push_back(
877 IPUrlInfo("test.com/", "", "", content::RESOURCE_TYPE_OBJECT
));
878 expected_urls
.push_back(
879 IPUrlInfo("more.com/", "", "", content::RESOURCE_TYPE_OBJECT
));
880 CheckIPUrlEqual(expected_urls
,
881 browse_info
->ips
["100.100.100.256"]);
884 TEST_F(ClientSideDetectionHostTest
, NavigationCancelsShouldClassifyUrl
) {
885 // Test that canceling pending should classify requests works as expected.
887 GURL
first_url("http://first.phishy.url.com");
888 GURL
second_url("http://second.url.com/");
889 // The first few checks are done synchronously so check that they have been
890 // done for the first URL, while the second URL has all the checks done. We
891 // need to manually set up the IsPrivateIPAddress mock since if the same mock
892 // expectation is specified twice, gmock will only use the last instance of
893 // it, meaning the first will never be matched.
894 EXPECT_CALL(*csd_service_
, IsPrivateIPAddress(_
))
895 .WillOnce(Return(false))
896 .WillOnce(Return(false));
897 ExpectPreClassificationChecks(first_url
, NULL
, &kFalse
, &kFalse
, &kFalse
,
898 NULL
, NULL
, NULL
, NULL
);
899 ExpectPreClassificationChecks(second_url
, NULL
, &kFalse
, &kFalse
, &kFalse
,
900 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
902 NavigateAndCommit(first_url
);
903 // Don't flush the message loop, as we want to navigate to a different
904 // url before the final pre-classification checks are run.
905 NavigateAndCommit(second_url
);
906 WaitAndCheckPreClassificationChecks();
909 TEST_F(ClientSideDetectionHostTest
, TestPreClassificationCheckPass
) {
910 // Navigate the tab to a page. We should see a StartPhishingDetection IPC.
911 GURL
url("http://host.com/");
912 ExpectPreClassificationChecks(url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
913 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
914 NavigateAndCommit(url
);
915 WaitAndCheckPreClassificationChecks();
917 ExpectStartPhishingDetection(&url
);
918 ExpectShouldClassifyForMalwareResult(true);
921 TEST_F(ClientSideDetectionHostTest
,
922 TestPreClassificationCheckInPageNavigation
) {
923 GURL
url("http://host.com/");
924 ExpectPreClassificationChecks(url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
925 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
926 NavigateAndCommit(url
);
927 WaitAndCheckPreClassificationChecks();
929 ExpectStartPhishingDetection(&url
);
930 ExpectShouldClassifyForMalwareResult(true);
932 // Now try an in-page navigation. This should not trigger an IPC.
933 EXPECT_CALL(*csd_service_
, IsPrivateIPAddress(_
)).Times(0);
934 GURL
inpage("http://host.com/#foo");
935 ExpectPreClassificationChecks(inpage
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
937 NavigateAndCommit(inpage
);
938 WaitAndCheckPreClassificationChecks();
940 ExpectStartPhishingDetection(NULL
);
941 ExpectShouldClassifyForMalwareResult(true);
944 TEST_F(ClientSideDetectionHostTest
, TestPreClassificationCheckXHTML
) {
945 // Check that XHTML is supported, in addition to the default HTML type.
946 GURL
url("http://host.com/xhtml");
947 RenderFrameHostTester::For(web_contents()->GetMainFrame())->
948 SetContentsMimeType("application/xhtml+xml");
949 ExpectPreClassificationChecks(url
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
950 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
951 NavigateAndCommit(url
);
952 WaitAndCheckPreClassificationChecks();
954 ExpectStartPhishingDetection(&url
);
955 ExpectShouldClassifyForMalwareResult(true);
958 TEST_F(ClientSideDetectionHostTest
, TestPreClassificationCheckTwoNavigations
) {
959 // Navigate to two hosts, which should cause two IPCs.
960 GURL
url1("http://host1.com/");
961 ExpectPreClassificationChecks(url1
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
962 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
963 NavigateAndCommit(url1
);
964 WaitAndCheckPreClassificationChecks();
966 ExpectStartPhishingDetection(&url1
);
967 ExpectShouldClassifyForMalwareResult(true);
969 GURL
url2("http://host2.com/");
970 ExpectPreClassificationChecks(url2
, &kFalse
, &kFalse
, &kFalse
, &kFalse
,
971 &kFalse
, &kFalse
, &kFalse
, &kFalse
);
972 NavigateAndCommit(url2
);
973 WaitAndCheckPreClassificationChecks();
975 ExpectStartPhishingDetection(&url2
);
976 ExpectShouldClassifyForMalwareResult(true);
979 TEST_F(ClientSideDetectionHostTest
, TestPreClassificationCheckMimeType
) {
980 // If the mime type is not one that we support, no IPC should be triggered
981 // but all pre-classification checks should run because we might classify
982 // other mime types for malware.
983 // Note: for this test to work correctly, the new URL must be on the
984 // same domain as the previous URL, otherwise it will create a new
985 // RenderViewHost that won't have the mime type set.
986 GURL
url("http://host2.com/image.jpg");
987 RenderFrameHostTester::For(web_contents()->GetMainFrame())->
988 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