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