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