Home | History | Annotate | Download | only in blocked_content
      1 // Copyright 2013 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 #include "base/command_line.h"
      6 #include "base/files/file_path.h"
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/path_service.h"
      9 #include "base/run_loop.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/autocomplete/autocomplete_match.h"
     12 #include "chrome/browser/autocomplete/autocomplete_result.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/browser/content_settings/host_content_settings_map.h"
     15 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/search_engines/template_url_service_factory.h"
     18 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
     19 #include "chrome/browser/ui/browser.h"
     20 #include "chrome/browser/ui/browser_commands.h"
     21 #include "chrome/browser/ui/browser_finder.h"
     22 #include "chrome/browser/ui/browser_window.h"
     23 #include "chrome/browser/ui/omnibox/location_bar.h"
     24 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
     25 #include "chrome/browser/ui/omnibox/omnibox_view.h"
     26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     27 #include "chrome/common/chrome_paths.h"
     28 #include "chrome/common/chrome_switches.h"
     29 #include "chrome/test/base/in_process_browser_test.h"
     30 #include "chrome/test/base/test_switches.h"
     31 #include "chrome/test/base/ui_test_utils.h"
     32 #include "content/public/browser/notification_registrar.h"
     33 #include "content/public/browser/notification_service.h"
     34 #include "content/public/browser/render_frame_host.h"
     35 #include "content/public/browser/web_contents.h"
     36 #include "content/public/browser/web_contents_observer.h"
     37 #include "content/public/common/url_constants.h"
     38 #include "content/public/test/browser_test_utils.h"
     39 #include "content/public/test/test_navigation_observer.h"
     40 #include "net/dns/mock_host_resolver.h"
     41 #include "net/test/embedded_test_server/embedded_test_server.h"
     42 #include "testing/gtest/include/gtest/gtest.h"
     43 
     44 using content::WebContents;
     45 
     46 namespace {
     47 
     48 // Counts the number of RenderViewHosts created.
     49 class CountRenderViewHosts : public content::NotificationObserver {
     50  public:
     51   CountRenderViewHosts()
     52       : count_(0) {
     53     registrar_.Add(this,
     54                    content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
     55                    content::NotificationService::AllSources());
     56   }
     57   virtual ~CountRenderViewHosts() {}
     58 
     59   int GetRenderViewHostCreatedCount() const { return count_; }
     60 
     61  private:
     62   virtual void Observe(int type,
     63                        const content::NotificationSource& source,
     64                        const content::NotificationDetails& details) OVERRIDE {
     65     count_++;
     66   }
     67 
     68   content::NotificationRegistrar registrar_;
     69 
     70   int count_;
     71 
     72   DISALLOW_COPY_AND_ASSIGN(CountRenderViewHosts);
     73 };
     74 
     75 class CloseObserver : public content::WebContentsObserver {
     76  public:
     77   explicit CloseObserver(WebContents* contents)
     78       : content::WebContentsObserver(contents) {}
     79 
     80   void Wait() {
     81     close_loop_.Run();
     82   }
     83 
     84   virtual void WebContentsDestroyed() OVERRIDE {
     85     close_loop_.Quit();
     86   }
     87 
     88  private:
     89   base::RunLoop close_loop_;
     90 
     91   DISALLOW_COPY_AND_ASSIGN(CloseObserver);
     92 };
     93 
     94 class PopupBlockerBrowserTest : public InProcessBrowserTest {
     95  public:
     96   PopupBlockerBrowserTest() {}
     97   virtual ~PopupBlockerBrowserTest() {}
     98 
     99   virtual void SetUpOnMainThread() OVERRIDE {
    100     InProcessBrowserTest::SetUpOnMainThread();
    101 
    102     host_resolver()->AddRule("*", "127.0.0.1");
    103     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    104   }
    105 
    106   int GetBlockedContentsCount() {
    107     // Do a round trip to the renderer first to flush any in-flight IPCs to
    108     // create a to-be-blocked window.
    109     WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
    110     CHECK(content::ExecuteScript(tab, std::string()));
    111     PopupBlockerTabHelper* popup_blocker_helper =
    112         PopupBlockerTabHelper::FromWebContents(tab);
    113     return popup_blocker_helper->GetBlockedPopupsCount();
    114   }
    115 
    116   void NavigateAndCheckPopupShown(const GURL& url) {
    117     content::WindowedNotificationObserver observer(
    118         chrome::NOTIFICATION_TAB_ADDED,
    119         content::NotificationService::AllSources());
    120     ui_test_utils::NavigateToURL(browser(), url);
    121     observer.Wait();
    122 
    123     ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
    124                                           browser()->host_desktop_type()));
    125 
    126     ASSERT_EQ(0, GetBlockedContentsCount());
    127   }
    128 
    129   enum WhatToExpect {
    130     ExpectPopup,
    131     ExpectTab
    132   };
    133 
    134   enum ShouldCheckTitle {
    135     CheckTitle,
    136     DontCheckTitle
    137   };
    138 
    139   // Navigates to the test indicated by |test_name| using |browser| which is
    140   // expected to try to open a popup. Verifies that the popup was blocked and
    141   // then opens the blocked popup. Once the popup stopped loading, verifies
    142   // that the title of the page is "PASS" if |check_title| is set.
    143   //
    144   // If |what_to_expect| is ExpectPopup, the popup is expected to open a new
    145   // window, or a background tab if it is false.
    146   //
    147   // Returns the WebContents of the launched popup.
    148   WebContents* RunCheckTest(Browser* browser,
    149                             const std::string& test_name,
    150                             WhatToExpect what_to_expect,
    151                             ShouldCheckTitle check_title) {
    152     GURL url(embedded_test_server()->GetURL(test_name));
    153 
    154     CountRenderViewHosts counter;
    155 
    156     ui_test_utils::NavigateToURL(browser, url);
    157 
    158     // Since the popup blocker blocked the window.open, there should be only one
    159     // tab.
    160     EXPECT_EQ(1u, chrome::GetBrowserCount(browser->profile(),
    161                                           browser->host_desktop_type()));
    162     EXPECT_EQ(1, browser->tab_strip_model()->count());
    163     WebContents* web_contents =
    164         browser->tab_strip_model()->GetActiveWebContents();
    165     EXPECT_EQ(url, web_contents->GetURL());
    166 
    167     // And no new RVH created.
    168     EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
    169 
    170     content::WindowedNotificationObserver observer(
    171         chrome::NOTIFICATION_TAB_ADDED,
    172         content::NotificationService::AllSources());
    173     ui_test_utils::BrowserAddedObserver browser_observer;
    174 
    175     // Launch the blocked popup.
    176     PopupBlockerTabHelper* popup_blocker_helper =
    177         PopupBlockerTabHelper::FromWebContents(web_contents);
    178     if (!popup_blocker_helper->GetBlockedPopupsCount()) {
    179       content::WindowedNotificationObserver observer(
    180           chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
    181           content::NotificationService::AllSources());
    182       observer.Wait();
    183     }
    184     EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
    185     std::map<int32, GURL> blocked_requests =
    186         popup_blocker_helper->GetBlockedPopupRequests();
    187     std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
    188     popup_blocker_helper->ShowBlockedPopup(iter->first);
    189 
    190     observer.Wait();
    191     Browser* new_browser;
    192     if (what_to_expect == ExpectPopup) {
    193       new_browser = browser_observer.WaitForSingleNewBrowser();
    194       web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
    195     } else {
    196       new_browser = browser;
    197       EXPECT_EQ(2, browser->tab_strip_model()->count());
    198       web_contents = browser->tab_strip_model()->GetWebContentsAt(1);
    199     }
    200 
    201     if (check_title == CheckTitle) {
    202       // Check that the check passed.
    203       base::string16 expected_title(base::ASCIIToUTF16("PASS"));
    204       content::TitleWatcher title_watcher(web_contents, expected_title);
    205       EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
    206     }
    207 
    208     return web_contents;
    209   }
    210 
    211  private:
    212   DISALLOW_COPY_AND_ASSIGN(PopupBlockerBrowserTest);
    213 };
    214 
    215 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    216                        BlockWebContentsCreation) {
    217 #if defined(OS_WIN) && defined(USE_ASH)
    218   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    219   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    220     return;
    221 #endif
    222 
    223   RunCheckTest(
    224       browser(),
    225       "/popup_blocker/popup-blocked-to-post-blank.html",
    226       ExpectPopup,
    227       DontCheckTitle);
    228 }
    229 
    230 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    231                        BlockWebContentsCreationIncognito) {
    232 #if defined(OS_WIN) && defined(USE_ASH)
    233   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    234   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    235     return;
    236 #endif
    237 
    238   RunCheckTest(
    239       CreateIncognitoBrowser(),
    240       "/popup_blocker/popup-blocked-to-post-blank.html",
    241       ExpectPopup,
    242       DontCheckTitle);
    243 }
    244 
    245 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    246                        PopupBlockedFakeClickOnAnchor) {
    247 #if defined(OS_WIN) && defined(USE_ASH)
    248   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    249   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    250     return;
    251 #endif
    252 
    253   RunCheckTest(
    254       browser(),
    255       "/popup_blocker/popup-fake-click-on-anchor.html",
    256       ExpectTab,
    257       DontCheckTitle);
    258 }
    259 
    260 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    261                        PopupBlockedFakeClickOnAnchorNoTarget) {
    262 #if defined(OS_WIN) && defined(USE_ASH)
    263   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    264   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    265     return;
    266 #endif
    267 
    268   RunCheckTest(
    269       browser(),
    270       "/popup_blocker/popup-fake-click-on-anchor2.html",
    271       ExpectTab,
    272       DontCheckTitle);
    273 }
    274 
    275 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, MultiplePopups) {
    276   GURL url(embedded_test_server()->GetURL("/popup_blocker/popup-many.html"));
    277   ui_test_utils::NavigateToURL(browser(), url);
    278   ASSERT_EQ(2, GetBlockedContentsCount());
    279 }
    280 
    281 // Verify that popups are launched on browser back button.
    282 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    283                        AllowPopupThroughContentSetting) {
    284   GURL url(embedded_test_server()->GetURL(
    285       "/popup_blocker/popup-blocked-to-post-blank.html"));
    286   browser()->profile()->GetHostContentSettingsMap()
    287       ->SetContentSetting(ContentSettingsPattern::FromURL(url),
    288                           ContentSettingsPattern::Wildcard(),
    289                           CONTENT_SETTINGS_TYPE_POPUPS,
    290                           std::string(),
    291                           CONTENT_SETTING_ALLOW);
    292 
    293   NavigateAndCheckPopupShown(url);
    294 }
    295 
    296 // Verify that content settings are applied based on the top-level frame URL.
    297 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    298                        AllowPopupThroughContentSettingIFrame) {
    299   GURL url(embedded_test_server()->GetURL("/popup_blocker/popup-frames.html"));
    300   browser()->profile()->GetHostContentSettingsMap()
    301       ->SetContentSetting(ContentSettingsPattern::FromURL(url),
    302                           ContentSettingsPattern::Wildcard(),
    303                           CONTENT_SETTINGS_TYPE_POPUPS,
    304                           std::string(),
    305                           CONTENT_SETTING_ALLOW);
    306 
    307   // Popup from the iframe should be allowed since the top-level URL is
    308   // whitelisted.
    309   NavigateAndCheckPopupShown(url);
    310 
    311   // Whitelist iframe URL instead.
    312   GURL::Replacements replace_host;
    313   std::string host_str("www.a.com");  // Must stay in scope with replace_host
    314   replace_host.SetHostStr(host_str);
    315   GURL frame_url(embedded_test_server()
    316                      ->GetURL("/popup_blocker/popup-frames-iframe.html")
    317                      .ReplaceComponents(replace_host));
    318   browser()->profile()->GetHostContentSettingsMap()->ClearSettingsForOneType(
    319       CONTENT_SETTINGS_TYPE_POPUPS);
    320   browser()->profile()->GetHostContentSettingsMap()
    321       ->SetContentSetting(ContentSettingsPattern::FromURL(frame_url),
    322                           ContentSettingsPattern::Wildcard(),
    323                           CONTENT_SETTINGS_TYPE_POPUPS,
    324                           std::string(),
    325                           CONTENT_SETTING_ALLOW);
    326 
    327   // Popup should be blocked.
    328   ui_test_utils::NavigateToURL(browser(), url);
    329   ASSERT_EQ(1, GetBlockedContentsCount());
    330 }
    331 
    332 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    333                        PopupsLaunchWhenTabIsClosed) {
    334   CommandLine::ForCurrentProcess()->AppendSwitch(
    335       switches::kDisablePopupBlocking);
    336   GURL url(
    337       embedded_test_server()->GetURL("/popup_blocker/popup-on-unload.html"));
    338   ui_test_utils::NavigateToURL(browser(), url);
    339 
    340   NavigateAndCheckPopupShown(embedded_test_server()->GetURL("/popup_blocker/"));
    341 }
    342 
    343 // Verify that when you unblock popup, the popup shows in history and omnibox.
    344 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
    345                        UnblockedPopupShowsInHistoryAndOmnibox) {
    346   CommandLine::ForCurrentProcess()->AppendSwitch(
    347       switches::kDisablePopupBlocking);
    348   GURL url(embedded_test_server()->GetURL(
    349       "/popup_blocker/popup-blocked-to-post-blank.html"));
    350   NavigateAndCheckPopupShown(url);
    351 
    352   std::string search_string =
    353       "data:text/html,<title>Popup Success!</title>you should not see this "
    354       "message if popup blocker is enabled";
    355 
    356   ui_test_utils::HistoryEnumerator history(browser()->profile());
    357   std::vector<GURL>& history_urls = history.urls();
    358   ASSERT_EQ(2u, history_urls.size());
    359   ASSERT_EQ(GURL(search_string), history_urls[0]);
    360   ASSERT_EQ(url, history_urls[1]);
    361 
    362   TemplateURLService* service = TemplateURLServiceFactory::GetForProfile(
    363       browser()->profile());
    364   ui_test_utils::WaitForTemplateURLServiceToLoad(service);
    365   LocationBar* location_bar = browser()->window()->GetLocationBar();
    366   ui_test_utils::SendToOmniboxAndSubmit(location_bar, search_string);
    367   OmniboxEditModel* model = location_bar->GetOmniboxView()->model();
    368   EXPECT_EQ(GURL(search_string), model->CurrentMatch(NULL).destination_url);
    369   EXPECT_EQ(base::ASCIIToUTF16(search_string),
    370             model->CurrentMatch(NULL).contents);
    371 }
    372 
    373 // This test fails on linux AURA with this change
    374 // https://codereview.chromium.org/23903056
    375 // BUG=https://code.google.com/p/chromium/issues/detail?id=295299
    376 // TODO(ananta). Debug and fix this test.
    377 #if defined(USE_AURA) && defined(OS_LINUX)
    378 #define MAYBE_WindowFeatures DISABLED_WindowFeatures
    379 #else
    380 #define MAYBE_WindowFeatures WindowFeatures
    381 #endif
    382 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, MAYBE_WindowFeatures) {
    383   WebContents* popup =
    384       RunCheckTest(browser(),
    385                    "/popup_blocker/popup-window-open.html",
    386                    ExpectPopup,
    387                    DontCheckTitle);
    388 
    389   // Check that the new popup has (roughly) the requested size.
    390   gfx::Size window_size = popup->GetContainerBounds().size();
    391   EXPECT_TRUE(349 <= window_size.width() && window_size.width() <= 351);
    392   EXPECT_TRUE(249 <= window_size.height() && window_size.height() <= 251);
    393 }
    394 
    395 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, CorrectReferrer) {
    396   RunCheckTest(browser(),
    397                "/popup_blocker/popup-referrer.html",
    398                ExpectPopup,
    399                CheckTitle);
    400 }
    401 
    402 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, WindowFeaturesBarProps) {
    403   RunCheckTest(browser(),
    404                "/popup_blocker/popup-windowfeatures.html",
    405                ExpectPopup,
    406                CheckTitle);
    407 }
    408 
    409 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, SessionStorage) {
    410   RunCheckTest(browser(),
    411                "/popup_blocker/popup-sessionstorage.html",
    412                ExpectPopup,
    413                CheckTitle);
    414 }
    415 
    416 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, Opener) {
    417   RunCheckTest(browser(),
    418                "/popup_blocker/popup-opener.html",
    419                ExpectPopup,
    420                CheckTitle);
    421 }
    422 
    423 // Tests that the popup can still close itself after navigating. This tests that
    424 // the openedByDOM bit is preserved across blocked popups.
    425 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, ClosableAfterNavigation) {
    426   // Open a popup.
    427   WebContents* popup =
    428       RunCheckTest(browser(),
    429                    "/popup_blocker/popup-opener.html",
    430                    ExpectPopup,
    431                    CheckTitle);
    432 
    433   // Navigate it elsewhere.
    434   content::TestNavigationObserver nav_observer(popup);
    435   popup->GetMainFrame()->ExecuteJavaScript(
    436       base::UTF8ToUTF16("location.href = '/empty.html'"));
    437   nav_observer.Wait();
    438 
    439   // Have it close itself.
    440   CloseObserver close_observer(popup);
    441   popup->GetMainFrame()->ExecuteJavaScript(
    442       base::UTF8ToUTF16("window.close()"));
    443   close_observer.Wait();
    444 }
    445 
    446 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, OpenerSuppressed) {
    447   RunCheckTest(browser(),
    448                "/popup_blocker/popup-openersuppressed.html",
    449                ExpectTab,
    450                CheckTitle);
    451 }
    452 
    453 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, ShiftClick) {
    454   RunCheckTest(
    455       browser(),
    456       "/popup_blocker/popup-fake-click-on-anchor3.html",
    457       ExpectPopup,
    458       CheckTitle);
    459 }
    460 
    461 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, WebUI) {
    462   WebContents* popup =
    463       RunCheckTest(browser(),
    464                    "/popup_blocker/popup-webui.html",
    465                    ExpectPopup,
    466                    DontCheckTitle);
    467 
    468   // Check that the new popup displays about:blank.
    469   EXPECT_EQ(GURL(url::kAboutBlankURL), popup->GetURL());
    470 }
    471 
    472 // Verify that the renderer can't DOS the browser by creating arbitrarily many
    473 // popups.
    474 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, DenialOfService) {
    475   GURL url(embedded_test_server()->GetURL("/popup_blocker/popup-dos.html"));
    476   ui_test_utils::NavigateToURL(browser(), url);
    477   ASSERT_EQ(25, GetBlockedContentsCount());
    478 }
    479 
    480 }  // namespace
    481