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