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/location.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/path_service.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/values.h"
16 #include "content/browser/child_process_security_policy_impl.h"
17 #include "content/browser/frame_host/render_frame_proxy_host.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/site_instance_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/browser/webui/web_ui_impl.h"
22 #include "content/common/content_constants_internal.h"
23 #include "content/public/browser/navigation_controller.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/common/bindings_policy.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/file_chooser_file_info.h"
31 #include "content/public/common/file_chooser_params.h"
32 #include "content/public/common/page_state.h"
33 #include "content/public/common/url_constants.h"
34 #include "content/public/test/browser_test_utils.h"
35 #include "content/public/test/content_browser_test.h"
36 #include "content/public/test/content_browser_test_utils.h"
37 #include "content/public/test/test_navigation_observer.h"
38 #include "content/public/test/test_utils.h"
39 #include "content/shell/browser/shell.h"
40 #include "net/base/net_util.h"
41 #include "net/dns/mock_host_resolver.h"
42 #include "net/test/embedded_test_server/embedded_test_server.h"
43 #include "net/test/spawned_test_server/spawned_test_server.h"
45 using base::ASCIIToUTF16
;
51 const char kOpenUrlViaClickTargetFunc
[] =
53 " var lnk = document.createElement(\"a\");\n"
55 " lnk.target = \"_blank\";\n"
56 " document.body.appendChild(lnk);\n"
60 // Adds a link with given url and target=_blank, and clicks on it.
61 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost
& adapter
,
63 EXPECT_TRUE(ExecuteScript(adapter
,
64 std::string(kOpenUrlViaClickTargetFunc
) + "(\"" + url
.spec() + "\");"));
67 Shell
* OpenPopup(const internal::ToRenderFrameHost
& opener
,
68 const std::string
& name
) {
69 ShellAddedObserver new_shell_observer
;
71 EXPECT_TRUE(ExecuteScriptAndExtractBool(
73 "window.domAutomationController.send(!!window.open('', '" + name
+ "'));",
76 Shell
* new_shell
= new_shell_observer
.GetShell();
80 } // anonymous namespace
82 class RenderFrameHostManagerTest
: public ContentBrowserTest
{
84 RenderFrameHostManagerTest() : foo_com_("foo.com") {
85 replace_host_
.SetHostStr(foo_com_
);
88 static bool GetFilePathWithHostAndPortReplacement(
89 const std::string
& original_file_path
,
90 const net::HostPortPair
& host_port_pair
,
91 std::string
* replacement_path
) {
92 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
93 replacement_text
.push_back(
94 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
95 return net::SpawnedTestServer::GetFilePathWithReplacements(
96 original_file_path
, replacement_text
, replacement_path
);
100 // Support multiple sites on the test server.
101 host_resolver()->AddRule("*", "127.0.0.1");
102 ASSERT_TRUE(test_server()->Start());
104 foo_host_port_
= test_server()->host_port_pair();
105 foo_host_port_
.set_host(foo_com_
);
108 void StartEmbeddedServer() {
109 // Support multiple sites on the embedded test server.
110 host_resolver()->AddRule("*", "127.0.0.1");
111 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
112 SetupCrossSiteRedirector(embedded_test_server());
115 // Returns a URL on foo.com with the given path.
116 GURL
GetCrossSiteURL(const std::string
& path
) {
117 GURL
cross_site_url(test_server()->GetURL(path
));
118 return cross_site_url
.ReplaceComponents(replace_host_
);
122 std::string foo_com_
;
123 GURL::Replacements replace_host_
;
124 net::HostPortPair foo_host_port_
;
127 // Web pages should not have script access to the swapped out page.
128 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, NoScriptAccessAfterSwapOut
) {
131 // Load a page with links that open in a new window.
132 std::string replacement_path
;
133 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
134 "files/click-noreferrer-links.html",
137 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
139 // Get the original SiteInstance for later comparison.
140 scoped_refptr
<SiteInstance
> orig_site_instance(
141 shell()->web_contents()->GetSiteInstance());
142 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
144 // Open a same-site link in a new window.
145 ShellAddedObserver new_shell_observer
;
146 bool success
= false;
147 EXPECT_TRUE(ExecuteScriptAndExtractBool(
148 shell()->web_contents(),
149 "window.domAutomationController.send(clickSameSiteTargetedLink());",
151 EXPECT_TRUE(success
);
152 Shell
* new_shell
= new_shell_observer
.GetShell();
154 // Wait for the navigation in the new window to finish, if it hasn't.
155 WaitForLoadStop(new_shell
->web_contents());
156 EXPECT_EQ("/files/navigate_opener.html",
157 new_shell
->web_contents()->GetLastCommittedURL().path());
159 // Should have the same SiteInstance.
160 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
162 // We should have access to the opened window's location.
164 EXPECT_TRUE(ExecuteScriptAndExtractBool(
165 shell()->web_contents(),
166 "window.domAutomationController.send(testScriptAccessToWindow());",
168 EXPECT_TRUE(success
);
170 // Now navigate the new window to a different site.
171 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
172 scoped_refptr
<SiteInstance
> new_site_instance(
173 new_shell
->web_contents()->GetSiteInstance());
174 EXPECT_NE(orig_site_instance
, new_site_instance
);
176 // We should no longer have script access to the opened window's location.
178 EXPECT_TRUE(ExecuteScriptAndExtractBool(
179 shell()->web_contents(),
180 "window.domAutomationController.send(testScriptAccessToWindow());",
182 EXPECT_FALSE(success
);
184 // We now navigate the window to an about:blank page.
186 EXPECT_TRUE(ExecuteScriptAndExtractBool(
187 shell()->web_contents(),
188 "window.domAutomationController.send(clickBlankTargetedLink());",
190 EXPECT_TRUE(success
);
192 // Wait for the navigation in the new window to finish.
193 WaitForLoadStop(new_shell
->web_contents());
194 GURL
blank_url(url::kAboutBlankURL
);
196 new_shell
->web_contents()->GetLastCommittedURL());
197 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
199 // We should have access to the opened window's location.
201 EXPECT_TRUE(ExecuteScriptAndExtractBool(
202 shell()->web_contents(),
203 "window.domAutomationController.send(testScriptAccessToWindow());",
205 EXPECT_TRUE(success
);
208 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
209 // and target=_blank should create a new SiteInstance.
210 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
211 SwapProcessWithRelNoreferrerAndTargetBlank
) {
214 // Load a page with links that open in a new window.
215 std::string replacement_path
;
216 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
217 "files/click-noreferrer-links.html",
220 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
222 // Get the original SiteInstance for later comparison.
223 scoped_refptr
<SiteInstance
> orig_site_instance(
224 shell()->web_contents()->GetSiteInstance());
225 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
227 // Test clicking a rel=noreferrer + target=blank link.
228 ShellAddedObserver new_shell_observer
;
229 bool success
= false;
230 EXPECT_TRUE(ExecuteScriptAndExtractBool(
231 shell()->web_contents(),
232 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
234 EXPECT_TRUE(success
);
236 // Wait for the window to open.
237 Shell
* new_shell
= new_shell_observer
.GetShell();
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.
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 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
256 // for rel=noreferrer links in new windows, even to same site pages and named
258 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
259 SwapProcessWithSameSiteRelNoreferrer
) {
262 // Load a page with links that open in a new window.
263 std::string replacement_path
;
264 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
265 "files/click-noreferrer-links.html",
268 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
270 // Get the original SiteInstance for later comparison.
271 scoped_refptr
<SiteInstance
> orig_site_instance(
272 shell()->web_contents()->GetSiteInstance());
273 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
275 // Test clicking a same-site rel=noreferrer + target=foo link.
276 ShellAddedObserver new_shell_observer
;
277 bool success
= false;
278 EXPECT_TRUE(ExecuteScriptAndExtractBool(
279 shell()->web_contents(),
280 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
282 EXPECT_TRUE(success
);
284 // Wait for the window to open.
285 Shell
* new_shell
= new_shell_observer
.GetShell();
287 // Opens in new window.
288 EXPECT_EQ("/files/title2.html",
289 new_shell
->web_contents()->GetVisibleURL().path());
291 // Wait for the cross-site transition in the new tab to finish.
292 WaitForLoadStop(new_shell
->web_contents());
293 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
294 new_shell
->web_contents());
295 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
296 pending_render_view_host());
298 // Should have a new SiteInstance (in a new BrowsingInstance).
299 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
300 new_shell
->web_contents()->GetSiteInstance());
301 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
304 // Test for crbug.com/24447. Following a cross-site link with just
305 // target=_blank should not create a new SiteInstance, unless we
306 // are running in --site-per-process mode.
307 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
308 DontSwapProcessWithOnlyTargetBlank
) {
311 // Load a page with links that open in a new window.
312 std::string replacement_path
;
313 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
314 "files/click-noreferrer-links.html",
317 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path
)));
319 // Get the original SiteInstance for later comparison.
320 scoped_refptr
<SiteInstance
> orig_site_instance(
321 shell()->web_contents()->GetSiteInstance());
322 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
324 // Test clicking a target=blank link.
325 ShellAddedObserver new_shell_observer
;
326 bool success
= false;
327 EXPECT_TRUE(ExecuteScriptAndExtractBool(
328 shell()->web_contents(),
329 "window.domAutomationController.send(clickTargetBlankLink());",
331 EXPECT_TRUE(success
);
333 // Wait for the window to open.
334 Shell
* new_shell
= new_shell_observer
.GetShell();
336 // Wait for the cross-site transition in the new tab to finish.
337 EXPECT_TRUE(WaitForLoadStop(new_shell
->web_contents()));
338 EXPECT_EQ("/files/title2.html",
339 new_shell
->web_contents()->GetLastCommittedURL().path());
341 // Should have the same SiteInstance unless we're in site-per-process mode.
342 scoped_refptr
<SiteInstance
> blank_site_instance(
343 new_shell
->web_contents()->GetSiteInstance());
344 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
345 switches::kSitePerProcess
))
346 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
348 EXPECT_NE(orig_site_instance
, blank_site_instance
);
351 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
352 // and no target=_blank should not create a new SiteInstance.
353 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
354 DontSwapProcessWithOnlyRelNoreferrer
) {
357 // Load a page with links that open in a new window.
358 std::string replacement_path
;
359 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
360 "files/click-noreferrer-links.html",
363 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
365 // Get the original SiteInstance for later comparison.
366 scoped_refptr
<SiteInstance
> orig_site_instance(
367 shell()->web_contents()->GetSiteInstance());
368 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
370 // Test clicking a rel=noreferrer link.
371 bool success
= false;
372 EXPECT_TRUE(ExecuteScriptAndExtractBool(
373 shell()->web_contents(),
374 "window.domAutomationController.send(clickNoRefLink());",
376 EXPECT_TRUE(success
);
378 // Wait for the cross-site transition in the current tab to finish.
379 WaitForLoadStop(shell()->web_contents());
381 // Opens in same window.
382 EXPECT_EQ(1u, Shell::windows().size());
383 EXPECT_EQ("/files/title2.html",
384 shell()->web_contents()->GetLastCommittedURL().path());
386 // Should have the same SiteInstance unless we're in site-per-process mode.
387 scoped_refptr
<SiteInstance
> noref_site_instance(
388 shell()->web_contents()->GetSiteInstance());
389 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
390 switches::kSitePerProcess
))
391 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
393 EXPECT_NE(orig_site_instance
, noref_site_instance
);
396 // Test for crbug.com/116192. Targeted links should still work after the
397 // named target window has swapped processes.
398 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
399 AllowTargetedNavigationsAfterSwap
) {
402 // Load a page with links that open in a new window.
403 std::string replacement_path
;
404 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
405 "files/click-noreferrer-links.html",
408 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
410 // Get the original SiteInstance for later comparison.
411 scoped_refptr
<SiteInstance
> orig_site_instance(
412 shell()->web_contents()->GetSiteInstance());
413 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
415 // Test clicking a target=foo link.
416 ShellAddedObserver new_shell_observer
;
417 bool success
= false;
418 EXPECT_TRUE(ExecuteScriptAndExtractBool(
419 shell()->web_contents(),
420 "window.domAutomationController.send(clickSameSiteTargetedLink());",
422 EXPECT_TRUE(success
);
423 Shell
* new_shell
= new_shell_observer
.GetShell();
425 // Wait for the navigation in the new tab to finish, if it hasn't.
426 WaitForLoadStop(new_shell
->web_contents());
427 EXPECT_EQ("/files/navigate_opener.html",
428 new_shell
->web_contents()->GetLastCommittedURL().path());
430 // Should have the same SiteInstance.
431 scoped_refptr
<SiteInstance
> blank_site_instance(
432 new_shell
->web_contents()->GetSiteInstance());
433 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
435 // Now navigate the new tab to a different site.
436 GURL
cross_site_url(GetCrossSiteURL("files/title1.html"));
437 NavigateToURL(new_shell
, cross_site_url
);
438 scoped_refptr
<SiteInstance
> new_site_instance(
439 new_shell
->web_contents()->GetSiteInstance());
440 EXPECT_NE(orig_site_instance
, new_site_instance
);
442 // Clicking the original link in the first tab should cause us to swap back.
443 TestNavigationObserver
navigation_observer(new_shell
->web_contents());
444 EXPECT_TRUE(ExecuteScriptAndExtractBool(
445 shell()->web_contents(),
446 "window.domAutomationController.send(clickSameSiteTargetedLink());",
448 EXPECT_TRUE(success
);
449 navigation_observer
.Wait();
451 // Should have swapped back and shown the new window again.
452 scoped_refptr
<SiteInstance
> revisit_site_instance(
453 new_shell
->web_contents()->GetSiteInstance());
454 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
456 // If it navigates away to another process, the original window should
457 // still be able to close it (using a cross-process close message).
458 NavigateToURL(new_shell
, cross_site_url
);
459 EXPECT_EQ(new_site_instance
.get(),
460 new_shell
->web_contents()->GetSiteInstance());
461 WebContentsDestroyedWatcher
close_watcher(new_shell
->web_contents());
462 EXPECT_TRUE(ExecuteScriptAndExtractBool(
463 shell()->web_contents(),
464 "window.domAutomationController.send(testCloseWindow());",
466 EXPECT_TRUE(success
);
467 close_watcher
.Wait();
470 // Test that setting the opener to null in a window affects cross-process
471 // navigations, including those to existing entries. http://crbug.com/156669.
472 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
473 #if defined(THREAD_SANITIZER)
474 #define MAYBE_DisownOpener DISABLED_DisownOpener
476 #define MAYBE_DisownOpener DisownOpener
478 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_DisownOpener
) {
481 // Load a page with links that open in a new window.
482 std::string replacement_path
;
483 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
484 "files/click-noreferrer-links.html",
487 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
489 // Get the original SiteInstance for later comparison.
490 scoped_refptr
<SiteInstance
> orig_site_instance(
491 shell()->web_contents()->GetSiteInstance());
492 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
494 // Test clicking a target=_blank link.
495 ShellAddedObserver new_shell_observer
;
496 bool success
= false;
497 EXPECT_TRUE(ExecuteScriptAndExtractBool(
498 shell()->web_contents(),
499 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
501 EXPECT_TRUE(success
);
502 Shell
* new_shell
= new_shell_observer
.GetShell();
503 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
505 // Wait for the navigation in the new tab to finish, if it hasn't.
506 WaitForLoadStop(new_shell
->web_contents());
507 EXPECT_EQ("/files/title2.html",
508 new_shell
->web_contents()->GetLastCommittedURL().path());
510 // Should have the same SiteInstance.
511 scoped_refptr
<SiteInstance
> blank_site_instance(
512 new_shell
->web_contents()->GetSiteInstance());
513 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
515 // Now navigate the new tab to a different site.
516 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
517 scoped_refptr
<SiteInstance
> new_site_instance(
518 new_shell
->web_contents()->GetSiteInstance());
519 EXPECT_NE(orig_site_instance
, new_site_instance
);
520 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
522 // Now disown the opener.
523 EXPECT_TRUE(ExecuteScript(new_shell
->web_contents(),
524 "window.opener = null;"));
525 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
527 // Go back and ensure the opener is still null.
529 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
530 new_shell
->web_contents()->GetController().GoBack();
531 back_nav_load_observer
.Wait();
534 EXPECT_TRUE(ExecuteScriptAndExtractBool(
535 new_shell
->web_contents(),
536 "window.domAutomationController.send(window.opener == null);",
538 EXPECT_TRUE(success
);
539 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
541 // Now navigate forward again (creating a new process) and check opener.
542 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
544 EXPECT_TRUE(ExecuteScriptAndExtractBool(
545 new_shell
->web_contents(),
546 "window.domAutomationController.send(window.opener == null);",
548 EXPECT_TRUE(success
);
549 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
552 // Test that subframes can disown their openers. http://crbug.com/225528.
553 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, DisownSubframeOpener
) {
554 const GURL
frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
555 NavigateToURL(shell(), frame_url
);
557 // Give the frame an opener using window.open.
558 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
559 "window.open('about:blank','foo');"));
561 // Now disown the frame's opener. Shouldn't crash.
562 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
563 "window.frames[0].opener = null;"));
566 // Check that window.name is preserved for top frames when they navigate
567 // cross-process. See https://crbug.com/504164.
568 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
569 PreserveTopFrameWindowNameOnCrossProcessNavigations
) {
570 StartEmbeddedServer();
572 GURL
main_url(embedded_test_server()->GetURL("/title1.html"));
573 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
575 // Get the original SiteInstance for later comparison.
576 scoped_refptr
<SiteInstance
> orig_site_instance(
577 shell()->web_contents()->GetSiteInstance());
578 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
580 // Open a popup using window.open with a 'foo' window.name.
581 Shell
* new_shell
= OpenPopup(shell()->web_contents(), "foo");
583 // The window.name for the new popup should be "foo".
585 EXPECT_TRUE(ExecuteScriptAndExtractString(
586 new_shell
->web_contents(),
587 "window.domAutomationController.send(window.name);", &name
));
588 EXPECT_EQ("foo", name
);
590 // Now navigate the new tab to a different site.
591 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
592 EXPECT_TRUE(NavigateToURL(new_shell
, foo_url
));
593 scoped_refptr
<SiteInstance
> new_site_instance(
594 new_shell
->web_contents()->GetSiteInstance());
595 EXPECT_NE(orig_site_instance
, new_site_instance
);
597 // window.name should still be "foo".
599 EXPECT_TRUE(ExecuteScriptAndExtractString(
600 new_shell
->web_contents(),
601 "window.domAutomationController.send(window.name);", &name
));
602 EXPECT_EQ("foo", name
);
604 // Open another popup from the 'foo' popup and navigate it cross-site.
605 Shell
* new_shell2
= OpenPopup(new_shell
->web_contents(), "bar");
606 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title3.html"));
607 EXPECT_TRUE(NavigateToURL(new_shell2
, bar_url
));
609 // Check that the new popup's window.opener has name "foo", which verifies
610 // that new swapped-out RenderViews also propagate window.name. This has to
611 // be done via window.open, since window.name isn't readable cross-origin.
612 bool success
= false;
613 EXPECT_TRUE(ExecuteScriptAndExtractBool(
614 new_shell2
->web_contents(),
615 "window.domAutomationController.send("
616 " window.opener === window.open('','foo'));",
618 EXPECT_TRUE(success
);
621 // Test for crbug.com/99202. PostMessage calls should still work after
622 // navigating the source and target windows to different sites.
624 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
625 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
626 // 3) Post a message from "foo" to opener, which replies back to "foo".
627 // 4) Post a message from _blank to "foo".
628 // 5) Post a message from "foo" to a subframe of opener, which replies back.
629 // 6) Post a message from _blank to a subframe of "foo".
630 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
631 SupportCrossProcessPostMessage
) {
634 // Load a page with links that open in a new window.
635 std::string replacement_path
;
636 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
637 "files/click-noreferrer-links.html",
640 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
642 // Get the original SiteInstance and RVHM for later comparison.
643 WebContents
* opener_contents
= shell()->web_contents();
644 scoped_refptr
<SiteInstance
> orig_site_instance(
645 opener_contents
->GetSiteInstance());
646 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
647 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
648 opener_contents
)->GetRenderManagerForTesting();
650 // 1) Open two more windows, one named. These initially have openers but no
651 // reference to each other. We will later post a message between them.
653 // First, a named target=foo window.
654 ShellAddedObserver new_shell_observer
;
655 bool success
= false;
656 EXPECT_TRUE(ExecuteScriptAndExtractBool(
658 "window.domAutomationController.send(clickSameSiteTargetedLink());",
660 EXPECT_TRUE(success
);
661 Shell
* new_shell
= new_shell_observer
.GetShell();
663 // Wait for the navigation in the new window to finish, if it hasn't, then
664 // send it to post_message.html on a different site.
665 WebContents
* foo_contents
= new_shell
->web_contents();
666 WaitForLoadStop(foo_contents
);
667 EXPECT_EQ("/files/navigate_opener.html",
668 foo_contents
->GetLastCommittedURL().path());
669 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
670 scoped_refptr
<SiteInstance
> foo_site_instance(
671 foo_contents
->GetSiteInstance());
672 EXPECT_NE(orig_site_instance
, foo_site_instance
);
674 // Second, a target=_blank window.
675 ShellAddedObserver new_shell_observer2
;
676 EXPECT_TRUE(ExecuteScriptAndExtractBool(
677 shell()->web_contents(),
678 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
680 EXPECT_TRUE(success
);
682 // Wait for the navigation in the new window to finish, if it hasn't, then
683 // send it to post_message.html on the original site.
684 Shell
* new_shell2
= new_shell_observer2
.GetShell();
685 WebContents
* new_contents
= new_shell2
->web_contents();
686 WaitForLoadStop(new_contents
);
687 EXPECT_EQ("/files/title2.html", new_contents
->GetLastCommittedURL().path());
688 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
689 EXPECT_EQ(orig_site_instance
.get(), new_contents
->GetSiteInstance());
690 RenderFrameHostManager
* new_manager
=
691 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
693 // We now have three windows. The opener should have a swapped out RVH
694 // for the new SiteInstance, but the _blank window should not.
695 EXPECT_EQ(3u, Shell::windows().size());
697 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
699 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
701 // 2) Fail to post a message from the foo window to the opener if the target
702 // origin is wrong. We won't see an error, but we can check for the right
703 // number of received messages below.
704 EXPECT_TRUE(ExecuteScriptAndExtractBool(
706 "window.domAutomationController.send(postToOpener('msg',"
707 " 'http://google.com'));",
709 EXPECT_TRUE(success
);
711 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
713 // 3) Post a message from the foo window to the opener. The opener will
714 // reply, causing the foo window to update its own title.
715 base::string16 expected_title
= ASCIIToUTF16("msg");
716 TitleWatcher
title_watcher(foo_contents
, expected_title
);
717 EXPECT_TRUE(ExecuteScriptAndExtractBool(
719 "window.domAutomationController.send(postToOpener('msg','*'));",
721 EXPECT_TRUE(success
);
723 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
724 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
726 // We should have received only 1 message in the opener and "foo" tabs,
727 // and updated the title.
728 int opener_received_messages
= 0;
729 EXPECT_TRUE(ExecuteScriptAndExtractInt(
731 "window.domAutomationController.send(window.receivedMessages);",
732 &opener_received_messages
));
733 int foo_received_messages
= 0;
734 EXPECT_TRUE(ExecuteScriptAndExtractInt(
736 "window.domAutomationController.send(window.receivedMessages);",
737 &foo_received_messages
));
738 EXPECT_EQ(1, foo_received_messages
);
739 EXPECT_EQ(1, opener_received_messages
);
740 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
742 // 4) Now post a message from the _blank window to the foo window. The
743 // foo window will update its title and will not reply.
744 expected_title
= ASCIIToUTF16("msg2");
745 TitleWatcher
title_watcher2(foo_contents
, expected_title
);
746 EXPECT_TRUE(ExecuteScriptAndExtractBool(
748 "window.domAutomationController.send(postToFoo('msg2'));",
750 EXPECT_TRUE(success
);
751 ASSERT_EQ(expected_title
, title_watcher2
.WaitAndGetTitle());
753 // This postMessage should have created a swapped out RVH for the new
754 // SiteInstance in the target=_blank window.
756 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
758 // TODO(nasko): Test subframe targeting of postMessage once
759 // http://crbug.com/153701 is fixed.
762 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
763 // messages which contain Transferables and get intercepted by
764 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
765 // swapped out) should work.
767 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
768 // 2) Post a message containing a message port from opener to "foo".
769 // 3) Post a message from "foo" back to opener via the passed message port.
770 // The test will be enabled when the feature implementation lands.
771 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
772 SupportCrossProcessPostMessageWithMessagePort
) {
775 // Load a page with links that open in a new window.
776 std::string replacement_path
;
777 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
778 "files/click-noreferrer-links.html",
781 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
783 // Get the original SiteInstance and RVHM for later comparison.
784 WebContents
* opener_contents
= shell()->web_contents();
785 scoped_refptr
<SiteInstance
> orig_site_instance(
786 opener_contents
->GetSiteInstance());
787 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
788 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
789 opener_contents
)->GetRenderManagerForTesting();
791 // 1) Open a named target=foo window. We will later post a message between the
792 // opener and the new window.
793 ShellAddedObserver new_shell_observer
;
794 bool success
= false;
795 EXPECT_TRUE(ExecuteScriptAndExtractBool(
797 "window.domAutomationController.send(clickSameSiteTargetedLink());",
799 EXPECT_TRUE(success
);
800 Shell
* new_shell
= new_shell_observer
.GetShell();
802 // Wait for the navigation in the new window to finish, if it hasn't, then
803 // send it to post_message.html on a different site.
804 WebContents
* foo_contents
= new_shell
->web_contents();
805 WaitForLoadStop(foo_contents
);
806 EXPECT_EQ("/files/navigate_opener.html",
807 foo_contents
->GetLastCommittedURL().path());
808 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
809 scoped_refptr
<SiteInstance
> foo_site_instance(
810 foo_contents
->GetSiteInstance());
811 EXPECT_NE(orig_site_instance
, foo_site_instance
);
813 // We now have two windows. The opener should have a swapped out RVH
814 // for the new SiteInstance.
815 EXPECT_EQ(2u, Shell::windows().size());
817 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
819 // 2) Post a message containing a MessagePort from opener to the the foo
820 // window. The foo window will reply via the passed port, causing the opener
821 // to update its own title.
822 base::string16 expected_title
= ASCIIToUTF16("msg-back-via-port");
823 TitleWatcher
title_observer(opener_contents
, expected_title
);
824 EXPECT_TRUE(ExecuteScriptAndExtractBool(
826 "window.domAutomationController.send(postWithPortToFoo());",
828 EXPECT_TRUE(success
);
830 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
831 ASSERT_EQ(expected_title
, title_observer
.WaitAndGetTitle());
833 // Check message counts.
834 int opener_received_messages_via_port
= 0;
835 EXPECT_TRUE(ExecuteScriptAndExtractInt(
837 "window.domAutomationController.send(window.receivedMessagesViaPort);",
838 &opener_received_messages_via_port
));
839 int foo_received_messages
= 0;
840 EXPECT_TRUE(ExecuteScriptAndExtractInt(
842 "window.domAutomationController.send(window.receivedMessages);",
843 &foo_received_messages
));
844 int foo_received_messages_with_port
= 0;
845 EXPECT_TRUE(ExecuteScriptAndExtractInt(
847 "window.domAutomationController.send(window.receivedMessagesWithPort);",
848 &foo_received_messages_with_port
));
849 EXPECT_EQ(1, foo_received_messages
);
850 EXPECT_EQ(1, foo_received_messages_with_port
);
851 EXPECT_EQ(1, opener_received_messages_via_port
);
852 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents
->GetTitle());
853 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents
->GetTitle());
856 // Test for crbug.com/116192. Navigations to a window's opener should
857 // still work after a process swap.
858 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
859 AllowTargetedNavigationsInOpenerAfterSwap
) {
862 // Load a page with links that open in a new window.
863 std::string replacement_path
;
864 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
865 "files/click-noreferrer-links.html",
868 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
870 // Get the original tab and SiteInstance for later comparison.
871 WebContents
* orig_contents
= shell()->web_contents();
872 scoped_refptr
<SiteInstance
> orig_site_instance(
873 orig_contents
->GetSiteInstance());
874 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
876 // Test clicking a target=foo link.
877 ShellAddedObserver new_shell_observer
;
878 bool success
= false;
879 EXPECT_TRUE(ExecuteScriptAndExtractBool(
881 "window.domAutomationController.send(clickSameSiteTargetedLink());",
883 EXPECT_TRUE(success
);
884 Shell
* new_shell
= new_shell_observer
.GetShell();
886 // Wait for the navigation in the new window to finish, if it hasn't.
887 WaitForLoadStop(new_shell
->web_contents());
888 EXPECT_EQ("/files/navigate_opener.html",
889 new_shell
->web_contents()->GetLastCommittedURL().path());
891 // Should have the same SiteInstance.
892 scoped_refptr
<SiteInstance
> blank_site_instance(
893 new_shell
->web_contents()->GetSiteInstance());
894 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
896 // Now navigate the original (opener) tab to a different site.
897 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
898 scoped_refptr
<SiteInstance
> new_site_instance(
899 shell()->web_contents()->GetSiteInstance());
900 EXPECT_NE(orig_site_instance
, new_site_instance
);
902 // The opened tab should be able to navigate the opener back to its process.
903 TestNavigationObserver
navigation_observer(orig_contents
);
904 EXPECT_TRUE(ExecuteScriptAndExtractBool(
905 new_shell
->web_contents(),
906 "window.domAutomationController.send(navigateOpener());",
908 EXPECT_TRUE(success
);
909 navigation_observer
.Wait();
911 // Should have swapped back into this process.
912 scoped_refptr
<SiteInstance
> revisit_site_instance(
913 shell()->web_contents()->GetSiteInstance());
914 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
917 // Test that subframes do not crash when sending a postMessage to the top frame
918 // from an unload handler while the top frame is being swapped out as part of
919 // navigating cross-process. https://crbug.com/475651.
920 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
921 PostMessageFromSubframeUnloadHandler
) {
924 GURL
frame_url(test_server()->GetURL("files/post_message.html"));
925 GURL
main_url("data:text/html,<iframe name='foo' src='" + frame_url
.spec() +
927 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
929 // Get the original SiteInstance for later comparison.
930 scoped_refptr
<SiteInstance
> orig_site_instance(
931 shell()->web_contents()->GetSiteInstance());
932 EXPECT_NE(nullptr, orig_site_instance
.get());
934 // It is safe to obtain the root frame tree node here, as it doesn't change.
935 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
938 ASSERT_EQ(1U, root
->child_count());
939 EXPECT_EQ(frame_url
, root
->child_at(0)->current_url());
941 // Register an unload handler that sends a postMessage to the top frame.
942 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
943 "registerUnload();"));
945 // Navigate the top frame cross-site. This will cause the top frame to be
946 // swapped out and run unload handlers, and the original renderer process
947 // should then terminate since it's not rendering any other frames.
948 RenderProcessHostWatcher
exit_observer(
949 root
->current_frame_host()->GetProcess(),
950 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
951 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
952 scoped_refptr
<SiteInstance
> new_site_instance(
953 shell()->web_contents()->GetSiteInstance());
954 EXPECT_NE(orig_site_instance
, new_site_instance
);
956 // Ensure that the original renderer process exited cleanly without crashing.
957 exit_observer
.Wait();
958 EXPECT_EQ(true, exit_observer
.did_exit_normally());
961 // Test that opening a new window in the same SiteInstance and then navigating
962 // both windows to a different SiteInstance allows the first process to exit.
963 // See http://crbug.com/126333.
964 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
965 ProcessExitWithSwappedOutViews
) {
968 // Load a page with links that open in a new window.
969 std::string replacement_path
;
970 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
971 "files/click-noreferrer-links.html",
974 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
976 // Get the original SiteInstance for later comparison.
977 scoped_refptr
<SiteInstance
> orig_site_instance(
978 shell()->web_contents()->GetSiteInstance());
979 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
981 // Test clicking a target=foo link.
982 ShellAddedObserver new_shell_observer
;
983 bool success
= false;
984 EXPECT_TRUE(ExecuteScriptAndExtractBool(
985 shell()->web_contents(),
986 "window.domAutomationController.send(clickSameSiteTargetedLink());",
988 EXPECT_TRUE(success
);
989 Shell
* new_shell
= new_shell_observer
.GetShell();
991 // Wait for the navigation in the new window to finish, if it hasn't.
992 WaitForLoadStop(new_shell
->web_contents());
993 EXPECT_EQ("/files/navigate_opener.html",
994 new_shell
->web_contents()->GetLastCommittedURL().path());
996 // Should have the same SiteInstance.
997 scoped_refptr
<SiteInstance
> opened_site_instance(
998 new_shell
->web_contents()->GetSiteInstance());
999 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
1001 // Now navigate the opened window to a different site.
1002 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1003 scoped_refptr
<SiteInstance
> new_site_instance(
1004 new_shell
->web_contents()->GetSiteInstance());
1005 EXPECT_NE(orig_site_instance
, new_site_instance
);
1007 // The original process should still be alive, since it is still used in the
1009 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
1010 EXPECT_TRUE(orig_process
->HasConnection());
1012 // Navigate the first window to a different site as well. The original
1013 // process should exit, since all of its views are now swapped out.
1014 RenderProcessHostWatcher
exit_observer(
1016 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1017 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1018 exit_observer
.Wait();
1019 scoped_refptr
<SiteInstance
> new_site_instance2(
1020 shell()->web_contents()->GetSiteInstance());
1021 EXPECT_EQ(new_site_instance
, new_site_instance2
);
1024 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
1025 // error should not make us ignore future renderer-initiated navigations.
1026 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ClickLinkAfter204Error
) {
1029 // Get the original SiteInstance for later comparison.
1030 scoped_refptr
<SiteInstance
> orig_site_instance(
1031 shell()->web_contents()->GetSiteInstance());
1032 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
1034 // Load a cross-site page that fails with a 204 error.
1035 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
1036 GetCrossSiteURL("nocontent")));
1038 // We should still be looking at the normal page. Because we started from a
1039 // blank new tab, the typed URL will still be visible until the user clears it
1040 // manually. The last committed URL will be the previous page.
1041 scoped_refptr
<SiteInstance
> post_nav_site_instance(
1042 shell()->web_contents()->GetSiteInstance());
1043 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
1044 EXPECT_EQ("/nocontent",
1045 shell()->web_contents()->GetVisibleURL().path());
1047 shell()->web_contents()->GetController().GetLastCommittedEntry());
1049 // Renderer-initiated navigations should work.
1050 base::string16 expected_title
= ASCIIToUTF16("Title Of Awesomeness");
1051 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1052 GURL url
= test_server()->GetURL("files/title2.html");
1053 EXPECT_TRUE(ExecuteScript(
1054 shell()->web_contents(),
1055 base::StringPrintf("location.href = '%s'", url
.spec().c_str())));
1056 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1058 // Opens in same tab.
1059 EXPECT_EQ(1u, Shell::windows().size());
1060 EXPECT_EQ("/files/title2.html",
1061 shell()->web_contents()->GetLastCommittedURL().path());
1063 // Should have the same SiteInstance.
1064 scoped_refptr
<SiteInstance
> new_site_instance(
1065 shell()->web_contents()->GetSiteInstance());
1066 EXPECT_EQ(orig_site_instance
, new_site_instance
);
1069 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1070 // initiated navigation in a new tab, until the content of the initial
1071 // about:blank page is modified by another window. At that point, we should
1072 // revert to showing about:blank to prevent a URL spoof.
1073 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ShowLoadingURLUntilSpoof
) {
1074 ASSERT_TRUE(test_server()->Start());
1076 // Load a page that can open a URL that won't commit in a new window.
1078 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1079 WebContents
* orig_contents
= shell()->web_contents();
1081 // Click a /nocontent link that opens in a new window but never commits.
1082 ShellAddedObserver new_shell_observer
;
1083 bool success
= false;
1084 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1086 "window.domAutomationController.send(clickNoContentTargetedLink());",
1088 EXPECT_TRUE(success
);
1090 // Wait for the window to open.
1091 Shell
* new_shell
= new_shell_observer
.GetShell();
1093 // Ensure the destination URL is visible, because it is considered the
1094 // initial navigation.
1095 WebContents
* contents
= new_shell
->web_contents();
1096 EXPECT_TRUE(contents
->GetController().IsInitialNavigation());
1097 EXPECT_EQ("/nocontent",
1098 contents
->GetController().GetVisibleEntry()->GetURL().path());
1100 // Now modify the contents of the new window from the opener. This will also
1101 // modify the title of the document to give us something to listen for.
1102 base::string16 expected_title
= ASCIIToUTF16("Modified Title");
1103 TitleWatcher
title_watcher(contents
, expected_title
);
1105 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1107 "window.domAutomationController.send(modifyNewWindow());",
1109 EXPECT_TRUE(success
);
1110 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1112 // At this point, we should no longer be showing the destination URL.
1113 // The visible entry should be null, resulting in about:blank in the address
1115 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1118 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1119 // initiated navigation in a new tab if it is not the initial navigation. In
1120 // this case, the renderer will not notify us of a modification, so we cannot
1121 // show the pending URL without allowing a spoof.
1122 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1123 DontShowLoadingURLIfNotInitialNav
) {
1124 ASSERT_TRUE(test_server()->Start());
1126 // Load a page that can open a URL that won't commit in a new window.
1128 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1129 WebContents
* orig_contents
= shell()->web_contents();
1131 // Click a /nocontent link that opens in a new window but never commits.
1132 // By using an onclick handler that first creates the window, the slow
1133 // navigation is not considered an initial navigation.
1134 ShellAddedObserver new_shell_observer
;
1135 bool success
= false;
1136 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1138 "window.domAutomationController.send("
1139 "clickNoContentScriptedTargetedLink());",
1141 EXPECT_TRUE(success
);
1143 // Wait for the window to open.
1144 Shell
* new_shell
= new_shell_observer
.GetShell();
1146 // Ensure the destination URL is not visible, because it is not the initial
1148 WebContents
* contents
= new_shell
->web_contents();
1149 EXPECT_FALSE(contents
->GetController().IsInitialNavigation());
1150 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1153 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1154 #if defined(THREAD_SANITIZER)
1155 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1157 #define MAYBE_BackForwardNotStale BackForwardNotStale
1159 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1160 // do not cause back/forward navigations to be considered stale by the
1162 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_BackForwardNotStale
) {
1164 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1166 // Visit a page on first site.
1167 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1169 // Visit three pages on second site.
1170 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1171 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1172 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1174 // History is now [blank, A1, B1, B2, *B3].
1175 WebContents
* contents
= shell()->web_contents();
1176 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
1178 // Open another window in same process to keep this process alive.
1179 Shell
* new_shell
= CreateBrowser();
1180 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1182 // Go back three times to first site.
1184 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1185 shell()->web_contents()->GetController().GoBack();
1186 back_nav_load_observer
.Wait();
1189 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1190 shell()->web_contents()->GetController().GoBack();
1191 back_nav_load_observer
.Wait();
1194 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1195 shell()->web_contents()->GetController().GoBack();
1196 back_nav_load_observer
.Wait();
1199 // Now go forward twice to B2. Shouldn't be left spinning.
1201 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1202 shell()->web_contents()->GetController().GoForward();
1203 forward_nav_load_observer
.Wait();
1206 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1207 shell()->web_contents()->GetController().GoForward();
1208 forward_nav_load_observer
.Wait();
1211 // Go back twice to first site.
1213 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1214 shell()->web_contents()->GetController().GoBack();
1215 back_nav_load_observer
.Wait();
1218 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1219 shell()->web_contents()->GetController().GoBack();
1220 back_nav_load_observer
.Wait();
1223 // Now go forward directly to B3. Shouldn't be left spinning.
1225 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1226 shell()->web_contents()->GetController().GoToIndex(4);
1227 forward_nav_load_observer
.Wait();
1231 // Test for http://crbug.com/130016.
1232 // Swapping out a render view should update its visiblity state.
1233 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1234 SwappedOutViewHasCorrectVisibilityState
) {
1235 // This test is invalid in --site-per-process mode, as swapped-out is no
1237 if (RenderFrameHostManager::IsSwappedOutStateForbidden())
1241 // Load a page with links that open in a new window.
1242 std::string replacement_path
;
1243 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1244 "files/click-noreferrer-links.html",
1246 &replacement_path
));
1247 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
1249 // Open a same-site link in a new widnow.
1250 ShellAddedObserver new_shell_observer
;
1251 bool success
= false;
1252 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1253 shell()->web_contents(),
1254 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1256 EXPECT_TRUE(success
);
1257 Shell
* new_shell
= new_shell_observer
.GetShell();
1259 // Wait for the navigation in the new tab to finish, if it hasn't.
1260 WaitForLoadStop(new_shell
->web_contents());
1261 EXPECT_EQ("/files/navigate_opener.html",
1262 new_shell
->web_contents()->GetLastCommittedURL().path());
1264 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
1266 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1268 "window.domAutomationController.send("
1269 " document.visibilityState == 'visible');",
1271 EXPECT_TRUE(success
);
1273 // Now navigate the new window to a different site. This should swap out the
1274 // tab's existing RenderView, causing it become hidden.
1275 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1277 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1279 "window.domAutomationController.send("
1280 " document.visibilityState == 'hidden');",
1282 EXPECT_TRUE(success
);
1284 // Going back should make the previously swapped-out view to become visible
1287 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
1288 new_shell
->web_contents()->GetController().GoBack();
1289 back_nav_load_observer
.Wait();
1292 EXPECT_EQ("/files/navigate_opener.html",
1293 new_shell
->web_contents()->GetLastCommittedURL().path());
1295 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
1297 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1299 "window.domAutomationController.send("
1300 " document.visibilityState == 'visible');",
1302 EXPECT_TRUE(success
);
1305 // This class ensures that all the given RenderViewHosts have properly been
1307 class RenderViewHostDestructionObserver
: public WebContentsObserver
{
1309 explicit RenderViewHostDestructionObserver(WebContents
* web_contents
)
1310 : WebContentsObserver(web_contents
) {}
1311 ~RenderViewHostDestructionObserver() override
{}
1312 void EnsureRVHGetsDestructed(RenderViewHost
* rvh
) {
1313 watched_render_view_hosts_
.insert(rvh
);
1315 size_t GetNumberOfWatchedRenderViewHosts() const {
1316 return watched_render_view_hosts_
.size();
1320 // WebContentsObserver implementation:
1321 void RenderViewDeleted(RenderViewHost
* rvh
) override
{
1322 watched_render_view_hosts_
.erase(rvh
);
1325 std::set
<RenderViewHost
*> watched_render_view_hosts_
;
1328 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1329 #if defined(THREAD_SANITIZER)
1330 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1332 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1334 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1335 // they may cause crashes or memory corruptions when trying to call dead
1336 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1337 // ensure that a separate SiteInstance is created when navigating to view-source
1338 // URLs, regardless of current URL.
1339 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1340 MAYBE_LeakingRenderViewHosts
) {
1343 // Observe the created render_view_host's to make sure they will not leak.
1344 RenderViewHostDestructionObserver
rvh_observers(shell()->web_contents());
1346 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1347 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1348 navigated_url
.spec());
1350 // Let's ensure that when we start with a blank window, navigating away to a
1351 // view-source URL, we create a new SiteInstance.
1352 RenderViewHost
* blank_rvh
= shell()->web_contents()->GetRenderViewHost();
1353 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1354 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1355 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1356 rvh_observers
.EnsureRVHGetsDestructed(blank_rvh
);
1358 // Now navigate to the view-source URL and ensure we got a different
1359 // SiteInstance and RenderViewHost.
1360 NavigateToURL(shell(), view_source_url
);
1361 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1362 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1363 GetRenderViewHost()->GetSiteInstance());
1364 rvh_observers
.EnsureRVHGetsDestructed(
1365 shell()->web_contents()->GetRenderViewHost());
1367 // Load a random page and then navigate to view-source: of it.
1368 // This used to cause two RVH instances for the same SiteInstance, which
1369 // was a problem. This is no longer the case.
1370 NavigateToURL(shell(), navigated_url
);
1371 SiteInstance
* site_instance1
= shell()->web_contents()->
1372 GetRenderViewHost()->GetSiteInstance();
1373 rvh_observers
.EnsureRVHGetsDestructed(
1374 shell()->web_contents()->GetRenderViewHost());
1376 NavigateToURL(shell(), view_source_url
);
1377 rvh_observers
.EnsureRVHGetsDestructed(
1378 shell()->web_contents()->GetRenderViewHost());
1379 SiteInstance
* site_instance2
= shell()->web_contents()->
1380 GetRenderViewHost()->GetSiteInstance();
1382 // Ensure that view-source navigations force a new SiteInstance.
1383 EXPECT_NE(site_instance1
, site_instance2
);
1385 // Now navigate to a different instance so that we swap out again.
1386 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1387 rvh_observers
.EnsureRVHGetsDestructed(
1388 shell()->web_contents()->GetRenderViewHost());
1390 // This used to leak a render view host.
1393 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1395 EXPECT_EQ(0U, rvh_observers
.GetNumberOfWatchedRenderViewHosts());
1398 // Test for crbug.com/143155. Frame tree updates during unload should not
1399 // interrupt the intended navigation and show swappedout:// instead.
1401 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1402 // 2) Send the second tab to a different foo.com SiteInstance.
1403 // This creates a swapped out opener for the first tab in the foo process.
1404 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1405 // tab's unload handler remove its frame.
1406 // This used to cause an update to the frame tree of the swapped out RV,
1407 // just as it was navigating to a real page. That pre-empted the real
1408 // navigation and visibly sent the tab to swappedout://.
1409 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1410 DontPreemptNavigationWithFrameTreeUpdate
) {
1413 // 1. Load a page that deletes its iframe during unload.
1414 NavigateToURL(shell(),
1415 test_server()->GetURL("files/remove_frame_on_unload.html"));
1417 // Get the original SiteInstance for later comparison.
1418 scoped_refptr
<SiteInstance
> orig_site_instance(
1419 shell()->web_contents()->GetSiteInstance());
1421 // Open a same-site page in a new window.
1422 ShellAddedObserver new_shell_observer
;
1423 bool success
= false;
1424 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1425 shell()->web_contents(),
1426 "window.domAutomationController.send(openWindow());",
1428 EXPECT_TRUE(success
);
1429 Shell
* new_shell
= new_shell_observer
.GetShell();
1431 // Wait for the navigation in the new window to finish, if it hasn't.
1432 WaitForLoadStop(new_shell
->web_contents());
1433 EXPECT_EQ("/files/title1.html",
1434 new_shell
->web_contents()->GetLastCommittedURL().path());
1436 // Should have the same SiteInstance.
1437 EXPECT_EQ(orig_site_instance
.get(),
1438 new_shell
->web_contents()->GetSiteInstance());
1440 // 2. Send the second tab to a different process.
1441 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1442 scoped_refptr
<SiteInstance
> new_site_instance(
1443 new_shell
->web_contents()->GetSiteInstance());
1444 EXPECT_NE(orig_site_instance
, new_site_instance
);
1446 // 3. Send the first tab to the second tab's process.
1447 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1449 // Make sure it ends up at the right page.
1450 WaitForLoadStop(shell()->web_contents());
1451 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1452 shell()->web_contents()->GetLastCommittedURL());
1453 EXPECT_EQ(new_site_instance
.get(),
1454 shell()->web_contents()->GetSiteInstance());
1457 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1458 // are meant to run in the current page. We had a bug where we expected a
1459 // BrowsingInstance swap to occur on pages like view-source and extensions,
1460 // which broke chrome://crash and javascript: URLs.
1461 // See http://crbug.com/335503.
1462 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, RendererDebugURLsDontSwap
) {
1463 ASSERT_TRUE(test_server()->Start());
1465 GURL
original_url(test_server()->GetURL("files/title2.html"));
1466 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1467 original_url
.spec());
1469 NavigateToURL(shell(), view_source_url
);
1471 // Check that javascript: URLs work.
1472 base::string16 expected_title
= ASCIIToUTF16("msg");
1473 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1474 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1475 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1477 // Crash the renderer of the view-source page.
1478 RenderProcessHostWatcher
crash_observer(
1479 shell()->web_contents(),
1480 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1482 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1483 crash_observer
.Wait();
1486 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1487 // Otherwise, we might try to load an unprivileged about:blank page into a
1488 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1489 // See http://crbug.com/334214.
1490 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1491 IgnoreRendererDebugURLsWhenCrashed
) {
1492 // Visit a WebUI page with bindings.
1493 GURL webui_url
= GURL(std::string(kChromeUIScheme
) + "://" +
1494 std::string(kChromeUIGpuHost
));
1495 NavigateToURL(shell(), webui_url
);
1496 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1497 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1499 // Crash the renderer of the WebUI page.
1500 RenderProcessHostWatcher
crash_observer(
1501 shell()->web_contents(),
1502 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1504 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1505 crash_observer
.Wait();
1507 // Load the crash URL again but don't wait for any action. If it is not
1508 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1509 shell()->LoadURL(GURL(kChromeUICrashURL
));
1511 // Ensure that such URLs can still work as the initial navigation of a tab.
1512 // We postpone the initial navigation of the tab using an empty GURL, so that
1513 // we can add a watcher for crashes.
1514 Shell
* shell2
= Shell::CreateNewWindow(
1515 shell()->web_contents()->GetBrowserContext(), GURL(), NULL
, gfx::Size());
1516 RenderProcessHostWatcher
crash_observer2(
1517 shell2
->web_contents(),
1518 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1520 NavigateToURLAndExpectNoCommit(shell2
, GURL(kChromeUIKillURL
)));
1521 crash_observer2
.Wait();
1524 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1525 // See http://crbug.com/428329.
1526 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1527 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1529 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1531 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1532 // Otherwise it might get picked up by InitRenderView when granting bindings
1533 // to other RenderViewHosts. See http://crbug.com/330811.
1534 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1535 MAYBE_ClearPendingWebUIOnCommit
) {
1536 // Visit a WebUI page with bindings.
1537 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1538 std::string(kChromeUIGpuHost
)));
1539 NavigateToURL(shell(), webui_url
);
1540 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1541 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1542 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1543 shell()->web_contents());
1544 WebUIImpl
* webui
= web_contents
->GetRenderManagerForTesting()->web_ui();
1546 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1548 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1549 // clear pending_web_ui() when it commits.
1550 GURL
webui_url2(webui_url
.spec() + "#foo");
1551 NavigateToURL(shell(), webui_url2
);
1552 EXPECT_EQ(webui
, web_contents
->GetRenderManagerForTesting()->web_ui());
1553 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1556 class RFHMProcessPerTabTest
: public RenderFrameHostManagerTest
{
1558 RFHMProcessPerTabTest() {}
1560 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1561 command_line
->AppendSwitch(switches::kProcessPerTab
);
1565 // Test that we still swap processes for BrowsingInstance changes even in
1566 // --process-per-tab mode. See http://crbug.com/343017.
1567 // Disabled on Android: http://crbug.com/345873.
1568 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1569 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1570 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1572 #define MAYBE_BackFromWebUI BackFromWebUI
1574 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest
, MAYBE_BackFromWebUI
) {
1575 ASSERT_TRUE(test_server()->Start());
1576 GURL
original_url(test_server()->GetURL("files/title2.html"));
1577 NavigateToURL(shell(), original_url
);
1579 // Visit a WebUI page with bindings.
1580 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1581 std::string(kChromeUIGpuHost
)));
1582 NavigateToURL(shell(), webui_url
);
1583 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1584 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1586 // Go back and ensure we have no WebUI bindings.
1587 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1588 shell()->web_contents()->GetController().GoBack();
1589 back_nav_load_observer
.Wait();
1590 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
1591 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1592 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1596 // The test loads url1, opens a link pointing to url2 in a new tab, and
1597 // navigates the new tab to url1.
1598 // The following is needed for the bug to happen:
1599 // - url1 must require webui bindings;
1600 // - navigating to url2 in the site instance of url1 should not swap
1601 // browsing instances, but should require a new site instance.
1602 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, WebUIGetsBindings
) {
1603 GURL
url1(std::string(kChromeUIScheme
) + "://" +
1604 std::string(kChromeUIGpuHost
));
1605 GURL
url2(std::string(kChromeUIScheme
) + "://" +
1606 std::string(kChromeUIAccessibilityHost
));
1608 // Visit a WebUI page with bindings.
1609 NavigateToURL(shell(), url1
);
1610 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1611 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1612 SiteInstance
* site_instance1
= shell()->web_contents()->GetSiteInstance();
1614 // Open a new tab. Initially it gets a render view in the original tab's
1615 // current site instance.
1616 TestNavigationObserver
nav_observer(NULL
);
1617 nav_observer
.StartWatchingNewWebContents();
1618 ShellAddedObserver shao
;
1619 OpenUrlViaClickTarget(shell()->web_contents(), url2
);
1620 nav_observer
.Wait();
1621 Shell
* new_shell
= shao
.GetShell();
1622 WebContentsImpl
* new_web_contents
= static_cast<WebContentsImpl
*>(
1623 new_shell
->web_contents());
1624 SiteInstance
* site_instance2
= new_web_contents
->GetSiteInstance();
1626 EXPECT_NE(site_instance2
, site_instance1
);
1627 EXPECT_TRUE(site_instance2
->IsRelatedSiteInstance(site_instance1
));
1628 RenderViewHost
* initial_rvh
= new_web_contents
->
1629 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1
);
1630 ASSERT_TRUE(initial_rvh
);
1631 // The following condition is what was causing the bug.
1632 EXPECT_EQ(0, initial_rvh
->GetEnabledBindings());
1634 // Navigate to url1 and check bindings.
1635 NavigateToURL(new_shell
, url1
);
1636 // The navigation should have used the first SiteInstance, otherwise
1637 // |initial_rvh| did not have a chance to be used.
1638 EXPECT_EQ(new_web_contents
->GetSiteInstance(), site_instance1
);
1639 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
1640 new_web_contents
->GetRenderViewHost()->GetEnabledBindings());
1644 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1645 // page and then to a regular page. The bug reproduces if blank page is visited
1646 // in between WebUI and regular page.
1647 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1648 ForceSwapAfterWebUIBindings
) {
1649 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1650 switches::kProcessPerTab
);
1651 ASSERT_TRUE(test_server()->Start());
1653 const GURL
web_ui_url(std::string(kChromeUIScheme
) + "://" +
1654 std::string(kChromeUIGpuHost
));
1655 NavigateToURL(shell(), web_ui_url
);
1656 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1657 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1659 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1661 GURL
regular_page_url(test_server()->GetURL("files/title2.html"));
1662 NavigateToURL(shell(), regular_page_url
);
1663 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1664 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1667 class FileChooserDelegate
: public WebContentsDelegate
{
1669 FileChooserDelegate(const base::FilePath
& file
)
1670 : file_(file
), file_chosen_(false) {}
1672 void RunFileChooser(WebContents
* web_contents
,
1673 const FileChooserParams
& params
) override
{
1674 // Send the selected file to the renderer process.
1675 FileChooserFileInfo file_info
;
1676 file_info
.file_path
= file_
;
1677 std::vector
<FileChooserFileInfo
> files
;
1678 files
.push_back(file_info
);
1679 web_contents
->GetRenderViewHost()->FilesSelectedInChooser(
1680 files
, FileChooserParams::Open
);
1682 file_chosen_
= true;
1685 bool file_chosen() { return file_chosen_
; }
1688 base::FilePath file_
;
1692 // Test for http://crbug.com/262948.
1693 // Flaky on Mac. http://crbug.com/452018
1694 #if defined(OS_MACOSX)
1695 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1696 DISABLED_RestoreFileAccessForHistoryNavigation
1698 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1699 RestoreFileAccessForHistoryNavigation
1701 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1702 MAYBE_RestoreFileAccessForHistoryNavigation
) {
1704 base::FilePath file
;
1705 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file
));
1706 file
= file
.AppendASCII("bar");
1708 // Navigate to url and get it to reference a file in its PageState.
1709 GURL
url1(test_server()->GetURL("files/file_input.html"));
1710 NavigateToURL(shell(), url1
);
1711 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1712 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file
));
1713 shell()->web_contents()->SetDelegate(delegate
.get());
1714 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1715 "document.getElementById('fileinput').click();"));
1716 EXPECT_TRUE(delegate
->file_chosen());
1717 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1720 // Navigate to a different process without access to the file, and wait for
1721 // the old process to exit.
1722 RenderProcessHostWatcher
exit_observer(
1723 shell()->web_contents()->GetRenderProcessHost(),
1724 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1725 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1726 exit_observer
.Wait();
1727 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1728 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1730 // Ensure that the file ended up in the PageState of the previous entry.
1731 NavigationEntry
* prev_entry
=
1732 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1733 EXPECT_EQ(url1
, prev_entry
->GetURL());
1734 const std::vector
<base::FilePath
>& files
=
1735 prev_entry
->GetPageState().GetReferencedFiles();
1736 ASSERT_EQ(1U, files
.size());
1737 EXPECT_EQ(file
, files
.at(0));
1739 // Go back, ending up in a different RenderProcessHost than before.
1740 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1741 shell()->web_contents()->GetController().GoBack();
1742 back_nav_load_observer
.Wait();
1743 EXPECT_NE(process_id
,
1744 shell()->web_contents()->GetRenderProcessHost()->GetID());
1746 // Ensure that the file access still exists in the new process ID.
1747 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1748 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1750 // Navigate to a same site page to trigger a PageState update and ensure the
1751 // renderer is not killed.
1753 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1756 // Test for http://crbug.com/441966.
1757 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1758 RestoreSubframeFileAccessForHistoryNavigation
) {
1760 base::FilePath file
;
1761 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file
));
1762 file
= file
.AppendASCII("bar");
1764 // Navigate to url and get it to reference a file in its PageState.
1765 GURL
url1(test_server()->GetURL("files/file_input_subframe.html"));
1766 NavigateToURL(shell(), url1
);
1767 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
1768 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
1769 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1770 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file
));
1771 shell()->web_contents()->SetDelegate(delegate
.get());
1772 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
1773 "document.getElementById('fileinput').click();"));
1774 EXPECT_TRUE(delegate
->file_chosen());
1775 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1778 // Navigate to a different process without access to the file, and wait for
1779 // the old process to exit.
1780 RenderProcessHostWatcher
exit_observer(
1781 shell()->web_contents()->GetRenderProcessHost(),
1782 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1783 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1784 exit_observer
.Wait();
1785 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1786 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1788 // Ensure that the file ended up in the PageState of the previous entry.
1789 NavigationEntry
* prev_entry
=
1790 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1791 EXPECT_EQ(url1
, prev_entry
->GetURL());
1792 const std::vector
<base::FilePath
>& files
=
1793 prev_entry
->GetPageState().GetReferencedFiles();
1794 ASSERT_EQ(1U, files
.size());
1795 EXPECT_EQ(file
, files
.at(0));
1797 // Go back, ending up in a different RenderProcessHost than before.
1798 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1799 shell()->web_contents()->GetController().GoBack();
1800 back_nav_load_observer
.Wait();
1801 EXPECT_NE(process_id
,
1802 shell()->web_contents()->GetRenderProcessHost()->GetID());
1804 // Ensure that the file access still exists in the new process ID.
1805 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1806 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1809 // This class implements waiting for RenderFrameHost destruction. It relies on
1810 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1812 // Note: RenderFrameDeleted is also fired when the process associated with the
1813 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1815 class RenderFrameHostDestructionObserver
: public WebContentsObserver
{
1817 explicit RenderFrameHostDestructionObserver(RenderFrameHost
* rfh
)
1818 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh
)),
1819 message_loop_runner_(new MessageLoopRunner
),
1821 render_frame_host_(rfh
) {}
1822 ~RenderFrameHostDestructionObserver() override
{}
1828 message_loop_runner_
->Run();
1831 // WebContentsObserver implementation:
1832 void RenderFrameDeleted(RenderFrameHost
* rfh
) override
{
1833 if (rfh
== render_frame_host_
) {
1838 if (deleted_
&& message_loop_runner_
->loop_running()) {
1839 base::ThreadTaskRunnerHandle::Get()->PostTask(
1840 FROM_HERE
, message_loop_runner_
->QuitClosure());
1845 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
1847 RenderFrameHost
* render_frame_host_
;
1850 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1851 // doing a simple cross-process navigation.
1852 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1853 CleanupOnCrossProcessNavigation
) {
1854 StartEmbeddedServer();
1856 // Do an initial navigation and capture objects we expect to be cleaned up
1857 // on cross-process navigation.
1858 GURL start_url
= embedded_test_server()->GetURL("/title1.html");
1859 NavigateToURL(shell(), start_url
);
1861 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1864 int32 orig_site_instance_id
=
1865 root
->current_frame_host()->GetSiteInstance()->GetId();
1866 int initial_process_id
=
1867 root
->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1868 int initial_rfh_id
= root
->current_frame_host()->GetRoutingID();
1869 int initial_rvh_id
=
1870 root
->current_frame_host()->render_view_host()->GetRoutingID();
1872 // Navigate cross-process and ensure that cleanup is performed as expected.
1873 GURL cross_site_url
=
1874 embedded_test_server()->GetURL("foo.com", "/title2.html");
1875 RenderFrameHostDestructionObserver
rfh_observer(root
->current_frame_host());
1876 NavigateToURL(shell(), cross_site_url
);
1877 rfh_observer
.Wait();
1879 EXPECT_NE(orig_site_instance_id
,
1880 root
->current_frame_host()->GetSiteInstance()->GetId());
1881 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id
, initial_rfh_id
));
1882 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id
, initial_rvh_id
));
1885 // Ensure that the opener chain proxies and RVHs are properly reinitialized if
1886 // a tab crashes and reloads. See https://crbug.com/505090.
1887 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1888 ReinitializeOpenerChainAfterCrashAndReload
) {
1889 StartEmbeddedServer();
1891 GURL main_url
= embedded_test_server()->GetURL("/title1.html");
1892 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1894 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1898 scoped_refptr
<SiteInstance
> orig_site_instance(
1899 shell()->web_contents()->GetSiteInstance());
1900 EXPECT_TRUE(orig_site_instance
);
1902 // Open a popup and navigate it cross-site.
1903 Shell
* new_shell
= OpenPopup(shell()->web_contents(), "foo");
1904 FrameTreeNode
* popup_root
=
1905 static_cast<WebContentsImpl
*>(new_shell
->web_contents())
1909 GURL cross_site_url
=
1910 embedded_test_server()->GetURL("foo.com", "/title2.html");
1911 EXPECT_TRUE(NavigateToURL(new_shell
, cross_site_url
));
1913 scoped_refptr
<SiteInstance
> foo_site_instance(
1914 new_shell
->web_contents()->GetSiteInstance());
1915 EXPECT_NE(foo_site_instance
, orig_site_instance
);
1917 // Kill the popup's process.
1918 RenderProcessHost
* popup_process
=
1919 popup_root
->current_frame_host()->GetProcess();
1920 RenderProcessHostWatcher
crash_observer(
1921 popup_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1922 popup_process
->Shutdown(0, false);
1923 crash_observer
.Wait();
1924 EXPECT_FALSE(popup_root
->current_frame_host()->IsRenderFrameLive());
1926 popup_root
->current_frame_host()->render_view_host()->IsRenderViewLive());
1928 // The swapped-out RVH and proxy for the opener page in the foo.com
1929 // SiteInstance should not be live.
1930 RenderFrameHostManager
* opener_manager
= root
->render_manager();
1931 RenderViewHostImpl
* opener_rvh
=
1932 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get());
1933 EXPECT_TRUE(opener_rvh
);
1934 EXPECT_FALSE(opener_rvh
->IsRenderViewLive());
1935 RenderFrameProxyHost
* opener_rfph
=
1936 opener_manager
->GetRenderFrameProxyHost(foo_site_instance
.get());
1937 EXPECT_TRUE(opener_rfph
);
1938 EXPECT_FALSE(opener_rfph
->is_render_frame_proxy_live());
1940 // Re-navigate the popup to the same URL and check that this recreates the
1941 // opener's swapped out RVH and proxy in the foo.com SiteInstance.
1942 EXPECT_TRUE(NavigateToURL(new_shell
, cross_site_url
));
1943 EXPECT_TRUE(opener_rvh
->IsRenderViewLive());
1944 EXPECT_TRUE(opener_rfph
->is_render_frame_proxy_live());
1947 } // namespace content