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.
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"
44 using content::WebContents
;
48 // Counts the number of RenderViewHosts created.
49 class CountRenderViewHosts
: public content::NotificationObserver
{
51 CountRenderViewHosts()
54 content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED
,
55 content::NotificationService::AllSources());
57 virtual ~CountRenderViewHosts() {}
59 int GetRenderViewHostCreatedCount() const { return count_
; }
62 virtual void Observe(int type
,
63 const content::NotificationSource
& source
,
64 const content::NotificationDetails
& details
) OVERRIDE
{
68 content::NotificationRegistrar registrar_
;
72 DISALLOW_COPY_AND_ASSIGN(CountRenderViewHosts
);
75 class CloseObserver
: public content::WebContentsObserver
{
77 explicit CloseObserver(WebContents
* contents
)
78 : content::WebContentsObserver(contents
) {}
84 virtual void WebContentsDestroyed(WebContents
* contents
) OVERRIDE
{
89 base::RunLoop close_loop_
;
91 DISALLOW_COPY_AND_ASSIGN(CloseObserver
);
94 class PopupBlockerBrowserTest
: public InProcessBrowserTest
{
96 PopupBlockerBrowserTest() {}
97 virtual ~PopupBlockerBrowserTest() {}
99 virtual void SetUpOnMainThread() OVERRIDE
{
100 InProcessBrowserTest::SetUpOnMainThread();
102 host_resolver()->AddRule("*", "127.0.0.1");
103 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
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();
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
);
123 ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
124 browser()->host_desktop_type()));
126 ASSERT_EQ(0, GetBlockedContentsCount());
134 enum ShouldCheckTitle
{
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.
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.
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
));
154 CountRenderViewHosts counter
;
156 ui_test_utils::NavigateToURL(browser
, url
);
158 // Since the popup blocker blocked the window.open, there should be only one
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());
167 // And no new RVH created.
168 EXPECT_EQ(0, counter
.GetRenderViewHostCreatedCount());
170 content::WindowedNotificationObserver
observer(
171 chrome::NOTIFICATION_TAB_ADDED
,
172 content::NotificationService::AllSources());
173 ui_test_utils::BrowserAddedObserver browser_observer
;
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());
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
);
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();
196 new_browser
= browser
;
197 EXPECT_EQ(2, browser
->tab_strip_model()->count());
198 web_contents
= browser
->tab_strip_model()->GetWebContentsAt(1);
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());
212 DISALLOW_COPY_AND_ASSIGN(PopupBlockerBrowserTest
);
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
))
225 "/popup_blocker/popup-blocked-to-post-blank.html",
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
))
239 CreateIncognitoBrowser(),
240 "/popup_blocker/popup-blocked-to-post-blank.html",
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
))
255 "/popup_blocker/popup-fake-click-on-anchor.html",
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
))
270 "/popup_blocker/popup-fake-click-on-anchor2.html",
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());
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
,
291 CONTENT_SETTING_ALLOW
);
293 NavigateAndCheckPopupShown(url
);
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
,
305 CONTENT_SETTING_ALLOW
);
307 // Popup from the iframe should be allowed since the top-level URL is
309 NavigateAndCheckPopupShown(url
);
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
,
325 CONTENT_SETTING_ALLOW
);
327 // Popup should be blocked.
328 ui_test_utils::NavigateToURL(browser(), url
);
329 ASSERT_EQ(1, GetBlockedContentsCount());
332 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
,
333 PopupsLaunchWhenTabIsClosed
) {
334 CommandLine::ForCurrentProcess()->AppendSwitch(
335 switches::kDisablePopupBlocking
);
337 embedded_test_server()->GetURL("/popup_blocker/popup-on-unload.html"));
338 ui_test_utils::NavigateToURL(browser(), url
);
340 NavigateAndCheckPopupShown(embedded_test_server()->GetURL("/popup_blocker/"));
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
);
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";
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]);
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
);
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
380 #define MAYBE_WindowFeatures WindowFeatures
382 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, MAYBE_WindowFeatures
) {
384 RunCheckTest(browser(),
385 "/popup_blocker/popup-window-open.html",
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);
395 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, CorrectReferrer
) {
396 RunCheckTest(browser(),
397 "/popup_blocker/popup-referrer.html",
402 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, WindowFeaturesBarProps
) {
403 RunCheckTest(browser(),
404 "/popup_blocker/popup-windowfeatures.html",
409 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, SessionStorage
) {
410 RunCheckTest(browser(),
411 "/popup_blocker/popup-sessionstorage.html",
416 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, Opener
) {
417 RunCheckTest(browser(),
418 "/popup_blocker/popup-opener.html",
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
) {
428 RunCheckTest(browser(),
429 "/popup_blocker/popup-opener.html",
433 // Navigate it elsewhere.
434 content::TestNavigationObserver
nav_observer(popup
);
435 popup
->GetMainFrame()->ExecuteJavaScript(
436 base::UTF8ToUTF16("location.href = '/empty.html'"));
439 // Have it close itself.
440 CloseObserver
close_observer(popup
);
441 popup
->GetMainFrame()->ExecuteJavaScript(
442 base::UTF8ToUTF16("window.close()"));
443 close_observer
.Wait();
446 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, OpenerSuppressed
) {
447 RunCheckTest(browser(),
448 "/popup_blocker/popup-openersuppressed.html",
453 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, ShiftClick
) {
456 "/popup_blocker/popup-fake-click-on-anchor3.html",
461 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest
, WebUI
) {
463 RunCheckTest(browser(),
464 "/popup_blocker/popup-webui.html",
468 // Check that the new popup displays about:blank.
469 EXPECT_EQ(GURL(content::kAboutBlankURL
), popup
->GetURL());
472 // Verify that the renderer can't DOS the browser by creating arbitrarily many
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());