popup_blocker_browsertest.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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/strings/utf_string_conversions.h"
10#include "chrome/browser/autocomplete/autocomplete_match.h"
11#include "chrome/browser/autocomplete/autocomplete_result.h"
12#include "chrome/browser/chrome_notification_types.h"
13#include "chrome/browser/content_settings/host_content_settings_map.h"
14#include "chrome/browser/content_settings/tab_specific_content_settings.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/search_engines/template_url_service_factory.h"
17#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.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/web_contents.h"
35#include "content/public/browser/web_contents_view.h"
36#include "content/public/common/url_constants.h"
37#include "content/public/test/browser_test_utils.h"
38#include "testing/gtest/include/gtest/gtest.h"
39
40using content::WebContents;
41
42namespace {
43
44static const base::FilePath::CharType* kTestDir =
45    FILE_PATH_LITERAL("popup_blocker");
46
47// Counts the number of RenderViewHosts created.
48class CountRenderViewHosts : public content::NotificationObserver {
49 public:
50  CountRenderViewHosts()
51      : count_(0) {
52    registrar_.Add(this,
53                   content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
54                   content::NotificationService::AllSources());
55  }
56  virtual ~CountRenderViewHosts() {}
57
58  int GetRenderViewHostCreatedCount() const { return count_; }
59
60 private:
61  virtual void Observe(int type,
62                       const content::NotificationSource& source,
63                       const content::NotificationDetails& details) OVERRIDE {
64    count_++;
65  }
66
67  content::NotificationRegistrar registrar_;
68
69  int count_;
70
71  DISALLOW_COPY_AND_ASSIGN(CountRenderViewHosts);
72};
73
74class PopupBlockerBrowserTest : public InProcessBrowserTest {
75 public:
76  PopupBlockerBrowserTest() {}
77
78  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
79    InProcessBrowserTest::SetUpCommandLine(command_line);
80    command_line->AppendSwitch(switches::kDisableBetterPopupBlocking);
81  }
82
83  // Returns a url that shows one popup.
84  GURL GetTestURL() {
85    return ui_test_utils::GetTestUrl(
86      base::FilePath(kTestDir),
87      base::FilePath(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html")));
88  }
89
90  std::vector<WebContents*> GetBlockedContents(Browser* browser) {
91    // Do a round trip to the renderer first to flush any in-flight IPCs to
92    // create a to-be-blocked window.
93    WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
94    CHECK(content::ExecuteScript(tab, std::string()));
95    BlockedContentTabHelper* blocked_content_tab_helper =
96        BlockedContentTabHelper::FromWebContents(tab);
97    std::vector<WebContents*> blocked_contents;
98    blocked_content_tab_helper->GetBlockedContents(&blocked_contents);
99    return blocked_contents;
100  }
101
102  void NavigateAndCheckPopupShown(Browser* browser, const GURL& url) {
103    content::WindowedNotificationObserver observer(
104        chrome::NOTIFICATION_TAB_ADDED,
105        content::NotificationService::AllSources());
106    ui_test_utils::NavigateToURL(browser, url);
107    observer.Wait();
108
109    ASSERT_EQ(2u, chrome::GetBrowserCount(browser->profile(),
110                                          browser->host_desktop_type()));
111
112    std::vector<WebContents*> blocked_contents = GetBlockedContents(browser);
113    ASSERT_TRUE(blocked_contents.empty());
114  }
115
116  void BasicTest(Browser* browser, const GURL& url) {
117    ui_test_utils::NavigateToURL(browser, url);
118
119    // If the popup blocker blocked the blank post, there should be only one
120    // tab in only one browser window and the URL of current tab must be equal
121    // to the original URL.
122    EXPECT_EQ(1u, chrome::GetBrowserCount(browser->profile(),
123                                          browser->host_desktop_type()));
124    EXPECT_EQ(1, browser->tab_strip_model()->count());
125    WebContents* web_contents =
126        browser->tab_strip_model()->GetActiveWebContents();
127    EXPECT_EQ(url, web_contents->GetURL());
128
129    std::vector<WebContents*> blocked_contents = GetBlockedContents(browser);
130    ASSERT_EQ(1u, blocked_contents.size());
131
132    content::WindowedNotificationObserver observer(
133        chrome::NOTIFICATION_TAB_ADDED,
134        content::NotificationService::AllSources());
135
136    BlockedContentTabHelper* blocked_content_tab_helper =
137        BlockedContentTabHelper::FromWebContents(web_contents);
138    blocked_content_tab_helper->LaunchForContents(blocked_contents[0]);
139
140    observer.Wait();
141  }
142};
143
144IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, PopupBlockedPostBlank) {
145  BasicTest(browser(), GetTestURL());
146}
147
148IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
149                       PopupBlockedPostBlankIncognito) {
150  BasicTest(CreateIncognitoBrowser(), GetTestURL());
151}
152
153IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
154                       PopupBlockedFakeClickOnAnchor) {
155  GURL url(ui_test_utils::GetTestUrl(
156      base::FilePath(kTestDir),
157      base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor.html"))));
158  BasicTest(browser(), url);
159}
160
161IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, MultiplePopups) {
162  GURL url(ui_test_utils::GetTestUrl(base::FilePath(
163      kTestDir), base::FilePath(FILE_PATH_LITERAL("popup-many.html"))));
164  ui_test_utils::NavigateToURL(browser(), url);
165  std::vector<WebContents*> blocked_contents = GetBlockedContents(browser());
166  ASSERT_EQ(2u, blocked_contents.size());
167}
168
169// Verify that popups are launched on browser back button.
170IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
171                       AllowPopupThroughContentSetting) {
172  GURL url(GetTestURL());
173  browser()->profile()->GetHostContentSettingsMap()
174      ->SetContentSetting(ContentSettingsPattern::FromURL(url),
175                          ContentSettingsPattern::Wildcard(),
176                          CONTENT_SETTINGS_TYPE_POPUPS,
177                          std::string(),
178                          CONTENT_SETTING_ALLOW);
179
180  NavigateAndCheckPopupShown(browser(), url);
181}
182
183IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, PopupsLaunchWhenTabIsClosed) {
184  CommandLine::ForCurrentProcess()->AppendSwitch(
185      switches::kDisablePopupBlocking);
186  GURL url = ui_test_utils::GetTestUrl(
187      base::FilePath(kTestDir),
188      base::FilePath(FILE_PATH_LITERAL("popup-on-unload.html")));
189  ui_test_utils::NavigateToURL(browser(), url);
190
191  NavigateAndCheckPopupShown(browser(), GURL(content::kAboutBlankURL));
192}
193
194// Verify that when you unblock popup, the popup shows in history and omnibox.
195IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
196                       UnblockedPopupShowsInHistoryAndOmnibox) {
197  CommandLine::ForCurrentProcess()->AppendSwitch(
198      switches::kDisablePopupBlocking);
199  GURL url(GetTestURL());
200  NavigateAndCheckPopupShown(browser(), url);
201
202  std::string search_string =
203      "data:text/html,<title>Popup Success!</title>you should not see this "
204      "message if popup blocker is enabled";
205
206  ui_test_utils::HistoryEnumerator history(browser()->profile());
207  std::vector<GURL>& history_urls = history.urls();
208  ASSERT_EQ(2u, history_urls.size());
209  ASSERT_EQ(GURL(search_string), history_urls[0]);
210  ASSERT_EQ(url, history_urls[1]);
211
212  TemplateURLService* service = TemplateURLServiceFactory::GetForProfile(
213      browser()->profile());
214  ui_test_utils::WaitForTemplateURLServiceToLoad(service);
215  LocationBar* location_bar = browser()->window()->GetLocationBar();
216  ui_test_utils::SendToOmniboxAndSubmit(location_bar, search_string);
217  OmniboxEditModel* model = location_bar->GetLocationEntry()->model();
218  EXPECT_EQ(GURL(search_string), model->CurrentMatch(NULL).destination_url);
219  EXPECT_EQ(ASCIIToUTF16(search_string), model->CurrentMatch(NULL).contents);
220}
221
222class BetterPopupBlockerBrowserTest : public PopupBlockerBrowserTest {
223 public:
224  BetterPopupBlockerBrowserTest() {}
225  virtual ~BetterPopupBlockerBrowserTest() {}
226
227  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
228    InProcessBrowserTest::SetUpCommandLine(command_line);
229  }
230
231  // Navigates to the test indicated by |test_name| which is expected to try to
232  // open a popup. Verifies that the popup was blocked and then opens the
233  // blocked popup. Once the popup stopped loading, verifies that the title of
234  // the page is "PASS".
235  //
236  // If |expect_new_browser| is true, the popup is expected to open a new
237  // window, or a background tab if it is false.
238  void RunCheckTest(const base::FilePath& test_name, bool expect_new_browser) {
239    GURL url(ui_test_utils::GetTestUrl(base::FilePath(kTestDir), test_name));
240
241    CountRenderViewHosts counter;
242
243    ui_test_utils::NavigateToURL(browser(), url);
244
245    // Since the popup blocker blocked the window.open, there should be only one
246    // tab.
247    EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
248                                          browser()->host_desktop_type()));
249    EXPECT_EQ(1, browser()->tab_strip_model()->count());
250    WebContents* web_contents =
251        browser()->tab_strip_model()->GetActiveWebContents();
252    EXPECT_EQ(url, web_contents->GetURL());
253
254    // And no new RVH created.
255    EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
256
257    content::WindowedNotificationObserver observer(
258        chrome::NOTIFICATION_TAB_ADDED,
259        content::NotificationService::AllSources());
260    ui_test_utils::BrowserAddedObserver browser_observer;
261
262    // Launch the blocked popup.
263    PopupBlockerTabHelper* popup_blocker_helper =
264        PopupBlockerTabHelper::FromWebContents(web_contents);
265    EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
266    std::map<int32, GURL> blocked_requests =
267        popup_blocker_helper->GetBlockedPopupRequests();
268    std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
269    popup_blocker_helper->ShowBlockedPopup(iter->first);
270
271    observer.Wait();
272    Browser* new_browser;
273    if (expect_new_browser) {
274      new_browser  = browser_observer.WaitForSingleNewBrowser();
275      web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
276    } else {
277      new_browser = browser();
278      EXPECT_EQ(2, browser()->tab_strip_model()->count());
279      web_contents = browser()->tab_strip_model()->GetWebContentsAt(1);
280    }
281
282    // Check that the check passed.
283    base::string16 expected_title(base::ASCIIToUTF16("PASS"));
284    content::TitleWatcher title_watcher(web_contents, expected_title);
285    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
286  }
287
288 private:
289  DISALLOW_COPY_AND_ASSIGN(BetterPopupBlockerBrowserTest);
290};
291
292IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest,
293                       BlockWebContentsCreation) {
294#if defined(OS_WIN) && defined(USE_ASH)
295  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
296  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
297    return;
298#endif
299
300  CountRenderViewHosts counter;
301
302  ui_test_utils::NavigateToURL(browser(), GetTestURL());
303
304  // Wait until the request actually has hit the popup blocker. The
305  // NavigateToURL call above returns as soon as the main tab stopped loading
306  // which can happen before the popup request was processed.
307  WebContents* web_contents =
308      browser()->tab_strip_model()->GetActiveWebContents();
309  PopupBlockerTabHelper* popup_blocker_helper =
310      PopupBlockerTabHelper::FromWebContents(web_contents);
311  if (!popup_blocker_helper->GetBlockedPopupsCount()) {
312    content::WindowedNotificationObserver observer(
313        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
314        content::NotificationService::AllSources());
315    observer.Wait();
316  }
317
318  // If the popup blocker blocked the blank post, there should be only one tab.
319  EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
320                                        browser()->host_desktop_type()));
321  EXPECT_EQ(1, browser()->tab_strip_model()->count());
322  EXPECT_EQ(GetTestURL(), web_contents->GetURL());
323
324  // And no new RVH created.
325  EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
326
327  content::WindowedNotificationObserver observer(
328      chrome::NOTIFICATION_TAB_ADDED,
329      content::NotificationService::AllSources());
330
331  // Launch the blocked popup.
332  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
333  std::map<int32, GURL> blocked_requests =
334      popup_blocker_helper->GetBlockedPopupRequests();
335  std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
336  popup_blocker_helper->ShowBlockedPopup(iter->first);
337
338  observer.Wait();
339}
340
341IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest,
342                       PopupBlockedFakeClickOnAnchorNoTarget) {
343#if defined(OS_WIN) && defined(USE_ASH)
344  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
345  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
346    return;
347#endif
348
349  GURL url(ui_test_utils::GetTestUrl(
350      base::FilePath(kTestDir),
351      base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor2.html"))));
352
353  CountRenderViewHosts counter;
354
355  ui_test_utils::NavigateToURL(browser(), url);
356
357  // If the popup blocker blocked the blank post, there should be only one tab.
358  EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
359                                        browser()->host_desktop_type()));
360  EXPECT_EQ(1, browser()->tab_strip_model()->count());
361  WebContents* web_contents =
362      browser()->tab_strip_model()->GetActiveWebContents();
363  EXPECT_EQ(url, web_contents->GetURL());
364
365  // And no new RVH created.
366  EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
367
368  content::WindowedNotificationObserver observer(
369      chrome::NOTIFICATION_TAB_ADDED,
370      content::NotificationService::AllSources());
371
372  // Launch the blocked popup.
373  PopupBlockerTabHelper* popup_blocker_helper =
374      PopupBlockerTabHelper::FromWebContents(web_contents);
375  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
376  std::map<int32, GURL> blocked_requests =
377      popup_blocker_helper->GetBlockedPopupRequests();
378  std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
379  popup_blocker_helper->ShowBlockedPopup(iter->first);
380
381  observer.Wait();
382}
383
384IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, WindowFeatures) {
385  GURL url(ui_test_utils::GetTestUrl(
386      base::FilePath(kTestDir),
387      base::FilePath(FILE_PATH_LITERAL("popup-window-open.html"))));
388
389  CountRenderViewHosts counter;
390
391  ui_test_utils::NavigateToURL(browser(), url);
392
393  // If the popup blocker blocked the blank post, there should be only one tab.
394  EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
395                                        browser()->host_desktop_type()));
396  EXPECT_EQ(1, browser()->tab_strip_model()->count());
397  WebContents* web_contents =
398      browser()->tab_strip_model()->GetActiveWebContents();
399  EXPECT_EQ(url, web_contents->GetURL());
400
401  // And no new RVH created.
402  EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
403
404  content::WindowedNotificationObserver observer(
405      chrome::NOTIFICATION_TAB_ADDED,
406      content::NotificationService::AllSources());
407  ui_test_utils::BrowserAddedObserver browser_observer;
408
409  // Launch the blocked popup.
410  PopupBlockerTabHelper* popup_blocker_helper =
411      PopupBlockerTabHelper::FromWebContents(web_contents);
412  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
413  std::map<int32, GURL> blocked_requests =
414      popup_blocker_helper->GetBlockedPopupRequests();
415  std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
416  popup_blocker_helper->ShowBlockedPopup(iter->first);
417
418  observer.Wait();
419  Browser* new_browser = browser_observer.WaitForSingleNewBrowser();
420
421  // Check that the new popup has (roughly) the requested size.
422  web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
423  gfx::Size window_size = web_contents->GetView()->GetContainerSize();
424  EXPECT_TRUE(349 <= window_size.width() && window_size.width() <= 351);
425  EXPECT_TRUE(249 <= window_size.height() && window_size.height() <= 251);
426}
427
428IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, CorrectReferrer) {
429  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-referrer.html")), true);
430}
431
432IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, WindowFeaturesBarProps) {
433  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-windowfeatures.html")),
434               true);
435}
436
437IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, SessionStorage) {
438  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-sessionstorage.html")),
439               true);
440}
441
442IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, Opener) {
443  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-opener.html")), true);
444}
445
446IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, OpenerSuppressed) {
447  RunCheckTest(
448      base::FilePath(FILE_PATH_LITERAL("popup-openersuppressed.html")), false);
449}
450
451}  // namespace
452