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.
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.
9
10#include "base/bind.h"
11#include "base/command_line.h"
12#include "base/prefs/pref_service.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/values.h"
15#include "chrome/browser/browser_process.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/safe_browsing/database_manager.h"
18#include "chrome/browser/safe_browsing/malware_details.h"
19#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
20#include "chrome/browser/safe_browsing/safe_browsing_service.h"
21#include "chrome/browser/safe_browsing/safe_browsing_util.h"
22#include "chrome/browser/safe_browsing/ui_manager.h"
23#include "chrome/browser/ui/browser.h"
24#include "chrome/browser/ui/browser_tabstrip.h"
25#include "chrome/browser/ui/tabs/tab_strip_model.h"
26#include "chrome/common/pref_names.h"
27#include "chrome/common/url_constants.h"
28#include "chrome/test/base/in_process_browser_test.h"
29#include "chrome/test/base/test_switches.h"
30#include "chrome/test/base/ui_test_utils.h"
31#include "content/public/browser/interstitial_page.h"
32#include "content/public/browser/navigation_controller.h"
33#include "content/public/browser/notification_types.h"
34#include "content/public/browser/render_frame_host.h"
35#include "content/public/browser/render_view_host.h"
36#include "content/public/browser/web_contents.h"
37#include "content/public/test/test_browser_thread.h"
38#include "content/public/test/test_utils.h"
39
40using content::BrowserThread;
41using content::InterstitialPage;
42using content::NavigationController;
43using content::WebContents;
44
45namespace {
46
47const char kEmptyPage[] = "files/empty.html";
48const char kMalwarePage[] = "files/safe_browsing/malware.html";
49const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";
50
51class InterstitialObserver : public content::WebContentsObserver {
52 public:
53  InterstitialObserver(content::WebContents* web_contents,
54                       const base::Closure& attach_callback,
55                       const base::Closure& detach_callback)
56      : WebContentsObserver(web_contents),
57        attach_callback_(attach_callback),
58        detach_callback_(detach_callback) {
59  }
60
61  virtual void DidAttachInterstitialPage() OVERRIDE {
62    attach_callback_.Run();
63  }
64
65  virtual void DidDetachInterstitialPage() OVERRIDE {
66    detach_callback_.Run();
67  }
68
69 private:
70  base::Closure attach_callback_;
71  base::Closure detach_callback_;
72
73  DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
74};
75
76// A SafeBrowsingDatabaseManager class that allows us to inject the malicious
77// URLs.
78class FakeSafeBrowsingDatabaseManager :  public SafeBrowsingDatabaseManager {
79 public:
80  explicit FakeSafeBrowsingDatabaseManager(SafeBrowsingService* service)
81      : SafeBrowsingDatabaseManager(service) { }
82
83  // Called on the IO thread to check if the given url is safe or not.  If we
84  // can synchronously determine that the url is safe, CheckUrl returns true.
85  // Otherwise it returns false, and "client" is called asynchronously with the
86  // result when it is ready.
87  // Overrides SafeBrowsingDatabaseManager::CheckBrowseUrl.
88  virtual bool CheckBrowseUrl(const GURL& gurl, Client* client) OVERRIDE {
89    if (badurls[gurl.spec()] == SB_THREAT_TYPE_SAFE)
90      return true;
91
92    BrowserThread::PostTask(
93        BrowserThread::IO, FROM_HERE,
94        base::Bind(&FakeSafeBrowsingDatabaseManager::OnCheckBrowseURLDone,
95                   this, gurl, client));
96    return false;
97  }
98
99  void OnCheckBrowseURLDone(const GURL& gurl, Client* client) {
100    std::vector<SBThreatType> expected_threats;
101    expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
102    expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
103    SafeBrowsingDatabaseManager::SafeBrowsingCheck sb_check(
104        std::vector<GURL>(1, gurl),
105        std::vector<SBFullHash>(),
106        client,
107        safe_browsing_util::MALWARE,
108        expected_threats);
109    sb_check.url_results[0] = badurls[gurl.spec()];
110    client->OnSafeBrowsingResult(sb_check);
111  }
112
113  void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
114    badurls[url.spec()] = threat_type;
115  }
116
117 private:
118  virtual ~FakeSafeBrowsingDatabaseManager() {}
119
120  base::hash_map<std::string, SBThreatType> badurls;
121  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
122};
123
124// A SafeBrowingUIManager class that allows intercepting malware details.
125class FakeSafeBrowsingUIManager :  public SafeBrowsingUIManager {
126 public:
127  explicit FakeSafeBrowsingUIManager(SafeBrowsingService* service) :
128      SafeBrowsingUIManager(service) { }
129
130  // Overrides SafeBrowsingUIManager
131  virtual void SendSerializedMalwareDetails(
132      const std::string& serialized) OVERRIDE {
133    // Notify the UI thread that we got a report.
134    BrowserThread::PostTask(
135        BrowserThread::UI,
136        FROM_HERE,
137        base::Bind(&FakeSafeBrowsingUIManager::OnMalwareDetailsDone,
138                   this,
139                   serialized));
140  }
141
142  void OnMalwareDetailsDone(const std::string& serialized) {
143    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
144    report_ = serialized;
145
146    EXPECT_FALSE(malware_details_done_callback_.is_null());
147    if (!malware_details_done_callback_.is_null()) {
148      malware_details_done_callback_.Run();
149      malware_details_done_callback_ = base::Closure();
150    }
151  }
152
153  void set_malware_details_done_callback(const base::Closure& callback) {
154    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
155    EXPECT_TRUE(malware_details_done_callback_.is_null());
156    malware_details_done_callback_ = callback;
157  }
158
159  std::string GetReport() {
160    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
161    return report_;
162  }
163
164 protected:
165  virtual ~FakeSafeBrowsingUIManager() { }
166
167 private:
168  std::string report_;
169  base::Closure malware_details_done_callback_;
170
171  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingUIManager);
172};
173
174class FakeSafeBrowsingService : public SafeBrowsingService {
175 public:
176  FakeSafeBrowsingService()
177      : fake_database_manager_(),
178        fake_ui_manager_() { }
179
180  // Returned pointer has the same lifespan as the database_manager_ refcounted
181  // object.
182  FakeSafeBrowsingDatabaseManager* fake_database_manager() {
183    return fake_database_manager_;
184  }
185  // Returned pointer has the same lifespan as the ui_manager_ refcounted
186  // object.
187  FakeSafeBrowsingUIManager* fake_ui_manager() {
188    return fake_ui_manager_;
189  }
190
191 protected:
192  virtual ~FakeSafeBrowsingService() { }
193
194  virtual SafeBrowsingDatabaseManager* CreateDatabaseManager() OVERRIDE {
195    fake_database_manager_ = new FakeSafeBrowsingDatabaseManager(this);
196    return fake_database_manager_;
197  }
198
199  virtual SafeBrowsingUIManager* CreateUIManager() OVERRIDE {
200    fake_ui_manager_ = new FakeSafeBrowsingUIManager(this);
201    return fake_ui_manager_;
202  }
203
204 private:
205  FakeSafeBrowsingDatabaseManager* fake_database_manager_;
206  FakeSafeBrowsingUIManager* fake_ui_manager_;
207
208  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService);
209};
210
211// Factory that creates FakeSafeBrowsingService instances.
212class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
213 public:
214  TestSafeBrowsingServiceFactory() :
215      most_recent_service_(NULL) { }
216  virtual ~TestSafeBrowsingServiceFactory() { }
217
218  virtual SafeBrowsingService* CreateSafeBrowsingService() OVERRIDE {
219    most_recent_service_ =  new FakeSafeBrowsingService();
220    return most_recent_service_;
221  }
222
223  FakeSafeBrowsingService* most_recent_service() const {
224    return most_recent_service_;
225  }
226
227 private:
228  FakeSafeBrowsingService* most_recent_service_;
229};
230
231// A MalwareDetails class lets us intercept calls from the renderer.
232class FakeMalwareDetails : public MalwareDetails {
233 public:
234  FakeMalwareDetails(
235      SafeBrowsingUIManager* delegate,
236      WebContents* web_contents,
237      const SafeBrowsingUIManager::UnsafeResource& unsafe_resource)
238      : MalwareDetails(delegate, web_contents, unsafe_resource),
239        got_dom_(false),
240        waiting_(false) { }
241
242  virtual void AddDOMDetails(
243      const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params)
244          OVERRIDE {
245    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
246    MalwareDetails::AddDOMDetails(params);
247
248    // Notify the UI thread that we got the dom details.
249    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
250                            base::Bind(&FakeMalwareDetails::OnDOMDetailsDone,
251                                       this));
252  }
253
254  void WaitForDOM() {
255    if (got_dom_) {
256      return;
257    }
258    // This condition might not trigger normally, but if you add a
259    // sleep(1) in malware_dom_details it triggers :).
260    waiting_ = true;
261    content::RunMessageLoop();
262    EXPECT_TRUE(got_dom_);
263  }
264
265 private:
266  virtual ~FakeMalwareDetails() {}
267
268  void OnDOMDetailsDone() {
269    got_dom_ = true;
270    if (waiting_) {
271      base::MessageLoopForUI::current()->Quit();
272    }
273  }
274
275  // Some logic to figure out if we should wait for the dom details or not.
276  // These variables should only be accessed in the UI thread.
277  bool got_dom_;
278  bool waiting_;
279};
280
281class TestMalwareDetailsFactory : public MalwareDetailsFactory {
282 public:
283  TestMalwareDetailsFactory() : details_() { }
284  virtual ~TestMalwareDetailsFactory() { }
285
286  virtual MalwareDetails* CreateMalwareDetails(
287      SafeBrowsingUIManager* delegate,
288      WebContents* web_contents,
289      const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) OVERRIDE {
290    details_ = new FakeMalwareDetails(delegate, web_contents,
291                                      unsafe_resource);
292    return details_;
293  }
294
295  FakeMalwareDetails* get_details() {
296    return details_;
297  }
298
299 private:
300  FakeMalwareDetails* details_;
301};
302
303// A SafeBrowingBlockingPage class that lets us wait until it's hidden.
304class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage {
305 public:
306  TestSafeBrowsingBlockingPage(SafeBrowsingUIManager* manager,
307                                 WebContents* web_contents,
308                                 const UnsafeResourceList& unsafe_resources)
309      : SafeBrowsingBlockingPage(manager, web_contents, unsafe_resources),
310        wait_for_delete_(false) {
311    // Don't wait the whole 3 seconds for the browser test.
312    malware_details_proceed_delay_ms_ = 100;
313  }
314
315  virtual ~TestSafeBrowsingBlockingPage() {
316    if (!wait_for_delete_)
317      return;
318
319    // Notify that we are gone
320    base::MessageLoopForUI::current()->Quit();
321    wait_for_delete_ = false;
322  }
323
324  void WaitForDelete() {
325    wait_for_delete_ = true;
326    content::RunMessageLoop();
327  }
328
329  // InterstitialPageDelegate methods:
330  virtual void CommandReceived(const std::string& command) OVERRIDE {
331    SafeBrowsingBlockingPage::CommandReceived(command);
332  }
333  virtual void OnProceed() OVERRIDE {
334    SafeBrowsingBlockingPage::OnProceed();
335  }
336  virtual void OnDontProceed() OVERRIDE {
337    SafeBrowsingBlockingPage::OnDontProceed();
338  }
339
340 private:
341  bool wait_for_delete_;
342};
343
344class TestSafeBrowsingBlockingPageFactory
345    : public SafeBrowsingBlockingPageFactory {
346 public:
347  TestSafeBrowsingBlockingPageFactory() { }
348  virtual ~TestSafeBrowsingBlockingPageFactory() { }
349
350  virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
351      SafeBrowsingUIManager* delegate,
352      WebContents* web_contents,
353      const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
354          OVERRIDE {
355    return new TestSafeBrowsingBlockingPage(delegate, web_contents,
356                                              unsafe_resources);
357  }
358};
359
360}  // namespace
361
362// Tests the safe browsing blocking page in a browser.
363class SafeBrowsingBlockingPageBrowserTest
364    : public InProcessBrowserTest,
365      public testing::WithParamInterface<int> {
366 public:
367  enum Visibility {
368    VISIBILITY_ERROR = -1,
369    HIDDEN = 0,
370    VISIBLE = 1
371  };
372
373  SafeBrowsingBlockingPageBrowserTest() {
374  }
375
376  virtual void SetUp() OVERRIDE {
377    SafeBrowsingService::RegisterFactory(&factory_);
378    SafeBrowsingBlockingPage::RegisterFactory(&blocking_page_factory_);
379    MalwareDetails::RegisterFactory(&details_factory_);
380    InProcessBrowserTest::SetUp();
381  }
382
383  virtual void TearDown() OVERRIDE {
384    InProcessBrowserTest::TearDown();
385    SafeBrowsingBlockingPage::RegisterFactory(NULL);
386    SafeBrowsingService::RegisterFactory(NULL);
387    MalwareDetails::RegisterFactory(NULL);
388  }
389
390  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
391    ASSERT_TRUE(test_server()->Start());
392  }
393
394  void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
395    FakeSafeBrowsingService* service =
396        static_cast<FakeSafeBrowsingService*>(
397            g_browser_process->safe_browsing_service());
398
399    ASSERT_TRUE(service);
400    service->fake_database_manager()->SetURLThreatType(url, threat_type);
401  }
402
403  // Adds a safebrowsing result of type |threat_type| to the fake safebrowsing
404  // service, navigates to that page, and returns the url.
405  GURL SetupWarningAndNavigate(SBThreatType threat_type) {
406    GURL url = test_server()->GetURL(kEmptyPage);
407    SetURLThreatType(url, threat_type);
408
409    ui_test_utils::NavigateToURL(browser(), url);
410    EXPECT_TRUE(WaitForReady());
411    return url;
412  }
413
414  // Adds a safebrowsing malware result to the fake safebrowsing service,
415  // navigates to a page with an iframe containing the malware site, and
416  // returns the url of the parent page.
417  GURL SetupMalwareIframeWarningAndNavigate() {
418    GURL url = test_server()->GetURL(kMalwarePage);
419    GURL iframe_url = test_server()->GetURL(kMalwareIframe);
420    SetURLThreatType(iframe_url, SB_THREAT_TYPE_URL_MALWARE);
421
422    ui_test_utils::NavigateToURL(browser(), url);
423    EXPECT_TRUE(WaitForReady());
424    return url;
425  }
426
427  void SendCommand(const std::string& command) {
428    WebContents* contents =
429        browser()->tab_strip_model()->GetActiveWebContents();
430    // We use InterstitialPage::GetInterstitialPage(tab) instead of
431    // tab->GetInterstitialPage() because the tab doesn't have a pointer
432    // to its interstital page until it gets a command from the renderer
433    // that it has indeed displayed it -- and this sometimes happens after
434    // NavigateToURL returns.
435    SafeBrowsingBlockingPage* interstitial_page =
436        static_cast<SafeBrowsingBlockingPage*>(
437            InterstitialPage::GetInterstitialPage(contents)->
438                GetDelegateForTesting());
439    ASSERT_TRUE(interstitial_page);
440    interstitial_page->CommandReceived(command);
441  }
442
443  void DontProceedThroughInterstitial() {
444    WebContents* contents =
445        browser()->tab_strip_model()->GetActiveWebContents();
446    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
447        contents);
448    ASSERT_TRUE(interstitial_page);
449    interstitial_page->DontProceed();
450  }
451
452  void ProceedThroughInterstitial() {
453    WebContents* contents =
454        browser()->tab_strip_model()->GetActiveWebContents();
455    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
456        contents);
457    ASSERT_TRUE(interstitial_page);
458    interstitial_page->Proceed();
459  }
460
461  void AssertNoInterstitial(bool wait_for_delete) {
462    WebContents* contents =
463        browser()->tab_strip_model()->GetActiveWebContents();
464
465    if (contents->ShowingInterstitialPage() && wait_for_delete) {
466      // We'll get notified when the interstitial is deleted.
467      TestSafeBrowsingBlockingPage* page =
468          static_cast<TestSafeBrowsingBlockingPage*>(
469              contents->GetInterstitialPage()->GetDelegateForTesting());
470      page->WaitForDelete();
471    }
472
473    // Can't use InterstitialPage::GetInterstitialPage() because that
474    // gets updated after the TestSafeBrowsingBlockingPage destructor
475    ASSERT_FALSE(contents->ShowingInterstitialPage());
476  }
477
478  bool YesInterstitial() {
479    WebContents* contents =
480        browser()->tab_strip_model()->GetActiveWebContents();
481    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
482        contents);
483    return interstitial_page != NULL;
484  }
485
486  void WaitForInterstitial() {
487    WebContents* contents =
488        browser()->tab_strip_model()->GetActiveWebContents();
489    scoped_refptr<content::MessageLoopRunner> loop_runner(
490        new content::MessageLoopRunner);
491    InterstitialObserver observer(contents,
492                                  loop_runner->QuitClosure(),
493                                  base::Closure());
494    if (!InterstitialPage::GetInterstitialPage(contents))
495      loop_runner->Run();
496  }
497
498  void SetReportSentCallback(const base::Closure& callback) {
499    factory_.most_recent_service()
500        ->fake_ui_manager()
501        ->set_malware_details_done_callback(callback);
502  }
503
504  std::string GetReportSent() {
505    return factory_.most_recent_service()->fake_ui_manager()->GetReport();
506  }
507
508  void MalwareRedirectCancelAndProceed(const std::string& open_function) {
509    GURL load_url = test_server()->GetURL(
510        "files/safe_browsing/interstitial_cancel.html");
511    GURL malware_url("http://localhost/files/safe_browsing/malware.html");
512    SetURLThreatType(malware_url, SB_THREAT_TYPE_URL_MALWARE);
513
514    // Load the test page.
515    ui_test_utils::NavigateToURL(browser(), load_url);
516    // Trigger the safe browsing interstitial page via a redirect in
517    // "openWin()".
518    ui_test_utils::NavigateToURLWithDisposition(
519        browser(),
520        GURL("javascript:" + open_function + "()"),
521        CURRENT_TAB,
522        ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
523    WaitForInterstitial();
524    // Cancel the redirect request while interstitial page is open.
525    browser()->tab_strip_model()->ActivateTabAt(0, true);
526    ui_test_utils::NavigateToURLWithDisposition(
527        browser(),
528        GURL("javascript:stopWin()"),
529        CURRENT_TAB,
530        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
531    browser()->tab_strip_model()->ActivateTabAt(1, true);
532    // Simulate the user clicking "proceed", there should be no crash.  Since
533    // clicking proceed may do nothing (see comment in MalwareRedirectCanceled
534    // below, and crbug.com/76460), we use SendCommand to trigger the callback
535    // directly rather than using ClickAndWaitForDetach since there might not
536    // be a notification to wait for.
537    SendCommand("\"proceed\"");
538  }
539
540  content::RenderViewHost* GetRenderViewHost() {
541    InterstitialPage* interstitial = InterstitialPage::GetInterstitialPage(
542        browser()->tab_strip_model()->GetActiveWebContents());
543    if (!interstitial)
544      return NULL;
545    return interstitial->GetRenderViewHostForTesting();
546  }
547
548  bool WaitForReady() {
549    content::RenderViewHost* rvh = GetRenderViewHost();
550    if (!rvh)
551      return false;
552    // Wait until all <script> tags have executed, including jstemplate.
553    // TODO(joaodasilva): it would be nice to avoid the busy loop, though in
554    // practice it spins at most once or twice.
555    std::string ready_state;
556    do {
557      scoped_ptr<base::Value> value = content::ExecuteScriptAndGetValue(
558          rvh->GetMainFrame(), "document.readyState");
559      if (!value.get() || !value->GetAsString(&ready_state))
560        return false;
561    } while (ready_state != "complete");
562    return true;
563  }
564
565  Visibility GetVisibility(const std::string& node_id) {
566    content::RenderViewHost* rvh = GetRenderViewHost();
567    if (!rvh)
568      return VISIBILITY_ERROR;
569    scoped_ptr<base::Value> value = content::ExecuteScriptAndGetValue(
570        rvh->GetMainFrame(),
571        "var node = document.getElementById('" + node_id + "');\n"
572        "if (node)\n"
573        "   node.offsetWidth > 0 && node.offsetHeight > 0;"
574        "else\n"
575        "  'node not found';\n");
576    if (!value.get())
577      return VISIBILITY_ERROR;
578    bool result = false;
579    if (!value->GetAsBoolean(&result))
580      return VISIBILITY_ERROR;
581    return result ? VISIBLE : HIDDEN;
582  }
583
584  bool Click(const std::string& node_id) {
585    content::RenderViewHost* rvh = GetRenderViewHost();
586    if (!rvh)
587      return false;
588    // We don't use ExecuteScriptAndGetValue for this one, since clicking
589    // the button/link may navigate away before the injected javascript can
590    // reply, hanging the test.
591    rvh->GetMainFrame()->ExecuteJavaScript(
592        base::ASCIIToUTF16(
593            "document.getElementById('" + node_id + "').click();\n"));
594    return true;
595  }
596
597  bool ClickAndWaitForDetach(const std::string& node_id) {
598    // We wait for interstitial_detached rather than nav_entry_committed, as
599    // going back from a main-frame malware interstitial page will not cause a
600    // nav entry committed event.
601    scoped_refptr<content::MessageLoopRunner> loop_runner(
602        new content::MessageLoopRunner);
603    InterstitialObserver observer(
604        browser()->tab_strip_model()->GetActiveWebContents(),
605        base::Closure(),
606        loop_runner->QuitClosure());
607    if (!Click(node_id))
608      return false;
609    loop_runner->Run();
610    return true;
611  }
612
613 protected:
614  TestMalwareDetailsFactory details_factory_;
615
616 private:
617  TestSafeBrowsingServiceFactory factory_;
618  TestSafeBrowsingBlockingPageFactory blocking_page_factory_;
619
620  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageBrowserTest);
621};
622
623// TODO(linux_aura) http://crbug.com/163931
624// TODO(win_aura) http://crbug.com/154081
625#if defined(USE_AURA) && !defined(OS_CHROMEOS)
626#define MAYBE_MalwareRedirectInIFrameCanceled DISABLED_MalwareRedirectInIFrameCanceled
627#else
628#define MAYBE_MalwareRedirectInIFrameCanceled MalwareRedirectInIFrameCanceled
629#endif
630IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
631                       MAYBE_MalwareRedirectInIFrameCanceled) {
632  // 1. Test the case that redirect is a subresource.
633  MalwareRedirectCancelAndProceed("openWinIFrame");
634  // If the redirect was from subresource but canceled, "proceed" will continue
635  // with the rest of resources.
636  AssertNoInterstitial(true);
637}
638
639IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
640                       MalwareRedirectCanceled) {
641  // 2. Test the case that redirect is the only resource.
642  MalwareRedirectCancelAndProceed("openWin");
643  // Clicking proceed won't do anything if the main request is cancelled
644  // already.  See crbug.com/76460.
645  EXPECT_TRUE(YesInterstitial());
646}
647
648IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
649                       MalwareDontProceed) {
650#if defined(OS_WIN) && defined(USE_ASH)
651  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
652  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
653    return;
654#endif
655
656  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
657
658  EXPECT_EQ(VISIBLE, GetVisibility("primary-button"));
659  EXPECT_EQ(HIDDEN, GetVisibility("details"));
660  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
661  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
662  EXPECT_TRUE(Click("details-button"));
663  EXPECT_EQ(VISIBLE, GetVisibility("details"));
664  EXPECT_EQ(VISIBLE, GetVisibility("proceed-link"));
665  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
666  EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
667
668  AssertNoInterstitial(false);   // Assert the interstitial is gone
669  EXPECT_EQ(GURL(url::kAboutBlankURL),  // Back to "about:blank"
670            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
671}
672
673IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
674                       HarmfulDontProceed) {
675#if defined(OS_WIN) && defined(USE_ASH)
676  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
677  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
678    return;
679#endif
680
681  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_HARMFUL);
682
683  EXPECT_EQ(VISIBLE, GetVisibility("primary-button"));
684  EXPECT_EQ(HIDDEN, GetVisibility("details"));
685  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
686  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
687  EXPECT_TRUE(Click("details-button"));
688  EXPECT_EQ(VISIBLE, GetVisibility("details"));
689  EXPECT_EQ(VISIBLE, GetVisibility("proceed-link"));
690  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
691  EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
692
693  AssertNoInterstitial(false);   // Assert the interstitial is gone
694  EXPECT_EQ(GURL(url::kAboutBlankURL),  // Back to "about:blank"
695            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
696}
697
698IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, MalwareProceed) {
699  GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
700
701  EXPECT_TRUE(ClickAndWaitForDetach("proceed-link"));
702  AssertNoInterstitial(true);  // Assert the interstitial is gone.
703  EXPECT_EQ(url,
704            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
705}
706
707IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, HarmfulProceed) {
708  GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_HARMFUL);
709
710  EXPECT_TRUE(ClickAndWaitForDetach("proceed-link"));
711  AssertNoInterstitial(true);  // Assert the interstitial is gone.
712  EXPECT_EQ(url,
713            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
714}
715
716IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
717                       MalwareIframeDontProceed) {
718#if defined(OS_WIN) && defined(USE_ASH)
719  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
720  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
721    return;
722#endif
723
724  SetupMalwareIframeWarningAndNavigate();
725
726  EXPECT_EQ(VISIBLE, GetVisibility("primary-button"));
727  EXPECT_EQ(HIDDEN, GetVisibility("details"));
728  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
729  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
730  EXPECT_TRUE(Click("details-button"));
731  EXPECT_EQ(VISIBLE, GetVisibility("details"));
732  EXPECT_EQ(VISIBLE, GetVisibility("proceed-link"));
733  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
734  EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
735
736  AssertNoInterstitial(false);  // Assert the interstitial is gone
737
738  EXPECT_EQ(GURL(url::kAboutBlankURL),  // Back to "about:blank"
739            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
740}
741
742IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
743    MalwareIframeProceed) {
744  GURL url = SetupMalwareIframeWarningAndNavigate();
745
746  EXPECT_TRUE(ClickAndWaitForDetach("proceed-link"));
747  AssertNoInterstitial(true);  // Assert the interstitial is gone
748
749  EXPECT_EQ(url,
750            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
751}
752
753IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
754                       MalwareIframeReportDetails) {
755  scoped_refptr<content::MessageLoopRunner> malware_report_sent_runner(
756      new content::MessageLoopRunner);
757  SetReportSentCallback(malware_report_sent_runner->QuitClosure());
758
759  GURL url = SetupMalwareIframeWarningAndNavigate();
760
761  // If the DOM details from renderer did not already return, wait for them.
762  details_factory_.get_details()->WaitForDOM();
763
764  EXPECT_TRUE(Click("opt-in-checkbox"));
765  EXPECT_TRUE(ClickAndWaitForDetach("proceed-link"));
766  AssertNoInterstitial(true);  // Assert the interstitial is gone
767
768  ASSERT_TRUE(browser()->profile()->GetPrefs()->GetBoolean(
769      prefs::kSafeBrowsingExtendedReportingEnabled));
770  EXPECT_EQ(url,
771            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
772
773  malware_report_sent_runner->Run();
774  std::string serialized = GetReportSent();
775  safe_browsing::ClientMalwareReportRequest report;
776  ASSERT_TRUE(report.ParseFromString(serialized));
777  // Verify the report is complete.
778  EXPECT_TRUE(report.complete());
779}
780
781// Verifies that the "proceed anyway" link isn't available when it is disabled
782// by the corresponding policy. Also verifies that sending the "proceed"
783// command anyway doesn't advance to the malware site.
784IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, ProceedDisabled) {
785#if defined(OS_WIN) && defined(USE_ASH)
786  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
787  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
788    return;
789#endif
790
791  // Simulate a policy disabling the "proceed anyway" link.
792  browser()->profile()->GetPrefs()->SetBoolean(
793      prefs::kSafeBrowsingProceedAnywayDisabled, true);
794
795  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
796
797  EXPECT_EQ(VISIBLE, GetVisibility("primary-button"));
798  EXPECT_EQ(HIDDEN, GetVisibility("details"));
799  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
800  EXPECT_EQ(HIDDEN, GetVisibility("final-paragraph"));
801  EXPECT_TRUE(Click("details-button"));
802  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
803  EXPECT_EQ(HIDDEN, GetVisibility("final-paragraph"));
804  SendCommand("proceed");
805
806  // The "proceed" command should go back instead, if proceeding is disabled.
807  AssertNoInterstitial(true);
808  EXPECT_EQ(GURL(url::kAboutBlankURL),  // Back to "about:blank"
809            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
810}
811
812// Verifies that the reporting checkbox is hidden on non-HTTP pages.
813// TODO(mattm): Should also verify that no report is sent, but there isn't a
814// good way to do that in the current design.
815IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
816                       ReportingDisabled) {
817#if defined(OS_WIN) && defined(USE_ASH)
818  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
819  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
820    return;
821#endif
822
823  browser()->profile()->GetPrefs()->SetBoolean(
824      prefs::kSafeBrowsingExtendedReportingEnabled, true);
825
826  net::SpawnedTestServer https_server(
827      net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
828      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
829  ASSERT_TRUE(https_server.Start());
830  GURL url = https_server.GetURL(kEmptyPage);
831  SetURLThreatType(url, SB_THREAT_TYPE_URL_MALWARE);
832  ui_test_utils::NavigateToURL(browser(), url);
833  ASSERT_TRUE(WaitForReady());
834
835  EXPECT_EQ(HIDDEN, GetVisibility("malware-opt-in"));
836  EXPECT_EQ(HIDDEN, GetVisibility("opt-in-checkbox"));
837  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
838  EXPECT_TRUE(Click("details-button"));
839  EXPECT_EQ(VISIBLE, GetVisibility("help-link"));
840  EXPECT_EQ(VISIBLE, GetVisibility("proceed-link"));
841
842  EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
843  AssertNoInterstitial(false);   // Assert the interstitial is gone
844  EXPECT_EQ(GURL(url::kAboutBlankURL),  // Back to "about:blank"
845            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
846}
847
848IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest,
849    PhishingDontProceed) {
850#if defined(OS_WIN) && defined(USE_ASH)
851  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
852  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
853    return;
854#endif
855
856  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
857
858  EXPECT_EQ(VISIBLE, GetVisibility("primary-button"));
859  EXPECT_EQ(HIDDEN, GetVisibility("details"));
860  EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
861  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
862  EXPECT_TRUE(Click("details-button"));
863  EXPECT_EQ(VISIBLE, GetVisibility("details"));
864  EXPECT_EQ(VISIBLE, GetVisibility("proceed-link"));
865  EXPECT_EQ(HIDDEN, GetVisibility("error-code"));
866  EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
867
868  AssertNoInterstitial(false);  // Assert the interstitial is gone
869  EXPECT_EQ(GURL(url::kAboutBlankURL),  // We are back to "about:blank".
870            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
871}
872
873IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, PhishingProceed) {
874  GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
875  EXPECT_TRUE(ClickAndWaitForDetach("proceed-link"));
876  AssertNoInterstitial(true);  // Assert the interstitial is gone
877  EXPECT_EQ(url,
878            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
879}
880
881IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, PhishingLearnMore) {
882  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
883  EXPECT_TRUE(ClickAndWaitForDetach("help-link"));
884  AssertNoInterstitial(false);  // Assert the interstitial is gone
885
886  // We are in the help page.
887  EXPECT_EQ(
888      "/transparencyreport/safebrowsing/",
889       browser()->tab_strip_model()->GetActiveWebContents()->GetURL().path());
890}
891