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.
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "content/browser/child_process_security_policy_impl.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/site_instance_impl.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/browser/webui/web_ui_impl.h"
17 #include "content/common/content_constants_internal.h"
18 #include "content/public/browser/navigation_controller.h"
19 #include "content/public/browser/navigation_entry.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_observer.h"
23 #include "content/public/common/bindings_policy.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/content_browser_test.h"
28 #include "content/public/test/content_browser_test_utils.h"
29 #include "content/public/test/test_navigation_observer.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "net/base/net_util.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "net/test/spawned_test_server/spawned_test_server.h"
36 using base::ASCIIToUTF16;
42 const char kOpenUrlViaClickTargetFunc[] =
44 " var lnk = document.createElement(\"a\");\n"
46 " lnk.target = \"_blank\";\n"
47 " document.body.appendChild(lnk);\n"
51 // Adds a link with given url and target=_blank, and clicks on it.
52 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter,
54 EXPECT_TRUE(ExecuteScript(adapter,
55 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
58 } // anonymous namespace
60 class RenderFrameHostManagerTest : public ContentBrowserTest {
62 RenderFrameHostManagerTest() : foo_com_("foo.com") {
63 replace_host_.SetHostStr(foo_com_);
66 static bool GetFilePathWithHostAndPortReplacement(
67 const std::string& original_file_path,
68 const net::HostPortPair& host_port_pair,
69 std::string* replacement_path) {
70 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
71 replacement_text.push_back(
72 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
73 return net::SpawnedTestServer::GetFilePathWithReplacements(
74 original_file_path, replacement_text, replacement_path);
78 // Support multiple sites on the test server.
79 host_resolver()->AddRule("*", "127.0.0.1");
80 ASSERT_TRUE(test_server()->Start());
82 foo_host_port_ = test_server()->host_port_pair();
83 foo_host_port_.set_host(foo_com_);
86 // Returns a URL on foo.com with the given path.
87 GURL GetCrossSiteURL(const std::string& path) {
88 GURL cross_site_url(test_server()->GetURL(path));
89 return cross_site_url.ReplaceComponents(replace_host_);
94 GURL::Replacements replace_host_;
95 net::HostPortPair foo_host_port_;
98 // Web pages should not have script access to the swapped out page.
99 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
102 // Load a page with links that open in a new window.
103 std::string replacement_path;
104 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
105 "files/click-noreferrer-links.html",
108 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
110 // Get the original SiteInstance for later comparison.
111 scoped_refptr<SiteInstance> orig_site_instance(
112 shell()->web_contents()->GetSiteInstance());
113 EXPECT_TRUE(orig_site_instance.get() != NULL);
115 // Open a same-site link in a new window.
116 ShellAddedObserver new_shell_observer;
117 bool success = false;
118 EXPECT_TRUE(ExecuteScriptAndExtractBool(
119 shell()->web_contents(),
120 "window.domAutomationController.send(clickSameSiteTargetedLink());",
122 EXPECT_TRUE(success);
123 Shell* new_shell = new_shell_observer.GetShell();
125 // Wait for the navigation in the new window to finish, if it hasn't.
126 WaitForLoadStop(new_shell->web_contents());
127 EXPECT_EQ("/files/navigate_opener.html",
128 new_shell->web_contents()->GetLastCommittedURL().path());
130 // Should have the same SiteInstance.
131 scoped_refptr<SiteInstance> blank_site_instance(
132 new_shell->web_contents()->GetSiteInstance());
133 EXPECT_EQ(orig_site_instance, blank_site_instance);
135 // We should have access to the opened window's location.
137 EXPECT_TRUE(ExecuteScriptAndExtractBool(
138 shell()->web_contents(),
139 "window.domAutomationController.send(testScriptAccessToWindow());",
141 EXPECT_TRUE(success);
143 // Now navigate the new window to a different site.
144 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
145 scoped_refptr<SiteInstance> new_site_instance(
146 new_shell->web_contents()->GetSiteInstance());
147 EXPECT_NE(orig_site_instance, new_site_instance);
149 // We should no longer have script access to the opened window's location.
151 EXPECT_TRUE(ExecuteScriptAndExtractBool(
152 shell()->web_contents(),
153 "window.domAutomationController.send(testScriptAccessToWindow());",
155 EXPECT_FALSE(success);
158 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
159 // and target=_blank should create a new SiteInstance.
160 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
161 SwapProcessWithRelNoreferrerAndTargetBlank) {
164 // Load a page with links that open in a new window.
165 std::string replacement_path;
166 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
167 "files/click-noreferrer-links.html",
170 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
172 // Get the original SiteInstance for later comparison.
173 scoped_refptr<SiteInstance> orig_site_instance(
174 shell()->web_contents()->GetSiteInstance());
175 EXPECT_TRUE(orig_site_instance.get() != NULL);
177 // Test clicking a rel=noreferrer + target=blank link.
178 ShellAddedObserver new_shell_observer;
179 bool success = false;
180 EXPECT_TRUE(ExecuteScriptAndExtractBool(
181 shell()->web_contents(),
182 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
184 EXPECT_TRUE(success);
186 // Wait for the window to open.
187 Shell* new_shell = new_shell_observer.GetShell();
189 EXPECT_EQ("/files/title2.html",
190 new_shell->web_contents()->GetVisibleURL().path());
192 // Wait for the cross-site transition in the new tab to finish.
193 WaitForLoadStop(new_shell->web_contents());
194 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
195 new_shell->web_contents());
196 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
197 pending_render_view_host());
199 // Should have a new SiteInstance.
200 scoped_refptr<SiteInstance> noref_blank_site_instance(
201 new_shell->web_contents()->GetSiteInstance());
202 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
205 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
206 // for rel=noreferrer links in new windows, even to same site pages and named
208 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
209 SwapProcessWithSameSiteRelNoreferrer) {
212 // Load a page with links that open in a new window.
213 std::string replacement_path;
214 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
215 "files/click-noreferrer-links.html",
218 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
220 // Get the original SiteInstance for later comparison.
221 scoped_refptr<SiteInstance> orig_site_instance(
222 shell()->web_contents()->GetSiteInstance());
223 EXPECT_TRUE(orig_site_instance.get() != NULL);
225 // Test clicking a same-site rel=noreferrer + target=foo link.
226 ShellAddedObserver new_shell_observer;
227 bool success = false;
228 EXPECT_TRUE(ExecuteScriptAndExtractBool(
229 shell()->web_contents(),
230 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
232 EXPECT_TRUE(success);
234 // Wait for the window to open.
235 Shell* new_shell = new_shell_observer.GetShell();
237 // Opens in new window.
238 EXPECT_EQ("/files/title2.html",
239 new_shell->web_contents()->GetVisibleURL().path());
241 // Wait for the cross-site transition in the new tab to finish.
242 WaitForLoadStop(new_shell->web_contents());
243 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
244 new_shell->web_contents());
245 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
246 pending_render_view_host());
248 // Should have a new SiteInstance (in a new BrowsingInstance).
249 scoped_refptr<SiteInstance> noref_blank_site_instance(
250 new_shell->web_contents()->GetSiteInstance());
251 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
254 // Test for crbug.com/24447. Following a cross-site link with just
255 // target=_blank should not create a new SiteInstance, unless we
256 // are running in --site-per-process mode.
257 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
258 DontSwapProcessWithOnlyTargetBlank) {
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",
267 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
281 EXPECT_TRUE(success);
283 // Wait for the window to open.
284 Shell* new_shell = new_shell_observer.GetShell();
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());
291 // Should have the same SiteInstance unless we're in site-per-process mode.
292 scoped_refptr<SiteInstance> blank_site_instance(
293 new_shell->web_contents()->GetSiteInstance());
294 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
295 switches::kSitePerProcess))
296 EXPECT_EQ(orig_site_instance, blank_site_instance);
298 EXPECT_NE(orig_site_instance, blank_site_instance);
301 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
302 // and no target=_blank should not create a new SiteInstance.
303 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
304 DontSwapProcessWithOnlyRelNoreferrer) {
307 // Load a page with links that open in a new window.
308 std::string replacement_path;
309 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
310 "files/click-noreferrer-links.html",
313 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
315 // Get the original SiteInstance for later comparison.
316 scoped_refptr<SiteInstance> orig_site_instance(
317 shell()->web_contents()->GetSiteInstance());
318 EXPECT_TRUE(orig_site_instance.get() != NULL);
320 // Test clicking a rel=noreferrer link.
321 bool success = false;
322 EXPECT_TRUE(ExecuteScriptAndExtractBool(
323 shell()->web_contents(),
324 "window.domAutomationController.send(clickNoRefLink());",
326 EXPECT_TRUE(success);
328 // Wait for the cross-site transition in the current tab to finish.
329 WaitForLoadStop(shell()->web_contents());
331 // Opens in same window.
332 EXPECT_EQ(1u, Shell::windows().size());
333 EXPECT_EQ("/files/title2.html",
334 shell()->web_contents()->GetLastCommittedURL().path());
336 // Should have the same SiteInstance unless we're in site-per-process mode.
337 scoped_refptr<SiteInstance> noref_site_instance(
338 shell()->web_contents()->GetSiteInstance());
339 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
340 switches::kSitePerProcess))
341 EXPECT_EQ(orig_site_instance, noref_site_instance);
343 EXPECT_NE(orig_site_instance, noref_site_instance);
346 // Test for crbug.com/116192. Targeted links should still work after the
347 // named target window has swapped processes.
348 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
349 AllowTargetedNavigationsAfterSwap) {
352 // Load a page with links that open in a new window.
353 std::string replacement_path;
354 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
355 "files/click-noreferrer-links.html",
358 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
360 // Get the original SiteInstance for later comparison.
361 scoped_refptr<SiteInstance> orig_site_instance(
362 shell()->web_contents()->GetSiteInstance());
363 EXPECT_TRUE(orig_site_instance.get() != NULL);
365 // Test clicking a target=foo link.
366 ShellAddedObserver new_shell_observer;
367 bool success = false;
368 EXPECT_TRUE(ExecuteScriptAndExtractBool(
369 shell()->web_contents(),
370 "window.domAutomationController.send(clickSameSiteTargetedLink());",
372 EXPECT_TRUE(success);
373 Shell* new_shell = new_shell_observer.GetShell();
375 // Wait for the navigation in the new tab to finish, if it hasn't.
376 WaitForLoadStop(new_shell->web_contents());
377 EXPECT_EQ("/files/navigate_opener.html",
378 new_shell->web_contents()->GetLastCommittedURL().path());
380 // Should have the same SiteInstance.
381 scoped_refptr<SiteInstance> blank_site_instance(
382 new_shell->web_contents()->GetSiteInstance());
383 EXPECT_EQ(orig_site_instance, blank_site_instance);
385 // Now navigate the new tab to a different site.
386 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
387 NavigateToURL(new_shell, cross_site_url);
388 scoped_refptr<SiteInstance> new_site_instance(
389 new_shell->web_contents()->GetSiteInstance());
390 EXPECT_NE(orig_site_instance, new_site_instance);
392 // Clicking the original link in the first tab should cause us to swap back.
393 TestNavigationObserver navigation_observer(new_shell->web_contents());
394 EXPECT_TRUE(ExecuteScriptAndExtractBool(
395 shell()->web_contents(),
396 "window.domAutomationController.send(clickSameSiteTargetedLink());",
398 EXPECT_TRUE(success);
399 navigation_observer.Wait();
401 // Should have swapped back and shown the new window again.
402 scoped_refptr<SiteInstance> revisit_site_instance(
403 new_shell->web_contents()->GetSiteInstance());
404 EXPECT_EQ(orig_site_instance, revisit_site_instance);
406 // If it navigates away to another process, the original window should
407 // still be able to close it (using a cross-process close message).
408 NavigateToURL(new_shell, cross_site_url);
409 EXPECT_EQ(new_site_instance.get(),
410 new_shell->web_contents()->GetSiteInstance());
411 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
412 EXPECT_TRUE(ExecuteScriptAndExtractBool(
413 shell()->web_contents(),
414 "window.domAutomationController.send(testCloseWindow());",
416 EXPECT_TRUE(success);
417 close_watcher.Wait();
420 // Test that setting the opener to null in a window affects cross-process
421 // navigations, including those to existing entries. http://crbug.com/156669.
422 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
423 #if defined(THREAD_SANITIZER)
424 #define MAYBE_DisownOpener DISABLED_DisownOpener
426 #define MAYBE_DisownOpener DisownOpener
428 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
431 // Load a page with links that open in a new window.
432 std::string replacement_path;
433 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
434 "files/click-noreferrer-links.html",
437 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
439 // Get the original SiteInstance for later comparison.
440 scoped_refptr<SiteInstance> orig_site_instance(
441 shell()->web_contents()->GetSiteInstance());
442 EXPECT_TRUE(orig_site_instance.get() != NULL);
444 // Test clicking a target=_blank link.
445 ShellAddedObserver new_shell_observer;
446 bool success = false;
447 EXPECT_TRUE(ExecuteScriptAndExtractBool(
448 shell()->web_contents(),
449 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
451 EXPECT_TRUE(success);
452 Shell* new_shell = new_shell_observer.GetShell();
453 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
455 // Wait for the navigation in the new tab to finish, if it hasn't.
456 WaitForLoadStop(new_shell->web_contents());
457 EXPECT_EQ("/files/title2.html",
458 new_shell->web_contents()->GetLastCommittedURL().path());
460 // Should have the same SiteInstance.
461 scoped_refptr<SiteInstance> blank_site_instance(
462 new_shell->web_contents()->GetSiteInstance());
463 EXPECT_EQ(orig_site_instance, blank_site_instance);
465 // Now navigate the new tab to a different site.
466 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
467 scoped_refptr<SiteInstance> new_site_instance(
468 new_shell->web_contents()->GetSiteInstance());
469 EXPECT_NE(orig_site_instance, new_site_instance);
470 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
472 // Now disown the opener.
473 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
474 "window.opener = null;"));
475 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
477 // Go back and ensure the opener is still null.
479 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
480 new_shell->web_contents()->GetController().GoBack();
481 back_nav_load_observer.Wait();
484 EXPECT_TRUE(ExecuteScriptAndExtractBool(
485 new_shell->web_contents(),
486 "window.domAutomationController.send(window.opener == null);",
488 EXPECT_TRUE(success);
489 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
491 // Now navigate forward again (creating a new process) and check opener.
492 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
494 EXPECT_TRUE(ExecuteScriptAndExtractBool(
495 new_shell->web_contents(),
496 "window.domAutomationController.send(window.opener == null);",
498 EXPECT_TRUE(success);
499 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
502 // Test that subframes can disown their openers. http://crbug.com/225528.
503 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
504 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
505 NavigateToURL(shell(), frame_url);
507 // Give the frame an opener using window.open.
508 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
509 "window.open('about:blank','foo');"));
511 // Now disown the frame's opener. Shouldn't crash.
512 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
513 "window.frames[0].opener = null;"));
516 // Test for crbug.com/99202. PostMessage calls should still work after
517 // navigating the source and target windows to different sites.
519 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
520 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
521 // 3) Post a message from "foo" to opener, which replies back to "foo".
522 // 4) Post a message from _blank to "foo".
523 // 5) Post a message from "foo" to a subframe of opener, which replies back.
524 // 6) Post a message from _blank to a subframe of "foo".
525 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
526 SupportCrossProcessPostMessage) {
529 // Load a page with links that open in a new window.
530 std::string replacement_path;
531 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
532 "files/click-noreferrer-links.html",
535 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
537 // Get the original SiteInstance and RVHM for later comparison.
538 WebContents* opener_contents = shell()->web_contents();
539 scoped_refptr<SiteInstance> orig_site_instance(
540 opener_contents->GetSiteInstance());
541 EXPECT_TRUE(orig_site_instance.get() != NULL);
542 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
543 opener_contents)->GetRenderManagerForTesting();
545 // 1) Open two more windows, one named. These initially have openers but no
546 // reference to each other. We will later post a message between them.
548 // First, a named target=foo window.
549 ShellAddedObserver new_shell_observer;
550 bool success = false;
551 EXPECT_TRUE(ExecuteScriptAndExtractBool(
553 "window.domAutomationController.send(clickSameSiteTargetedLink());",
555 EXPECT_TRUE(success);
556 Shell* new_shell = new_shell_observer.GetShell();
558 // Wait for the navigation in the new window to finish, if it hasn't, then
559 // send it to post_message.html on a different site.
560 WebContents* foo_contents = new_shell->web_contents();
561 WaitForLoadStop(foo_contents);
562 EXPECT_EQ("/files/navigate_opener.html",
563 foo_contents->GetLastCommittedURL().path());
564 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
565 scoped_refptr<SiteInstance> foo_site_instance(
566 foo_contents->GetSiteInstance());
567 EXPECT_NE(orig_site_instance, foo_site_instance);
569 // Second, a target=_blank window.
570 ShellAddedObserver new_shell_observer2;
571 EXPECT_TRUE(ExecuteScriptAndExtractBool(
572 shell()->web_contents(),
573 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
575 EXPECT_TRUE(success);
577 // Wait for the navigation in the new window to finish, if it hasn't, then
578 // send it to post_message.html on the original site.
579 Shell* new_shell2 = new_shell_observer2.GetShell();
580 WebContents* new_contents = new_shell2->web_contents();
581 WaitForLoadStop(new_contents);
582 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
583 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
584 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
585 RenderFrameHostManager* new_manager =
586 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
588 // We now have three windows. The opener should have a swapped out RVH
589 // for the new SiteInstance, but the _blank window should not.
590 EXPECT_EQ(3u, Shell::windows().size());
592 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
594 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
596 // 2) Fail to post a message from the foo window to the opener if the target
597 // origin is wrong. We won't see an error, but we can check for the right
598 // number of received messages below.
599 EXPECT_TRUE(ExecuteScriptAndExtractBool(
601 "window.domAutomationController.send(postToOpener('msg',"
602 " 'http://google.com'));",
604 EXPECT_TRUE(success);
606 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
608 // 3) Post a message from the foo window to the opener. The opener will
609 // reply, causing the foo window to update its own title.
610 base::string16 expected_title = ASCIIToUTF16("msg");
611 TitleWatcher title_watcher(foo_contents, expected_title);
612 EXPECT_TRUE(ExecuteScriptAndExtractBool(
614 "window.domAutomationController.send(postToOpener('msg','*'));",
616 EXPECT_TRUE(success);
618 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
619 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
621 // We should have received only 1 message in the opener and "foo" tabs,
622 // and updated the title.
623 int opener_received_messages = 0;
624 EXPECT_TRUE(ExecuteScriptAndExtractInt(
626 "window.domAutomationController.send(window.receivedMessages);",
627 &opener_received_messages));
628 int foo_received_messages = 0;
629 EXPECT_TRUE(ExecuteScriptAndExtractInt(
631 "window.domAutomationController.send(window.receivedMessages);",
632 &foo_received_messages));
633 EXPECT_EQ(1, foo_received_messages);
634 EXPECT_EQ(1, opener_received_messages);
635 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
637 // 4) Now post a message from the _blank window to the foo window. The
638 // foo window will update its title and will not reply.
639 expected_title = ASCIIToUTF16("msg2");
640 TitleWatcher title_watcher2(foo_contents, expected_title);
641 EXPECT_TRUE(ExecuteScriptAndExtractBool(
643 "window.domAutomationController.send(postToFoo('msg2'));",
645 EXPECT_TRUE(success);
646 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
648 // This postMessage should have created a swapped out RVH for the new
649 // SiteInstance in the target=_blank window.
651 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
653 // TODO(nasko): Test subframe targeting of postMessage once
654 // http://crbug.com/153701 is fixed.
657 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
658 // messages which contain Transferables and get intercepted by
659 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
660 // swapped out) should work.
662 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
663 // 2) Post a message containing a message port from opener to "foo".
664 // 3) Post a message from "foo" back to opener via the passed message port.
665 // The test will be enabled when the feature implementation lands.
666 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
667 SupportCrossProcessPostMessageWithMessagePort) {
670 // Load a page with links that open in a new window.
671 std::string replacement_path;
672 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
673 "files/click-noreferrer-links.html",
676 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
678 // Get the original SiteInstance and RVHM for later comparison.
679 WebContents* opener_contents = shell()->web_contents();
680 scoped_refptr<SiteInstance> orig_site_instance(
681 opener_contents->GetSiteInstance());
682 EXPECT_TRUE(orig_site_instance.get() != NULL);
683 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
684 opener_contents)->GetRenderManagerForTesting();
686 // 1) Open a named target=foo window. We will later post a message between the
687 // opener and the new window.
688 ShellAddedObserver new_shell_observer;
689 bool success = false;
690 EXPECT_TRUE(ExecuteScriptAndExtractBool(
692 "window.domAutomationController.send(clickSameSiteTargetedLink());",
694 EXPECT_TRUE(success);
695 Shell* new_shell = new_shell_observer.GetShell();
697 // Wait for the navigation in the new window to finish, if it hasn't, then
698 // send it to post_message.html on a different site.
699 WebContents* foo_contents = new_shell->web_contents();
700 WaitForLoadStop(foo_contents);
701 EXPECT_EQ("/files/navigate_opener.html",
702 foo_contents->GetLastCommittedURL().path());
703 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
704 scoped_refptr<SiteInstance> foo_site_instance(
705 foo_contents->GetSiteInstance());
706 EXPECT_NE(orig_site_instance, foo_site_instance);
708 // We now have two windows. The opener should have a swapped out RVH
709 // for the new SiteInstance.
710 EXPECT_EQ(2u, Shell::windows().size());
712 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
714 // 2) Post a message containing a MessagePort from opener to the the foo
715 // window. The foo window will reply via the passed port, causing the opener
716 // to update its own title.
717 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
718 TitleWatcher title_observer(opener_contents, expected_title);
719 EXPECT_TRUE(ExecuteScriptAndExtractBool(
721 "window.domAutomationController.send(postWithPortToFoo());",
723 EXPECT_TRUE(success);
725 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
726 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
728 // Check message counts.
729 int opener_received_messages_via_port = 0;
730 EXPECT_TRUE(ExecuteScriptAndExtractInt(
732 "window.domAutomationController.send(window.receivedMessagesViaPort);",
733 &opener_received_messages_via_port));
734 int foo_received_messages = 0;
735 EXPECT_TRUE(ExecuteScriptAndExtractInt(
737 "window.domAutomationController.send(window.receivedMessages);",
738 &foo_received_messages));
739 int foo_received_messages_with_port = 0;
740 EXPECT_TRUE(ExecuteScriptAndExtractInt(
742 "window.domAutomationController.send(window.receivedMessagesWithPort);",
743 &foo_received_messages_with_port));
744 EXPECT_EQ(1, foo_received_messages);
745 EXPECT_EQ(1, foo_received_messages_with_port);
746 EXPECT_EQ(1, opener_received_messages_via_port);
747 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
748 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
751 // Test for crbug.com/116192. Navigations to a window's opener should
752 // still work after a process swap.
753 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
754 AllowTargetedNavigationsInOpenerAfterSwap) {
757 // Load a page with links that open in a new window.
758 std::string replacement_path;
759 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
760 "files/click-noreferrer-links.html",
763 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
765 // Get the original tab and SiteInstance for later comparison.
766 WebContents* orig_contents = shell()->web_contents();
767 scoped_refptr<SiteInstance> orig_site_instance(
768 orig_contents->GetSiteInstance());
769 EXPECT_TRUE(orig_site_instance.get() != NULL);
771 // Test clicking a target=foo link.
772 ShellAddedObserver new_shell_observer;
773 bool success = false;
774 EXPECT_TRUE(ExecuteScriptAndExtractBool(
776 "window.domAutomationController.send(clickSameSiteTargetedLink());",
778 EXPECT_TRUE(success);
779 Shell* new_shell = new_shell_observer.GetShell();
781 // Wait for the navigation in the new window to finish, if it hasn't.
782 WaitForLoadStop(new_shell->web_contents());
783 EXPECT_EQ("/files/navigate_opener.html",
784 new_shell->web_contents()->GetLastCommittedURL().path());
786 // Should have the same SiteInstance.
787 scoped_refptr<SiteInstance> blank_site_instance(
788 new_shell->web_contents()->GetSiteInstance());
789 EXPECT_EQ(orig_site_instance, blank_site_instance);
791 // Now navigate the original (opener) tab to a different site.
792 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
793 scoped_refptr<SiteInstance> new_site_instance(
794 shell()->web_contents()->GetSiteInstance());
795 EXPECT_NE(orig_site_instance, new_site_instance);
797 // The opened tab should be able to navigate the opener back to its process.
798 TestNavigationObserver navigation_observer(orig_contents);
799 EXPECT_TRUE(ExecuteScriptAndExtractBool(
800 new_shell->web_contents(),
801 "window.domAutomationController.send(navigateOpener());",
803 EXPECT_TRUE(success);
804 navigation_observer.Wait();
806 // Should have swapped back into this process.
807 scoped_refptr<SiteInstance> revisit_site_instance(
808 shell()->web_contents()->GetSiteInstance());
809 EXPECT_EQ(orig_site_instance, revisit_site_instance);
812 // Test that opening a new window in the same SiteInstance and then navigating
813 // both windows to a different SiteInstance allows the first process to exit.
814 // See http://crbug.com/126333.
815 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
816 ProcessExitWithSwappedOutViews) {
819 // Load a page with links that open in a new window.
820 std::string replacement_path;
821 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
822 "files/click-noreferrer-links.html",
825 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
827 // Get the original SiteInstance for later comparison.
828 scoped_refptr<SiteInstance> orig_site_instance(
829 shell()->web_contents()->GetSiteInstance());
830 EXPECT_TRUE(orig_site_instance.get() != NULL);
832 // Test clicking a target=foo link.
833 ShellAddedObserver new_shell_observer;
834 bool success = false;
835 EXPECT_TRUE(ExecuteScriptAndExtractBool(
836 shell()->web_contents(),
837 "window.domAutomationController.send(clickSameSiteTargetedLink());",
839 EXPECT_TRUE(success);
840 Shell* new_shell = new_shell_observer.GetShell();
842 // Wait for the navigation in the new window to finish, if it hasn't.
843 WaitForLoadStop(new_shell->web_contents());
844 EXPECT_EQ("/files/navigate_opener.html",
845 new_shell->web_contents()->GetLastCommittedURL().path());
847 // Should have the same SiteInstance.
848 scoped_refptr<SiteInstance> opened_site_instance(
849 new_shell->web_contents()->GetSiteInstance());
850 EXPECT_EQ(orig_site_instance, opened_site_instance);
852 // Now navigate the opened window to a different site.
853 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
854 scoped_refptr<SiteInstance> new_site_instance(
855 new_shell->web_contents()->GetSiteInstance());
856 EXPECT_NE(orig_site_instance, new_site_instance);
858 // The original process should still be alive, since it is still used in the
860 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
861 EXPECT_TRUE(orig_process->HasConnection());
863 // Navigate the first window to a different site as well. The original
864 // process should exit, since all of its views are now swapped out.
865 RenderProcessHostWatcher exit_observer(
867 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
868 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
869 exit_observer.Wait();
870 scoped_refptr<SiteInstance> new_site_instance2(
871 shell()->web_contents()->GetSiteInstance());
872 EXPECT_EQ(new_site_instance, new_site_instance2);
875 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
876 // error should not make us ignore future renderer-initiated navigations.
877 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
880 // Get the original SiteInstance for later comparison.
881 scoped_refptr<SiteInstance> orig_site_instance(
882 shell()->web_contents()->GetSiteInstance());
883 EXPECT_TRUE(orig_site_instance.get() != NULL);
885 // Load a cross-site page that fails with a 204 error.
886 NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
888 // We should still be looking at the normal page. Because we started from a
889 // blank new tab, the typed URL will still be visible until the user clears it
890 // manually. The last committed URL will be the previous page.
891 scoped_refptr<SiteInstance> post_nav_site_instance(
892 shell()->web_contents()->GetSiteInstance());
893 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
894 EXPECT_EQ("/nocontent",
895 shell()->web_contents()->GetVisibleURL().path());
897 shell()->web_contents()->GetController().GetLastCommittedEntry());
899 // Renderer-initiated navigations should work.
900 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
901 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
902 GURL url = test_server()->GetURL("files/title2.html");
903 EXPECT_TRUE(ExecuteScript(
904 shell()->web_contents(),
905 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
906 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
908 // Opens in same tab.
909 EXPECT_EQ(1u, Shell::windows().size());
910 EXPECT_EQ("/files/title2.html",
911 shell()->web_contents()->GetLastCommittedURL().path());
913 // Should have the same SiteInstance.
914 scoped_refptr<SiteInstance> new_site_instance(
915 shell()->web_contents()->GetSiteInstance());
916 EXPECT_EQ(orig_site_instance, new_site_instance);
919 // Test for crbug.com/9682. We should show the URL for a pending renderer-
920 // initiated navigation in a new tab, until the content of the initial
921 // about:blank page is modified by another window. At that point, we should
922 // revert to showing about:blank to prevent a URL spoof.
923 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
924 ASSERT_TRUE(test_server()->Start());
926 // Load a page that can open a URL that won't commit in a new window.
928 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
929 WebContents* orig_contents = shell()->web_contents();
931 // Click a /nocontent link that opens in a new window but never commits.
932 ShellAddedObserver new_shell_observer;
933 bool success = false;
934 EXPECT_TRUE(ExecuteScriptAndExtractBool(
936 "window.domAutomationController.send(clickNoContentTargetedLink());",
938 EXPECT_TRUE(success);
940 // Wait for the window to open.
941 Shell* new_shell = new_shell_observer.GetShell();
943 // Ensure the destination URL is visible, because it is considered the
944 // initial navigation.
945 WebContents* contents = new_shell->web_contents();
946 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
947 EXPECT_EQ("/nocontent",
948 contents->GetController().GetVisibleEntry()->GetURL().path());
950 // Now modify the contents of the new window from the opener. This will also
951 // modify the title of the document to give us something to listen for.
952 base::string16 expected_title = ASCIIToUTF16("Modified Title");
953 TitleWatcher title_watcher(contents, expected_title);
955 EXPECT_TRUE(ExecuteScriptAndExtractBool(
957 "window.domAutomationController.send(modifyNewWindow());",
959 EXPECT_TRUE(success);
960 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
962 // At this point, we should no longer be showing the destination URL.
963 // The visible entry should be null, resulting in about:blank in the address
965 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
968 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
969 // initiated navigation in a new tab if it is not the initial navigation. In
970 // this case, the renderer will not notify us of a modification, so we cannot
971 // show the pending URL without allowing a spoof.
972 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
973 DontShowLoadingURLIfNotInitialNav) {
974 ASSERT_TRUE(test_server()->Start());
976 // Load a page that can open a URL that won't commit in a new window.
978 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
979 WebContents* orig_contents = shell()->web_contents();
981 // Click a /nocontent link that opens in a new window but never commits.
982 // By using an onclick handler that first creates the window, the slow
983 // navigation is not considered an initial navigation.
984 ShellAddedObserver new_shell_observer;
985 bool success = false;
986 EXPECT_TRUE(ExecuteScriptAndExtractBool(
988 "window.domAutomationController.send("
989 "clickNoContentScriptedTargetedLink());",
991 EXPECT_TRUE(success);
993 // Wait for the window to open.
994 Shell* new_shell = new_shell_observer.GetShell();
996 // Ensure the destination URL is not visible, because it is not the initial
998 WebContents* contents = new_shell->web_contents();
999 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1000 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1003 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1004 #if defined(THREAD_SANITIZER)
1005 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1007 #define MAYBE_BackForwardNotStale BackForwardNotStale
1009 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1010 // do not cause back/forward navigations to be considered stale by the
1012 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1014 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1016 // Visit a page on first site.
1017 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1019 // Visit three pages on second site.
1020 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1021 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1022 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1024 // History is now [blank, A1, B1, B2, *B3].
1025 WebContents* contents = shell()->web_contents();
1026 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1028 // Open another window in same process to keep this process alive.
1029 Shell* new_shell = CreateBrowser();
1030 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1032 // Go back three times to first site.
1034 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1035 shell()->web_contents()->GetController().GoBack();
1036 back_nav_load_observer.Wait();
1039 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1040 shell()->web_contents()->GetController().GoBack();
1041 back_nav_load_observer.Wait();
1044 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1045 shell()->web_contents()->GetController().GoBack();
1046 back_nav_load_observer.Wait();
1049 // Now go forward twice to B2. Shouldn't be left spinning.
1051 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1052 shell()->web_contents()->GetController().GoForward();
1053 forward_nav_load_observer.Wait();
1056 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1057 shell()->web_contents()->GetController().GoForward();
1058 forward_nav_load_observer.Wait();
1061 // Go back twice to first site.
1063 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1064 shell()->web_contents()->GetController().GoBack();
1065 back_nav_load_observer.Wait();
1068 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1069 shell()->web_contents()->GetController().GoBack();
1070 back_nav_load_observer.Wait();
1073 // Now go forward directly to B3. Shouldn't be left spinning.
1075 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1076 shell()->web_contents()->GetController().GoToIndex(4);
1077 forward_nav_load_observer.Wait();
1081 // Test for http://crbug.com/130016.
1082 // Swapping out a render view should update its visiblity state.
1083 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1084 SwappedOutViewHasCorrectVisibilityState) {
1087 // Load a page with links that open in a new window.
1088 std::string replacement_path;
1089 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1090 "files/click-noreferrer-links.html",
1092 &replacement_path));
1093 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1095 // Open a same-site link in a new widnow.
1096 ShellAddedObserver new_shell_observer;
1097 bool success = false;
1098 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1099 shell()->web_contents(),
1100 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1102 EXPECT_TRUE(success);
1103 Shell* new_shell = new_shell_observer.GetShell();
1105 // Wait for the navigation in the new tab to finish, if it hasn't.
1106 WaitForLoadStop(new_shell->web_contents());
1107 EXPECT_EQ("/files/navigate_opener.html",
1108 new_shell->web_contents()->GetLastCommittedURL().path());
1110 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1112 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1114 "window.domAutomationController.send("
1115 " document.visibilityState == 'visible');",
1117 EXPECT_TRUE(success);
1119 // Now navigate the new window to a different site. This should swap out the
1120 // tab's existing RenderView, causing it become hidden.
1121 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1123 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1125 "window.domAutomationController.send("
1126 " document.visibilityState == 'hidden');",
1128 EXPECT_TRUE(success);
1130 // Going back should make the previously swapped-out view to become visible
1133 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1134 new_shell->web_contents()->GetController().GoBack();
1135 back_nav_load_observer.Wait();
1138 EXPECT_EQ("/files/navigate_opener.html",
1139 new_shell->web_contents()->GetLastCommittedURL().path());
1141 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1143 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1145 "window.domAutomationController.send("
1146 " document.visibilityState == 'visible');",
1148 EXPECT_TRUE(success);
1151 // This class ensures that all the given RenderViewHosts have properly been
1153 class RenderViewHostDestructionObserver : public WebContentsObserver {
1155 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1156 : WebContentsObserver(web_contents) {}
1157 ~RenderViewHostDestructionObserver() override {}
1158 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1159 watched_render_view_hosts_.insert(rvh);
1161 size_t GetNumberOfWatchedRenderViewHosts() const {
1162 return watched_render_view_hosts_.size();
1166 // WebContentsObserver implementation:
1167 void RenderViewDeleted(RenderViewHost* rvh) override {
1168 watched_render_view_hosts_.erase(rvh);
1171 std::set<RenderViewHost*> watched_render_view_hosts_;
1174 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1175 #if defined(THREAD_SANITIZER)
1176 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1178 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1180 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1181 // they may cause crashes or memory corruptions when trying to call dead
1182 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1183 // ensure that a separate SiteInstance is created when navigating to view-source
1184 // URLs, regardless of current URL.
1185 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1186 MAYBE_LeakingRenderViewHosts) {
1189 // Observe the created render_view_host's to make sure they will not leak.
1190 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1192 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1193 GURL view_source_url(kViewSourceScheme + std::string(":") +
1194 navigated_url.spec());
1196 // Let's ensure that when we start with a blank window, navigating away to a
1197 // view-source URL, we create a new SiteInstance.
1198 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1199 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1200 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1201 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1202 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1204 // Now navigate to the view-source URL and ensure we got a different
1205 // SiteInstance and RenderViewHost.
1206 NavigateToURL(shell(), view_source_url);
1207 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1208 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1209 GetRenderViewHost()->GetSiteInstance());
1210 rvh_observers.EnsureRVHGetsDestructed(
1211 shell()->web_contents()->GetRenderViewHost());
1213 // Load a random page and then navigate to view-source: of it.
1214 // This used to cause two RVH instances for the same SiteInstance, which
1215 // was a problem. This is no longer the case.
1216 NavigateToURL(shell(), navigated_url);
1217 SiteInstance* site_instance1 = shell()->web_contents()->
1218 GetRenderViewHost()->GetSiteInstance();
1219 rvh_observers.EnsureRVHGetsDestructed(
1220 shell()->web_contents()->GetRenderViewHost());
1222 NavigateToURL(shell(), view_source_url);
1223 rvh_observers.EnsureRVHGetsDestructed(
1224 shell()->web_contents()->GetRenderViewHost());
1225 SiteInstance* site_instance2 = shell()->web_contents()->
1226 GetRenderViewHost()->GetSiteInstance();
1228 // Ensure that view-source navigations force a new SiteInstance.
1229 EXPECT_NE(site_instance1, site_instance2);
1231 // Now navigate to a different instance so that we swap out again.
1232 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1233 rvh_observers.EnsureRVHGetsDestructed(
1234 shell()->web_contents()->GetRenderViewHost());
1236 // This used to leak a render view host.
1239 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1241 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1244 // Test for crbug.com/143155. Frame tree updates during unload should not
1245 // interrupt the intended navigation and show swappedout:// instead.
1247 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1248 // 2) Send the second tab to a different foo.com SiteInstance.
1249 // This creates a swapped out opener for the first tab in the foo process.
1250 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1251 // tab's unload handler remove its frame.
1252 // This used to cause an update to the frame tree of the swapped out RV,
1253 // just as it was navigating to a real page. That pre-empted the real
1254 // navigation and visibly sent the tab to swappedout://.
1255 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1256 DontPreemptNavigationWithFrameTreeUpdate) {
1259 // 1. Load a page that deletes its iframe during unload.
1260 NavigateToURL(shell(),
1261 test_server()->GetURL("files/remove_frame_on_unload.html"));
1263 // Get the original SiteInstance for later comparison.
1264 scoped_refptr<SiteInstance> orig_site_instance(
1265 shell()->web_contents()->GetSiteInstance());
1267 // Open a same-site page in a new window.
1268 ShellAddedObserver new_shell_observer;
1269 bool success = false;
1270 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1271 shell()->web_contents(),
1272 "window.domAutomationController.send(openWindow());",
1274 EXPECT_TRUE(success);
1275 Shell* new_shell = new_shell_observer.GetShell();
1277 // Wait for the navigation in the new window to finish, if it hasn't.
1278 WaitForLoadStop(new_shell->web_contents());
1279 EXPECT_EQ("/files/title1.html",
1280 new_shell->web_contents()->GetLastCommittedURL().path());
1282 // Should have the same SiteInstance.
1283 EXPECT_EQ(orig_site_instance.get(),
1284 new_shell->web_contents()->GetSiteInstance());
1286 // 2. Send the second tab to a different process.
1287 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1288 scoped_refptr<SiteInstance> new_site_instance(
1289 new_shell->web_contents()->GetSiteInstance());
1290 EXPECT_NE(orig_site_instance, new_site_instance);
1292 // 3. Send the first tab to the second tab's process.
1293 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1295 // Make sure it ends up at the right page.
1296 WaitForLoadStop(shell()->web_contents());
1297 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1298 shell()->web_contents()->GetLastCommittedURL());
1299 EXPECT_EQ(new_site_instance.get(),
1300 shell()->web_contents()->GetSiteInstance());
1303 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1304 // are meant to run in the current page. We had a bug where we expected a
1305 // BrowsingInstance swap to occur on pages like view-source and extensions,
1306 // which broke chrome://crash and javascript: URLs.
1307 // See http://crbug.com/335503.
1308 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1309 ASSERT_TRUE(test_server()->Start());
1311 GURL original_url(test_server()->GetURL("files/title2.html"));
1312 GURL view_source_url(kViewSourceScheme + std::string(":") +
1313 original_url.spec());
1315 NavigateToURL(shell(), view_source_url);
1317 // Check that javascript: URLs work.
1318 base::string16 expected_title = ASCIIToUTF16("msg");
1319 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1320 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1321 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1323 // Crash the renderer of the view-source page.
1324 RenderProcessHostWatcher crash_observer(
1325 shell()->web_contents(),
1326 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1327 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1328 crash_observer.Wait();
1331 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1332 // Otherwise, we might try to load an unprivileged about:blank page into a
1333 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1334 // See http://crbug.com/334214.
1335 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1336 IgnoreRendererDebugURLsWhenCrashed) {
1337 // Visit a WebUI page with bindings.
1338 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1339 std::string(kChromeUIGpuHost));
1340 NavigateToURL(shell(), webui_url);
1341 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1342 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1344 // Crash the renderer of the WebUI page.
1345 RenderProcessHostWatcher crash_observer(
1346 shell()->web_contents(),
1347 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1348 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1349 crash_observer.Wait();
1351 // Load the crash URL again but don't wait for any action. If it is not
1352 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1353 shell()->LoadURL(GURL(kChromeUICrashURL));
1355 // Ensure that such URLs can still work as the initial navigation of a tab.
1356 // We postpone the initial navigation of the tab using an empty GURL, so that
1357 // we can add a watcher for crashes.
1358 Shell* shell2 = Shell::CreateNewWindow(
1359 shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1360 MSG_ROUTING_NONE, gfx::Size());
1361 RenderProcessHostWatcher crash_observer2(
1362 shell2->web_contents(),
1363 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1364 NavigateToURL(shell2, GURL(kChromeUIKillURL));
1365 crash_observer2.Wait();
1368 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1369 // See http://crbug.com/428329.
1370 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1371 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1373 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1375 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1376 // Otherwise it might get picked up by InitRenderView when granting bindings
1377 // to other RenderViewHosts. See http://crbug.com/330811.
1378 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1379 MAYBE_ClearPendingWebUIOnCommit) {
1380 // Visit a WebUI page with bindings.
1381 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1382 std::string(kChromeUIGpuHost)));
1383 NavigateToURL(shell(), webui_url);
1384 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1385 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1386 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1387 shell()->web_contents());
1388 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1390 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1392 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1393 // clear pending_web_ui() when it commits.
1394 GURL webui_url2(webui_url.spec() + "#foo");
1395 NavigateToURL(shell(), webui_url2);
1396 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1397 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1400 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1402 RFHMProcessPerTabTest() {}
1404 void SetUpCommandLine(CommandLine* command_line) override {
1405 command_line->AppendSwitch(switches::kProcessPerTab);
1409 // Test that we still swap processes for BrowsingInstance changes even in
1410 // --process-per-tab mode. See http://crbug.com/343017.
1411 // Disabled on Android: http://crbug.com/345873.
1412 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1413 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1414 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1416 #define MAYBE_BackFromWebUI BackFromWebUI
1418 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1419 ASSERT_TRUE(test_server()->Start());
1420 GURL original_url(test_server()->GetURL("files/title2.html"));
1421 NavigateToURL(shell(), original_url);
1423 // Visit a WebUI page with bindings.
1424 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1425 std::string(kChromeUIGpuHost)));
1426 NavigateToURL(shell(), webui_url);
1427 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1428 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1430 // Go back and ensure we have no WebUI bindings.
1431 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1432 shell()->web_contents()->GetController().GoBack();
1433 back_nav_load_observer.Wait();
1434 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1435 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1436 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1440 // The test loads url1, opens a link pointing to url2 in a new tab, and
1441 // navigates the new tab to url1.
1442 // The following is needed for the bug to happen:
1443 // - url1 must require webui bindings;
1444 // - navigating to url2 in the site instance of url1 should not swap
1445 // browsing instances, but should require a new site instance.
1446 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1447 GURL url1(std::string(kChromeUIScheme) + "://" +
1448 std::string(kChromeUIGpuHost));
1449 GURL url2(std::string(kChromeUIScheme) + "://" +
1450 std::string(kChromeUIAccessibilityHost));
1452 // Visit a WebUI page with bindings.
1453 NavigateToURL(shell(), url1);
1454 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1455 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1456 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1458 // Open a new tab. Initially it gets a render view in the original tab's
1459 // current site instance.
1460 TestNavigationObserver nav_observer(NULL);
1461 nav_observer.StartWatchingNewWebContents();
1462 ShellAddedObserver shao;
1463 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1464 nav_observer.Wait();
1465 Shell* new_shell = shao.GetShell();
1466 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1467 new_shell->web_contents());
1468 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1470 EXPECT_NE(site_instance2, site_instance1);
1471 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1472 RenderViewHost* initial_rvh = new_web_contents->
1473 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1474 ASSERT_TRUE(initial_rvh);
1475 // The following condition is what was causing the bug.
1476 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1478 // Navigate to url1 and check bindings.
1479 NavigateToURL(new_shell, url1);
1480 // The navigation should have used the first SiteInstance, otherwise
1481 // |initial_rvh| did not have a chance to be used.
1482 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1483 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1484 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1488 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1489 // page and then to a regular page. The bug reproduces if blank page is visited
1490 // in between WebUI and regular page.
1491 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1492 ForceSwapAfterWebUIBindings) {
1493 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kProcessPerTab);
1494 ASSERT_TRUE(test_server()->Start());
1496 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1497 std::string(kChromeUIGpuHost));
1498 NavigateToURL(shell(), web_ui_url);
1499 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1500 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1502 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1504 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1505 NavigateToURL(shell(), regular_page_url);
1506 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1507 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1510 } // namespace content