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