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