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