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/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"
37 using base::ASCIIToUTF16;
43 const char kOpenUrlViaClickTargetFunc[] =
45 " var lnk = document.createElement(\"a\");\n"
47 " lnk.target = \"_blank\";\n"
48 " document.body.appendChild(lnk);\n"
52 // Adds a link with given url and target=_blank, and clicks on it.
53 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter,
55 EXPECT_TRUE(ExecuteScript(adapter,
56 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
59 } // anonymous namespace
61 class RenderFrameHostManagerTest : public ContentBrowserTest {
63 RenderFrameHostManagerTest() : foo_com_("foo.com") {
64 replace_host_.SetHostStr(foo_com_);
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);
79 // Support multiple sites on the test server.
80 host_resolver()->AddRule("*", "127.0.0.1");
81 ASSERT_TRUE(test_server()->Start());
83 foo_host_port_ = test_server()->host_port_pair();
84 foo_host_port_.set_host(foo_com_);
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_);
95 GURL::Replacements replace_host_;
96 net::HostPortPair foo_host_port_;
99 // Web pages should not have script access to the swapped out page.
100 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
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",
109 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
123 EXPECT_TRUE(success);
124 Shell* new_shell = new_shell_observer.GetShell();
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());
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);
136 // We should have access to the opened window's location.
138 EXPECT_TRUE(ExecuteScriptAndExtractBool(
139 shell()->web_contents(),
140 "window.domAutomationController.send(testScriptAccessToWindow());",
142 EXPECT_TRUE(success);
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);
150 // We should no longer have script access to the opened window's location.
152 EXPECT_TRUE(ExecuteScriptAndExtractBool(
153 shell()->web_contents(),
154 "window.domAutomationController.send(testScriptAccessToWindow());",
156 EXPECT_FALSE(success);
159 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
160 // and target=_blank should create a new SiteInstance.
161 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
162 SwapProcessWithRelNoreferrerAndTargetBlank) {
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",
171 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
185 EXPECT_TRUE(success);
187 // Wait for the window to open.
188 Shell* new_shell = new_shell_observer.GetShell();
190 EXPECT_EQ("/files/title2.html",
191 new_shell->web_contents()->GetVisibleURL().path());
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());
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);
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
209 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
210 SwapProcessWithSameSiteRelNoreferrer) {
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",
219 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
233 EXPECT_TRUE(success);
235 // Wait for the window to open.
236 Shell* new_shell = new_shell_observer.GetShell();
238 // Opens in new window.
239 EXPECT_EQ("/files/title2.html",
240 new_shell->web_contents()->GetVisibleURL().path());
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());
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);
255 // Test for crbug.com/24447. Following a cross-site link with just
256 // target=_blank should not create a new SiteInstance.
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.
292 scoped_refptr<SiteInstance> blank_site_instance(
293 new_shell->web_contents()->GetSiteInstance());
294 EXPECT_EQ(orig_site_instance, blank_site_instance);
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.
299 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
300 DontSwapProcessWithOnlyRelNoreferrer) {
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",
309 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
316 // Test clicking a rel=noreferrer link.
317 bool success = false;
318 EXPECT_TRUE(ExecuteScriptAndExtractBool(
319 shell()->web_contents(),
320 "window.domAutomationController.send(clickNoRefLink());",
322 EXPECT_TRUE(success);
324 // Wait for the cross-site transition in the current tab to finish.
325 WaitForLoadStop(shell()->web_contents());
327 // Opens in same window.
328 EXPECT_EQ(1u, Shell::windows().size());
329 EXPECT_EQ("/files/title2.html",
330 shell()->web_contents()->GetLastCommittedURL().path());
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);
338 // Test for crbug.com/116192. Targeted links should still work after the
339 // named target window has swapped processes.
340 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
341 AllowTargetedNavigationsAfterSwap) {
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",
350 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
364 EXPECT_TRUE(success);
365 Shell* new_shell = new_shell_observer.GetShell();
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());
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);
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);
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());",
390 EXPECT_TRUE(success);
391 navigation_observer.Wait();
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);
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());",
408 EXPECT_TRUE(success);
409 close_watcher.Wait();
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
420 #define MAYBE_DisownOpener DisownOpener
422 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
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",
431 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
445 EXPECT_TRUE(success);
446 Shell* new_shell = new_shell_observer.GetShell();
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());
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);
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);
464 // Now disown the opener.
465 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
466 "window.opener = null;"));
468 // Go back and ensure the opener is still null.
470 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
471 new_shell->web_contents()->GetController().GoBack();
472 back_nav_load_observer.Wait();
475 EXPECT_TRUE(ExecuteScriptAndExtractBool(
476 new_shell->web_contents(),
477 "window.domAutomationController.send(window.opener == null);",
479 EXPECT_TRUE(success);
481 // Now navigate forward again (creating a new process) and check opener.
482 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
484 EXPECT_TRUE(ExecuteScriptAndExtractBool(
485 new_shell->web_contents(),
486 "window.domAutomationController.send(window.opener == null);",
488 EXPECT_TRUE(success);
491 // Test that subframes can disown their openers. http://crbug.com/225528.
492 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
493 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
494 NavigateToURL(shell(), frame_url);
496 // Give the frame an opener using window.open.
497 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
498 "window.open('about:blank','foo');"));
500 // Now disown the frame's opener. Shouldn't crash.
501 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
502 "window.frames[0].opener = null;"));
505 // Test for crbug.com/99202. PostMessage calls should still work after
506 // navigating the source and target windows to different sites.
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".
514 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
515 SupportCrossProcessPostMessage) {
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",
524 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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();
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.
537 // First, a named target=foo window.
538 ShellAddedObserver new_shell_observer;
539 bool success = false;
540 EXPECT_TRUE(ExecuteScriptAndExtractBool(
542 "window.domAutomationController.send(clickSameSiteTargetedLink());",
544 EXPECT_TRUE(success);
545 Shell* new_shell = new_shell_observer.GetShell();
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);
558 // Second, a target=_blank window.
559 ShellAddedObserver new_shell_observer2;
560 EXPECT_TRUE(ExecuteScriptAndExtractBool(
561 shell()->web_contents(),
562 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
564 EXPECT_TRUE(success);
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();
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());
581 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
583 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
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(
590 "window.domAutomationController.send(postToOpener('msg',"
591 " 'http://google.com'));",
593 EXPECT_TRUE(success);
595 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
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(
603 "window.domAutomationController.send(postToOpener('msg','*'));",
605 EXPECT_TRUE(success);
607 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
608 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
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(
615 "window.domAutomationController.send(window.receivedMessages);",
616 &opener_received_messages));
617 int foo_received_messages = 0;
618 EXPECT_TRUE(ExecuteScriptAndExtractInt(
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());
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(
632 "window.domAutomationController.send(postToFoo('msg2'));",
634 EXPECT_TRUE(success);
635 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
637 // This postMessage should have created a swapped out RVH for the new
638 // SiteInstance in the target=_blank window.
640 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
642 // TODO(nasko): Test subframe targeting of postMessage once
643 // http://crbug.com/153701 is fixed.
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.
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.
655 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
656 SupportCrossProcessPostMessageWithMessagePort) {
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",
665 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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();
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(
681 "window.domAutomationController.send(clickSameSiteTargetedLink());",
683 EXPECT_TRUE(success);
684 Shell* new_shell = new_shell_observer.GetShell();
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);
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());
701 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
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(
710 "window.domAutomationController.send(postWithPortToFoo());",
712 EXPECT_TRUE(success);
714 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
715 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
717 // Check message counts.
718 int opener_received_messages_via_port = 0;
719 EXPECT_TRUE(ExecuteScriptAndExtractInt(
721 "window.domAutomationController.send(window.receivedMessagesViaPort);",
722 &opener_received_messages_via_port));
723 int foo_received_messages = 0;
724 EXPECT_TRUE(ExecuteScriptAndExtractInt(
726 "window.domAutomationController.send(window.receivedMessages);",
727 &foo_received_messages));
728 int foo_received_messages_with_port = 0;
729 EXPECT_TRUE(ExecuteScriptAndExtractInt(
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());
740 // Test for crbug.com/116192. Navigations to a window's opener should
741 // still work after a process swap.
742 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
743 AllowTargetedNavigationsInOpenerAfterSwap) {
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",
752 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
760 // Test clicking a target=foo link.
761 ShellAddedObserver new_shell_observer;
762 bool success = false;
763 EXPECT_TRUE(ExecuteScriptAndExtractBool(
765 "window.domAutomationController.send(clickSameSiteTargetedLink());",
767 EXPECT_TRUE(success);
768 Shell* new_shell = new_shell_observer.GetShell();
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());
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);
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);
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());",
792 EXPECT_TRUE(success);
793 navigation_observer.Wait();
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);
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.
804 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
805 ProcessExitWithSwappedOutViews) {
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",
814 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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);
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());",
828 EXPECT_TRUE(success);
829 Shell* new_shell = new_shell_observer.GetShell();
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());
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);
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);
847 // The original process should still be alive, since it is still used in the
849 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
850 EXPECT_TRUE(orig_process->HasConnection());
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(
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);
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.
866 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
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);
874 // Load a cross-site page that fails with a 204 error.
875 NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
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());
886 shell()->web_contents()->GetController().GetLastCommittedEntry());
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());
897 // Opens in same tab.
898 EXPECT_EQ(1u, Shell::windows().size());
899 EXPECT_EQ("/files/title2.html",
900 shell()->web_contents()->GetLastCommittedURL().path());
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);
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.
912 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
913 ASSERT_TRUE(test_server()->Start());
915 // Load a page that can open a URL that won't commit in a new window.
917 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
918 WebContents* orig_contents = shell()->web_contents();
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(
925 "window.domAutomationController.send(clickNoContentTargetedLink());",
927 EXPECT_TRUE(success);
929 // Wait for the window to open.
930 Shell* new_shell = new_shell_observer.GetShell();
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());
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);
944 EXPECT_TRUE(ExecuteScriptAndExtractBool(
946 "window.domAutomationController.send(modifyNewWindow());",
948 EXPECT_TRUE(success);
949 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
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
954 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
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.
961 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
962 DontShowLoadingURLIfNotInitialNav) {
963 ASSERT_TRUE(test_server()->Start());
965 // Load a page that can open a URL that won't commit in a new window.
967 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
968 WebContents* orig_contents = shell()->web_contents();
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(
977 "window.domAutomationController.send("
978 "clickNoContentScriptedTargetedLink());",
980 EXPECT_TRUE(success);
982 // Wait for the window to open.
983 Shell* new_shell = new_shell_observer.GetShell();
985 // Ensure the destination URL is not visible, because it is not the initial
987 WebContents* contents = new_shell->web_contents();
988 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
989 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
992 // Crashes under ThreadSanitizer, http://crbug.com/356758.
993 #if defined(THREAD_SANITIZER)
994 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
996 #define MAYBE_BackForwardNotStale BackForwardNotStale
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
1001 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1003 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1005 // Visit a page on first site.
1006 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
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"));
1013 // History is now [blank, A1, B1, B2, *B3].
1014 WebContents* contents = shell()->web_contents();
1015 EXPECT_EQ(5, contents->GetController().GetEntryCount());
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"));
1021 // Go back three times to first site.
1023 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1024 shell()->web_contents()->GetController().GoBack();
1025 back_nav_load_observer.Wait();
1028 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1029 shell()->web_contents()->GetController().GoBack();
1030 back_nav_load_observer.Wait();
1033 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1034 shell()->web_contents()->GetController().GoBack();
1035 back_nav_load_observer.Wait();
1038 // Now go forward twice to B2. Shouldn't be left spinning.
1040 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1041 shell()->web_contents()->GetController().GoForward();
1042 forward_nav_load_observer.Wait();
1045 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1046 shell()->web_contents()->GetController().GoForward();
1047 forward_nav_load_observer.Wait();
1050 // Go back twice to first site.
1052 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1053 shell()->web_contents()->GetController().GoBack();
1054 back_nav_load_observer.Wait();
1057 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1058 shell()->web_contents()->GetController().GoBack();
1059 back_nav_load_observer.Wait();
1062 // Now go forward directly to B3. Shouldn't be left spinning.
1064 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1065 shell()->web_contents()->GetController().GoToIndex(4);
1066 forward_nav_load_observer.Wait();
1070 // Test for http://crbug.com/130016.
1071 // Swapping out a render view should update its visiblity state.
1072 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1073 SwappedOutViewHasCorrectVisibilityState) {
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",
1081 &replacement_path));
1082 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
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());",
1091 EXPECT_TRUE(success);
1092 Shell* new_shell = new_shell_observer.GetShell();
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());
1099 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1101 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1103 "window.domAutomationController.send("
1104 " document.visibilityState == 'visible');",
1106 EXPECT_TRUE(success);
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"));
1112 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1114 "window.domAutomationController.send("
1115 " document.visibilityState == 'hidden');",
1117 EXPECT_TRUE(success);
1119 // Going back should make the previously swapped-out view to become visible
1122 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1123 new_shell->web_contents()->GetController().GoBack();
1124 back_nav_load_observer.Wait();
1127 EXPECT_EQ("/files/navigate_opener.html",
1128 new_shell->web_contents()->GetLastCommittedURL().path());
1130 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1132 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1134 "window.domAutomationController.send("
1135 " document.visibilityState == 'visible');",
1137 EXPECT_TRUE(success);
1140 // This class ensures that all the given RenderViewHosts have properly been
1142 class RenderViewHostDestructionObserver : public WebContentsObserver {
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);
1150 size_t GetNumberOfWatchedRenderViewHosts() const {
1151 return watched_render_view_hosts_.size();
1155 // WebContentsObserver implementation:
1156 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
1157 watched_render_view_hosts_.erase(rvh);
1160 std::set<RenderViewHost*> watched_render_view_hosts_;
1163 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1164 #if defined(THREAD_SANITIZER)
1165 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1167 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
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.
1174 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1175 MAYBE_LeakingRenderViewHosts) {
1178 // Observe the created render_view_host's to make sure they will not leak.
1179 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1181 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1182 GURL view_source_url(kViewSourceScheme + std::string(":") +
1183 navigated_url.spec());
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);
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());
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());
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();
1217 // Ensure that view-source navigations force a new SiteInstance.
1218 EXPECT_NE(site_instance1, site_instance2);
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());
1225 // This used to leak a render view host.
1228 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1230 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1233 // Test for crbug.com/143155. Frame tree updates during unload should not
1234 // interrupt the intended navigation and show swappedout:// instead.
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://.
1244 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1245 DontPreemptNavigationWithFrameTreeUpdate) {
1248 // 1. Load a page that deletes its iframe during unload.
1249 NavigateToURL(shell(),
1250 test_server()->GetURL("files/remove_frame_on_unload.html"));
1252 // Get the original SiteInstance for later comparison.
1253 scoped_refptr<SiteInstance> orig_site_instance(
1254 shell()->web_contents()->GetSiteInstance());
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());",
1263 EXPECT_TRUE(success);
1264 Shell* new_shell = new_shell_observer.GetShell();
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());
1271 // Should have the same SiteInstance.
1272 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
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);
1280 // 3. Send the first tab to the second tab's process.
1281 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
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());
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.
1295 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1296 ASSERT_TRUE(test_server()->Start());
1298 GURL original_url(test_server()->GetURL("files/title2.html"));
1299 GURL view_source_url(kViewSourceScheme + std::string(":") +
1300 original_url.spec());
1302 NavigateToURL(shell(), view_source_url);
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());
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();
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.
1322 IN_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()));
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();
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));
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();
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.
1358 IN_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();
1369 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
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());
1379 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1381 RFHMProcessPerTabTest() {}
1383 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1384 command_line->AppendSwitch(switches::kProcessPerTab);
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
1395 #define MAYBE_BackFromWebUI BackFromWebUI
1397 IN_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);
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()));
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()));
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.
1425 IN_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));
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();
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();
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());
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());
1466 } // namespace content