render_frame_host_manager_browsertest.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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 // Load a page with links that open in a new window. 848 // The links will point to foo.com. 849 std::string replacement_path; 850 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 851 "files/click-noreferrer-links.html", 852 foo_host_port_, 853 &replacement_path)); 854 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 855 856 // Get the original SiteInstance for later comparison. 857 scoped_refptr<SiteInstance> orig_site_instance( 858 shell()->web_contents()->GetSiteInstance()); 859 EXPECT_TRUE(orig_site_instance.get() != NULL); 860 861 // Load a cross-site page that fails with a 204 error. 862 NavigateToURL(shell(),GetCrossSiteURL("nocontent")); 863 864 // We should still be looking at the normal page. The typed URL will 865 // still be visible until the user clears it manually, but the last 866 // committed URL will be the previous page. 867 scoped_refptr<SiteInstance> post_nav_site_instance( 868 shell()->web_contents()->GetSiteInstance()); 869 EXPECT_EQ(orig_site_instance, post_nav_site_instance); 870 EXPECT_EQ("/nocontent", 871 shell()->web_contents()->GetVisibleURL().path()); 872 EXPECT_EQ("/files/click-noreferrer-links.html", 873 shell()->web_contents()->GetController(). 874 GetLastCommittedEntry()->GetVirtualURL().path()); 875 876 // Renderer-initiated navigations should work. 877 bool success = false; 878 EXPECT_TRUE(ExecuteScriptAndExtractBool( 879 shell()->web_contents(), 880 "window.domAutomationController.send(clickNoRefLink());", 881 &success)); 882 EXPECT_TRUE(success); 883 884 // Wait for the cross-site transition in the current tab to finish. 885 WaitForLoadStop(shell()->web_contents()); 886 887 // Opens in same tab. 888 EXPECT_EQ(1u, Shell::windows().size()); 889 EXPECT_EQ("/files/title2.html", 890 shell()->web_contents()->GetLastCommittedURL().path()); 891 892 // Should have the same SiteInstance. 893 scoped_refptr<SiteInstance> noref_site_instance( 894 shell()->web_contents()->GetSiteInstance()); 895 EXPECT_EQ(orig_site_instance, noref_site_instance); 896} 897 898// Test for crbug.com/9682. We should show the URL for a pending renderer- 899// initiated navigation in a new tab, until the content of the initial 900// about:blank page is modified by another window. At that point, we should 901// revert to showing about:blank to prevent a URL spoof. 902IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) { 903 ASSERT_TRUE(test_server()->Start()); 904 905 // Load a page that can open a URL that won't commit in a new window. 906 NavigateToURL( 907 shell(), test_server()->GetURL("files/click-nocontent-link.html")); 908 WebContents* orig_contents = shell()->web_contents(); 909 910 // Click a /nocontent link that opens in a new window but never commits. 911 ShellAddedObserver new_shell_observer; 912 bool success = false; 913 EXPECT_TRUE(ExecuteScriptAndExtractBool( 914 orig_contents, 915 "window.domAutomationController.send(clickNoContentTargetedLink());", 916 &success)); 917 EXPECT_TRUE(success); 918 919 // Wait for the window to open. 920 Shell* new_shell = new_shell_observer.GetShell(); 921 922 // Ensure the destination URL is visible, because it is considered the 923 // initial navigation. 924 WebContents* contents = new_shell->web_contents(); 925 EXPECT_TRUE(contents->GetController().IsInitialNavigation()); 926 EXPECT_EQ("/nocontent", 927 contents->GetController().GetVisibleEntry()->GetURL().path()); 928 929 // Now modify the contents of the new window from the opener. This will also 930 // modify the title of the document to give us something to listen for. 931 base::string16 expected_title = ASCIIToUTF16("Modified Title"); 932 TitleWatcher title_watcher(contents, expected_title); 933 success = false; 934 EXPECT_TRUE(ExecuteScriptAndExtractBool( 935 orig_contents, 936 "window.domAutomationController.send(modifyNewWindow());", 937 &success)); 938 EXPECT_TRUE(success); 939 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 940 941 // At this point, we should no longer be showing the destination URL. 942 // The visible entry should be null, resulting in about:blank in the address 943 // bar. 944 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); 945} 946 947// Test for crbug.com/9682. We should not show the URL for a pending renderer- 948// initiated navigation in a new tab if it is not the initial navigation. In 949// this case, the renderer will not notify us of a modification, so we cannot 950// show the pending URL without allowing a spoof. 951IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 952 DontShowLoadingURLIfNotInitialNav) { 953 ASSERT_TRUE(test_server()->Start()); 954 955 // Load a page that can open a URL that won't commit in a new window. 956 NavigateToURL( 957 shell(), test_server()->GetURL("files/click-nocontent-link.html")); 958 WebContents* orig_contents = shell()->web_contents(); 959 960 // Click a /nocontent link that opens in a new window but never commits. 961 // By using an onclick handler that first creates the window, the slow 962 // navigation is not considered an initial navigation. 963 ShellAddedObserver new_shell_observer; 964 bool success = false; 965 EXPECT_TRUE(ExecuteScriptAndExtractBool( 966 orig_contents, 967 "window.domAutomationController.send(" 968 "clickNoContentScriptedTargetedLink());", 969 &success)); 970 EXPECT_TRUE(success); 971 972 // Wait for the window to open. 973 Shell* new_shell = new_shell_observer.GetShell(); 974 975 // Ensure the destination URL is not visible, because it is not the initial 976 // navigation. 977 WebContents* contents = new_shell->web_contents(); 978 EXPECT_FALSE(contents->GetController().IsInitialNavigation()); 979 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); 980} 981 982// Crashes under ThreadSanitizer, http://crbug.com/356758. 983#if defined(THREAD_SANITIZER) 984#define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale 985#else 986#define MAYBE_BackForwardNotStale BackForwardNotStale 987#endif 988// Test for http://crbug.com/93427. Ensure that cross-site navigations 989// do not cause back/forward navigations to be considered stale by the 990// renderer. 991IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) { 992 StartServer(); 993 NavigateToURL(shell(), GURL(kAboutBlankURL)); 994 995 // Visit a page on first site. 996 NavigateToURL(shell(), test_server()->GetURL("files/title1.html")); 997 998 // Visit three pages on second site. 999 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 1000 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html")); 1001 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html")); 1002 1003 // History is now [blank, A1, B1, B2, *B3]. 1004 WebContents* contents = shell()->web_contents(); 1005 EXPECT_EQ(5, contents->GetController().GetEntryCount()); 1006 1007 // Open another window in same process to keep this process alive. 1008 Shell* new_shell = CreateBrowser(); 1009 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1010 1011 // Go back three times to first site. 1012 { 1013 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1014 shell()->web_contents()->GetController().GoBack(); 1015 back_nav_load_observer.Wait(); 1016 } 1017 { 1018 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1019 shell()->web_contents()->GetController().GoBack(); 1020 back_nav_load_observer.Wait(); 1021 } 1022 { 1023 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1024 shell()->web_contents()->GetController().GoBack(); 1025 back_nav_load_observer.Wait(); 1026 } 1027 1028 // Now go forward twice to B2. Shouldn't be left spinning. 1029 { 1030 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1031 shell()->web_contents()->GetController().GoForward(); 1032 forward_nav_load_observer.Wait(); 1033 } 1034 { 1035 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1036 shell()->web_contents()->GetController().GoForward(); 1037 forward_nav_load_observer.Wait(); 1038 } 1039 1040 // Go back twice to first site. 1041 { 1042 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1043 shell()->web_contents()->GetController().GoBack(); 1044 back_nav_load_observer.Wait(); 1045 } 1046 { 1047 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1048 shell()->web_contents()->GetController().GoBack(); 1049 back_nav_load_observer.Wait(); 1050 } 1051 1052 // Now go forward directly to B3. Shouldn't be left spinning. 1053 { 1054 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); 1055 shell()->web_contents()->GetController().GoToIndex(4); 1056 forward_nav_load_observer.Wait(); 1057 } 1058} 1059 1060// Test for http://crbug.com/130016. 1061// Swapping out a render view should update its visiblity state. 1062IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1063 SwappedOutViewHasCorrectVisibilityState) { 1064 StartServer(); 1065 1066 // Load a page with links that open in a new window. 1067 std::string replacement_path; 1068 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( 1069 "files/click-noreferrer-links.html", 1070 foo_host_port_, 1071 &replacement_path)); 1072 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); 1073 1074 // Open a same-site link in a new widnow. 1075 ShellAddedObserver new_shell_observer; 1076 bool success = false; 1077 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1078 shell()->web_contents(), 1079 "window.domAutomationController.send(clickSameSiteTargetedLink());", 1080 &success)); 1081 EXPECT_TRUE(success); 1082 Shell* new_shell = new_shell_observer.GetShell(); 1083 1084 // Wait for the navigation in the new tab to finish, if it hasn't. 1085 WaitForLoadStop(new_shell->web_contents()); 1086 EXPECT_EQ("/files/navigate_opener.html", 1087 new_shell->web_contents()->GetLastCommittedURL().path()); 1088 1089 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost(); 1090 1091 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1092 rvh, 1093 "window.domAutomationController.send(" 1094 " document.visibilityState == 'visible');", 1095 &success)); 1096 EXPECT_TRUE(success); 1097 1098 // Now navigate the new window to a different site. This should swap out the 1099 // tab's existing RenderView, causing it become hidden. 1100 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1101 1102 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1103 rvh, 1104 "window.domAutomationController.send(" 1105 " document.visibilityState == 'hidden');", 1106 &success)); 1107 EXPECT_TRUE(success); 1108 1109 // Going back should make the previously swapped-out view to become visible 1110 // again. 1111 { 1112 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); 1113 new_shell->web_contents()->GetController().GoBack(); 1114 back_nav_load_observer.Wait(); 1115 } 1116 1117 EXPECT_EQ("/files/navigate_opener.html", 1118 new_shell->web_contents()->GetLastCommittedURL().path()); 1119 1120 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost()); 1121 1122 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1123 rvh, 1124 "window.domAutomationController.send(" 1125 " document.visibilityState == 'visible');", 1126 &success)); 1127 EXPECT_TRUE(success); 1128} 1129 1130// This class ensures that all the given RenderViewHosts have properly been 1131// shutdown. 1132class RenderViewHostDestructionObserver : public WebContentsObserver { 1133 public: 1134 explicit RenderViewHostDestructionObserver(WebContents* web_contents) 1135 : WebContentsObserver(web_contents) {} 1136 virtual ~RenderViewHostDestructionObserver() {} 1137 void EnsureRVHGetsDestructed(RenderViewHost* rvh) { 1138 watched_render_view_hosts_.insert(rvh); 1139 } 1140 size_t GetNumberOfWatchedRenderViewHosts() const { 1141 return watched_render_view_hosts_.size(); 1142 } 1143 1144 private: 1145 // WebContentsObserver implementation: 1146 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE { 1147 watched_render_view_hosts_.erase(rvh); 1148 } 1149 1150 std::set<RenderViewHost*> watched_render_view_hosts_; 1151}; 1152 1153// Crashes under ThreadSanitizer, http://crbug.com/356758. 1154#if defined(THREAD_SANITIZER) 1155#define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts 1156#else 1157#define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts 1158#endif 1159// Test for crbug.com/90867. Make sure we don't leak render view hosts since 1160// they may cause crashes or memory corruptions when trying to call dead 1161// delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to 1162// ensure that a separate SiteInstance is created when navigating to view-source 1163// URLs, regardless of current URL. 1164IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1165 MAYBE_LeakingRenderViewHosts) { 1166 StartServer(); 1167 1168 // Observe the created render_view_host's to make sure they will not leak. 1169 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents()); 1170 1171 GURL navigated_url(test_server()->GetURL("files/title2.html")); 1172 GURL view_source_url(kViewSourceScheme + std::string(":") + 1173 navigated_url.spec()); 1174 1175 // Let's ensure that when we start with a blank window, navigating away to a 1176 // view-source URL, we create a new SiteInstance. 1177 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost(); 1178 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance(); 1179 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL()); 1180 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL()); 1181 rvh_observers.EnsureRVHGetsDestructed(blank_rvh); 1182 1183 // Now navigate to the view-source URL and ensure we got a different 1184 // SiteInstance and RenderViewHost. 1185 NavigateToURL(shell(), view_source_url); 1186 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost()); 1187 EXPECT_NE(blank_site_instance, shell()->web_contents()-> 1188 GetRenderViewHost()->GetSiteInstance()); 1189 rvh_observers.EnsureRVHGetsDestructed( 1190 shell()->web_contents()->GetRenderViewHost()); 1191 1192 // Load a random page and then navigate to view-source: of it. 1193 // This used to cause two RVH instances for the same SiteInstance, which 1194 // was a problem. This is no longer the case. 1195 NavigateToURL(shell(), navigated_url); 1196 SiteInstance* site_instance1 = shell()->web_contents()-> 1197 GetRenderViewHost()->GetSiteInstance(); 1198 rvh_observers.EnsureRVHGetsDestructed( 1199 shell()->web_contents()->GetRenderViewHost()); 1200 1201 NavigateToURL(shell(), view_source_url); 1202 rvh_observers.EnsureRVHGetsDestructed( 1203 shell()->web_contents()->GetRenderViewHost()); 1204 SiteInstance* site_instance2 = shell()->web_contents()-> 1205 GetRenderViewHost()->GetSiteInstance(); 1206 1207 // Ensure that view-source navigations force a new SiteInstance. 1208 EXPECT_NE(site_instance1, site_instance2); 1209 1210 // Now navigate to a different instance so that we swap out again. 1211 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html")); 1212 rvh_observers.EnsureRVHGetsDestructed( 1213 shell()->web_contents()->GetRenderViewHost()); 1214 1215 // This used to leak a render view host. 1216 shell()->Close(); 1217 1218 RunAllPendingInMessageLoop(); // Needed on ChromeOS. 1219 1220 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts()); 1221} 1222 1223// Test for crbug.com/143155. Frame tree updates during unload should not 1224// interrupt the intended navigation and show swappedout:// instead. 1225// Specifically: 1226// 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener. 1227// 2) Send the second tab to a different foo.com SiteInstance. 1228// This creates a swapped out opener for the first tab in the foo process. 1229// 3) Navigate the first tab to the foo.com SiteInstance, and have the first 1230// tab's unload handler remove its frame. 1231// This used to cause an update to the frame tree of the swapped out RV, 1232// just as it was navigating to a real page. That pre-empted the real 1233// navigation and visibly sent the tab to swappedout://. 1234IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1235 DontPreemptNavigationWithFrameTreeUpdate) { 1236 StartServer(); 1237 1238 // 1. Load a page that deletes its iframe during unload. 1239 NavigateToURL(shell(), 1240 test_server()->GetURL("files/remove_frame_on_unload.html")); 1241 1242 // Get the original SiteInstance for later comparison. 1243 scoped_refptr<SiteInstance> orig_site_instance( 1244 shell()->web_contents()->GetSiteInstance()); 1245 1246 // Open a same-site page in a new window. 1247 ShellAddedObserver new_shell_observer; 1248 bool success = false; 1249 EXPECT_TRUE(ExecuteScriptAndExtractBool( 1250 shell()->web_contents(), 1251 "window.domAutomationController.send(openWindow());", 1252 &success)); 1253 EXPECT_TRUE(success); 1254 Shell* new_shell = new_shell_observer.GetShell(); 1255 1256 // Wait for the navigation in the new window to finish, if it hasn't. 1257 WaitForLoadStop(new_shell->web_contents()); 1258 EXPECT_EQ("/files/title1.html", 1259 new_shell->web_contents()->GetLastCommittedURL().path()); 1260 1261 // Should have the same SiteInstance. 1262 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance()); 1263 1264 // 2. Send the second tab to a different process. 1265 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html")); 1266 scoped_refptr<SiteInstance> new_site_instance( 1267 new_shell->web_contents()->GetSiteInstance()); 1268 EXPECT_NE(orig_site_instance, new_site_instance); 1269 1270 // 3. Send the first tab to the second tab's process. 1271 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); 1272 1273 // Make sure it ends up at the right page. 1274 WaitForLoadStop(shell()->web_contents()); 1275 EXPECT_EQ(GetCrossSiteURL("files/title1.html"), 1276 shell()->web_contents()->GetLastCommittedURL()); 1277 EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance()); 1278} 1279 1280// Ensure that renderer-side debug URLs do not cause a process swap, since they 1281// are meant to run in the current page. We had a bug where we expected a 1282// BrowsingInstance swap to occur on pages like view-source and extensions, 1283// which broke chrome://crash and javascript: URLs. 1284// See http://crbug.com/335503. 1285IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) { 1286 ASSERT_TRUE(test_server()->Start()); 1287 1288 GURL original_url(test_server()->GetURL("files/title2.html")); 1289 GURL view_source_url(kViewSourceScheme + std::string(":") + 1290 original_url.spec()); 1291 1292 NavigateToURL(shell(), view_source_url); 1293 1294 // Check that javascript: URLs work. 1295 base::string16 expected_title = ASCIIToUTF16("msg"); 1296 TitleWatcher title_watcher(shell()->web_contents(), expected_title); 1297 shell()->LoadURL(GURL("javascript:document.title='msg'")); 1298 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 1299 1300 // Crash the renderer of the view-source page. 1301 RenderProcessHostWatcher crash_observer( 1302 shell()->web_contents(), 1303 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1304 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 1305 crash_observer.Wait(); 1306} 1307 1308// Ensure that renderer-side debug URLs don't take effect on crashed renderers. 1309// Otherwise, we might try to load an unprivileged about:blank page into a 1310// WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView. 1311// See http://crbug.com/334214. 1312IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 1313 IgnoreRendererDebugURLsWhenCrashed) { 1314 // Visit a WebUI page with bindings. 1315 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" + 1316 std::string(kChromeUIGpuHost)); 1317 NavigateToURL(shell(), webui_url); 1318 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1319 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1320 1321 // Crash the renderer of the WebUI page. 1322 RenderProcessHostWatcher crash_observer( 1323 shell()->web_contents(), 1324 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1325 NavigateToURL(shell(), GURL(kChromeUICrashURL)); 1326 crash_observer.Wait(); 1327 1328 // Load the crash URL again but don't wait for any action. If it is not 1329 // ignored this time, we will fail the WebUI CHECK in InitRenderView. 1330 shell()->LoadURL(GURL(kChromeUICrashURL)); 1331 1332 // Ensure that such URLs can still work as the initial navigation of a tab. 1333 // We postpone the initial navigation of the tab using an empty GURL, so that 1334 // we can add a watcher for crashes. 1335 Shell* shell2 = Shell::CreateNewWindow( 1336 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, 1337 MSG_ROUTING_NONE, gfx::Size()); 1338 RenderProcessHostWatcher crash_observer2( 1339 shell2->web_contents(), 1340 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 1341 NavigateToURL(shell2, GURL(kChromeUIKillURL)); 1342 crash_observer2.Wait(); 1343} 1344 1345// Ensure that pending_and_current_web_ui_ is cleared when a URL commits. 1346// Otherwise it might get picked up by InitRenderView when granting bindings 1347// to other RenderViewHosts. See http://crbug.com/330811. 1348IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) { 1349 // Visit a WebUI page with bindings. 1350 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" + 1351 std::string(kChromeUIGpuHost))); 1352 NavigateToURL(shell(), webui_url); 1353 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1354 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1355 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 1356 shell()->web_contents()); 1357 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui(); 1358 EXPECT_TRUE(webui); 1359 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui()); 1360 1361 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we 1362 // clear pending_web_ui() when it commits. 1363 GURL webui_url2(webui_url.spec() + "#foo"); 1364 NavigateToURL(shell(), webui_url2); 1365 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui()); 1366 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui()); 1367} 1368 1369class RFHMProcessPerTabTest : public RenderFrameHostManagerTest { 1370 public: 1371 RFHMProcessPerTabTest() {} 1372 1373 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1374 command_line->AppendSwitch(switches::kProcessPerTab); 1375 } 1376}; 1377 1378// Test that we still swap processes for BrowsingInstance changes even in 1379// --process-per-tab mode. See http://crbug.com/343017. 1380// Disabled on Android: http://crbug.com/345873. 1381// Crashes under ThreadSanitizer, http://crbug.com/356758. 1382#if defined(OS_ANDROID) || defined(THREAD_SANITIZER) 1383#define MAYBE_BackFromWebUI DISABLED_BackFromWebUI 1384#else 1385#define MAYBE_BackFromWebUI BackFromWebUI 1386#endif 1387IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) { 1388 ASSERT_TRUE(test_server()->Start()); 1389 GURL original_url(test_server()->GetURL("files/title2.html")); 1390 NavigateToURL(shell(), original_url); 1391 1392 // Visit a WebUI page with bindings. 1393 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" + 1394 std::string(kChromeUIGpuHost))); 1395 NavigateToURL(shell(), webui_url); 1396 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1397 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1398 1399 // Go back and ensure we have no WebUI bindings. 1400 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); 1401 shell()->web_contents()->GetController().GoBack(); 1402 back_nav_load_observer.Wait(); 1403 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL()); 1404 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1405 shell()->web_contents()->GetRenderProcessHost()->GetID())); 1406} 1407 1408} // namespace content 1409