render_frame_host_manager_browsertest.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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/content_browser_test.h" 28#include "content/public/test/content_browser_test_utils.h" 29#include "content/public/test/test_navigation_observer.h" 30#include "content/public/test/test_utils.h" 31#include "content/shell/browser/shell.h" 32#include "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// This test also crashes under ThreadSanitizer, http://crbug.com/356758. 395#if defined(OS_WIN) || defined(THREAD_SANITIZER) 396#define MAYBE_DisownOpener DISABLED_DisownOpener 397#else 398#define MAYBE_DisownOpener DisownOpener 399#endif 400IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) { 401 StartServer(); 402 403 // Load a page with links that open in a new window. 404 std::string replacement_path; 405 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 406 "files/click-noreferrer-links.html", 407 foo_host_port_, 408 &replacement_path)); 409 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 410 411 // Get the original SiteInstance for later comparison. 412 scoped_refptr<SiteInstance> orig_site_instance( 413 shell()->web_contents()->GetSiteInstance()); 414 EXPECT_TRUE(orig_site_instance.get() != NULL); 415 416 // Test clicking a target=_blank link. 417 ShellAddedObserver new_shell_observer; 418 bool success = false; 419 EXPECT_TRUE(ExecuteScriptAndExtractBool( 420 shell()->web_contents(), 421 "window.domAutomationController.send(clickSameSiteTargetBlankLink());", 422 &success)); 423 EXPECT_TRUE(success); 424 Shell* new_shell = new_shell_observer.GetShell(); 425 426 // Wait for the navigation in the new tab to finish, if it hasn't. 427 WaitForLoadStop(new_shell->web_contents()); 428 EXPECT_EQ("/files/title2.html", 429 new_shell->web_contents()->GetLastCommittedURL().path()); 430 431 // Should have the same SiteInstance. 432 scoped_refptr<SiteInstance> blank_site_instance( 433 new_shell->web_contents()->GetSiteInstance()); 434 EXPECT_EQ(orig_site_instance, blank_site_instance); 435 436 // Now navigate the new tab to a different site. 437 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 438 scoped_refptr<SiteInstance> new_site_instance( 439 new_shell->web_contents()->GetSiteInstance()); 440 EXPECT_NE(orig_site_instance, new_site_instance); 441 442 // Now disown the opener. 443 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(), 444 "window.opener = null;")); 445 446 // Go back and ensure the opener is still null. 447 { 448 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); 449 new_shell->web_contents()->GetController().GoBack(); 450 back_nav_load_observer.Wait(); 451 } 452 success = false; 453 EXPECT_TRUE(ExecuteScriptAndExtractBool( 454 new_shell->web_contents(), 455 "window.domAutomationController.send(window.opener == null);", 456 &success)); 457 EXPECT_TRUE(success); 458 459 // Now navigate forward again (creating a new process) and check opener. 460 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 461 success = false; 462 EXPECT_TRUE(ExecuteScriptAndExtractBool( 463 new_shell->web_contents(), 464 "window.domAutomationController.send(window.opener == null);", 465 &success)); 466 EXPECT_TRUE(success); 467} 468 469// Test that subframes can disown their openers. http://crbug.com/225528. 470IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) { 471 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>"); 472 NavigateToURL(shell(), frame_url); 473 474 // Give the frame an opener using window.open. 475 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), 476 "window.open('about:blank','foo');")); 477 478 // Now disown the frame's opener. Shouldn't crash. 479 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), 480 "window.frames[0].opener = null;")); 481} 482 483// Test for crbug.com/99202. PostMessage calls should still work after 484// navigating the source and target windows to different sites. 485// Specifically: 486// 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process. 487// 2) Fail to post a message from "foo" to opener with the wrong target origin. 488// 3) Post a message from "foo" to opener, which replies back to "foo". 489// 4) Post a message from _blank to "foo". 490// 5) Post a message from "foo" to a subframe of opener, which replies back. 491// 6) Post a message from _blank to a subframe of "foo". 492IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 493 SupportCrossProcessPostMessage) { 494 StartServer(); 495 496 // Load a page with links that open in a new window. 497 std::string replacement_path; 498 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 499 "files/click-noreferrer-links.html", 500 foo_host_port_, 501 &replacement_path)); 502 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 503 504 // Get the original SiteInstance and RVHM for later comparison. 505 WebContents* opener_contents = shell()->web_contents(); 506 scoped_refptr<SiteInstance> orig_site_instance( 507 opener_contents->GetSiteInstance()); 508 EXPECT_TRUE(orig_site_instance.get() != NULL); 509 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>( 510 opener_contents)->GetRenderManagerForTesting(); 511 512 // 1) Open two more windows, one named. These initially have openers but no 513 // reference to each other. We will later post a message between them. 514 515 // First, a named target=foo window. 516 ShellAddedObserver new_shell_observer; 517 bool success = false; 518 EXPECT_TRUE(ExecuteScriptAndExtractBool( 519 opener_contents, 520 "window.domAutomationController.send(clickSameSiteTargetedLink());", 521 &success)); 522 EXPECT_TRUE(success); 523 Shell* new_shell = new_shell_observer.GetShell(); 524 525 // Wait for the navigation in the new window to finish, if it hasn't, then 526 // send it to post_message.html on a different site. 527 WebContents* foo_contents = new_shell->web_contents(); 528 WaitForLoadStop(foo_contents); 529 EXPECT_EQ("/files/navigate_opener.html", 530 foo_contents->GetLastCommittedURL().path()); 531 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html")); 532 scoped_refptr<SiteInstance> foo_site_instance( 533 foo_contents->GetSiteInstance()); 534 EXPECT_NE(orig_site_instance, foo_site_instance); 535 536 // Second, a target=_blank window. 537 ShellAddedObserver new_shell_observer2; 538 EXPECT_TRUE(ExecuteScriptAndExtractBool( 539 shell()->web_contents(), 540 "window.domAutomationController.send(clickSameSiteTargetBlankLink());", 541 &success)); 542 EXPECT_TRUE(success); 543 544 // Wait for the navigation in the new window to finish, if it hasn't, then 545 // send it to post_message.html on the original site. 546 Shell* new_shell2 = new_shell_observer2.GetShell(); 547 WebContents* new_contents = new_shell2->web_contents(); 548 WaitForLoadStop(new_contents); 549 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path()); 550 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html")); 551 EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance()); 552 RenderFrameHostManager* new_manager = 553 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting(); 554 555 // We now have three windows. The opener should have a swapped out RVH 556 // for the new SiteInstance, but the _blank window should not. 557 EXPECT_EQ(3u, Shell::windows().size()); 558 EXPECT_TRUE( 559 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 560 EXPECT_FALSE( 561 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 562 563 // 2) Fail to post a message from the foo window to the opener if the target 564 // origin is wrong. We won't see an error, but we can check for the right 565 // number of received messages below. 566 EXPECT_TRUE(ExecuteScriptAndExtractBool( 567 foo_contents, 568 "window.domAutomationController.send(postToOpener('msg'," 569 " 'http://google.com'));", 570 &success)); 571 EXPECT_TRUE(success); 572 ASSERT_FALSE( 573 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); 574 575 // 3) Post a message from the foo window to the opener. The opener will 576 // reply, causing the foo window to update its own title. 577 base::string16 expected_title = ASCIIToUTF16("msg"); 578 TitleWatcher title_watcher(foo_contents, expected_title); 579 EXPECT_TRUE(ExecuteScriptAndExtractBool( 580 foo_contents, 581 "window.domAutomationController.send(postToOpener('msg','*'));", 582 &success)); 583 EXPECT_TRUE(success); 584 ASSERT_FALSE( 585 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); 586 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 587 588 // We should have received only 1 message in the opener and "foo" tabs, 589 // and updated the title. 590 int opener_received_messages = 0; 591 EXPECT_TRUE(ExecuteScriptAndExtractInt( 592 opener_contents, 593 "window.domAutomationController.send(window.receivedMessages);", 594 &opener_received_messages)); 595 int foo_received_messages = 0; 596 EXPECT_TRUE(ExecuteScriptAndExtractInt( 597 foo_contents, 598 "window.domAutomationController.send(window.receivedMessages);", 599 &foo_received_messages)); 600 EXPECT_EQ(1, foo_received_messages); 601 EXPECT_EQ(1, opener_received_messages); 602 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle()); 603 604 // 4) Now post a message from the _blank window to the foo window. The 605 // foo window will update its title and will not reply. 606 expected_title = ASCIIToUTF16("msg2"); 607 TitleWatcher title_watcher2(foo_contents, expected_title); 608 EXPECT_TRUE(ExecuteScriptAndExtractBool( 609 new_contents, 610 "window.domAutomationController.send(postToFoo('msg2'));", 611 &success)); 612 EXPECT_TRUE(success); 613 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle()); 614 615 // This postMessage should have created a swapped out RVH for the new 616 // SiteInstance in the target=_blank window. 617 EXPECT_TRUE( 618 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 619 620 // TODO(nasko): Test subframe targeting of postMessage once 621 // http://crbug.com/153701 is fixed. 622} 623 624// Test for crbug.com/278336. MessagePorts should work cross-process. I.e., 625// messages which contain Transferables and get intercepted by 626// RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is 627// swapped out) should work. 628// Specifically: 629// 1) Create 2 windows (opener and "foo") and send "foo" cross-process. 630// 2) Post a message containing a message port from opener to "foo". 631// 3) Post a message from "foo" back to opener via the passed message port. 632// The test will be enabled when the feature implementation lands. 633IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 634 SupportCrossProcessPostMessageWithMessagePort) { 635 StartServer(); 636 637 // Load a page with links that open in a new window. 638 std::string replacement_path; 639 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 640 "files/click-noreferrer-links.html", 641 foo_host_port_, 642 &replacement_path)); 643 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 644 645 // Get the original SiteInstance and RVHM for later comparison. 646 WebContents* opener_contents = shell()->web_contents(); 647 scoped_refptr<SiteInstance> orig_site_instance( 648 opener_contents->GetSiteInstance()); 649 EXPECT_TRUE(orig_site_instance.get() != NULL); 650 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>( 651 opener_contents)->GetRenderManagerForTesting(); 652 653 // 1) Open a named target=foo window. We will later post a message between the 654 // opener and the new window. 655 ShellAddedObserver new_shell_observer; 656 bool success = false; 657 EXPECT_TRUE(ExecuteScriptAndExtractBool( 658 opener_contents, 659 "window.domAutomationController.send(clickSameSiteTargetedLink());", 660 &success)); 661 EXPECT_TRUE(success); 662 Shell* new_shell = new_shell_observer.GetShell(); 663 664 // Wait for the navigation in the new window to finish, if it hasn't, then 665 // send it to post_message.html on a different site. 666 WebContents* foo_contents = new_shell->web_contents(); 667 WaitForLoadStop(foo_contents); 668 EXPECT_EQ("/files/navigate_opener.html", 669 foo_contents->GetLastCommittedURL().path()); 670 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html")); 671 scoped_refptr<SiteInstance> foo_site_instance( 672 foo_contents->GetSiteInstance()); 673 EXPECT_NE(orig_site_instance, foo_site_instance); 674 675 // We now have two windows. The opener should have a swapped out RVH 676 // for the new SiteInstance. 677 EXPECT_EQ(2u, Shell::windows().size()); 678 EXPECT_TRUE( 679 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); 680 681 // 2) Post a message containing a MessagePort from opener to the the foo 682 // window. The foo window will reply via the passed port, causing the opener 683 // to update its own title. 684 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port"); 685 TitleWatcher title_observer(opener_contents, expected_title); 686 EXPECT_TRUE(ExecuteScriptAndExtractBool( 687 opener_contents, 688 "window.domAutomationController.send(postWithPortToFoo());", 689 &success)); 690 EXPECT_TRUE(success); 691 ASSERT_FALSE( 692 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); 693 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle()); 694 695 // Check message counts. 696 int opener_received_messages_via_port = 0; 697 EXPECT_TRUE(ExecuteScriptAndExtractInt( 698 opener_contents, 699 "window.domAutomationController.send(window.receivedMessagesViaPort);", 700 &opener_received_messages_via_port)); 701 int foo_received_messages = 0; 702 EXPECT_TRUE(ExecuteScriptAndExtractInt( 703 foo_contents, 704 "window.domAutomationController.send(window.receivedMessages);", 705 &foo_received_messages)); 706 int foo_received_messages_with_port = 0; 707 EXPECT_TRUE(ExecuteScriptAndExtractInt( 708 foo_contents, 709 "window.domAutomationController.send(window.receivedMessagesWithPort);", 710 &foo_received_messages_with_port)); 711 EXPECT_EQ(1, foo_received_messages); 712 EXPECT_EQ(1, foo_received_messages_with_port); 713 EXPECT_EQ(1, opener_received_messages_via_port); 714 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle()); 715 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle()); 716} 717 718// Test for crbug.com/116192. Navigations to a window's opener should 719// still work after a process swap. 720IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 721 AllowTargetedNavigationsInOpenerAfterSwap) { 722 StartServer(); 723 724 // Load a page with links that open in a new window. 725 std::string replacement_path; 726 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 727 "files/click-noreferrer-links.html", 728 foo_host_port_, 729 &replacement_path)); 730 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 731 732 // Get the original tab and SiteInstance for later comparison. 733 WebContents* orig_contents = shell()->web_contents(); 734 scoped_refptr<SiteInstance> orig_site_instance( 735 orig_contents->GetSiteInstance()); 736 EXPECT_TRUE(orig_site_instance.get() != NULL); 737 738 // Test clicking a target=foo link. 739 ShellAddedObserver new_shell_observer; 740 bool success = false; 741 EXPECT_TRUE(ExecuteScriptAndExtractBool( 742 orig_contents, 743 "window.domAutomationController.send(clickSameSiteTargetedLink());", 744 &success)); 745 EXPECT_TRUE(success); 746 Shell* new_shell = new_shell_observer.GetShell(); 747 748 // Wait for the navigation in the new window to finish, if it hasn't. 749 WaitForLoadStop(new_shell->web_contents()); 750 EXPECT_EQ("/files/navigate_opener.html", 751 new_shell->web_contents()->GetLastCommittedURL().path()); 752 753 // Should have the same SiteInstance. 754 scoped_refptr<SiteInstance> blank_site_instance( 755 new_shell->web_contents()->GetSiteInstance()); 756 EXPECT_EQ(orig_site_instance, blank_site_instance); 757 758 // Now navigate the original (opener) tab to a different site. 759 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 760 scoped_refptr<SiteInstance> new_site_instance( 761 shell()->web_contents()->GetSiteInstance()); 762 EXPECT_NE(orig_site_instance, new_site_instance); 763 764 // The opened tab should be able to navigate the opener back to its process. 765 TestNavigationObserver navigation_observer(orig_contents); 766 EXPECT_TRUE(ExecuteScriptAndExtractBool( 767 new_shell->web_contents(), 768 "window.domAutomationController.send(navigateOpener());", 769 &success)); 770 EXPECT_TRUE(success); 771 navigation_observer.Wait(); 772 773 // Should have swapped back into this process. 774 scoped_refptr<SiteInstance> revisit_site_instance( 775 shell()->web_contents()->GetSiteInstance()); 776 EXPECT_EQ(orig_site_instance, revisit_site_instance); 777} 778 779// Test that opening a new window in the same SiteInstance and then navigating 780// both windows to a different SiteInstance allows the first process to exit. 781// See http://crbug.com/126333. 782IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 783 ProcessExitWithSwappedOutViews) { 784 StartServer(); 785 786 // Load a page with links that open in a new window. 787 std::string replacement_path; 788 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 789 "files/click-noreferrer-links.html", 790 foo_host_port_, 791 &replacement_path)); 792 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 793 794 // Get the original SiteInstance for later comparison. 795 scoped_refptr<SiteInstance> orig_site_instance( 796 shell()->web_contents()->GetSiteInstance()); 797 EXPECT_TRUE(orig_site_instance.get() != NULL); 798 799 // Test clicking a target=foo link. 800 ShellAddedObserver new_shell_observer; 801 bool success = false; 802 EXPECT_TRUE(ExecuteScriptAndExtractBool( 803 shell()->web_contents(), 804 "window.domAutomationController.send(clickSameSiteTargetedLink());", 805 &success)); 806 EXPECT_TRUE(success); 807 Shell* new_shell = new_shell_observer.GetShell(); 808 809 // Wait for the navigation in the new window to finish, if it hasn't. 810 WaitForLoadStop(new_shell->web_contents()); 811 EXPECT_EQ("/files/navigate_opener.html", 812 new_shell->web_contents()->GetLastCommittedURL().path()); 813 814 // Should have the same SiteInstance. 815 scoped_refptr<SiteInstance> opened_site_instance( 816 new_shell->web_contents()->GetSiteInstance()); 817 EXPECT_EQ(orig_site_instance, opened_site_instance); 818 819 // Now navigate the opened window to a different site. 820 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 821 scoped_refptr<SiteInstance> new_site_instance( 822 new_shell->web_contents()->GetSiteInstance()); 823 EXPECT_NE(orig_site_instance, new_site_instance); 824 825 // The original process should still be alive, since it is still used in the 826 // first window. 827 RenderProcessHost* orig_process = orig_site_instance->GetProcess(); 828 EXPECT_TRUE(orig_process->HasConnection()); 829 830 // Navigate the first window to a different site as well. The original 831 // process should exit, since all of its views are now swapped out. 832 RenderProcessHostWatcher exit_observer( 833 orig_process, 834 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION); 835 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 836 exit_observer.Wait(); 837 scoped_refptr<SiteInstance> new_site_instance2( 838 shell()->web_contents()->GetSiteInstance()); 839 EXPECT_EQ(new_site_instance, new_site_instance2); 840} 841 842// Test for crbug.com/76666. A cross-site navigation that fails with a 204 843// error should not make us ignore future renderer-initiated navigations. 844IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) { 845 StartServer(); 846 847 // Get the original SiteInstance for later comparison. 848 scoped_refptr<SiteInstance> orig_site_instance( 849 shell()->web_contents()->GetSiteInstance()); 850 EXPECT_TRUE(orig_site_instance.get() != NULL); 851 852 // Load a cross-site page that fails with a 204 error. 853 NavigateToURL(shell(), GetCrossSiteURL("nocontent")); 854 855 // We should still be looking at the normal page. Because we started from a 856 // blank new tab, the typed URL will still be visible until the user clears it 857 // manually. The last committed URL will be the previous page. 858 scoped_refptr<SiteInstance> post_nav_site_instance( 859 shell()->web_contents()->GetSiteInstance()); 860 EXPECT_EQ(orig_site_instance, post_nav_site_instance); 861 EXPECT_EQ("/nocontent", 862 shell()->web_contents()->GetVisibleURL().path()); 863 EXPECT_FALSE( 864 shell()->web_contents()->GetController().GetLastCommittedEntry()); 865 866 // Renderer-initiated navigations should work. 867 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness"); 868 TitleWatcher title_watcher(shell()->web_contents(), expected_title); 869 GURL url = test_server()->GetURL("files/title2.html"); 870 EXPECT_TRUE(ExecuteScript( 871 shell()->web_contents(), 872 base::StringPrintf("location.href = '%s'", url.spec().c_str()))); 873 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 874 875 // Opens in same tab. 876 EXPECT_EQ(1u, Shell::windows().size()); 877 EXPECT_EQ("/files/title2.html", 878 shell()->web_contents()->GetLastCommittedURL().path()); 879 880 // Should have the same SiteInstance. 881 scoped_refptr<SiteInstance> new_site_instance( 882 shell()->web_contents()->GetSiteInstance()); 883 EXPECT_EQ(orig_site_instance, new_site_instance); 884} 885 886// Test for crbug.com/9682. We should show the URL for a pending renderer- 887// initiated navigation in a new tab, until the content of the initial 888// about:blank page is modified by another window. At that point, we should 889// revert to showing about:blank to prevent a URL spoof. 890IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) { 891 ASSERT_TRUE(test_server()->Start()); 892 893 // Load a page that can open a URL that won't commit in a new window. 894 NavigateToURL( 895 shell(), test_server()->GetURL("files/click-nocontent-link.html")); 896 WebContents* orig_contents = shell()->web_contents(); 897 898 // Click a /nocontent link that opens in a new window but never commits. 899 ShellAddedObserver new_shell_observer; 900 bool success = false; 901 EXPECT_TRUE(ExecuteScriptAndExtractBool( 902 orig_contents, 903 "window.domAutomationController.send(clickNoContentTargetedLink());", 904 &success)); 905 EXPECT_TRUE(success); 906 907 // Wait for the window to open. 908 Shell* new_shell = new_shell_observer.GetShell(); 909 910 // Ensure the destination URL is visible, because it is considered the 911 // initial navigation. 912 WebContents* contents = new_shell->web_contents(); 913 EXPECT_TRUE(contents->GetController().IsInitialNavigation()); 914 EXPECT_EQ("/nocontent", 915 contents->GetController().GetVisibleEntry()->GetURL().path()); 916 917 // Now modify the contents of the new window from the opener. This will also 918 // modify the title of the document to give us something to listen for. 919 base::string16 expected_title = ASCIIToUTF16("Modified Title"); 920 TitleWatcher title_watcher(contents, expected_title); 921 success = false; 922 EXPECT_TRUE(ExecuteScriptAndExtractBool( 923 orig_contents, 924 "window.domAutomationController.send(modifyNewWindow());", 925 &success)); 926 EXPECT_TRUE(success); 927 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 928 929 // At this point, we should no longer be showing the destination URL. 930 // The visible entry should be null, resulting in about:blank in the address 931 // bar. 932 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); 933} 934 935// Test for crbug.com/9682. We should not show the URL for a pending renderer- 936// initiated navigation in a new tab if it is not the initial navigation. In 937// this case, the renderer will not notify us of a modification, so we cannot 938// show the pending URL without allowing a spoof. 939IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 940 DontShowLoadingURLIfNotInitialNav) { 941 ASSERT_TRUE(test_server()->Start()); 942 943 // Load a page that can open a URL that won't commit in a new window. 944 NavigateToURL( 945 shell(), test_server()->GetURL("files/click-nocontent-link.html")); 946 WebContents* orig_contents = shell()->web_contents(); 947 948 // Click a /nocontent link that opens in a new window but never commits. 949 // By using an onclick handler that first creates the window, the slow 950 // navigation is not considered an initial navigation. 951 ShellAddedObserver new_shell_observer; 952 bool success = false; 953 EXPECT_TRUE(ExecuteScriptAndExtractBool( 954 orig_contents, 955 "window.domAutomationController.send(" 956 "clickNoContentScriptedTargetedLink());", 957 &success)); 958 EXPECT_TRUE(success); 959 960 // Wait for the window to open. 961 Shell* new_shell = new_shell_observer.GetShell(); 962 963 // Ensure the destination URL is not visible, because it is not the initial 964 // navigation. 965 WebContents* contents = new_shell->web_contents(); 966 EXPECT_FALSE(contents->GetController().IsInitialNavigation()); 967 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); 968} 969 970// Crashes under ThreadSanitizer, http://crbug.com/356758. 971#if defined(THREAD_SANITIZER) 972#define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale 973#else 974#define MAYBE_BackForwardNotStale BackForwardNotStale 975#endif 976// Test for http://crbug.com/93427. Ensure that cross-site navigations 977// do not cause back/forward navigations to be considered stale by the 978// renderer. 979IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) { 980 StartServer(); 981 NavigateToURL(shell(), GURL(kAboutBlankURL)); 982 983 // Visit a page on first site. 984 NavigateToURL(shell(), test_server()->GetURL("files/title1.html")); 985 986 // Visit three pages on second site. 987 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 988 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html")); 989 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html")); 990 991 // History is now [blank, A1, B1, B2, *B3]. 992 WebContents* contents = shell()->web_contents(); 993 EXPECT_EQ(5, contents->GetController().GetEntryCount()); 994 995 // Open another window in same process to keep this process alive. 996 Shell* new_shell = CreateBrowser(); 997 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 998 999 // Go back three times to first site. 1000 { 1001 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1002 shell()->web_contents()->GetController().GoBack(); 1003 back_nav_load_observer.Wait(); 1004 } 1005 { 1006 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1007 shell()->web_contents()->GetController().GoBack(); 1008 back_nav_load_observer.Wait(); 1009 } 1010 { 1011 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1012 shell()->web_contents()->GetController().GoBack(); 1013 back_nav_load_observer.Wait(); 1014 } 1015 1016 // Now go forward twice to B2. Shouldn't be left spinning. 1017 { 1018 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1019 shell()->web_contents()->GetController().GoForward(); 1020 forward_nav_load_observer.Wait(); 1021 } 1022 { 1023 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1024 shell()->web_contents()->GetController().GoForward(); 1025 forward_nav_load_observer.Wait(); 1026 } 1027 1028 // Go back twice to first site. 1029 { 1030 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1031 shell()->web_contents()->GetController().GoBack(); 1032 back_nav_load_observer.Wait(); 1033 } 1034 { 1035 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1036 shell()->web_contents()->GetController().GoBack(); 1037 back_nav_load_observer.Wait(); 1038 } 1039 1040 // Now go forward directly to B3. Shouldn't be left spinning. 1041 { 1042 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1043 shell()->web_contents()->GetController().GoToIndex(4); 1044 forward_nav_load_observer.Wait(); 1045 } 1046} 1047 1048// Test for http://crbug.com/130016. 1049// Swapping out a render view should update its visiblity state. 1050IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1051 SwappedOutViewHasCorrectVisibilityState) { 1052 StartServer(); 1053 1054 // Load a page with links that open in a new window. 1055 std::string replacement_path; 1056 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 1057 "files/click-noreferrer-links.html", 1058 foo_host_port_, 1059 &replacement_path)); 1060 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 1061 1062 // Open a same-site link in a new widnow. 1063 ShellAddedObserver new_shell_observer; 1064 bool success = false; 1065 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1066 shell()->web_contents(), 1067 "window.domAutomationController.send(clickSameSiteTargetedLink());", 1068 &success)); 1069 EXPECT_TRUE(success); 1070 Shell* new_shell = new_shell_observer.GetShell(); 1071 1072 // Wait for the navigation in the new tab to finish, if it hasn't. 1073 WaitForLoadStop(new_shell->web_contents()); 1074 EXPECT_EQ("/files/navigate_opener.html", 1075 new_shell->web_contents()->GetLastCommittedURL().path()); 1076 1077 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost(); 1078 1079 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1080 rvh, 1081 "window.domAutomationController.send(" 1082 " document.visibilityState == 'visible');", 1083 &success)); 1084 EXPECT_TRUE(success); 1085 1086 // Now navigate the new window to a different site. This should swap out the 1087 // tab's existing RenderView, causing it become hidden. 1088 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1089 1090 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1091 rvh, 1092 "window.domAutomationController.send(" 1093 " document.visibilityState == 'hidden');", 1094 &success)); 1095 EXPECT_TRUE(success); 1096 1097 // Going back should make the previously swapped-out view to become visible 1098 // again. 1099 { 1100 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); 1101 new_shell->web_contents()->GetController().GoBack(); 1102 back_nav_load_observer.Wait(); 1103 } 1104 1105 EXPECT_EQ("/files/navigate_opener.html", 1106 new_shell->web_contents()->GetLastCommittedURL().path()); 1107 1108 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost()); 1109 1110 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1111 rvh, 1112 "window.domAutomationController.send(" 1113 " document.visibilityState == 'visible');", 1114 &success)); 1115 EXPECT_TRUE(success); 1116} 1117 1118// This class ensures that all the given RenderViewHosts have properly been 1119// shutdown. 1120class RenderViewHostDestructionObserver : public WebContentsObserver { 1121 public: 1122 explicit RenderViewHostDestructionObserver(WebContents* web_contents) 1123 : WebContentsObserver(web_contents) {} 1124 virtual ~RenderViewHostDestructionObserver() {} 1125 void EnsureRVHGetsDestructed(RenderViewHost* rvh) { 1126 watched_render_view_hosts_.insert(rvh); 1127 } 1128 size_t GetNumberOfWatchedRenderViewHosts() const { 1129 return watched_render_view_hosts_.size(); 1130 } 1131 1132 private: 1133 // WebContentsObserver implementation: 1134 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE { 1135 watched_render_view_hosts_.erase(rvh); 1136 } 1137 1138 std::set<RenderViewHost*> watched_render_view_hosts_; 1139}; 1140 1141// Crashes under ThreadSanitizer, http://crbug.com/356758. 1142#if defined(THREAD_SANITIZER) 1143#define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts 1144#else 1145#define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts 1146#endif 1147// Test for crbug.com/90867. Make sure we don't leak render view hosts since 1148// they may cause crashes or memory corruptions when trying to call dead 1149// delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to 1150// ensure that a separate SiteInstance is created when navigating to view-source 1151// URLs, regardless of current URL. 1152IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1153 MAYBE_LeakingRenderViewHosts) { 1154 StartServer(); 1155 1156 // Observe the created render_view_host's to make sure they will not leak. 1157 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents()); 1158 1159 GURL navigated_url(test_server()->GetURL("files/title2.html")); 1160 GURL view_source_url(kViewSourceScheme + std::string(":") + 1161 navigated_url.spec()); 1162 1163 // Let's ensure that when we start with a blank window, navigating away to a 1164 // view-source URL, we create a new SiteInstance. 1165 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost(); 1166 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance(); 1167 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL()); 1168 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL()); 1169 rvh_observers.EnsureRVHGetsDestructed(blank_rvh); 1170 1171 // Now navigate to the view-source URL and ensure we got a different 1172 // SiteInstance and RenderViewHost. 1173 NavigateToURL(shell(), view_source_url); 1174 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost()); 1175 EXPECT_NE(blank_site_instance, shell()->web_contents()-> 1176 GetRenderViewHost()->GetSiteInstance()); 1177 rvh_observers.EnsureRVHGetsDestructed( 1178 shell()->web_contents()->GetRenderViewHost()); 1179 1180 // Load a random page and then navigate to view-source: of it. 1181 // This used to cause two RVH instances for the same SiteInstance, which 1182 // was a problem. This is no longer the case. 1183 NavigateToURL(shell(), navigated_url); 1184 SiteInstance* site_instance1 = shell()->web_contents()-> 1185 GetRenderViewHost()->GetSiteInstance(); 1186 rvh_observers.EnsureRVHGetsDestructed( 1187 shell()->web_contents()->GetRenderViewHost()); 1188 1189 NavigateToURL(shell(), view_source_url); 1190 rvh_observers.EnsureRVHGetsDestructed( 1191 shell()->web_contents()->GetRenderViewHost()); 1192 SiteInstance* site_instance2 = shell()->web_contents()-> 1193 GetRenderViewHost()->GetSiteInstance(); 1194 1195 // Ensure that view-source navigations force a new SiteInstance. 1196 EXPECT_NE(site_instance1, site_instance2); 1197 1198 // Now navigate to a different instance so that we swap out again. 1199 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html")); 1200 rvh_observers.EnsureRVHGetsDestructed( 1201 shell()->web_contents()->GetRenderViewHost()); 1202 1203 // This used to leak a render view host. 1204 shell()->Close(); 1205 1206 RunAllPendingInMessageLoop(); // Needed on ChromeOS. 1207 1208 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts()); 1209} 1210 1211// Test for crbug.com/143155. Frame tree updates during unload should not 1212// interrupt the intended navigation and show swappedout:// instead. 1213// Specifically: 1214// 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener. 1215// 2) Send the second tab to a different foo.com SiteInstance. 1216// This creates a swapped out opener for the first tab in the foo process. 1217// 3) Navigate the first tab to the foo.com SiteInstance, and have the first 1218// tab's unload handler remove its frame. 1219// This used to cause an update to the frame tree of the swapped out RV, 1220// just as it was navigating to a real page. That pre-empted the real 1221// navigation and visibly sent the tab to swappedout://. 1222IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1223 DontPreemptNavigationWithFrameTreeUpdate) { 1224 StartServer(); 1225 1226 // 1. Load a page that deletes its iframe during unload. 1227 NavigateToURL(shell(), 1228 test_server()->GetURL("files/remove_frame_on_unload.html")); 1229 1230 // Get the original SiteInstance for later comparison. 1231 scoped_refptr<SiteInstance> orig_site_instance( 1232 shell()->web_contents()->GetSiteInstance()); 1233 1234 // Open a same-site page in a new window. 1235 ShellAddedObserver new_shell_observer; 1236 bool success = false; 1237 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1238 shell()->web_contents(), 1239 "window.domAutomationController.send(openWindow());", 1240 &success)); 1241 EXPECT_TRUE(success); 1242 Shell* new_shell = new_shell_observer.GetShell(); 1243 1244 // Wait for the navigation in the new window to finish, if it hasn't. 1245 WaitForLoadStop(new_shell->web_contents()); 1246 EXPECT_EQ("/files/title1.html", 1247 new_shell->web_contents()->GetLastCommittedURL().path()); 1248 1249 // Should have the same SiteInstance. 1250 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance()); 1251 1252 // 2. Send the second tab to a different process. 1253 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1254 scoped_refptr<SiteInstance> new_site_instance( 1255 new_shell->web_contents()->GetSiteInstance()); 1256 EXPECT_NE(orig_site_instance, new_site_instance); 1257 1258 // 3. Send the first tab to the second tab's process. 1259 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 1260 1261 // Make sure it ends up at the right page. 1262 WaitForLoadStop(shell()->web_contents()); 1263 EXPECT_EQ(GetCrossSiteURL("files/title1.html"), 1264 shell()->web_contents()->GetLastCommittedURL()); 1265 EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance()); 1266} 1267 1268// Ensure that renderer-side debug URLs do not cause a process swap, since they 1269// are meant to run in the current page. We had a bug where we expected a 1270// BrowsingInstance swap to occur on pages like view-source and extensions, 1271// which broke chrome://crash and javascript: URLs. 1272// See http://crbug.com/335503. 1273IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) { 1274 ASSERT_TRUE(test_server()->Start()); 1275 1276 GURL original_url(test_server()->GetURL("files/title2.html")); 1277 GURL view_source_url(kViewSourceScheme + std::string(":") + 1278 original_url.spec()); 1279 1280 NavigateToURL(shell(), view_source_url); 1281 1282 // Check that javascript: URLs work. 1283 base::string16 expected_title = ASCIIToUTF16("msg"); 1284 TitleWatcher title_watcher(shell()->web_contents(), expected_title); 1285 shell()->LoadURL(GURL("javascript:document.title='msg'")); 1286 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 1287 1288 // Crash the renderer of the view-source page. 1289 RenderProcessHostWatcher crash_observer( 1290 shell()->web_contents(), 1291 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1292 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 1293 crash_observer.Wait(); 1294} 1295 1296// Ensure that renderer-side debug URLs don't take effect on crashed renderers. 1297// Otherwise, we might try to load an unprivileged about:blank page into a 1298// WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView. 1299// See http://crbug.com/334214. 1300IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1301 IgnoreRendererDebugURLsWhenCrashed) { 1302 // Visit a WebUI page with bindings. 1303 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" + 1304 std::string(kChromeUIGpuHost)); 1305 NavigateToURL(shell(), webui_url); 1306 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1307 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1308 1309 // Crash the renderer of the WebUI page. 1310 RenderProcessHostWatcher crash_observer( 1311 shell()->web_contents(), 1312 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1313 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 1314 crash_observer.Wait(); 1315 1316 // Load the crash URL again but don't wait for any action. If it is not 1317 // ignored this time, we will fail the WebUI CHECK in InitRenderView. 1318 shell()->LoadURL(GURL(kChromeUICrashURL)); 1319 1320 // Ensure that such URLs can still work as the initial navigation of a tab. 1321 // We postpone the initial navigation of the tab using an empty GURL, so that 1322 // we can add a watcher for crashes. 1323 Shell* shell2 = Shell::CreateNewWindow( 1324 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, 1325 MSG_ROUTING_NONE, gfx::Size()); 1326 RenderProcessHostWatcher crash_observer2( 1327 shell2->web_contents(), 1328 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1329 NavigateToURL(shell2, GURL(kChromeUIKillURL)); 1330 crash_observer2.Wait(); 1331} 1332 1333// Ensure that pending_and_current_web_ui_ is cleared when a URL commits. 1334// Otherwise it might get picked up by InitRenderView when granting bindings 1335// to other RenderViewHosts. See http://crbug.com/330811. 1336IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) { 1337 // Visit a WebUI page with bindings. 1338 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" + 1339 std::string(kChromeUIGpuHost))); 1340 NavigateToURL(shell(), webui_url); 1341 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1342 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1343 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 1344 shell()->web_contents()); 1345 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui(); 1346 EXPECT_TRUE(webui); 1347 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui()); 1348 1349 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we 1350 // clear pending_web_ui() when it commits. 1351 GURL webui_url2(webui_url.spec() + "#foo"); 1352 NavigateToURL(shell(), webui_url2); 1353 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui()); 1354 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui()); 1355} 1356 1357class RFHMProcessPerTabTest : public RenderFrameHostManagerTest { 1358 public: 1359 RFHMProcessPerTabTest() {} 1360 1361 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1362 command_line->AppendSwitch(switches::kProcessPerTab); 1363 } 1364}; 1365 1366// Test that we still swap processes for BrowsingInstance changes even in 1367// --process-per-tab mode. See http://crbug.com/343017. 1368// Disabled on Android: http://crbug.com/345873. 1369// Crashes under ThreadSanitizer, http://crbug.com/356758. 1370#if defined(OS_ANDROID) || defined(THREAD_SANITIZER) 1371#define MAYBE_BackFromWebUI DISABLED_BackFromWebUI 1372#else 1373#define MAYBE_BackFromWebUI BackFromWebUI 1374#endif 1375IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) { 1376 ASSERT_TRUE(test_server()->Start()); 1377 GURL original_url(test_server()->GetURL("files/title2.html")); 1378 NavigateToURL(shell(), original_url); 1379 1380 // Visit a WebUI page with bindings. 1381 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" + 1382 std::string(kChromeUIGpuHost))); 1383 NavigateToURL(shell(), webui_url); 1384 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1385 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1386 1387 // Go back and ensure we have no WebUI bindings. 1388 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1389 shell()->web_contents()->GetController().GoBack(); 1390 back_nav_load_observer.Wait(); 1391 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL()); 1392 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1393 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1394} 1395 1396} // namespace content 1397