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 <set> 6 7 #include "base/command_line.h" 8 #include "base/json/json_reader.h" 9 #include "base/memory/ref_counted.h" 10 #include "base/path_service.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/values.h" 13 #include "content/browser/child_process_security_policy_impl.h" 14 #include "content/browser/renderer_host/render_view_host_impl.h" 15 #include "content/browser/site_instance_impl.h" 16 #include "content/browser/web_contents/web_contents_impl.h" 17 #include "content/browser/webui/web_ui_impl.h" 18 #include "content/common/content_constants_internal.h" 19 #include "content/public/browser/navigation_controller.h" 20 #include "content/public/browser/navigation_entry.h" 21 #include "content/public/browser/render_process_host.h" 22 #include "content/public/browser/web_contents.h" 23 #include "content/public/browser/web_contents_observer.h" 24 #include "content/public/common/bindings_policy.h" 25 #include "content/public/common/content_switches.h" 26 #include "content/public/common/url_constants.h" 27 #include "content/public/test/browser_test_utils.h" 28 #include "content/public/test/content_browser_test.h" 29 #include "content/public/test/content_browser_test_utils.h" 30 #include "content/public/test/test_navigation_observer.h" 31 #include "content/public/test/test_utils.h" 32 #include "content/shell/browser/shell.h" 33 #include "net/base/net_util.h" 34 #include "net/dns/mock_host_resolver.h" 35 #include "net/test/spawned_test_server/spawned_test_server.h" 36 37 using base::ASCIIToUTF16; 38 39 namespace content { 40 41 namespace { 42 43 const char kOpenUrlViaClickTargetFunc[] = 44 "(function(url) {\n" 45 " var lnk = document.createElement(\"a\");\n" 46 " lnk.href = url;\n" 47 " lnk.target = \"_blank\";\n" 48 " document.body.appendChild(lnk);\n" 49 " lnk.click();\n" 50 "})"; 51 52 // Adds a link with given url and target=_blank, and clicks on it. 53 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter, 54 const GURL& url) { 55 EXPECT_TRUE(ExecuteScript(adapter, 56 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");")); 57 } 58 59 } // anonymous namespace 60 61 class RenderFrameHostManagerTest : public ContentBrowserTest { 62 public: 63 RenderFrameHostManagerTest() : foo_com_("foo.com") { 64 replace_host_.SetHostStr(foo_com_); 65 } 66 67 static bool GetFilePathWithHostAndPortReplacement( 68 const std::string& original_file_path, 69 const net::HostPortPair& host_port_pair, 70 std::string* replacement_path) { 71 std::vector<net::SpawnedTestServer::StringPair> replacement_text; 72 replacement_text.push_back( 73 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString())); 74 return net::SpawnedTestServer::GetFilePathWithReplacements( 75 original_file_path, replacement_text, replacement_path); 76 } 77 78 void StartServer() { 79 // Support multiple sites on the test server. 80 host_resolver()->AddRule("*", "127.0.0.1"); 81 ASSERT_TRUE(test_server()->Start()); 82 83 foo_host_port_ = test_server()->host_port_pair(); 84 foo_host_port_.set_host(foo_com_); 85 } 86 87 // Returns a URL on foo.com with the given path. 88 GURL GetCrossSiteURL(const std::string& path) { 89 GURL cross_site_url(test_server()->GetURL(path)); 90 return cross_site_url.ReplaceComponents(replace_host_); 91 } 92 93 protected: 94 std::string foo_com_; 95 GURL::Replacements replace_host_; 96 net::HostPortPair foo_host_port_; 97 }; 98 99 // Web pages should not have script access to the swapped out page. 100 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) { 101 StartServer(); 102 103 // Load a page with links that open in a new window. 104 std::string replacement_path; 105 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 106 "files/click-noreferrer-links.html", 107 foo_host_port_, 108 &replacement_path)); 109 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 110 111 // Get the original SiteInstance for later comparison. 112 scoped_refptr<SiteInstance> orig_site_instance( 113 shell()->web_contents()->GetSiteInstance()); 114 EXPECT_TRUE(orig_site_instance.get() != NULL); 115 116 // Open a same-site link in a new window. 117 ShellAddedObserver new_shell_observer; 118 bool success = false; 119 EXPECT_TRUE(ExecuteScriptAndExtractBool( 120 shell()->web_contents(), 121 "window.domAutomationController.send(clickSameSiteTargetedLink());", 122 &success)); 123 EXPECT_TRUE(success); 124 Shell* new_shell = new_shell_observer.GetShell(); 125 126 // Wait for the navigation in the new window to finish, if it hasn't. 127 WaitForLoadStop(new_shell->web_contents()); 128 EXPECT_EQ("/files/navigate_opener.html", 129 new_shell->web_contents()->GetLastCommittedURL().path()); 130 131 // Should have the same SiteInstance. 132 scoped_refptr<SiteInstance> blank_site_instance( 133 new_shell->web_contents()->GetSiteInstance()); 134 EXPECT_EQ(orig_site_instance, blank_site_instance); 135 136 // We should have access to the opened window's location. 137 success = false; 138 EXPECT_TRUE(ExecuteScriptAndExtractBool( 139 shell()->web_contents(), 140 "window.domAutomationController.send(testScriptAccessToWindow());", 141 &success)); 142 EXPECT_TRUE(success); 143 144 // Now navigate the new window to a different site. 145 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 146 scoped_refptr<SiteInstance> new_site_instance( 147 new_shell->web_contents()->GetSiteInstance()); 148 EXPECT_NE(orig_site_instance, new_site_instance); 149 150 // We should no longer have script access to the opened window's location. 151 success = false; 152 EXPECT_TRUE(ExecuteScriptAndExtractBool( 153 shell()->web_contents(), 154 "window.domAutomationController.send(testScriptAccessToWindow());", 155 &success)); 156 EXPECT_FALSE(success); 157 } 158 159 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer 160 // and target=_blank should create a new SiteInstance. 161 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 162 SwapProcessWithRelNoreferrerAndTargetBlank) { 163 StartServer(); 164 165 // Load a page with links that open in a new window. 166 std::string replacement_path; 167 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 168 "files/click-noreferrer-links.html", 169 foo_host_port_, 170 &replacement_path)); 171 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 172 173 // Get the original SiteInstance for later comparison. 174 scoped_refptr<SiteInstance> orig_site_instance( 175 shell()->web_contents()->GetSiteInstance()); 176 EXPECT_TRUE(orig_site_instance.get() != NULL); 177 178 // Test clicking a rel=noreferrer + target=blank link. 179 ShellAddedObserver new_shell_observer; 180 bool success = false; 181 EXPECT_TRUE(ExecuteScriptAndExtractBool( 182 shell()->web_contents(), 183 "window.domAutomationController.send(clickNoRefTargetBlankLink());", 184 &success)); 185 EXPECT_TRUE(success); 186 187 // Wait for the window to open. 188 Shell* new_shell = new_shell_observer.GetShell(); 189 190 EXPECT_EQ("/files/title2.html", 191 new_shell->web_contents()->GetVisibleURL().path()); 192 193 // Wait for the cross-site transition in the new tab to finish. 194 WaitForLoadStop(new_shell->web_contents()); 195 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 196 new_shell->web_contents()); 197 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()-> 198 pending_render_view_host()); 199 200 // Should have a new SiteInstance. 201 scoped_refptr<SiteInstance> noref_blank_site_instance( 202 new_shell->web_contents()->GetSiteInstance()); 203 EXPECT_NE(orig_site_instance, noref_blank_site_instance); 204 } 205 206 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance) 207 // for rel=noreferrer links in new windows, even to same site pages and named 208 // targets. 209 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 210 SwapProcessWithSameSiteRelNoreferrer) { 211 StartServer(); 212 213 // Load a page with links that open in a new window. 214 std::string replacement_path; 215 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 216 "files/click-noreferrer-links.html", 217 foo_host_port_, 218 &replacement_path)); 219 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 220 221 // Get the original SiteInstance for later comparison. 222 scoped_refptr<SiteInstance> orig_site_instance( 223 shell()->web_contents()->GetSiteInstance()); 224 EXPECT_TRUE(orig_site_instance.get() != NULL); 225 226 // Test clicking a same-site rel=noreferrer + target=foo link. 227 ShellAddedObserver new_shell_observer; 228 bool success = false; 229 EXPECT_TRUE(ExecuteScriptAndExtractBool( 230 shell()->web_contents(), 231 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());", 232 &success)); 233 EXPECT_TRUE(success); 234 235 // Wait for the window to open. 236 Shell* new_shell = new_shell_observer.GetShell(); 237 238 // Opens in new window. 239 EXPECT_EQ("/files/title2.html", 240 new_shell->web_contents()->GetVisibleURL().path()); 241 242 // Wait for the cross-site transition in the new tab to finish. 243 WaitForLoadStop(new_shell->web_contents()); 244 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 245 new_shell->web_contents()); 246 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()-> 247 pending_render_view_host()); 248 249 // Should have a new SiteInstance (in a new BrowsingInstance). 250 scoped_refptr<SiteInstance> noref_blank_site_instance( 251 new_shell->web_contents()->GetSiteInstance()); 252 EXPECT_NE(orig_site_instance, noref_blank_site_instance); 253 } 254 255 // Test for crbug.com/24447. Following a cross-site link with just 256 // target=_blank should not create a new SiteInstance. 257 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 258 DontSwapProcessWithOnlyTargetBlank) { 259 StartServer(); 260 261 // Load a page with links that open in a new window. 262 std::string replacement_path; 263 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 264 "files/click-noreferrer-links.html", 265 foo_host_port_, 266 &replacement_path)); 267 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 268 269 // Get the original SiteInstance for later comparison. 270 scoped_refptr<SiteInstance> orig_site_instance( 271 shell()->web_contents()->GetSiteInstance()); 272 EXPECT_TRUE(orig_site_instance.get() != NULL); 273 274 // Test clicking a target=blank link. 275 ShellAddedObserver new_shell_observer; 276 bool success = false; 277 EXPECT_TRUE(ExecuteScriptAndExtractBool( 278 shell()->web_contents(), 279 "window.domAutomationController.send(clickTargetBlankLink());", 280 &success)); 281 EXPECT_TRUE(success); 282 283 // Wait for the window to open. 284 Shell* new_shell = new_shell_observer.GetShell(); 285 286 // Wait for the cross-site transition in the new tab to finish. 287 WaitForLoadStop(new_shell->web_contents()); 288 EXPECT_EQ("/files/title2.html", 289 new_shell->web_contents()->GetLastCommittedURL().path()); 290 291 // Should have the same SiteInstance. 292 scoped_refptr<SiteInstance> blank_site_instance( 293 new_shell->web_contents()->GetSiteInstance()); 294 EXPECT_EQ(orig_site_instance, blank_site_instance); 295 } 296 297 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer 298 // and no target=_blank should not create a new SiteInstance. 299 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 300 DontSwapProcessWithOnlyRelNoreferrer) { 301 StartServer(); 302 303 // Load a page with links that open in a new window. 304 std::string replacement_path; 305 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 306 "files/click-noreferrer-links.html", 307 foo_host_port_, 308 &replacement_path)); 309 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 310 311 // Get the original SiteInstance for later comparison. 312 scoped_refptr<SiteInstance> orig_site_instance( 313 shell()->web_contents()->GetSiteInstance()); 314 EXPECT_TRUE(orig_site_instance.get() != NULL); 315 316 // Test clicking a rel=noreferrer link. 317 bool success = false; 318 EXPECT_TRUE(ExecuteScriptAndExtractBool( 319 shell()->web_contents(), 320 "window.domAutomationController.send(clickNoRefLink());", 321 &success)); 322 EXPECT_TRUE(success); 323 324 // Wait for the cross-site transition in the current tab to finish. 325 WaitForLoadStop(shell()->web_contents()); 326 327 // Opens in same window. 328 EXPECT_EQ(1u, Shell::windows().size()); 329 EXPECT_EQ("/files/title2.html", 330 shell()->web_contents()->GetLastCommittedURL().path()); 331 332 // Should have the same SiteInstance. 333 scoped_refptr<SiteInstance> noref_site_instance( 334 shell()->web_contents()->GetSiteInstance()); 335 EXPECT_EQ(orig_site_instance, noref_site_instance); 336 } 337 338 // Test for crbug.com/116192. Targeted links should still work after the 339 // named target window has swapped processes. 340 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 341 AllowTargetedNavigationsAfterSwap) { 342 StartServer(); 343 344 // Load a page with links that open in a new window. 345 std::string replacement_path; 346 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 347 "files/click-noreferrer-links.html", 348 foo_host_port_, 349 &replacement_path)); 350 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 351 352 // Get the original SiteInstance for later comparison. 353 scoped_refptr<SiteInstance> orig_site_instance( 354 shell()->web_contents()->GetSiteInstance()); 355 EXPECT_TRUE(orig_site_instance.get() != NULL); 356 357 // Test clicking a target=foo link. 358 ShellAddedObserver new_shell_observer; 359 bool success = false; 360 EXPECT_TRUE(ExecuteScriptAndExtractBool( 361 shell()->web_contents(), 362 "window.domAutomationController.send(clickSameSiteTargetedLink());", 363 &success)); 364 EXPECT_TRUE(success); 365 Shell* new_shell = new_shell_observer.GetShell(); 366 367 // Wait for the navigation in the new tab to finish, if it hasn't. 368 WaitForLoadStop(new_shell->web_contents()); 369 EXPECT_EQ("/files/navigate_opener.html", 370 new_shell->web_contents()->GetLastCommittedURL().path()); 371 372 // Should have the same SiteInstance. 373 scoped_refptr<SiteInstance> blank_site_instance( 374 new_shell->web_contents()->GetSiteInstance()); 375 EXPECT_EQ(orig_site_instance, blank_site_instance); 376 377 // Now navigate the new tab to a different site. 378 GURL cross_site_url(GetCrossSiteURL("files/title1.html")); 379 NavigateToURL(new_shell, cross_site_url); 380 scoped_refptr<SiteInstance> new_site_instance( 381 new_shell->web_contents()->GetSiteInstance()); 382 EXPECT_NE(orig_site_instance, new_site_instance); 383 384 // Clicking the original link in the first tab should cause us to swap back. 385 TestNavigationObserver navigation_observer(new_shell->web_contents()); 386 EXPECT_TRUE(ExecuteScriptAndExtractBool( 387 shell()->web_contents(), 388 "window.domAutomationController.send(clickSameSiteTargetedLink());", 389 &success)); 390 EXPECT_TRUE(success); 391 navigation_observer.Wait(); 392 393 // Should have swapped back and shown the new window again. 394 scoped_refptr<SiteInstance> revisit_site_instance( 395 new_shell->web_contents()->GetSiteInstance()); 396 EXPECT_EQ(orig_site_instance, revisit_site_instance); 397 398 // If it navigates away to another process, the original window should 399 // still be able to close it (using a cross-process close message). 400 NavigateToURL(new_shell, cross_site_url); 401 EXPECT_EQ(new_site_instance, 402 new_shell->web_contents()->GetSiteInstance()); 403 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents()); 404 EXPECT_TRUE(ExecuteScriptAndExtractBool( 405 shell()->web_contents(), 406 "window.domAutomationController.send(testCloseWindow());", 407 &success)); 408 EXPECT_TRUE(success); 409 close_watcher.Wait(); 410 } 411 412 // Test that setting the opener to null in a window affects cross-process 413 // navigations, including those to existing entries. http://crbug.com/156669. 414 // Flaky on windows: http://crbug.com/291249 415 // This test also crashes under ThreadSanitizer, http://crbug.com/356758. 416 #if defined(OS_WIN) || defined(THREAD_SANITIZER) 417 #define MAYBE_DisownOpener DISABLED_DisownOpener 418 #else 419 #define MAYBE_DisownOpener DisownOpener 420 #endif 421 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) { 422 StartServer(); 423 424 // Load a page with links that open in a new window. 425 std::string replacement_path; 426 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 427 "files/click-noreferrer-links.html", 428 foo_host_port_, 429 &replacement_path)); 430 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 431 432 // Get the original SiteInstance for later comparison. 433 scoped_refptr<SiteInstance> orig_site_instance( 434 shell()->web_contents()->GetSiteInstance()); 435 EXPECT_TRUE(orig_site_instance.get() != NULL); 436 437 // Test clicking a target=_blank link. 438 ShellAddedObserver new_shell_observer; 439 bool success = false; 440 EXPECT_TRUE(ExecuteScriptAndExtractBool( 441 shell()->web_contents(), 442 "window.domAutomationController.send(clickSameSiteTargetBlankLink());", 443 &success)); 444 EXPECT_TRUE(success); 445 Shell* new_shell = new_shell_observer.GetShell(); 446 447 // Wait for the navigation in the new tab to finish, if it hasn't. 448 WaitForLoadStop(new_shell->web_contents()); 449 EXPECT_EQ("/files/title2.html", 450 new_shell->web_contents()->GetLastCommittedURL().path()); 451 452 // Should have the same SiteInstance. 453 scoped_refptr<SiteInstance> blank_site_instance( 454 new_shell->web_contents()->GetSiteInstance()); 455 EXPECT_EQ(orig_site_instance, blank_site_instance); 456 457 // Now navigate the new tab to a different site. 458 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 459 scoped_refptr<SiteInstance> new_site_instance( 460 new_shell->web_contents()->GetSiteInstance()); 461 EXPECT_NE(orig_site_instance, new_site_instance); 462 463 // Now disown the opener. 464 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(), 465 "window.opener = null;")); 466 467 // Go back and ensure the opener is still null. 468 { 469 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); 470 new_shell->web_contents()->GetController().GoBack(); 471 back_nav_load_observer.Wait(); 472 } 473 success = false; 474 EXPECT_TRUE(ExecuteScriptAndExtractBool( 475 new_shell->web_contents(), 476 "window.domAutomationController.send(window.opener == null);", 477 &success)); 478 EXPECT_TRUE(success); 479 480 // Now navigate forward again (creating a new process) and check opener. 481 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 482 success = false; 483 EXPECT_TRUE(ExecuteScriptAndExtractBool( 484 new_shell->web_contents(), 485 "window.domAutomationController.send(window.opener == null);", 486 &success)); 487 EXPECT_TRUE(success); 488 } 489 490 // Test that subframes can disown their openers. http://crbug.com/225528. 491 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) { 492 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>"); 493 NavigateToURL(shell(), frame_url); 494 495 // Give the frame an opener using window.open. 496 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), 497 "window.open('about:blank','foo');")); 498 499 // Now disown the frame's opener. Shouldn't crash. 500 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), 501 "window.frames[0].opener = null;")); 502 } 503 504 // Test for crbug.com/99202. PostMessage calls should still work after 505 // navigating the source and target windows to different sites. 506 // Specifically: 507 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process. 508 // 2) Fail to post a message from "foo" to opener with the wrong target origin. 509 // 3) Post a message from "foo" to opener, which replies back to "foo". 510 // 4) Post a message from _blank to "foo". 511 // 5) Post a message from "foo" to a subframe of opener, which replies back. 512 // 6) Post a message from _blank to a subframe of "foo". 513 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 514 SupportCrossProcessPostMessage) { 515 StartServer(); 516 517 // Load a page with links that open in a new window. 518 std::string replacement_path; 519 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 520 "files/click-noreferrer-links.html", 521 foo_host_port_, 522 &replacement_path)); 523 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 524 525 // Get the original SiteInstance and RVHM for later comparison. 526 WebContents* opener_contents = shell()->web_contents(); 527 scoped_refptr<SiteInstance> orig_site_instance( 528 opener_contents->GetSiteInstance()); 529 EXPECT_TRUE(orig_site_instance.get() != NULL); 530 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>( 531 opener_contents)->GetRenderManagerForTesting(); 532 533 // 1) Open two more windows, one named. These initially have openers but no 534 // reference to each other. We will later post a message between them. 535 536 // First, a named target=foo window. 537 ShellAddedObserver new_shell_observer; 538 bool success = false; 539 EXPECT_TRUE(ExecuteScriptAndExtractBool( 540 opener_contents, 541 "window.domAutomationController.send(clickSameSiteTargetedLink());", 542 &success)); 543 EXPECT_TRUE(success); 544 Shell* new_shell = new_shell_observer.GetShell(); 545 546 // Wait for the navigation in the new window to finish, if it hasn't, then 547 // send it to post_message.html on a different site. 548 WebContents* foo_contents = new_shell->web_contents(); 549 WaitForLoadStop(foo_contents); 550 EXPECT_EQ("/files/navigate_opener.html", 551 foo_contents->GetLastCommittedURL().path()); 552 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html")); 553 scoped_refptr<SiteInstance> foo_site_instance( 554 foo_contents->GetSiteInstance()); 555 EXPECT_NE(orig_site_instance, foo_site_instance); 556 557 // Second, a target=_blank window. 558 ShellAddedObserver new_shell_observer2; 559 EXPECT_TRUE(ExecuteScriptAndExtractBool( 560 shell()->web_contents(), 561 "window.domAutomationController.send(clickSameSiteTargetBlankLink());", 562 &success)); 563 EXPECT_TRUE(success); 564 565 // Wait for the navigation in the new window to finish, if it hasn't, then 566 // send it to post_message.html on the original site. 567 Shell* new_shell2 = new_shell_observer2.GetShell(); 568 WebContents* new_contents = new_shell2->web_contents(); 569 WaitForLoadStop(new_contents); 570 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path()); 571 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html")); 572 EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance()); 573 RenderFrameHostManager* new_manager = 574 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting(); 575 576 // We now have three windows. The opener should have a swapped out RVH 577 // for the new SiteInstance, but the _blank window should not. 578 EXPECT_EQ(3u, Shell::windows().size()); 579 EXPECT_TRUE( 580 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 581 EXPECT_FALSE( 582 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 583 584 // 2) Fail to post a message from the foo window to the opener if the target 585 // origin is wrong. We won't see an error, but we can check for the right 586 // number of received messages below. 587 EXPECT_TRUE(ExecuteScriptAndExtractBool( 588 foo_contents, 589 "window.domAutomationController.send(postToOpener('msg'," 590 " 'http://google.com'));", 591 &success)); 592 EXPECT_TRUE(success); 593 ASSERT_FALSE( 594 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); 595 596 // 3) Post a message from the foo window to the opener. The opener will 597 // reply, causing the foo window to update its own title. 598 base::string16 expected_title = ASCIIToUTF16("msg"); 599 TitleWatcher title_watcher(foo_contents, expected_title); 600 EXPECT_TRUE(ExecuteScriptAndExtractBool( 601 foo_contents, 602 "window.domAutomationController.send(postToOpener('msg','*'));", 603 &success)); 604 EXPECT_TRUE(success); 605 ASSERT_FALSE( 606 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); 607 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 608 609 // We should have received only 1 message in the opener and "foo" tabs, 610 // and updated the title. 611 int opener_received_messages = 0; 612 EXPECT_TRUE(ExecuteScriptAndExtractInt( 613 opener_contents, 614 "window.domAutomationController.send(window.receivedMessages);", 615 &opener_received_messages)); 616 int foo_received_messages = 0; 617 EXPECT_TRUE(ExecuteScriptAndExtractInt( 618 foo_contents, 619 "window.domAutomationController.send(window.receivedMessages);", 620 &foo_received_messages)); 621 EXPECT_EQ(1, foo_received_messages); 622 EXPECT_EQ(1, opener_received_messages); 623 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle()); 624 625 // 4) Now post a message from the _blank window to the foo window. The 626 // foo window will update its title and will not reply. 627 expected_title = ASCIIToUTF16("msg2"); 628 TitleWatcher title_watcher2(foo_contents, expected_title); 629 EXPECT_TRUE(ExecuteScriptAndExtractBool( 630 new_contents, 631 "window.domAutomationController.send(postToFoo('msg2'));", 632 &success)); 633 EXPECT_TRUE(success); 634 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle()); 635 636 // This postMessage should have created a swapped out RVH for the new 637 // SiteInstance in the target=_blank window. 638 EXPECT_TRUE( 639 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 640 641 // TODO(nasko): Test subframe targeting of postMessage once 642 // http://crbug.com/153701 is fixed. 643 } 644 645 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e., 646 // messages which contain Transferables and get intercepted by 647 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is 648 // swapped out) should work. 649 // Specifically: 650 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process. 651 // 2) Post a message containing a message port from opener to "foo". 652 // 3) Post a message from "foo" back to opener via the passed message port. 653 // The test will be enabled when the feature implementation lands. 654 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 655 SupportCrossProcessPostMessageWithMessagePort) { 656 StartServer(); 657 658 // Load a page with links that open in a new window. 659 std::string replacement_path; 660 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 661 "files/click-noreferrer-links.html", 662 foo_host_port_, 663 &replacement_path)); 664 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 665 666 // Get the original SiteInstance and RVHM for later comparison. 667 WebContents* opener_contents = shell()->web_contents(); 668 scoped_refptr<SiteInstance> orig_site_instance( 669 opener_contents->GetSiteInstance()); 670 EXPECT_TRUE(orig_site_instance.get() != NULL); 671 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>( 672 opener_contents)->GetRenderManagerForTesting(); 673 674 // 1) Open a named target=foo window. We will later post a message between the 675 // opener and the new window. 676 ShellAddedObserver new_shell_observer; 677 bool success = false; 678 EXPECT_TRUE(ExecuteScriptAndExtractBool( 679 opener_contents, 680 "window.domAutomationController.send(clickSameSiteTargetedLink());", 681 &success)); 682 EXPECT_TRUE(success); 683 Shell* new_shell = new_shell_observer.GetShell(); 684 685 // Wait for the navigation in the new window to finish, if it hasn't, then 686 // send it to post_message.html on a different site. 687 WebContents* foo_contents = new_shell->web_contents(); 688 WaitForLoadStop(foo_contents); 689 EXPECT_EQ("/files/navigate_opener.html", 690 foo_contents->GetLastCommittedURL().path()); 691 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html")); 692 scoped_refptr<SiteInstance> foo_site_instance( 693 foo_contents->GetSiteInstance()); 694 EXPECT_NE(orig_site_instance, foo_site_instance); 695 696 // We now have two windows. The opener should have a swapped out RVH 697 // for the new SiteInstance. 698 EXPECT_EQ(2u, Shell::windows().size()); 699 EXPECT_TRUE( 700 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 701 702 // 2) Post a message containing a MessagePort from opener to the the foo 703 // window. The foo window will reply via the passed port, causing the opener 704 // to update its own title. 705 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port"); 706 TitleWatcher title_observer(opener_contents, expected_title); 707 EXPECT_TRUE(ExecuteScriptAndExtractBool( 708 opener_contents, 709 "window.domAutomationController.send(postWithPortToFoo());", 710 &success)); 711 EXPECT_TRUE(success); 712 ASSERT_FALSE( 713 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); 714 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle()); 715 716 // Check message counts. 717 int opener_received_messages_via_port = 0; 718 EXPECT_TRUE(ExecuteScriptAndExtractInt( 719 opener_contents, 720 "window.domAutomationController.send(window.receivedMessagesViaPort);", 721 &opener_received_messages_via_port)); 722 int foo_received_messages = 0; 723 EXPECT_TRUE(ExecuteScriptAndExtractInt( 724 foo_contents, 725 "window.domAutomationController.send(window.receivedMessages);", 726 &foo_received_messages)); 727 int foo_received_messages_with_port = 0; 728 EXPECT_TRUE(ExecuteScriptAndExtractInt( 729 foo_contents, 730 "window.domAutomationController.send(window.receivedMessagesWithPort);", 731 &foo_received_messages_with_port)); 732 EXPECT_EQ(1, foo_received_messages); 733 EXPECT_EQ(1, foo_received_messages_with_port); 734 EXPECT_EQ(1, opener_received_messages_via_port); 735 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle()); 736 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle()); 737 } 738 739 // Test for crbug.com/116192. Navigations to a window's opener should 740 // still work after a process swap. 741 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 742 AllowTargetedNavigationsInOpenerAfterSwap) { 743 StartServer(); 744 745 // Load a page with links that open in a new window. 746 std::string replacement_path; 747 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 748 "files/click-noreferrer-links.html", 749 foo_host_port_, 750 &replacement_path)); 751 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 752 753 // Get the original tab and SiteInstance for later comparison. 754 WebContents* orig_contents = shell()->web_contents(); 755 scoped_refptr<SiteInstance> orig_site_instance( 756 orig_contents->GetSiteInstance()); 757 EXPECT_TRUE(orig_site_instance.get() != NULL); 758 759 // Test clicking a target=foo link. 760 ShellAddedObserver new_shell_observer; 761 bool success = false; 762 EXPECT_TRUE(ExecuteScriptAndExtractBool( 763 orig_contents, 764 "window.domAutomationController.send(clickSameSiteTargetedLink());", 765 &success)); 766 EXPECT_TRUE(success); 767 Shell* new_shell = new_shell_observer.GetShell(); 768 769 // Wait for the navigation in the new window to finish, if it hasn't. 770 WaitForLoadStop(new_shell->web_contents()); 771 EXPECT_EQ("/files/navigate_opener.html", 772 new_shell->web_contents()->GetLastCommittedURL().path()); 773 774 // Should have the same SiteInstance. 775 scoped_refptr<SiteInstance> blank_site_instance( 776 new_shell->web_contents()->GetSiteInstance()); 777 EXPECT_EQ(orig_site_instance, blank_site_instance); 778 779 // Now navigate the original (opener) tab to a different site. 780 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 781 scoped_refptr<SiteInstance> new_site_instance( 782 shell()->web_contents()->GetSiteInstance()); 783 EXPECT_NE(orig_site_instance, new_site_instance); 784 785 // The opened tab should be able to navigate the opener back to its process. 786 TestNavigationObserver navigation_observer(orig_contents); 787 EXPECT_TRUE(ExecuteScriptAndExtractBool( 788 new_shell->web_contents(), 789 "window.domAutomationController.send(navigateOpener());", 790 &success)); 791 EXPECT_TRUE(success); 792 navigation_observer.Wait(); 793 794 // Should have swapped back into this process. 795 scoped_refptr<SiteInstance> revisit_site_instance( 796 shell()->web_contents()->GetSiteInstance()); 797 EXPECT_EQ(orig_site_instance, revisit_site_instance); 798 } 799 800 // Test that opening a new window in the same SiteInstance and then navigating 801 // both windows to a different SiteInstance allows the first process to exit. 802 // See http://crbug.com/126333. 803 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 804 ProcessExitWithSwappedOutViews) { 805 StartServer(); 806 807 // Load a page with links that open in a new window. 808 std::string replacement_path; 809 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 810 "files/click-noreferrer-links.html", 811 foo_host_port_, 812 &replacement_path)); 813 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 814 815 // Get the original SiteInstance for later comparison. 816 scoped_refptr<SiteInstance> orig_site_instance( 817 shell()->web_contents()->GetSiteInstance()); 818 EXPECT_TRUE(orig_site_instance.get() != NULL); 819 820 // Test clicking a target=foo link. 821 ShellAddedObserver new_shell_observer; 822 bool success = false; 823 EXPECT_TRUE(ExecuteScriptAndExtractBool( 824 shell()->web_contents(), 825 "window.domAutomationController.send(clickSameSiteTargetedLink());", 826 &success)); 827 EXPECT_TRUE(success); 828 Shell* new_shell = new_shell_observer.GetShell(); 829 830 // Wait for the navigation in the new window to finish, if it hasn't. 831 WaitForLoadStop(new_shell->web_contents()); 832 EXPECT_EQ("/files/navigate_opener.html", 833 new_shell->web_contents()->GetLastCommittedURL().path()); 834 835 // Should have the same SiteInstance. 836 scoped_refptr<SiteInstance> opened_site_instance( 837 new_shell->web_contents()->GetSiteInstance()); 838 EXPECT_EQ(orig_site_instance, opened_site_instance); 839 840 // Now navigate the opened window to a different site. 841 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 842 scoped_refptr<SiteInstance> new_site_instance( 843 new_shell->web_contents()->GetSiteInstance()); 844 EXPECT_NE(orig_site_instance, new_site_instance); 845 846 // The original process should still be alive, since it is still used in the 847 // first window. 848 RenderProcessHost* orig_process = orig_site_instance->GetProcess(); 849 EXPECT_TRUE(orig_process->HasConnection()); 850 851 // Navigate the first window to a different site as well. The original 852 // process should exit, since all of its views are now swapped out. 853 RenderProcessHostWatcher exit_observer( 854 orig_process, 855 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION); 856 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 857 exit_observer.Wait(); 858 scoped_refptr<SiteInstance> new_site_instance2( 859 shell()->web_contents()->GetSiteInstance()); 860 EXPECT_EQ(new_site_instance, new_site_instance2); 861 } 862 863 // Test for crbug.com/76666. A cross-site navigation that fails with a 204 864 // error should not make us ignore future renderer-initiated navigations. 865 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) { 866 StartServer(); 867 868 // Get the original SiteInstance for later comparison. 869 scoped_refptr<SiteInstance> orig_site_instance( 870 shell()->web_contents()->GetSiteInstance()); 871 EXPECT_TRUE(orig_site_instance.get() != NULL); 872 873 // Load a cross-site page that fails with a 204 error. 874 NavigateToURL(shell(), GetCrossSiteURL("nocontent")); 875 876 // We should still be looking at the normal page. Because we started from a 877 // blank new tab, the typed URL will still be visible until the user clears it 878 // manually. The last committed URL will be the previous page. 879 scoped_refptr<SiteInstance> post_nav_site_instance( 880 shell()->web_contents()->GetSiteInstance()); 881 EXPECT_EQ(orig_site_instance, post_nav_site_instance); 882 EXPECT_EQ("/nocontent", 883 shell()->web_contents()->GetVisibleURL().path()); 884 EXPECT_FALSE( 885 shell()->web_contents()->GetController().GetLastCommittedEntry()); 886 887 // Renderer-initiated navigations should work. 888 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness"); 889 TitleWatcher title_watcher(shell()->web_contents(), expected_title); 890 GURL url = test_server()->GetURL("files/title2.html"); 891 EXPECT_TRUE(ExecuteScript( 892 shell()->web_contents(), 893 base::StringPrintf("location.href = '%s'", url.spec().c_str()))); 894 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 895 896 // Opens in same tab. 897 EXPECT_EQ(1u, Shell::windows().size()); 898 EXPECT_EQ("/files/title2.html", 899 shell()->web_contents()->GetLastCommittedURL().path()); 900 901 // Should have the same SiteInstance. 902 scoped_refptr<SiteInstance> new_site_instance( 903 shell()->web_contents()->GetSiteInstance()); 904 EXPECT_EQ(orig_site_instance, new_site_instance); 905 } 906 907 // Test for crbug.com/9682. We should show the URL for a pending renderer- 908 // initiated navigation in a new tab, until the content of the initial 909 // about:blank page is modified by another window. At that point, we should 910 // revert to showing about:blank to prevent a URL spoof. 911 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) { 912 ASSERT_TRUE(test_server()->Start()); 913 914 // Load a page that can open a URL that won't commit in a new window. 915 NavigateToURL( 916 shell(), test_server()->GetURL("files/click-nocontent-link.html")); 917 WebContents* orig_contents = shell()->web_contents(); 918 919 // Click a /nocontent link that opens in a new window but never commits. 920 ShellAddedObserver new_shell_observer; 921 bool success = false; 922 EXPECT_TRUE(ExecuteScriptAndExtractBool( 923 orig_contents, 924 "window.domAutomationController.send(clickNoContentTargetedLink());", 925 &success)); 926 EXPECT_TRUE(success); 927 928 // Wait for the window to open. 929 Shell* new_shell = new_shell_observer.GetShell(); 930 931 // Ensure the destination URL is visible, because it is considered the 932 // initial navigation. 933 WebContents* contents = new_shell->web_contents(); 934 EXPECT_TRUE(contents->GetController().IsInitialNavigation()); 935 EXPECT_EQ("/nocontent", 936 contents->GetController().GetVisibleEntry()->GetURL().path()); 937 938 // Now modify the contents of the new window from the opener. This will also 939 // modify the title of the document to give us something to listen for. 940 base::string16 expected_title = ASCIIToUTF16("Modified Title"); 941 TitleWatcher title_watcher(contents, expected_title); 942 success = false; 943 EXPECT_TRUE(ExecuteScriptAndExtractBool( 944 orig_contents, 945 "window.domAutomationController.send(modifyNewWindow());", 946 &success)); 947 EXPECT_TRUE(success); 948 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 949 950 // At this point, we should no longer be showing the destination URL. 951 // The visible entry should be null, resulting in about:blank in the address 952 // bar. 953 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); 954 } 955 956 // Test for crbug.com/9682. We should not show the URL for a pending renderer- 957 // initiated navigation in a new tab if it is not the initial navigation. In 958 // this case, the renderer will not notify us of a modification, so we cannot 959 // show the pending URL without allowing a spoof. 960 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 961 DontShowLoadingURLIfNotInitialNav) { 962 ASSERT_TRUE(test_server()->Start()); 963 964 // Load a page that can open a URL that won't commit in a new window. 965 NavigateToURL( 966 shell(), test_server()->GetURL("files/click-nocontent-link.html")); 967 WebContents* orig_contents = shell()->web_contents(); 968 969 // Click a /nocontent link that opens in a new window but never commits. 970 // By using an onclick handler that first creates the window, the slow 971 // navigation is not considered an initial navigation. 972 ShellAddedObserver new_shell_observer; 973 bool success = false; 974 EXPECT_TRUE(ExecuteScriptAndExtractBool( 975 orig_contents, 976 "window.domAutomationController.send(" 977 "clickNoContentScriptedTargetedLink());", 978 &success)); 979 EXPECT_TRUE(success); 980 981 // Wait for the window to open. 982 Shell* new_shell = new_shell_observer.GetShell(); 983 984 // Ensure the destination URL is not visible, because it is not the initial 985 // navigation. 986 WebContents* contents = new_shell->web_contents(); 987 EXPECT_FALSE(contents->GetController().IsInitialNavigation()); 988 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); 989 } 990 991 // Crashes under ThreadSanitizer, http://crbug.com/356758. 992 #if defined(THREAD_SANITIZER) 993 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale 994 #else 995 #define MAYBE_BackForwardNotStale BackForwardNotStale 996 #endif 997 // Test for http://crbug.com/93427. Ensure that cross-site navigations 998 // do not cause back/forward navigations to be considered stale by the 999 // renderer. 1000 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) { 1001 StartServer(); 1002 NavigateToURL(shell(), GURL(url::kAboutBlankURL)); 1003 1004 // Visit a page on first site. 1005 NavigateToURL(shell(), test_server()->GetURL("files/title1.html")); 1006 1007 // Visit three pages on second site. 1008 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 1009 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html")); 1010 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html")); 1011 1012 // History is now [blank, A1, B1, B2, *B3]. 1013 WebContents* contents = shell()->web_contents(); 1014 EXPECT_EQ(5, contents->GetController().GetEntryCount()); 1015 1016 // Open another window in same process to keep this process alive. 1017 Shell* new_shell = CreateBrowser(); 1018 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1019 1020 // Go back three times to first site. 1021 { 1022 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1023 shell()->web_contents()->GetController().GoBack(); 1024 back_nav_load_observer.Wait(); 1025 } 1026 { 1027 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1028 shell()->web_contents()->GetController().GoBack(); 1029 back_nav_load_observer.Wait(); 1030 } 1031 { 1032 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1033 shell()->web_contents()->GetController().GoBack(); 1034 back_nav_load_observer.Wait(); 1035 } 1036 1037 // Now go forward twice to B2. Shouldn't be left spinning. 1038 { 1039 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1040 shell()->web_contents()->GetController().GoForward(); 1041 forward_nav_load_observer.Wait(); 1042 } 1043 { 1044 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1045 shell()->web_contents()->GetController().GoForward(); 1046 forward_nav_load_observer.Wait(); 1047 } 1048 1049 // Go back twice to first site. 1050 { 1051 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1052 shell()->web_contents()->GetController().GoBack(); 1053 back_nav_load_observer.Wait(); 1054 } 1055 { 1056 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1057 shell()->web_contents()->GetController().GoBack(); 1058 back_nav_load_observer.Wait(); 1059 } 1060 1061 // Now go forward directly to B3. Shouldn't be left spinning. 1062 { 1063 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1064 shell()->web_contents()->GetController().GoToIndex(4); 1065 forward_nav_load_observer.Wait(); 1066 } 1067 } 1068 1069 // Test for http://crbug.com/130016. 1070 // Swapping out a render view should update its visiblity state. 1071 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1072 SwappedOutViewHasCorrectVisibilityState) { 1073 StartServer(); 1074 1075 // Load a page with links that open in a new window. 1076 std::string replacement_path; 1077 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 1078 "files/click-noreferrer-links.html", 1079 foo_host_port_, 1080 &replacement_path)); 1081 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 1082 1083 // Open a same-site link in a new widnow. 1084 ShellAddedObserver new_shell_observer; 1085 bool success = false; 1086 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1087 shell()->web_contents(), 1088 "window.domAutomationController.send(clickSameSiteTargetedLink());", 1089 &success)); 1090 EXPECT_TRUE(success); 1091 Shell* new_shell = new_shell_observer.GetShell(); 1092 1093 // Wait for the navigation in the new tab to finish, if it hasn't. 1094 WaitForLoadStop(new_shell->web_contents()); 1095 EXPECT_EQ("/files/navigate_opener.html", 1096 new_shell->web_contents()->GetLastCommittedURL().path()); 1097 1098 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost(); 1099 1100 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1101 rvh, 1102 "window.domAutomationController.send(" 1103 " document.visibilityState == 'visible');", 1104 &success)); 1105 EXPECT_TRUE(success); 1106 1107 // Now navigate the new window to a different site. This should swap out the 1108 // tab's existing RenderView, causing it become hidden. 1109 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1110 1111 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1112 rvh, 1113 "window.domAutomationController.send(" 1114 " document.visibilityState == 'hidden');", 1115 &success)); 1116 EXPECT_TRUE(success); 1117 1118 // Going back should make the previously swapped-out view to become visible 1119 // again. 1120 { 1121 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); 1122 new_shell->web_contents()->GetController().GoBack(); 1123 back_nav_load_observer.Wait(); 1124 } 1125 1126 EXPECT_EQ("/files/navigate_opener.html", 1127 new_shell->web_contents()->GetLastCommittedURL().path()); 1128 1129 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost()); 1130 1131 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1132 rvh, 1133 "window.domAutomationController.send(" 1134 " document.visibilityState == 'visible');", 1135 &success)); 1136 EXPECT_TRUE(success); 1137 } 1138 1139 // This class ensures that all the given RenderViewHosts have properly been 1140 // shutdown. 1141 class RenderViewHostDestructionObserver : public WebContentsObserver { 1142 public: 1143 explicit RenderViewHostDestructionObserver(WebContents* web_contents) 1144 : WebContentsObserver(web_contents) {} 1145 virtual ~RenderViewHostDestructionObserver() {} 1146 void EnsureRVHGetsDestructed(RenderViewHost* rvh) { 1147 watched_render_view_hosts_.insert(rvh); 1148 } 1149 size_t GetNumberOfWatchedRenderViewHosts() const { 1150 return watched_render_view_hosts_.size(); 1151 } 1152 1153 private: 1154 // WebContentsObserver implementation: 1155 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE { 1156 watched_render_view_hosts_.erase(rvh); 1157 } 1158 1159 std::set<RenderViewHost*> watched_render_view_hosts_; 1160 }; 1161 1162 // Crashes under ThreadSanitizer, http://crbug.com/356758. 1163 #if defined(THREAD_SANITIZER) 1164 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts 1165 #else 1166 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts 1167 #endif 1168 // Test for crbug.com/90867. Make sure we don't leak render view hosts since 1169 // they may cause crashes or memory corruptions when trying to call dead 1170 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to 1171 // ensure that a separate SiteInstance is created when navigating to view-source 1172 // URLs, regardless of current URL. 1173 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1174 MAYBE_LeakingRenderViewHosts) { 1175 StartServer(); 1176 1177 // Observe the created render_view_host's to make sure they will not leak. 1178 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents()); 1179 1180 GURL navigated_url(test_server()->GetURL("files/title2.html")); 1181 GURL view_source_url(kViewSourceScheme + std::string(":") + 1182 navigated_url.spec()); 1183 1184 // Let's ensure that when we start with a blank window, navigating away to a 1185 // view-source URL, we create a new SiteInstance. 1186 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost(); 1187 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance(); 1188 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL()); 1189 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL()); 1190 rvh_observers.EnsureRVHGetsDestructed(blank_rvh); 1191 1192 // Now navigate to the view-source URL and ensure we got a different 1193 // SiteInstance and RenderViewHost. 1194 NavigateToURL(shell(), view_source_url); 1195 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost()); 1196 EXPECT_NE(blank_site_instance, shell()->web_contents()-> 1197 GetRenderViewHost()->GetSiteInstance()); 1198 rvh_observers.EnsureRVHGetsDestructed( 1199 shell()->web_contents()->GetRenderViewHost()); 1200 1201 // Load a random page and then navigate to view-source: of it. 1202 // This used to cause two RVH instances for the same SiteInstance, which 1203 // was a problem. This is no longer the case. 1204 NavigateToURL(shell(), navigated_url); 1205 SiteInstance* site_instance1 = shell()->web_contents()-> 1206 GetRenderViewHost()->GetSiteInstance(); 1207 rvh_observers.EnsureRVHGetsDestructed( 1208 shell()->web_contents()->GetRenderViewHost()); 1209 1210 NavigateToURL(shell(), view_source_url); 1211 rvh_observers.EnsureRVHGetsDestructed( 1212 shell()->web_contents()->GetRenderViewHost()); 1213 SiteInstance* site_instance2 = shell()->web_contents()-> 1214 GetRenderViewHost()->GetSiteInstance(); 1215 1216 // Ensure that view-source navigations force a new SiteInstance. 1217 EXPECT_NE(site_instance1, site_instance2); 1218 1219 // Now navigate to a different instance so that we swap out again. 1220 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html")); 1221 rvh_observers.EnsureRVHGetsDestructed( 1222 shell()->web_contents()->GetRenderViewHost()); 1223 1224 // This used to leak a render view host. 1225 shell()->Close(); 1226 1227 RunAllPendingInMessageLoop(); // Needed on ChromeOS. 1228 1229 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts()); 1230 } 1231 1232 // Test for crbug.com/143155. Frame tree updates during unload should not 1233 // interrupt the intended navigation and show swappedout:// instead. 1234 // Specifically: 1235 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener. 1236 // 2) Send the second tab to a different foo.com SiteInstance. 1237 // This creates a swapped out opener for the first tab in the foo process. 1238 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first 1239 // tab's unload handler remove its frame. 1240 // This used to cause an update to the frame tree of the swapped out RV, 1241 // just as it was navigating to a real page. That pre-empted the real 1242 // navigation and visibly sent the tab to swappedout://. 1243 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1244 DontPreemptNavigationWithFrameTreeUpdate) { 1245 StartServer(); 1246 1247 // 1. Load a page that deletes its iframe during unload. 1248 NavigateToURL(shell(), 1249 test_server()->GetURL("files/remove_frame_on_unload.html")); 1250 1251 // Get the original SiteInstance for later comparison. 1252 scoped_refptr<SiteInstance> orig_site_instance( 1253 shell()->web_contents()->GetSiteInstance()); 1254 1255 // Open a same-site page in a new window. 1256 ShellAddedObserver new_shell_observer; 1257 bool success = false; 1258 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1259 shell()->web_contents(), 1260 "window.domAutomationController.send(openWindow());", 1261 &success)); 1262 EXPECT_TRUE(success); 1263 Shell* new_shell = new_shell_observer.GetShell(); 1264 1265 // Wait for the navigation in the new window to finish, if it hasn't. 1266 WaitForLoadStop(new_shell->web_contents()); 1267 EXPECT_EQ("/files/title1.html", 1268 new_shell->web_contents()->GetLastCommittedURL().path()); 1269 1270 // Should have the same SiteInstance. 1271 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance()); 1272 1273 // 2. Send the second tab to a different process. 1274 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1275 scoped_refptr<SiteInstance> new_site_instance( 1276 new_shell->web_contents()->GetSiteInstance()); 1277 EXPECT_NE(orig_site_instance, new_site_instance); 1278 1279 // 3. Send the first tab to the second tab's process. 1280 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 1281 1282 // Make sure it ends up at the right page. 1283 WaitForLoadStop(shell()->web_contents()); 1284 EXPECT_EQ(GetCrossSiteURL("files/title1.html"), 1285 shell()->web_contents()->GetLastCommittedURL()); 1286 EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance()); 1287 } 1288 1289 // Ensure that renderer-side debug URLs do not cause a process swap, since they 1290 // are meant to run in the current page. We had a bug where we expected a 1291 // BrowsingInstance swap to occur on pages like view-source and extensions, 1292 // which broke chrome://crash and javascript: URLs. 1293 // See http://crbug.com/335503. 1294 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) { 1295 ASSERT_TRUE(test_server()->Start()); 1296 1297 GURL original_url(test_server()->GetURL("files/title2.html")); 1298 GURL view_source_url(kViewSourceScheme + std::string(":") + 1299 original_url.spec()); 1300 1301 NavigateToURL(shell(), view_source_url); 1302 1303 // Check that javascript: URLs work. 1304 base::string16 expected_title = ASCIIToUTF16("msg"); 1305 TitleWatcher title_watcher(shell()->web_contents(), expected_title); 1306 shell()->LoadURL(GURL("javascript:document.title='msg'")); 1307 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 1308 1309 // Crash the renderer of the view-source page. 1310 RenderProcessHostWatcher crash_observer( 1311 shell()->web_contents(), 1312 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1313 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 1314 crash_observer.Wait(); 1315 } 1316 1317 // Ensure that renderer-side debug URLs don't take effect on crashed renderers. 1318 // Otherwise, we might try to load an unprivileged about:blank page into a 1319 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView. 1320 // See http://crbug.com/334214. 1321 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1322 IgnoreRendererDebugURLsWhenCrashed) { 1323 // Visit a WebUI page with bindings. 1324 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" + 1325 std::string(kChromeUIGpuHost)); 1326 NavigateToURL(shell(), webui_url); 1327 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1328 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1329 1330 // Crash the renderer of the WebUI page. 1331 RenderProcessHostWatcher crash_observer( 1332 shell()->web_contents(), 1333 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1334 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 1335 crash_observer.Wait(); 1336 1337 // Load the crash URL again but don't wait for any action. If it is not 1338 // ignored this time, we will fail the WebUI CHECK in InitRenderView. 1339 shell()->LoadURL(GURL(kChromeUICrashURL)); 1340 1341 // Ensure that such URLs can still work as the initial navigation of a tab. 1342 // We postpone the initial navigation of the tab using an empty GURL, so that 1343 // we can add a watcher for crashes. 1344 Shell* shell2 = Shell::CreateNewWindow( 1345 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, 1346 MSG_ROUTING_NONE, gfx::Size()); 1347 RenderProcessHostWatcher crash_observer2( 1348 shell2->web_contents(), 1349 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1350 NavigateToURL(shell2, GURL(kChromeUIKillURL)); 1351 crash_observer2.Wait(); 1352 } 1353 1354 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits. 1355 // Otherwise it might get picked up by InitRenderView when granting bindings 1356 // to other RenderViewHosts. See http://crbug.com/330811. 1357 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) { 1358 // Visit a WebUI page with bindings. 1359 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" + 1360 std::string(kChromeUIGpuHost))); 1361 NavigateToURL(shell(), webui_url); 1362 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1363 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1364 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 1365 shell()->web_contents()); 1366 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui(); 1367 EXPECT_TRUE(webui); 1368 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui()); 1369 1370 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we 1371 // clear pending_web_ui() when it commits. 1372 GURL webui_url2(webui_url.spec() + "#foo"); 1373 NavigateToURL(shell(), webui_url2); 1374 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui()); 1375 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui()); 1376 } 1377 1378 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest { 1379 public: 1380 RFHMProcessPerTabTest() {} 1381 1382 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1383 command_line->AppendSwitch(switches::kProcessPerTab); 1384 } 1385 }; 1386 1387 // Test that we still swap processes for BrowsingInstance changes even in 1388 // --process-per-tab mode. See http://crbug.com/343017. 1389 // Disabled on Android: http://crbug.com/345873. 1390 // Crashes under ThreadSanitizer, http://crbug.com/356758. 1391 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER) 1392 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI 1393 #else 1394 #define MAYBE_BackFromWebUI BackFromWebUI 1395 #endif 1396 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) { 1397 ASSERT_TRUE(test_server()->Start()); 1398 GURL original_url(test_server()->GetURL("files/title2.html")); 1399 NavigateToURL(shell(), original_url); 1400 1401 // Visit a WebUI page with bindings. 1402 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" + 1403 std::string(kChromeUIGpuHost))); 1404 NavigateToURL(shell(), webui_url); 1405 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1406 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1407 1408 // Go back and ensure we have no WebUI bindings. 1409 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1410 shell()->web_contents()->GetController().GoBack(); 1411 back_nav_load_observer.Wait(); 1412 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL()); 1413 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1414 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1415 } 1416 1417 // crbug.com/372360 1418 // The test loads url1, opens a link pointing to url2 in a new tab, and 1419 // navigates the new tab to url1. 1420 // The following is needed for the bug to happen: 1421 // - url1 must require webui bindings; 1422 // - navigating to url2 in the site instance of url1 should not swap 1423 // browsing instances, but should require a new site instance. 1424 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) { 1425 GURL url1(std::string(kChromeUIScheme) + "://" + 1426 std::string(kChromeUIGpuHost)); 1427 GURL url2(std::string(kChromeUIScheme) + "://" + 1428 std::string(kChromeUIAccessibilityHost)); 1429 1430 // Visit a WebUI page with bindings. 1431 NavigateToURL(shell(), url1); 1432 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1433 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1434 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance(); 1435 1436 // Open a new tab. Initially it gets a render view in the original tab's 1437 // current site instance. 1438 TestNavigationObserver nav_observer(NULL); 1439 nav_observer.StartWatchingNewWebContents(); 1440 ShellAddedObserver shao; 1441 OpenUrlViaClickTarget(shell()->web_contents(), url2); 1442 nav_observer.Wait(); 1443 Shell* new_shell = shao.GetShell(); 1444 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>( 1445 new_shell->web_contents()); 1446 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance(); 1447 1448 EXPECT_NE(site_instance2, site_instance1); 1449 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1)); 1450 RenderViewHost* initial_rvh = new_web_contents-> 1451 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1); 1452 ASSERT_TRUE(initial_rvh); 1453 // The following condition is what was causing the bug. 1454 EXPECT_EQ(0, initial_rvh->GetEnabledBindings()); 1455 1456 // Navigate to url1 and check bindings. 1457 NavigateToURL(new_shell, url1); 1458 // The navigation should have used the first SiteInstance, otherwise 1459 // |initial_rvh| did not have a chance to be used. 1460 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1); 1461 EXPECT_EQ(BINDINGS_POLICY_WEB_UI, 1462 new_web_contents->GetRenderViewHost()->GetEnabledBindings()); 1463 } 1464 1465 } // namespace content 1466