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