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