Convert SafeBrowsingBlockingPage and test to new Bind/Callback system.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_blocking_page_test.cc
blobdc64322d9a08662a6ccac7adde58a0bbde13b37d
1 // Copyright (c) 2011 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.
4 //
5 // This test creates a fake safebrowsing service, where we can inject
6 // malware and phishing urls. It then uses a real browser to go to
7 // these urls, and sends "goback" or "proceed" commands and verifies
8 // they work.
10 #include "base/bind.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/prefs/pref_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/safe_browsing/malware_details.h"
15 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
16 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "content/browser/browser_thread.h"
24 #include "content/browser/renderer_host/render_process_host.h"
25 #include "content/browser/renderer_host/resource_dispatcher_host.h"
26 #include "content/browser/tab_contents/tab_contents.h"
27 #include "content/browser/tab_contents/tab_contents_view.h"
29 // A SafeBrowingService class that allows us to inject the malicious URLs.
30 class FakeSafeBrowsingService : public SafeBrowsingService {
31 public:
32 FakeSafeBrowsingService() {}
34 virtual ~FakeSafeBrowsingService() {}
36 // Called on the IO thread to check if the given url is safe or not. If we
37 // can synchronously determine that the url is safe, CheckUrl returns true.
38 // Otherwise it returns false, and "client" is called asynchronously with the
39 // result when it is ready.
40 // Overrides SafeBrowsingService::CheckBrowseUrl.
41 virtual bool CheckBrowseUrl(const GURL& gurl, Client* client) {
42 if (badurls[gurl.spec()] == SAFE)
43 return true;
45 BrowserThread::PostTask(
46 BrowserThread::IO, FROM_HERE,
47 base::Bind(&FakeSafeBrowsingService::OnCheckBrowseURLDone,
48 this, gurl, client));
49 return false;
52 void OnCheckBrowseURLDone(const GURL& gurl, Client* client) {
53 SafeBrowsingService::SafeBrowsingCheck check;
54 check.urls.push_back(gurl);
55 check.client = client;
56 check.result = badurls[gurl.spec()];
57 client->OnSafeBrowsingResult(check);
60 void AddURLResult(const GURL& url, UrlCheckResult checkresult) {
61 badurls[url.spec()] = checkresult;
64 // Overrides SafeBrowsingService.
65 virtual void SendSerializedMalwareDetails(const std::string& serialized) {
66 reports_.push_back(serialized);
67 // Notify the UI thread that we got a report.
68 BrowserThread::PostTask(
69 BrowserThread::UI, FROM_HERE,
70 base::Bind(&FakeSafeBrowsingService::OnMalwareDetailsDone, this));
73 void OnMalwareDetailsDone() {
74 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
75 MessageLoopForUI::current()->Quit();
78 std::string GetReport() {
79 EXPECT_TRUE(reports_.size() == 1);
80 return reports_[0];
83 std::vector<std::string> reports_;
85 private:
86 base::hash_map<std::string, UrlCheckResult> badurls;
89 // Factory that creates FakeSafeBrowsingService instances.
90 class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
91 public:
92 TestSafeBrowsingServiceFactory() { }
93 virtual ~TestSafeBrowsingServiceFactory() { }
95 virtual SafeBrowsingService* CreateSafeBrowsingService() {
96 return new FakeSafeBrowsingService();
100 // A MalwareDetails class lets us intercept calls from the renderer.
101 class FakeMalwareDetails : public MalwareDetails {
102 public:
103 FakeMalwareDetails(SafeBrowsingService* sb_service,
104 TabContents* tab_contents,
105 const SafeBrowsingService::UnsafeResource& unsafe_resource)
106 : MalwareDetails(sb_service, tab_contents, unsafe_resource) { }
108 virtual ~FakeMalwareDetails() {}
110 virtual void AddDOMDetails(
111 const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params) {
112 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
113 MalwareDetails::AddDOMDetails(params);
115 // Notify the UI thread that we got the dom details.
116 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
117 base::Bind(&FakeMalwareDetails::OnDOMDetailsDone,
118 this));
121 void OnDOMDetailsDone() {
122 got_dom_ = true;
123 if (waiting_) {
124 MessageLoopForUI::current()->Quit();
128 bool got_dom() const {
129 return got_dom_;
132 bool waiting() const {
133 return waiting_;
136 void set_got_dom(bool got_dom) {
137 got_dom_ = got_dom;
140 void set_waiting(bool waiting) {
141 waiting_ = waiting;
144 safe_browsing::ClientMalwareReportRequest* get_report() {
145 return report_.get();
148 private:
149 // Some logic to figure out if we should wait for the dom details or not.
150 // These variables should only be accessed in the UI thread.
151 bool got_dom_;
152 bool waiting_;
156 class TestMalwareDetailsFactory : public MalwareDetailsFactory {
157 public:
158 TestMalwareDetailsFactory() { }
159 virtual ~TestMalwareDetailsFactory() { }
161 virtual MalwareDetails* CreateMalwareDetails(
162 SafeBrowsingService* sb_service,
163 TabContents* tab_contents,
164 const SafeBrowsingService::UnsafeResource& unsafe_resource) {
165 details_ = new FakeMalwareDetails(sb_service, tab_contents,
166 unsafe_resource);
167 return details_;
170 FakeMalwareDetails* get_details() {
171 return details_;
174 private:
175 FakeMalwareDetails* details_;
178 // A SafeBrowingBlockingPage class that lets us wait until it's hidden.
179 class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage {
180 public:
181 TestSafeBrowsingBlockingPage(SafeBrowsingService* service,
182 TabContents* tab_contents,
183 const UnsafeResourceList& unsafe_resources)
184 : SafeBrowsingBlockingPage(service, tab_contents, unsafe_resources) {
185 // Don't wait the whole 3 seconds for the browser test.
186 malware_details_proceed_delay_ms_ = 100;
187 wait_for_delete_ = false;
190 ~TestSafeBrowsingBlockingPage() {
191 if (wait_for_delete_) {
192 // Notify that we are gone
193 MessageLoopForUI::current()->Quit();
197 void set_wait_for_delete() {
198 wait_for_delete_ = true;
201 private:
202 bool wait_for_delete_;
205 class TestSafeBrowsingBlockingPageFactory
206 : public SafeBrowsingBlockingPageFactory {
207 public:
208 TestSafeBrowsingBlockingPageFactory() { }
209 ~TestSafeBrowsingBlockingPageFactory() { }
211 virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
212 SafeBrowsingService* service,
213 TabContents* tab_contents,
214 const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources) {
215 return new TestSafeBrowsingBlockingPage(service, tab_contents,
216 unsafe_resources);
220 // Tests the safe browsing blocking page in a browser.
221 class SafeBrowsingBlockingPageTest : public InProcessBrowserTest,
222 public SafeBrowsingService::Client {
223 public:
224 SafeBrowsingBlockingPageTest() {
227 virtual void SetUp() {
228 SafeBrowsingService::RegisterFactory(&factory_);
229 SafeBrowsingBlockingPage::RegisterFactory(&blocking_page_factory_);
230 MalwareDetails::RegisterFactory(&details_factory_);
231 InProcessBrowserTest::SetUp();
234 virtual void TearDown() {
235 InProcessBrowserTest::TearDown();
236 SafeBrowsingBlockingPage::RegisterFactory(NULL);
237 SafeBrowsingService::RegisterFactory(NULL);
238 MalwareDetails::RegisterFactory(NULL);
241 virtual void SetUpInProcessBrowserTestFixture() {
242 ASSERT_TRUE(test_server()->Start());
245 // SafeBrowsingService::Client implementation.
246 virtual void OnSafeBrowsingResult(
247 const SafeBrowsingService::SafeBrowsingCheck& check) {
250 virtual void OnBlockingPageComplete(bool proceed) {
253 void AddURLResult(const GURL& url,
254 SafeBrowsingService::UrlCheckResult checkresult) {
255 FakeSafeBrowsingService* service =
256 static_cast<FakeSafeBrowsingService*>(
257 g_browser_process->safe_browsing_service());
259 ASSERT_TRUE(service);
260 service->AddURLResult(url, checkresult);
263 void SendCommand(const std::string& command) {
264 TabContents* contents = browser()->GetSelectedTabContents();
265 // We use InterstitialPage::GetInterstitialPage(tab) instead of
266 // tab->interstitial_page() because the tab doesn't have a pointer
267 // to its interstital page until it gets a command from the renderer
268 // that it has indeed displayed it -- and this sometimes happens after
269 // NavigateToURL returns.
270 SafeBrowsingBlockingPage* interstitial_page =
271 static_cast<SafeBrowsingBlockingPage*>(
272 InterstitialPage::GetInterstitialPage(contents));
273 ASSERT_TRUE(interstitial_page);
274 interstitial_page->CommandReceived(command);
277 void DontProceedThroughInterstitial() {
278 TabContents* contents = browser()->GetSelectedTabContents();
279 InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
280 contents);
281 ASSERT_TRUE(interstitial_page);
282 interstitial_page->DontProceed();
285 void ProceedThroughInterstitial() {
286 TabContents* contents = browser()->GetSelectedTabContents();
287 InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
288 contents);
289 ASSERT_TRUE(interstitial_page);
290 interstitial_page->Proceed();
293 void AssertNoInterstitial(bool wait_for_delete) {
294 TabContents* contents = browser()->GetSelectedTabContents();
296 if (contents->showing_interstitial_page() && wait_for_delete) {
297 // We'll get notified when the interstitial is deleted.
298 static_cast<TestSafeBrowsingBlockingPage*>(
299 contents->interstitial_page())->set_wait_for_delete();
300 ui_test_utils::RunMessageLoop();
303 // Can't use InterstitialPage::GetInterstitialPage() because that
304 // gets updated after the TestSafeBrowsingBlockingPage destructor
305 ASSERT_FALSE(contents->showing_interstitial_page());
308 bool YesInterstitial() {
309 TabContents* contents = browser()->GetSelectedTabContents();
310 InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
311 contents);
312 return interstitial_page != NULL;
315 void WaitForInterstitial() {
316 TabContents* contents = browser()->GetSelectedTabContents();
317 ui_test_utils::WindowedNotificationObserver interstitial_observer(
318 content::NOTIFICATION_INTERSTITIAL_ATTACHED,
319 Source<TabContents>(contents));
320 if (!InterstitialPage::GetInterstitialPage(contents))
321 interstitial_observer.Wait();
324 void AssertReportSent() {
325 // When a report is scheduled in the IO thread we should get notified.
326 ui_test_utils::RunMessageLoop();
328 FakeSafeBrowsingService* service =
329 static_cast<FakeSafeBrowsingService*>(
330 g_browser_process->safe_browsing_service());
332 std::string serialized = service->GetReport();
334 safe_browsing::ClientMalwareReportRequest report;
335 ASSERT_TRUE(report.ParseFromString(serialized));
337 // Verify the report is complete.
338 EXPECT_TRUE(report.complete());
341 void MalwareRedirectCancelAndProceed(const std::string open_function);
343 protected:
344 TestMalwareDetailsFactory details_factory_;
346 private:
347 TestSafeBrowsingServiceFactory factory_;
348 TestSafeBrowsingBlockingPageFactory blocking_page_factory_;
350 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageTest);
353 void SafeBrowsingBlockingPageTest::MalwareRedirectCancelAndProceed(
354 const std::string open_function) {
355 GURL load_url = test_server()->GetURL(
356 "files/safe_browsing/interstitial_cancel.html");
357 GURL malware_url("http://localhost/files/safe_browsing/malware.html");
358 AddURLResult(malware_url, SafeBrowsingService::URL_MALWARE);
360 // Load the test page.
361 ui_test_utils::NavigateToURL(browser(), load_url);
362 // Trigger the safe browsing interstitial page via a redirect in "openWin()".
363 ui_test_utils::NavigateToURLWithDisposition(
364 browser(),
365 GURL("javascript:" + open_function + "()"),
366 CURRENT_TAB,
367 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
368 WaitForInterstitial();
369 // Cancel the redirect request while interstitial page is open.
370 browser()->ActivateTabAt(0, true);
371 ui_test_utils::NavigateToURLWithDisposition(
372 browser(),
373 GURL("javascript:stopWin()"),
374 CURRENT_TAB,
375 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
376 browser()->ActivateTabAt(1, true);
377 // Simulate the user clicking "proceed", there should be no crash.
378 SendCommand("\"proceed\"");
381 namespace {
383 const char kEmptyPage[] = "files/empty.html";
384 const char kMalwarePage[] = "files/safe_browsing/malware.html";
385 const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";
387 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
388 MalwareRedirectInIFrameCanceled) {
389 // 1. Test the case that redirect is a subresource.
390 MalwareRedirectCancelAndProceed("openWinIFrame");
391 // If the redirect was from subresource but canceled, "proceed" will continue
392 // with the rest of resources.
393 AssertNoInterstitial(true);
396 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareRedirectCanceled) {
397 // 2. Test the case that redirect is the only resource.
398 MalwareRedirectCancelAndProceed("openWin");
399 // Clicking proceed won't do anything if the main request is cancelled
400 // already. See crbug.com/76460.
401 EXPECT_TRUE(YesInterstitial());
404 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareDontProceed) {
405 GURL url = test_server()->GetURL(kEmptyPage);
406 AddURLResult(url, SafeBrowsingService::URL_MALWARE);
408 ui_test_utils::NavigateToURL(browser(), url);
410 SendCommand("\"takeMeBack\""); // Simulate the user clicking "back"
411 AssertNoInterstitial(false); // Assert the interstitial is gone
412 EXPECT_EQ(GURL(chrome::kAboutBlankURL), // Back to "about:blank"
413 browser()->GetSelectedTabContents()->GetURL());
416 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareProceed) {
417 GURL url = test_server()->GetURL(kEmptyPage);
418 AddURLResult(url, SafeBrowsingService::URL_MALWARE);
420 ui_test_utils::NavigateToURL(browser(), url);
421 ui_test_utils::WindowedNotificationObserver observer(
422 content::NOTIFICATION_LOAD_STOP,
423 Source<NavigationController>(
424 &browser()->GetSelectedTabContentsWrapper()->controller()));
425 SendCommand("\"proceed\""); // Simulate the user clicking "proceed"
426 observer.Wait();
427 AssertNoInterstitial(true); // Assert the interstitial is gone.
428 EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
431 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingDontProceed) {
432 GURL url = test_server()->GetURL(kEmptyPage);
433 AddURLResult(url, SafeBrowsingService::URL_PHISHING);
435 ui_test_utils::NavigateToURL(browser(), url);
437 SendCommand("\"takeMeBack\""); // Simulate the user clicking "proceed"
438 AssertNoInterstitial(false); // Assert the interstitial is gone
439 EXPECT_EQ(GURL(chrome::kAboutBlankURL), // We are back to "about:blank".
440 browser()->GetSelectedTabContents()->GetURL());
443 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingProceed) {
444 GURL url = test_server()->GetURL(kEmptyPage);
445 AddURLResult(url, SafeBrowsingService::URL_PHISHING);
447 ui_test_utils::NavigateToURL(browser(), url);
449 ui_test_utils::WindowedNotificationObserver observer(
450 content::NOTIFICATION_LOAD_STOP,
451 Source<NavigationController>(
452 &browser()->GetSelectedTabContentsWrapper()->controller()));
453 SendCommand("\"proceed\""); // Simulate the user clicking "proceed".
454 observer.Wait();
455 AssertNoInterstitial(true); // Assert the interstitial is gone
456 EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
459 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingReportError) {
460 GURL url = test_server()->GetURL(kEmptyPage);
461 AddURLResult(url, SafeBrowsingService::URL_PHISHING);
463 ui_test_utils::NavigateToURL(browser(), url);
465 ui_test_utils::WindowedNotificationObserver observer(
466 content::NOTIFICATION_LOAD_STOP,
467 Source<NavigationController>(
468 &browser()->GetSelectedTabContentsWrapper()->controller()));
469 SendCommand("\"reportError\""); // Simulate the user clicking "report error"
470 observer.Wait();
471 AssertNoInterstitial(false); // Assert the interstitial is gone
473 // We are in the error reporting page.
474 EXPECT_EQ("/safebrowsing/report_error/",
475 browser()->GetSelectedTabContents()->GetURL().path());
478 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
479 PhishingLearnMore) {
480 GURL url = test_server()->GetURL(kEmptyPage);
481 AddURLResult(url, SafeBrowsingService::URL_PHISHING);
483 ui_test_utils::NavigateToURL(browser(), url);
485 ui_test_utils::WindowedNotificationObserver observer(
486 content::NOTIFICATION_LOAD_STOP,
487 Source<NavigationController>(
488 &browser()->GetSelectedTabContentsWrapper()->controller()));
489 SendCommand("\"learnMore\""); // Simulate the user clicking "learn more"
490 observer.Wait();
491 AssertNoInterstitial(false); // Assert the interstitial is gone
493 // We are in the help page.
494 EXPECT_EQ("/support/bin/answer.py",
495 browser()->GetSelectedTabContents()->GetURL().path());
498 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeDontProceed) {
499 GURL url = test_server()->GetURL(kMalwarePage);
500 GURL iframe_url = test_server()->GetURL(kMalwareIframe);
501 AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);
503 ui_test_utils::NavigateToURL(browser(), url);
505 SendCommand("\"takeMeBack\""); // Simulate the user clicking "back"
506 AssertNoInterstitial(false); // Assert the interstitial is gone
508 EXPECT_EQ(GURL(chrome::kAboutBlankURL), // Back to "about:blank"
509 browser()->GetSelectedTabContents()->GetURL());
512 // Crashy, http://crbug.com/68834.
513 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
514 DISABLED_MalwareIframeProceed) {
515 GURL url = test_server()->GetURL(kMalwarePage);
516 GURL iframe_url = test_server()->GetURL(kMalwareIframe);
517 AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);
519 ui_test_utils::NavigateToURL(browser(), url);
521 SendCommand("\"proceed\""); // Simulate the user clicking "proceed"
522 AssertNoInterstitial(true); // Assert the interstitial is gone
524 EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
527 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
528 MalwareIframeReportDetails) {
529 GURL url = test_server()->GetURL(kMalwarePage);
530 GURL iframe_url = test_server()->GetURL(kMalwareIframe);
531 AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);
533 ui_test_utils::NavigateToURL(browser(), url);
535 // If the DOM details from renderer did not already return, wait for them.
536 if (!details_factory_.get_details()->got_dom()) {
537 // This condition might not trigger normally, but if you add a
538 // sleep(1) in malware_dom_details it triggers :).
539 details_factory_.get_details()->set_waiting(true);
540 LOG(INFO) << "Waiting for dom details.";
541 ui_test_utils::RunMessageLoop();
542 } else {
543 LOG(INFO) << "Already got the dom details.";
546 SendCommand("\"doReport\""); // Simulate the user checking the checkbox.
547 EXPECT_TRUE(browser()->GetProfile()->GetPrefs()->GetBoolean(
548 prefs::kSafeBrowsingReportingEnabled));
550 SendCommand("\"proceed\""); // Simulate the user clicking "back"
551 AssertNoInterstitial(true); // Assert the interstitial is gone
553 EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
554 AssertReportSent();
557 } // namespace