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