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/common/site_isolation_policy.h"
24 #include "content/public/browser/navigation_controller.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/common/bindings_policy.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/file_chooser_file_info.h"
32 #include "content/public/common/file_chooser_params.h"
33 #include "content/public/common/page_state.h"
34 #include "content/public/common/url_constants.h"
35 #include "content/public/test/browser_test_utils.h"
36 #include "content/public/test/content_browser_test.h"
37 #include "content/public/test/content_browser_test_utils.h"
38 #include "content/public/test/test_navigation_observer.h"
39 #include "content/public/test/test_utils.h"
40 #include "content/shell/browser/shell.h"
41 #include "content/test/content_browser_test_utils_internal.h"
42 #include "net/base/net_util.h"
43 #include "net/dns/mock_host_resolver.h"
44 #include "net/test/embedded_test_server/embedded_test_server.h"
45 #include "net/test/spawned_test_server/spawned_test_server.h"
47 using base::ASCIIToUTF16
;
53 const char kOpenUrlViaClickTargetFunc
[] =
55 " var lnk = document.createElement(\"a\");\n"
57 " lnk.target = \"_blank\";\n"
58 " document.body.appendChild(lnk);\n"
62 // Adds a link with given url and target=_blank, and clicks on it.
63 void OpenUrlViaClickTarget(const ToRenderFrameHost
& adapter
, const GURL
& url
) {
64 EXPECT_TRUE(ExecuteScript(adapter
,
65 std::string(kOpenUrlViaClickTargetFunc
) + "(\"" + url
.spec() + "\");"));
68 } // anonymous namespace
70 class RenderFrameHostManagerTest
: public ContentBrowserTest
{
72 RenderFrameHostManagerTest() : foo_com_("foo.com") {
73 replace_host_
.SetHostStr(foo_com_
);
76 static bool GetFilePathWithHostAndPortReplacement(
77 const std::string
& original_file_path
,
78 const net::HostPortPair
& host_port_pair
,
79 std::string
* replacement_path
) {
80 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
81 replacement_text
.push_back(
82 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
83 return net::SpawnedTestServer::GetFilePathWithReplacements(
84 original_file_path
, replacement_text
, replacement_path
);
88 // Support multiple sites on the test server.
89 host_resolver()->AddRule("*", "127.0.0.1");
90 ASSERT_TRUE(test_server()->Start());
92 foo_host_port_
= test_server()->host_port_pair();
93 foo_host_port_
.set_host(foo_com_
);
96 void StartEmbeddedServer() {
97 // Support multiple sites on the embedded test server.
98 host_resolver()->AddRule("*", "127.0.0.1");
99 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
100 SetupCrossSiteRedirector(embedded_test_server());
103 // Returns a URL on foo.com with the given path.
104 GURL
GetCrossSiteURL(const std::string
& path
) {
105 GURL
cross_site_url(test_server()->GetURL(path
));
106 return cross_site_url
.ReplaceComponents(replace_host_
);
110 std::string foo_com_
;
111 GURL::Replacements replace_host_
;
112 net::HostPortPair foo_host_port_
;
115 // Web pages should not have script access to the swapped out page.
116 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, NoScriptAccessAfterSwapOut
) {
119 // Load a page with links that open in a new window.
120 std::string replacement_path
;
121 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
122 "files/click-noreferrer-links.html",
125 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
127 // Get the original SiteInstance for later comparison.
128 scoped_refptr
<SiteInstance
> orig_site_instance(
129 shell()->web_contents()->GetSiteInstance());
130 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
132 // Open a same-site link in a new window.
133 ShellAddedObserver new_shell_observer
;
134 bool success
= false;
135 EXPECT_TRUE(ExecuteScriptAndExtractBool(
136 shell()->web_contents(),
137 "window.domAutomationController.send(clickSameSiteTargetedLink());",
139 EXPECT_TRUE(success
);
140 Shell
* new_shell
= new_shell_observer
.GetShell();
142 // Wait for the navigation in the new window to finish, if it hasn't.
143 WaitForLoadStop(new_shell
->web_contents());
144 EXPECT_EQ("/files/navigate_opener.html",
145 new_shell
->web_contents()->GetLastCommittedURL().path());
147 // Should have the same SiteInstance.
148 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
150 // We should have access to the opened window's location.
152 EXPECT_TRUE(ExecuteScriptAndExtractBool(
153 shell()->web_contents(),
154 "window.domAutomationController.send(testScriptAccessToWindow());",
156 EXPECT_TRUE(success
);
158 // Now navigate the new window to a different site.
159 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
160 scoped_refptr
<SiteInstance
> new_site_instance(
161 new_shell
->web_contents()->GetSiteInstance());
162 EXPECT_NE(orig_site_instance
, new_site_instance
);
164 // We should no longer have script access to the opened window's location.
166 EXPECT_TRUE(ExecuteScriptAndExtractBool(
167 shell()->web_contents(),
168 "window.domAutomationController.send(testScriptAccessToWindow());",
170 EXPECT_FALSE(success
);
172 // We now navigate the window to an about:blank page.
174 EXPECT_TRUE(ExecuteScriptAndExtractBool(
175 shell()->web_contents(),
176 "window.domAutomationController.send(clickBlankTargetedLink());",
178 EXPECT_TRUE(success
);
180 // Wait for the navigation in the new window to finish.
181 WaitForLoadStop(new_shell
->web_contents());
182 GURL
blank_url(url::kAboutBlankURL
);
184 new_shell
->web_contents()->GetLastCommittedURL());
185 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
187 // We should have access to the opened window's location.
189 EXPECT_TRUE(ExecuteScriptAndExtractBool(
190 shell()->web_contents(),
191 "window.domAutomationController.send(testScriptAccessToWindow());",
193 EXPECT_TRUE(success
);
196 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
197 // and target=_blank should create a new SiteInstance.
198 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
199 SwapProcessWithRelNoreferrerAndTargetBlank
) {
202 // Load a page with links that open in a new window.
203 std::string replacement_path
;
204 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
205 "files/click-noreferrer-links.html",
208 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
210 // Get the original SiteInstance for later comparison.
211 scoped_refptr
<SiteInstance
> orig_site_instance(
212 shell()->web_contents()->GetSiteInstance());
213 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
215 // Test clicking a rel=noreferrer + target=blank link.
216 ShellAddedObserver new_shell_observer
;
217 bool success
= false;
218 EXPECT_TRUE(ExecuteScriptAndExtractBool(
219 shell()->web_contents(),
220 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
222 EXPECT_TRUE(success
);
224 // Wait for the window to open.
225 Shell
* new_shell
= new_shell_observer
.GetShell();
227 EXPECT_EQ("/files/title2.html",
228 new_shell
->web_contents()->GetVisibleURL().path());
230 // Wait for the cross-site transition in the new tab to finish.
231 WaitForLoadStop(new_shell
->web_contents());
232 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
233 new_shell
->web_contents());
234 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
235 pending_render_view_host());
237 // Should have a new SiteInstance.
238 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
239 new_shell
->web_contents()->GetSiteInstance());
240 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
243 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
244 // for rel=noreferrer links in new windows, even to same site pages and named
246 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
247 SwapProcessWithSameSiteRelNoreferrer
) {
250 // Load a page with links that open in a new window.
251 std::string replacement_path
;
252 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
253 "files/click-noreferrer-links.html",
256 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
258 // Get the original SiteInstance for later comparison.
259 scoped_refptr
<SiteInstance
> orig_site_instance(
260 shell()->web_contents()->GetSiteInstance());
261 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
263 // Test clicking a same-site rel=noreferrer + target=foo link.
264 ShellAddedObserver new_shell_observer
;
265 bool success
= false;
266 EXPECT_TRUE(ExecuteScriptAndExtractBool(
267 shell()->web_contents(),
268 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
270 EXPECT_TRUE(success
);
272 // Wait for the window to open.
273 Shell
* new_shell
= new_shell_observer
.GetShell();
275 // Opens in new window.
276 EXPECT_EQ("/files/title2.html",
277 new_shell
->web_contents()->GetVisibleURL().path());
279 // Wait for the cross-site transition in the new tab to finish.
280 WaitForLoadStop(new_shell
->web_contents());
281 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
282 new_shell
->web_contents());
283 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
284 pending_render_view_host());
286 // Should have a new SiteInstance (in a new BrowsingInstance).
287 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
288 new_shell
->web_contents()->GetSiteInstance());
289 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
292 // Test for crbug.com/24447. Following a cross-site link with just
293 // target=_blank should not create a new SiteInstance, unless we
294 // are running in --site-per-process mode.
295 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
296 DontSwapProcessWithOnlyTargetBlank
) {
299 // Load a page with links that open in a new window.
300 std::string replacement_path
;
301 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
302 "files/click-noreferrer-links.html",
305 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path
)));
307 // Get the original SiteInstance for later comparison.
308 scoped_refptr
<SiteInstance
> orig_site_instance(
309 shell()->web_contents()->GetSiteInstance());
310 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
312 // Test clicking a target=blank link.
313 ShellAddedObserver new_shell_observer
;
314 bool success
= false;
315 EXPECT_TRUE(ExecuteScriptAndExtractBool(
316 shell()->web_contents(),
317 "window.domAutomationController.send(clickTargetBlankLink());",
319 EXPECT_TRUE(success
);
321 // Wait for the window to open.
322 Shell
* new_shell
= new_shell_observer
.GetShell();
324 // Wait for the cross-site transition in the new tab to finish.
325 EXPECT_TRUE(WaitForLoadStop(new_shell
->web_contents()));
326 EXPECT_EQ("/files/title2.html",
327 new_shell
->web_contents()->GetLastCommittedURL().path());
329 // Should have the same SiteInstance unless we're in site-per-process mode.
330 scoped_refptr
<SiteInstance
> blank_site_instance(
331 new_shell
->web_contents()->GetSiteInstance());
332 if (AreAllSitesIsolatedForTesting())
333 EXPECT_NE(orig_site_instance
, blank_site_instance
);
335 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
338 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
339 // and no target=_blank should not create a new SiteInstance.
340 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
341 DontSwapProcessWithOnlyRelNoreferrer
) {
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 rel=noreferrer link.
358 bool success
= false;
359 EXPECT_TRUE(ExecuteScriptAndExtractBool(
360 shell()->web_contents(),
361 "window.domAutomationController.send(clickNoRefLink());",
363 EXPECT_TRUE(success
);
365 // Wait for the cross-site transition in the current tab to finish.
366 WaitForLoadStop(shell()->web_contents());
368 // Opens in same window.
369 EXPECT_EQ(1u, Shell::windows().size());
370 EXPECT_EQ("/files/title2.html",
371 shell()->web_contents()->GetLastCommittedURL().path());
373 // Should have the same SiteInstance unless we're in site-per-process mode.
374 scoped_refptr
<SiteInstance
> noref_site_instance(
375 shell()->web_contents()->GetSiteInstance());
376 if (AreAllSitesIsolatedForTesting())
377 EXPECT_NE(orig_site_instance
, noref_site_instance
);
379 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
382 // Test for crbug.com/116192. Targeted links should still work after the
383 // named target window has swapped processes.
384 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
385 AllowTargetedNavigationsAfterSwap
) {
388 // Load a page with links that open in a new window.
389 std::string replacement_path
;
390 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
391 "files/click-noreferrer-links.html",
394 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
396 // Get the original SiteInstance for later comparison.
397 scoped_refptr
<SiteInstance
> orig_site_instance(
398 shell()->web_contents()->GetSiteInstance());
399 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
401 // Test clicking a target=foo link.
402 ShellAddedObserver new_shell_observer
;
403 bool success
= false;
404 EXPECT_TRUE(ExecuteScriptAndExtractBool(
405 shell()->web_contents(),
406 "window.domAutomationController.send(clickSameSiteTargetedLink());",
408 EXPECT_TRUE(success
);
409 Shell
* new_shell
= new_shell_observer
.GetShell();
411 // Wait for the navigation in the new tab to finish, if it hasn't.
412 WaitForLoadStop(new_shell
->web_contents());
413 EXPECT_EQ("/files/navigate_opener.html",
414 new_shell
->web_contents()->GetLastCommittedURL().path());
416 // Should have the same SiteInstance.
417 scoped_refptr
<SiteInstance
> blank_site_instance(
418 new_shell
->web_contents()->GetSiteInstance());
419 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
421 // Now navigate the new tab to a different site.
422 GURL
cross_site_url(GetCrossSiteURL("files/title1.html"));
423 NavigateToURL(new_shell
, cross_site_url
);
424 scoped_refptr
<SiteInstance
> new_site_instance(
425 new_shell
->web_contents()->GetSiteInstance());
426 EXPECT_NE(orig_site_instance
, new_site_instance
);
428 // Clicking the original link in the first tab should cause us to swap back.
429 TestNavigationObserver
navigation_observer(new_shell
->web_contents());
430 EXPECT_TRUE(ExecuteScriptAndExtractBool(
431 shell()->web_contents(),
432 "window.domAutomationController.send(clickSameSiteTargetedLink());",
434 EXPECT_TRUE(success
);
435 navigation_observer
.Wait();
437 // Should have swapped back and shown the new window again.
438 scoped_refptr
<SiteInstance
> revisit_site_instance(
439 new_shell
->web_contents()->GetSiteInstance());
440 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
442 // If it navigates away to another process, the original window should
443 // still be able to close it (using a cross-process close message).
444 NavigateToURL(new_shell
, cross_site_url
);
445 EXPECT_EQ(new_site_instance
.get(),
446 new_shell
->web_contents()->GetSiteInstance());
447 WebContentsDestroyedWatcher
close_watcher(new_shell
->web_contents());
448 EXPECT_TRUE(ExecuteScriptAndExtractBool(
449 shell()->web_contents(),
450 "window.domAutomationController.send(testCloseWindow());",
452 EXPECT_TRUE(success
);
453 close_watcher
.Wait();
456 // Test that setting the opener to null in a window affects cross-process
457 // navigations, including those to existing entries. http://crbug.com/156669.
458 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
459 #if defined(THREAD_SANITIZER)
460 #define MAYBE_DisownOpener DISABLED_DisownOpener
462 #define MAYBE_DisownOpener DisownOpener
464 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_DisownOpener
) {
467 // Load a page with links that open in a new window.
468 std::string replacement_path
;
469 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
470 "files/click-noreferrer-links.html",
473 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
475 // Get the original SiteInstance for later comparison.
476 scoped_refptr
<SiteInstance
> orig_site_instance(
477 shell()->web_contents()->GetSiteInstance());
478 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
480 // Test clicking a target=_blank link.
481 ShellAddedObserver new_shell_observer
;
482 bool success
= false;
483 EXPECT_TRUE(ExecuteScriptAndExtractBool(
484 shell()->web_contents(),
485 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
487 EXPECT_TRUE(success
);
488 Shell
* new_shell
= new_shell_observer
.GetShell();
489 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
491 // Wait for the navigation in the new tab to finish, if it hasn't.
492 WaitForLoadStop(new_shell
->web_contents());
493 EXPECT_EQ("/files/title2.html",
494 new_shell
->web_contents()->GetLastCommittedURL().path());
496 // Should have the same SiteInstance.
497 scoped_refptr
<SiteInstance
> blank_site_instance(
498 new_shell
->web_contents()->GetSiteInstance());
499 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
501 // Now navigate the new tab to a different site.
502 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
503 scoped_refptr
<SiteInstance
> new_site_instance(
504 new_shell
->web_contents()->GetSiteInstance());
505 EXPECT_NE(orig_site_instance
, new_site_instance
);
506 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
508 // Now disown the opener.
509 EXPECT_TRUE(ExecuteScript(new_shell
->web_contents(),
510 "window.opener = null;"));
511 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
513 // Go back and ensure the opener is still null.
515 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
516 new_shell
->web_contents()->GetController().GoBack();
517 back_nav_load_observer
.Wait();
520 EXPECT_TRUE(ExecuteScriptAndExtractBool(
521 new_shell
->web_contents(),
522 "window.domAutomationController.send(window.opener == null);",
524 EXPECT_TRUE(success
);
525 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
527 // Now navigate forward again (creating a new process) and check opener.
528 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
530 EXPECT_TRUE(ExecuteScriptAndExtractBool(
531 new_shell
->web_contents(),
532 "window.domAutomationController.send(window.opener == null);",
534 EXPECT_TRUE(success
);
535 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
538 // Test that subframes can disown their openers. http://crbug.com/225528.
539 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, DisownSubframeOpener
) {
540 const GURL
frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
541 NavigateToURL(shell(), frame_url
);
543 // Give the frame an opener using window.open.
544 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
545 "window.open('about:blank','foo');"));
547 // Now disown the frame's opener. Shouldn't crash.
548 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
549 "window.frames[0].opener = null;"));
552 // Check that window.name is preserved for top frames when they navigate
553 // cross-process. See https://crbug.com/504164.
554 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
555 PreserveTopFrameWindowNameOnCrossProcessNavigations
) {
556 StartEmbeddedServer();
558 GURL
main_url(embedded_test_server()->GetURL("/title1.html"));
559 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
561 // Get the original SiteInstance for later comparison.
562 scoped_refptr
<SiteInstance
> orig_site_instance(
563 shell()->web_contents()->GetSiteInstance());
564 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
566 // Open a popup using window.open with a 'foo' window.name.
568 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL
), "foo");
569 EXPECT_TRUE(new_shell
);
571 // The window.name for the new popup should be "foo".
573 EXPECT_TRUE(ExecuteScriptAndExtractString(
574 new_shell
->web_contents(),
575 "window.domAutomationController.send(window.name);", &name
));
576 EXPECT_EQ("foo", name
);
578 // Now navigate the new tab to a different site.
579 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
580 EXPECT_TRUE(NavigateToURL(new_shell
, foo_url
));
581 scoped_refptr
<SiteInstance
> new_site_instance(
582 new_shell
->web_contents()->GetSiteInstance());
583 EXPECT_NE(orig_site_instance
, new_site_instance
);
585 // window.name should still be "foo".
587 EXPECT_TRUE(ExecuteScriptAndExtractString(
588 new_shell
->web_contents(),
589 "window.domAutomationController.send(window.name);", &name
));
590 EXPECT_EQ("foo", name
);
592 // Open another popup from the 'foo' popup and navigate it cross-site.
594 OpenPopup(new_shell
->web_contents(), GURL(url::kAboutBlankURL
), "bar");
595 EXPECT_TRUE(new_shell2
);
596 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title3.html"));
597 EXPECT_TRUE(NavigateToURL(new_shell2
, bar_url
));
599 // Check that the new popup's window.opener has name "foo", which verifies
600 // that new swapped-out RenderViews also propagate window.name. This has to
601 // be done via window.open, since window.name isn't readable cross-origin.
602 bool success
= false;
603 EXPECT_TRUE(ExecuteScriptAndExtractBool(
604 new_shell2
->web_contents(),
605 "window.domAutomationController.send("
606 " window.opener === window.open('','foo'));",
608 EXPECT_TRUE(success
);
611 // Test for crbug.com/99202. PostMessage calls should still work after
612 // navigating the source and target windows to different sites.
614 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
615 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
616 // 3) Post a message from "foo" to opener, which replies back to "foo".
617 // 4) Post a message from _blank to "foo".
618 // 5) Post a message from "foo" to a subframe of opener, which replies back.
619 // 6) Post a message from _blank to a subframe of "foo".
620 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
621 SupportCrossProcessPostMessage
) {
624 // Load a page with links that open in a new window.
625 std::string replacement_path
;
626 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
627 "files/click-noreferrer-links.html",
630 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
632 // Get the original SiteInstance and RVHM for later comparison.
633 WebContents
* opener_contents
= shell()->web_contents();
634 scoped_refptr
<SiteInstance
> orig_site_instance(
635 opener_contents
->GetSiteInstance());
636 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
637 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
638 opener_contents
)->GetRenderManagerForTesting();
640 // 1) Open two more windows, one named. These initially have openers but no
641 // reference to each other. We will later post a message between them.
643 // First, a named target=foo window.
644 ShellAddedObserver new_shell_observer
;
645 bool success
= false;
646 EXPECT_TRUE(ExecuteScriptAndExtractBool(
648 "window.domAutomationController.send(clickSameSiteTargetedLink());",
650 EXPECT_TRUE(success
);
651 Shell
* new_shell
= new_shell_observer
.GetShell();
653 // Wait for the navigation in the new window to finish, if it hasn't, then
654 // send it to post_message.html on a different site.
655 WebContents
* foo_contents
= new_shell
->web_contents();
656 WaitForLoadStop(foo_contents
);
657 EXPECT_EQ("/files/navigate_opener.html",
658 foo_contents
->GetLastCommittedURL().path());
659 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
660 scoped_refptr
<SiteInstance
> foo_site_instance(
661 foo_contents
->GetSiteInstance());
662 EXPECT_NE(orig_site_instance
, foo_site_instance
);
664 // Second, a target=_blank window.
665 ShellAddedObserver new_shell_observer2
;
666 EXPECT_TRUE(ExecuteScriptAndExtractBool(
667 shell()->web_contents(),
668 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
670 EXPECT_TRUE(success
);
672 // Wait for the navigation in the new window to finish, if it hasn't, then
673 // send it to post_message.html on the original site.
674 Shell
* new_shell2
= new_shell_observer2
.GetShell();
675 WebContents
* new_contents
= new_shell2
->web_contents();
676 WaitForLoadStop(new_contents
);
677 EXPECT_EQ("/files/title2.html", new_contents
->GetLastCommittedURL().path());
678 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
679 EXPECT_EQ(orig_site_instance
.get(), new_contents
->GetSiteInstance());
680 RenderFrameHostManager
* new_manager
=
681 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
683 // We now have three windows. The opener should have a swapped out RVH
684 // for the new SiteInstance, but the _blank window should not.
685 EXPECT_EQ(3u, Shell::windows().size());
687 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
689 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
691 // 2) Fail to post a message from the foo window to the opener if the target
692 // origin is wrong. We won't see an error, but we can check for the right
693 // number of received messages below.
694 EXPECT_TRUE(ExecuteScriptAndExtractBool(
696 "window.domAutomationController.send(postToOpener('msg',"
697 " 'http://google.com'));",
699 EXPECT_TRUE(success
);
701 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
703 // 3) Post a message from the foo window to the opener. The opener will
704 // reply, causing the foo window to update its own title.
705 base::string16 expected_title
= ASCIIToUTF16("msg");
706 TitleWatcher
title_watcher(foo_contents
, expected_title
);
707 EXPECT_TRUE(ExecuteScriptAndExtractBool(
709 "window.domAutomationController.send(postToOpener('msg','*'));",
711 EXPECT_TRUE(success
);
713 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
714 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
716 // We should have received only 1 message in the opener and "foo" tabs,
717 // and updated the title.
718 int opener_received_messages
= 0;
719 EXPECT_TRUE(ExecuteScriptAndExtractInt(
721 "window.domAutomationController.send(window.receivedMessages);",
722 &opener_received_messages
));
723 int foo_received_messages
= 0;
724 EXPECT_TRUE(ExecuteScriptAndExtractInt(
726 "window.domAutomationController.send(window.receivedMessages);",
727 &foo_received_messages
));
728 EXPECT_EQ(1, foo_received_messages
);
729 EXPECT_EQ(1, opener_received_messages
);
730 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
732 // 4) Now post a message from the _blank window to the foo window. The
733 // foo window will update its title and will not reply.
734 expected_title
= ASCIIToUTF16("msg2");
735 TitleWatcher
title_watcher2(foo_contents
, expected_title
);
736 EXPECT_TRUE(ExecuteScriptAndExtractBool(
738 "window.domAutomationController.send(postToFoo('msg2'));",
740 EXPECT_TRUE(success
);
741 ASSERT_EQ(expected_title
, title_watcher2
.WaitAndGetTitle());
743 // This postMessage should have created a swapped out RVH for the new
744 // SiteInstance in the target=_blank window.
746 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
748 // TODO(nasko): Test subframe targeting of postMessage once
749 // http://crbug.com/153701 is fixed.
752 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
753 // messages which contain Transferables and get intercepted by
754 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
755 // swapped out) should work.
757 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
758 // 2) Post a message containing a message port from opener to "foo".
759 // 3) Post a message from "foo" back to opener via the passed message port.
760 // The test will be enabled when the feature implementation lands.
761 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
762 SupportCrossProcessPostMessageWithMessagePort
) {
765 // Load a page with links that open in a new window.
766 std::string replacement_path
;
767 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
768 "files/click-noreferrer-links.html",
771 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
773 // Get the original SiteInstance and RVHM for later comparison.
774 WebContents
* opener_contents
= shell()->web_contents();
775 scoped_refptr
<SiteInstance
> orig_site_instance(
776 opener_contents
->GetSiteInstance());
777 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
778 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
779 opener_contents
)->GetRenderManagerForTesting();
781 // 1) Open a named target=foo window. We will later post a message between the
782 // opener and the new window.
783 ShellAddedObserver new_shell_observer
;
784 bool success
= false;
785 EXPECT_TRUE(ExecuteScriptAndExtractBool(
787 "window.domAutomationController.send(clickSameSiteTargetedLink());",
789 EXPECT_TRUE(success
);
790 Shell
* new_shell
= new_shell_observer
.GetShell();
792 // Wait for the navigation in the new window to finish, if it hasn't, then
793 // send it to post_message.html on a different site.
794 WebContents
* foo_contents
= new_shell
->web_contents();
795 WaitForLoadStop(foo_contents
);
796 EXPECT_EQ("/files/navigate_opener.html",
797 foo_contents
->GetLastCommittedURL().path());
798 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
799 scoped_refptr
<SiteInstance
> foo_site_instance(
800 foo_contents
->GetSiteInstance());
801 EXPECT_NE(orig_site_instance
, foo_site_instance
);
803 // We now have two windows. The opener should have a swapped out RVH
804 // for the new SiteInstance.
805 EXPECT_EQ(2u, Shell::windows().size());
807 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
809 // 2) Post a message containing a MessagePort from opener to the the foo
810 // window. The foo window will reply via the passed port, causing the opener
811 // to update its own title.
812 base::string16 expected_title
= ASCIIToUTF16("msg-back-via-port");
813 TitleWatcher
title_observer(opener_contents
, expected_title
);
814 EXPECT_TRUE(ExecuteScriptAndExtractBool(
816 "window.domAutomationController.send(postWithPortToFoo());",
818 EXPECT_TRUE(success
);
820 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
821 ASSERT_EQ(expected_title
, title_observer
.WaitAndGetTitle());
823 // Check message counts.
824 int opener_received_messages_via_port
= 0;
825 EXPECT_TRUE(ExecuteScriptAndExtractInt(
827 "window.domAutomationController.send(window.receivedMessagesViaPort);",
828 &opener_received_messages_via_port
));
829 int foo_received_messages
= 0;
830 EXPECT_TRUE(ExecuteScriptAndExtractInt(
832 "window.domAutomationController.send(window.receivedMessages);",
833 &foo_received_messages
));
834 int foo_received_messages_with_port
= 0;
835 EXPECT_TRUE(ExecuteScriptAndExtractInt(
837 "window.domAutomationController.send(window.receivedMessagesWithPort);",
838 &foo_received_messages_with_port
));
839 EXPECT_EQ(1, foo_received_messages
);
840 EXPECT_EQ(1, foo_received_messages_with_port
);
841 EXPECT_EQ(1, opener_received_messages_via_port
);
842 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents
->GetTitle());
843 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents
->GetTitle());
846 // Test for crbug.com/116192. Navigations to a window's opener should
847 // still work after a process swap.
848 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
849 AllowTargetedNavigationsInOpenerAfterSwap
) {
852 // Load a page with links that open in a new window.
853 std::string replacement_path
;
854 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
855 "files/click-noreferrer-links.html",
858 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
860 // Get the original tab and SiteInstance for later comparison.
861 WebContents
* orig_contents
= shell()->web_contents();
862 scoped_refptr
<SiteInstance
> orig_site_instance(
863 orig_contents
->GetSiteInstance());
864 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
866 // Test clicking a target=foo link.
867 ShellAddedObserver new_shell_observer
;
868 bool success
= false;
869 EXPECT_TRUE(ExecuteScriptAndExtractBool(
871 "window.domAutomationController.send(clickSameSiteTargetedLink());",
873 EXPECT_TRUE(success
);
874 Shell
* new_shell
= new_shell_observer
.GetShell();
876 // Wait for the navigation in the new window to finish, if it hasn't.
877 WaitForLoadStop(new_shell
->web_contents());
878 EXPECT_EQ("/files/navigate_opener.html",
879 new_shell
->web_contents()->GetLastCommittedURL().path());
881 // Should have the same SiteInstance.
882 scoped_refptr
<SiteInstance
> blank_site_instance(
883 new_shell
->web_contents()->GetSiteInstance());
884 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
886 // Now navigate the original (opener) tab to a different site.
887 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
888 scoped_refptr
<SiteInstance
> new_site_instance(
889 shell()->web_contents()->GetSiteInstance());
890 EXPECT_NE(orig_site_instance
, new_site_instance
);
892 // The opened tab should be able to navigate the opener back to its process.
893 TestNavigationObserver
navigation_observer(orig_contents
);
894 EXPECT_TRUE(ExecuteScriptAndExtractBool(
895 new_shell
->web_contents(),
896 "window.domAutomationController.send(navigateOpener());",
898 EXPECT_TRUE(success
);
899 navigation_observer
.Wait();
901 // Should have swapped back into this process.
902 scoped_refptr
<SiteInstance
> revisit_site_instance(
903 shell()->web_contents()->GetSiteInstance());
904 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
907 // Test that subframes do not crash when sending a postMessage to the top frame
908 // from an unload handler while the top frame is being swapped out as part of
909 // navigating cross-process. https://crbug.com/475651.
910 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
911 PostMessageFromSubframeUnloadHandler
) {
914 GURL
frame_url(test_server()->GetURL("files/post_message.html"));
915 GURL
main_url("data:text/html,<iframe name='foo' src='" + frame_url
.spec() +
917 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
919 // Get the original SiteInstance for later comparison.
920 scoped_refptr
<SiteInstance
> orig_site_instance(
921 shell()->web_contents()->GetSiteInstance());
922 EXPECT_NE(nullptr, orig_site_instance
.get());
924 // It is safe to obtain the root frame tree node here, as it doesn't change.
925 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
928 ASSERT_EQ(1U, root
->child_count());
929 EXPECT_EQ(frame_url
, root
->child_at(0)->current_url());
931 // Register an unload handler that sends a postMessage to the top frame.
932 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
933 "registerUnload();"));
935 // Navigate the top frame cross-site. This will cause the top frame to be
936 // swapped out and run unload handlers, and the original renderer process
937 // should then terminate since it's not rendering any other frames.
938 RenderProcessHostWatcher
exit_observer(
939 root
->current_frame_host()->GetProcess(),
940 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
941 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
942 scoped_refptr
<SiteInstance
> new_site_instance(
943 shell()->web_contents()->GetSiteInstance());
944 EXPECT_NE(orig_site_instance
, new_site_instance
);
946 // Ensure that the original renderer process exited cleanly without crashing.
947 exit_observer
.Wait();
948 EXPECT_EQ(true, exit_observer
.did_exit_normally());
951 // Test that opening a new window in the same SiteInstance and then navigating
952 // both windows to a different SiteInstance allows the first process to exit.
953 // See http://crbug.com/126333.
954 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
955 ProcessExitWithSwappedOutViews
) {
958 // Load a page with links that open in a new window.
959 std::string replacement_path
;
960 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
961 "files/click-noreferrer-links.html",
964 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
966 // Get the original SiteInstance for later comparison.
967 scoped_refptr
<SiteInstance
> orig_site_instance(
968 shell()->web_contents()->GetSiteInstance());
969 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
971 // Test clicking a target=foo link.
972 ShellAddedObserver new_shell_observer
;
973 bool success
= false;
974 EXPECT_TRUE(ExecuteScriptAndExtractBool(
975 shell()->web_contents(),
976 "window.domAutomationController.send(clickSameSiteTargetedLink());",
978 EXPECT_TRUE(success
);
979 Shell
* new_shell
= new_shell_observer
.GetShell();
981 // Wait for the navigation in the new window to finish, if it hasn't.
982 WaitForLoadStop(new_shell
->web_contents());
983 EXPECT_EQ("/files/navigate_opener.html",
984 new_shell
->web_contents()->GetLastCommittedURL().path());
986 // Should have the same SiteInstance.
987 scoped_refptr
<SiteInstance
> opened_site_instance(
988 new_shell
->web_contents()->GetSiteInstance());
989 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
991 // Now navigate the opened window to a different site.
992 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
993 scoped_refptr
<SiteInstance
> new_site_instance(
994 new_shell
->web_contents()->GetSiteInstance());
995 EXPECT_NE(orig_site_instance
, new_site_instance
);
997 // The original process should still be alive, since it is still used in the
999 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
1000 EXPECT_TRUE(orig_process
->HasConnection());
1002 // Navigate the first window to a different site as well. The original
1003 // process should exit, since all of its views are now swapped out.
1004 RenderProcessHostWatcher
exit_observer(
1006 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1007 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1008 exit_observer
.Wait();
1009 scoped_refptr
<SiteInstance
> new_site_instance2(
1010 shell()->web_contents()->GetSiteInstance());
1011 EXPECT_EQ(new_site_instance
, new_site_instance2
);
1014 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
1015 // error should not make us ignore future renderer-initiated navigations.
1016 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ClickLinkAfter204Error
) {
1019 // Get the original SiteInstance for later comparison.
1020 scoped_refptr
<SiteInstance
> orig_site_instance(
1021 shell()->web_contents()->GetSiteInstance());
1022 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
1024 // Load a cross-site page that fails with a 204 error.
1025 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
1026 GetCrossSiteURL("nocontent")));
1028 // We should still be looking at the normal page. Because we started from a
1029 // blank new tab, the typed URL will still be visible until the user clears it
1030 // manually. The last committed URL will be the previous page.
1031 scoped_refptr
<SiteInstance
> post_nav_site_instance(
1032 shell()->web_contents()->GetSiteInstance());
1033 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
1034 EXPECT_EQ("/nocontent",
1035 shell()->web_contents()->GetVisibleURL().path());
1037 shell()->web_contents()->GetController().GetLastCommittedEntry());
1039 // Renderer-initiated navigations should work.
1040 base::string16 expected_title
= ASCIIToUTF16("Title Of Awesomeness");
1041 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1042 GURL url
= test_server()->GetURL("files/title2.html");
1043 EXPECT_TRUE(ExecuteScript(
1044 shell()->web_contents(),
1045 base::StringPrintf("location.href = '%s'", url
.spec().c_str())));
1046 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1048 // Opens in same tab.
1049 EXPECT_EQ(1u, Shell::windows().size());
1050 EXPECT_EQ("/files/title2.html",
1051 shell()->web_contents()->GetLastCommittedURL().path());
1053 // Should have the same SiteInstance.
1054 scoped_refptr
<SiteInstance
> new_site_instance(
1055 shell()->web_contents()->GetSiteInstance());
1056 EXPECT_EQ(orig_site_instance
, new_site_instance
);
1059 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1060 // initiated navigation in a new tab, until the content of the initial
1061 // about:blank page is modified by another window. At that point, we should
1062 // revert to showing about:blank to prevent a URL spoof.
1063 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ShowLoadingURLUntilSpoof
) {
1064 ASSERT_TRUE(test_server()->Start());
1066 // Load a page that can open a URL that won't commit in a new window.
1068 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1069 WebContents
* orig_contents
= shell()->web_contents();
1071 // Click a /nocontent link that opens in a new window but never commits.
1072 ShellAddedObserver new_shell_observer
;
1073 bool success
= false;
1074 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1076 "window.domAutomationController.send(clickNoContentTargetedLink());",
1078 EXPECT_TRUE(success
);
1080 // Wait for the window to open.
1081 Shell
* new_shell
= new_shell_observer
.GetShell();
1083 // Ensure the destination URL is visible, because it is considered the
1084 // initial navigation.
1085 WebContents
* contents
= new_shell
->web_contents();
1086 EXPECT_TRUE(contents
->GetController().IsInitialNavigation());
1087 EXPECT_EQ("/nocontent",
1088 contents
->GetController().GetVisibleEntry()->GetURL().path());
1090 // Now modify the contents of the new window from the opener. This will also
1091 // modify the title of the document to give us something to listen for.
1092 base::string16 expected_title
= ASCIIToUTF16("Modified Title");
1093 TitleWatcher
title_watcher(contents
, expected_title
);
1095 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1097 "window.domAutomationController.send(modifyNewWindow());",
1099 EXPECT_TRUE(success
);
1100 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1102 // At this point, we should no longer be showing the destination URL.
1103 // The visible entry should be null, resulting in about:blank in the address
1105 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1108 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1109 // initiated navigation in a new tab if it is not the initial navigation. In
1110 // this case, the renderer will not notify us of a modification, so we cannot
1111 // show the pending URL without allowing a spoof.
1112 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1113 DontShowLoadingURLIfNotInitialNav
) {
1114 ASSERT_TRUE(test_server()->Start());
1116 // Load a page that can open a URL that won't commit in a new window.
1118 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1119 WebContents
* orig_contents
= shell()->web_contents();
1121 // Click a /nocontent link that opens in a new window but never commits.
1122 // By using an onclick handler that first creates the window, the slow
1123 // navigation is not considered an initial navigation.
1124 ShellAddedObserver new_shell_observer
;
1125 bool success
= false;
1126 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1128 "window.domAutomationController.send("
1129 "clickNoContentScriptedTargetedLink());",
1131 EXPECT_TRUE(success
);
1133 // Wait for the window to open.
1134 Shell
* new_shell
= new_shell_observer
.GetShell();
1136 // Ensure the destination URL is not visible, because it is not the initial
1138 WebContents
* contents
= new_shell
->web_contents();
1139 EXPECT_FALSE(contents
->GetController().IsInitialNavigation());
1140 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1143 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1144 #if defined(THREAD_SANITIZER)
1145 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1147 #define MAYBE_BackForwardNotStale BackForwardNotStale
1149 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1150 // do not cause back/forward navigations to be considered stale by the
1152 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_BackForwardNotStale
) {
1154 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1156 // Visit a page on first site.
1157 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1159 // Visit three pages on second site.
1160 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1161 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1162 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1164 // History is now [blank, A1, B1, B2, *B3].
1165 WebContents
* contents
= shell()->web_contents();
1166 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
1168 // Open another window in same process to keep this process alive.
1169 Shell
* new_shell
= CreateBrowser();
1170 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1172 // Go back three times to first site.
1174 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1175 shell()->web_contents()->GetController().GoBack();
1176 back_nav_load_observer
.Wait();
1179 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1180 shell()->web_contents()->GetController().GoBack();
1181 back_nav_load_observer
.Wait();
1184 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1185 shell()->web_contents()->GetController().GoBack();
1186 back_nav_load_observer
.Wait();
1189 // Now go forward twice to B2. Shouldn't be left spinning.
1191 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1192 shell()->web_contents()->GetController().GoForward();
1193 forward_nav_load_observer
.Wait();
1196 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1197 shell()->web_contents()->GetController().GoForward();
1198 forward_nav_load_observer
.Wait();
1201 // Go back twice to first site.
1203 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1204 shell()->web_contents()->GetController().GoBack();
1205 back_nav_load_observer
.Wait();
1208 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1209 shell()->web_contents()->GetController().GoBack();
1210 back_nav_load_observer
.Wait();
1213 // Now go forward directly to B3. Shouldn't be left spinning.
1215 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1216 shell()->web_contents()->GetController().GoToIndex(4);
1217 forward_nav_load_observer
.Wait();
1221 // Test for http://crbug.com/130016.
1222 // Swapping out a render view should update its visiblity state.
1223 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1224 SwappedOutViewHasCorrectVisibilityState
) {
1225 // This test is invalid in --site-per-process mode, as swapped-out is no
1227 if (SiteIsolationPolicy::IsSwappedOutStateForbidden())
1231 // Load a page with links that open in a new window.
1232 std::string replacement_path
;
1233 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1234 "files/click-noreferrer-links.html",
1236 &replacement_path
));
1237 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
1239 // Open a same-site link in a new widnow.
1240 ShellAddedObserver new_shell_observer
;
1241 bool success
= false;
1242 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1243 shell()->web_contents(),
1244 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1246 EXPECT_TRUE(success
);
1247 Shell
* new_shell
= new_shell_observer
.GetShell();
1249 // Wait for the navigation in the new tab to finish, if it hasn't.
1250 WaitForLoadStop(new_shell
->web_contents());
1251 EXPECT_EQ("/files/navigate_opener.html",
1252 new_shell
->web_contents()->GetLastCommittedURL().path());
1254 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
1256 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1258 "window.domAutomationController.send("
1259 " document.visibilityState == 'visible');",
1261 EXPECT_TRUE(success
);
1263 // Now navigate the new window to a different site. This should swap out the
1264 // tab's existing RenderView, causing it become hidden.
1265 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1267 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1269 "window.domAutomationController.send("
1270 " document.visibilityState == 'hidden');",
1272 EXPECT_TRUE(success
);
1274 // Going back should make the previously swapped-out view to become visible
1277 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
1278 new_shell
->web_contents()->GetController().GoBack();
1279 back_nav_load_observer
.Wait();
1282 EXPECT_EQ("/files/navigate_opener.html",
1283 new_shell
->web_contents()->GetLastCommittedURL().path());
1285 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
1287 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1289 "window.domAutomationController.send("
1290 " document.visibilityState == 'visible');",
1292 EXPECT_TRUE(success
);
1295 // This class ensures that all the given RenderViewHosts have properly been
1297 class RenderViewHostDestructionObserver
: public WebContentsObserver
{
1299 explicit RenderViewHostDestructionObserver(WebContents
* web_contents
)
1300 : WebContentsObserver(web_contents
) {}
1301 ~RenderViewHostDestructionObserver() override
{}
1302 void EnsureRVHGetsDestructed(RenderViewHost
* rvh
) {
1303 watched_render_view_hosts_
.insert(rvh
);
1305 size_t GetNumberOfWatchedRenderViewHosts() const {
1306 return watched_render_view_hosts_
.size();
1310 // WebContentsObserver implementation:
1311 void RenderViewDeleted(RenderViewHost
* rvh
) override
{
1312 watched_render_view_hosts_
.erase(rvh
);
1315 std::set
<RenderViewHost
*> watched_render_view_hosts_
;
1318 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1319 #if defined(THREAD_SANITIZER)
1320 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1322 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1324 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1325 // they may cause crashes or memory corruptions when trying to call dead
1326 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1327 // ensure that a separate SiteInstance is created when navigating to view-source
1328 // URLs, regardless of current URL.
1329 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1330 MAYBE_LeakingRenderViewHosts
) {
1333 // Observe the created render_view_host's to make sure they will not leak.
1334 RenderViewHostDestructionObserver
rvh_observers(shell()->web_contents());
1336 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1337 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1338 navigated_url
.spec());
1340 // Let's ensure that when we start with a blank window, navigating away to a
1341 // view-source URL, we create a new SiteInstance.
1342 RenderViewHost
* blank_rvh
= shell()->web_contents()->GetRenderViewHost();
1343 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1344 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1345 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1346 rvh_observers
.EnsureRVHGetsDestructed(blank_rvh
);
1348 // Now navigate to the view-source URL and ensure we got a different
1349 // SiteInstance and RenderViewHost.
1350 NavigateToURL(shell(), view_source_url
);
1351 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1352 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1353 GetRenderViewHost()->GetSiteInstance());
1354 rvh_observers
.EnsureRVHGetsDestructed(
1355 shell()->web_contents()->GetRenderViewHost());
1357 // Load a random page and then navigate to view-source: of it.
1358 // This used to cause two RVH instances for the same SiteInstance, which
1359 // was a problem. This is no longer the case.
1360 NavigateToURL(shell(), navigated_url
);
1361 SiteInstance
* site_instance1
= shell()->web_contents()->
1362 GetRenderViewHost()->GetSiteInstance();
1363 rvh_observers
.EnsureRVHGetsDestructed(
1364 shell()->web_contents()->GetRenderViewHost());
1366 NavigateToURL(shell(), view_source_url
);
1367 rvh_observers
.EnsureRVHGetsDestructed(
1368 shell()->web_contents()->GetRenderViewHost());
1369 SiteInstance
* site_instance2
= shell()->web_contents()->
1370 GetRenderViewHost()->GetSiteInstance();
1372 // Ensure that view-source navigations force a new SiteInstance.
1373 EXPECT_NE(site_instance1
, site_instance2
);
1375 // Now navigate to a different instance so that we swap out again.
1376 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1377 rvh_observers
.EnsureRVHGetsDestructed(
1378 shell()->web_contents()->GetRenderViewHost());
1380 // This used to leak a render view host.
1383 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1385 EXPECT_EQ(0U, rvh_observers
.GetNumberOfWatchedRenderViewHosts());
1388 // Test for crbug.com/143155. Frame tree updates during unload should not
1389 // interrupt the intended navigation and show swappedout:// instead.
1391 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1392 // 2) Send the second tab to a different foo.com SiteInstance.
1393 // This creates a swapped out opener for the first tab in the foo process.
1394 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1395 // tab's unload handler remove its frame.
1396 // This used to cause an update to the frame tree of the swapped out RV,
1397 // just as it was navigating to a real page. That pre-empted the real
1398 // navigation and visibly sent the tab to swappedout://.
1399 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1400 DontPreemptNavigationWithFrameTreeUpdate
) {
1403 // 1. Load a page that deletes its iframe during unload.
1404 NavigateToURL(shell(),
1405 test_server()->GetURL("files/remove_frame_on_unload.html"));
1407 // Get the original SiteInstance for later comparison.
1408 scoped_refptr
<SiteInstance
> orig_site_instance(
1409 shell()->web_contents()->GetSiteInstance());
1411 // Open a same-site page in a new window.
1412 ShellAddedObserver new_shell_observer
;
1413 bool success
= false;
1414 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1415 shell()->web_contents(),
1416 "window.domAutomationController.send(openWindow());",
1418 EXPECT_TRUE(success
);
1419 Shell
* new_shell
= new_shell_observer
.GetShell();
1421 // Wait for the navigation in the new window to finish, if it hasn't.
1422 WaitForLoadStop(new_shell
->web_contents());
1423 EXPECT_EQ("/files/title1.html",
1424 new_shell
->web_contents()->GetLastCommittedURL().path());
1426 // Should have the same SiteInstance.
1427 EXPECT_EQ(orig_site_instance
.get(),
1428 new_shell
->web_contents()->GetSiteInstance());
1430 // 2. Send the second tab to a different process.
1431 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1432 scoped_refptr
<SiteInstance
> new_site_instance(
1433 new_shell
->web_contents()->GetSiteInstance());
1434 EXPECT_NE(orig_site_instance
, new_site_instance
);
1436 // 3. Send the first tab to the second tab's process.
1437 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1439 // Make sure it ends up at the right page.
1440 WaitForLoadStop(shell()->web_contents());
1441 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1442 shell()->web_contents()->GetLastCommittedURL());
1443 EXPECT_EQ(new_site_instance
.get(),
1444 shell()->web_contents()->GetSiteInstance());
1447 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1448 // are meant to run in the current page. We had a bug where we expected a
1449 // BrowsingInstance swap to occur on pages like view-source and extensions,
1450 // which broke chrome://crash and javascript: URLs.
1451 // See http://crbug.com/335503.
1452 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, RendererDebugURLsDontSwap
) {
1453 ASSERT_TRUE(test_server()->Start());
1455 GURL
original_url(test_server()->GetURL("files/title2.html"));
1456 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1457 original_url
.spec());
1459 NavigateToURL(shell(), view_source_url
);
1461 // Check that javascript: URLs work.
1462 base::string16 expected_title
= ASCIIToUTF16("msg");
1463 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1464 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1465 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1467 // Crash the renderer of the view-source page.
1468 RenderProcessHostWatcher
crash_observer(
1469 shell()->web_contents(),
1470 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1472 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1473 crash_observer
.Wait();
1476 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1477 // Otherwise, we might try to load an unprivileged about:blank page into a
1478 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1479 // See http://crbug.com/334214.
1480 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1481 IgnoreRendererDebugURLsWhenCrashed
) {
1482 // Visit a WebUI page with bindings.
1483 GURL webui_url
= GURL(std::string(kChromeUIScheme
) + "://" +
1484 std::string(kChromeUIGpuHost
));
1485 NavigateToURL(shell(), webui_url
);
1486 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1487 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1489 // Crash the renderer of the WebUI page.
1490 RenderProcessHostWatcher
crash_observer(
1491 shell()->web_contents(),
1492 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1494 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1495 crash_observer
.Wait();
1497 // Load the crash URL again but don't wait for any action. If it is not
1498 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1499 shell()->LoadURL(GURL(kChromeUICrashURL
));
1501 // Ensure that such URLs can still work as the initial navigation of a tab.
1502 // We postpone the initial navigation of the tab using an empty GURL, so that
1503 // we can add a watcher for crashes.
1504 Shell
* shell2
= Shell::CreateNewWindow(
1505 shell()->web_contents()->GetBrowserContext(), GURL(), NULL
, gfx::Size());
1506 RenderProcessHostWatcher
crash_observer2(
1507 shell2
->web_contents(),
1508 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1510 NavigateToURLAndExpectNoCommit(shell2
, GURL(kChromeUIKillURL
)));
1511 crash_observer2
.Wait();
1514 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1515 // See http://crbug.com/428329.
1516 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1517 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1519 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1521 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1522 // Otherwise it might get picked up by InitRenderView when granting bindings
1523 // to other RenderViewHosts. See http://crbug.com/330811.
1524 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1525 MAYBE_ClearPendingWebUIOnCommit
) {
1526 // Visit a WebUI page with bindings.
1527 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1528 std::string(kChromeUIGpuHost
)));
1529 NavigateToURL(shell(), webui_url
);
1530 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1531 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1532 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1533 shell()->web_contents());
1534 WebUIImpl
* webui
= web_contents
->GetRenderManagerForTesting()->web_ui();
1536 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1538 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1539 // clear pending_web_ui() when it commits.
1540 GURL
webui_url2(webui_url
.spec() + "#foo");
1541 NavigateToURL(shell(), webui_url2
);
1542 EXPECT_EQ(webui
, web_contents
->GetRenderManagerForTesting()->web_ui());
1543 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1546 class RFHMProcessPerTabTest
: public RenderFrameHostManagerTest
{
1548 RFHMProcessPerTabTest() {}
1550 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1551 command_line
->AppendSwitch(switches::kProcessPerTab
);
1555 // Test that we still swap processes for BrowsingInstance changes even in
1556 // --process-per-tab mode. See http://crbug.com/343017.
1557 // Disabled on Android: http://crbug.com/345873.
1558 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1559 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1560 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1562 #define MAYBE_BackFromWebUI BackFromWebUI
1564 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest
, MAYBE_BackFromWebUI
) {
1565 ASSERT_TRUE(test_server()->Start());
1566 GURL
original_url(test_server()->GetURL("files/title2.html"));
1567 NavigateToURL(shell(), original_url
);
1569 // Visit a WebUI page with bindings.
1570 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1571 std::string(kChromeUIGpuHost
)));
1572 NavigateToURL(shell(), webui_url
);
1573 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1574 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1576 // Go back and ensure we have no WebUI bindings.
1577 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1578 shell()->web_contents()->GetController().GoBack();
1579 back_nav_load_observer
.Wait();
1580 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
1581 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1582 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1586 // The test loads url1, opens a link pointing to url2 in a new tab, and
1587 // navigates the new tab to url1.
1588 // The following is needed for the bug to happen:
1589 // - url1 must require webui bindings;
1590 // - navigating to url2 in the site instance of url1 should not swap
1591 // browsing instances, but should require a new site instance.
1592 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, WebUIGetsBindings
) {
1593 GURL
url1(std::string(kChromeUIScheme
) + "://" +
1594 std::string(kChromeUIGpuHost
));
1595 GURL
url2(std::string(kChromeUIScheme
) + "://" +
1596 std::string(kChromeUIAccessibilityHost
));
1598 // Visit a WebUI page with bindings.
1599 NavigateToURL(shell(), url1
);
1600 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1601 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1602 SiteInstance
* site_instance1
= shell()->web_contents()->GetSiteInstance();
1604 // Open a new tab. Initially it gets a render view in the original tab's
1605 // current site instance.
1606 TestNavigationObserver
nav_observer(NULL
);
1607 nav_observer
.StartWatchingNewWebContents();
1608 ShellAddedObserver shao
;
1609 OpenUrlViaClickTarget(shell()->web_contents(), url2
);
1610 nav_observer
.Wait();
1611 Shell
* new_shell
= shao
.GetShell();
1612 WebContentsImpl
* new_web_contents
= static_cast<WebContentsImpl
*>(
1613 new_shell
->web_contents());
1614 SiteInstance
* site_instance2
= new_web_contents
->GetSiteInstance();
1616 EXPECT_NE(site_instance2
, site_instance1
);
1617 EXPECT_TRUE(site_instance2
->IsRelatedSiteInstance(site_instance1
));
1618 RenderViewHost
* initial_rvh
= new_web_contents
->
1619 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1
);
1620 ASSERT_TRUE(initial_rvh
);
1621 // The following condition is what was causing the bug.
1622 EXPECT_EQ(0, initial_rvh
->GetEnabledBindings());
1624 // Navigate to url1 and check bindings.
1625 NavigateToURL(new_shell
, url1
);
1626 // The navigation should have used the first SiteInstance, otherwise
1627 // |initial_rvh| did not have a chance to be used.
1628 EXPECT_EQ(new_web_contents
->GetSiteInstance(), site_instance1
);
1629 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
1630 new_web_contents
->GetRenderViewHost()->GetEnabledBindings());
1634 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1635 // page and then to a regular page. The bug reproduces if blank page is visited
1636 // in between WebUI and regular page.
1637 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1638 ForceSwapAfterWebUIBindings
) {
1639 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1640 switches::kProcessPerTab
);
1641 ASSERT_TRUE(test_server()->Start());
1643 const GURL
web_ui_url(std::string(kChromeUIScheme
) + "://" +
1644 std::string(kChromeUIGpuHost
));
1645 NavigateToURL(shell(), web_ui_url
);
1646 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1647 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1649 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1651 GURL
regular_page_url(test_server()->GetURL("files/title2.html"));
1652 NavigateToURL(shell(), regular_page_url
);
1653 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1654 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1657 class FileChooserDelegate
: public WebContentsDelegate
{
1659 FileChooserDelegate(const base::FilePath
& file
)
1660 : file_(file
), file_chosen_(false) {}
1662 void RunFileChooser(WebContents
* web_contents
,
1663 const FileChooserParams
& params
) override
{
1664 // Send the selected file to the renderer process.
1665 FileChooserFileInfo file_info
;
1666 file_info
.file_path
= file_
;
1667 std::vector
<FileChooserFileInfo
> files
;
1668 files
.push_back(file_info
);
1669 web_contents
->GetRenderViewHost()->FilesSelectedInChooser(
1670 files
, FileChooserParams::Open
);
1672 file_chosen_
= true;
1675 bool file_chosen() { return file_chosen_
; }
1678 base::FilePath file_
;
1682 // Test for http://crbug.com/262948.
1683 // Flaky on Mac. http://crbug.com/452018
1684 #if defined(OS_MACOSX)
1685 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1686 DISABLED_RestoreFileAccessForHistoryNavigation
1688 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1689 RestoreFileAccessForHistoryNavigation
1691 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1692 MAYBE_RestoreFileAccessForHistoryNavigation
) {
1694 base::FilePath file
;
1695 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file
));
1696 file
= file
.AppendASCII("bar");
1698 // Navigate to url and get it to reference a file in its PageState.
1699 GURL
url1(test_server()->GetURL("files/file_input.html"));
1700 NavigateToURL(shell(), url1
);
1701 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1702 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file
));
1703 shell()->web_contents()->SetDelegate(delegate
.get());
1704 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1705 "document.getElementById('fileinput').click();"));
1706 EXPECT_TRUE(delegate
->file_chosen());
1707 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1710 // Navigate to a different process without access to the file, and wait for
1711 // the old process to exit.
1712 RenderProcessHostWatcher
exit_observer(
1713 shell()->web_contents()->GetRenderProcessHost(),
1714 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1715 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1716 exit_observer
.Wait();
1717 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1718 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1720 // Ensure that the file ended up in the PageState of the previous entry.
1721 NavigationEntry
* prev_entry
=
1722 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1723 EXPECT_EQ(url1
, prev_entry
->GetURL());
1724 const std::vector
<base::FilePath
>& files
=
1725 prev_entry
->GetPageState().GetReferencedFiles();
1726 ASSERT_EQ(1U, files
.size());
1727 EXPECT_EQ(file
, files
.at(0));
1729 // Go back, ending up in a different RenderProcessHost than before.
1730 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1731 shell()->web_contents()->GetController().GoBack();
1732 back_nav_load_observer
.Wait();
1733 EXPECT_NE(process_id
,
1734 shell()->web_contents()->GetRenderProcessHost()->GetID());
1736 // Ensure that the file access still exists in the new process ID.
1737 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1738 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1740 // Navigate to a same site page to trigger a PageState update and ensure the
1741 // renderer is not killed.
1743 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1746 // Test for http://crbug.com/441966.
1747 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1748 RestoreSubframeFileAccessForHistoryNavigation
) {
1750 base::FilePath file
;
1751 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file
));
1752 file
= file
.AppendASCII("bar");
1754 // Navigate to url and get it to reference a file in its PageState.
1755 GURL
url1(test_server()->GetURL("files/file_input_subframe.html"));
1756 NavigateToURL(shell(), url1
);
1757 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
1758 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
1759 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1760 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file
));
1761 shell()->web_contents()->SetDelegate(delegate
.get());
1762 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
1763 "document.getElementById('fileinput').click();"));
1764 EXPECT_TRUE(delegate
->file_chosen());
1765 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1768 // Navigate to a different process without access to the file, and wait for
1769 // the old process to exit.
1770 RenderProcessHostWatcher
exit_observer(
1771 shell()->web_contents()->GetRenderProcessHost(),
1772 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1773 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1774 exit_observer
.Wait();
1775 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1776 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1778 // Ensure that the file ended up in the PageState of the previous entry.
1779 NavigationEntry
* prev_entry
=
1780 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1781 EXPECT_EQ(url1
, prev_entry
->GetURL());
1782 const std::vector
<base::FilePath
>& files
=
1783 prev_entry
->GetPageState().GetReferencedFiles();
1784 ASSERT_EQ(1U, files
.size());
1785 EXPECT_EQ(file
, files
.at(0));
1787 // Go back, ending up in a different RenderProcessHost than before.
1788 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1789 shell()->web_contents()->GetController().GoBack();
1790 back_nav_load_observer
.Wait();
1791 EXPECT_NE(process_id
,
1792 shell()->web_contents()->GetRenderProcessHost()->GetID());
1794 // Ensure that the file access still exists in the new process ID.
1795 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1796 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1799 // This class implements waiting for RenderFrameHost destruction. It relies on
1800 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1802 // Note: RenderFrameDeleted is also fired when the process associated with the
1803 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1805 class RenderFrameHostDestructionObserver
: public WebContentsObserver
{
1807 explicit RenderFrameHostDestructionObserver(RenderFrameHost
* rfh
)
1808 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh
)),
1809 message_loop_runner_(new MessageLoopRunner
),
1811 render_frame_host_(rfh
) {}
1812 ~RenderFrameHostDestructionObserver() override
{}
1818 message_loop_runner_
->Run();
1821 // WebContentsObserver implementation:
1822 void RenderFrameDeleted(RenderFrameHost
* rfh
) override
{
1823 if (rfh
== render_frame_host_
) {
1828 if (deleted_
&& message_loop_runner_
->loop_running()) {
1829 base::ThreadTaskRunnerHandle::Get()->PostTask(
1830 FROM_HERE
, message_loop_runner_
->QuitClosure());
1835 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
1837 RenderFrameHost
* render_frame_host_
;
1840 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1841 // doing a simple cross-process navigation.
1842 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1843 CleanupOnCrossProcessNavigation
) {
1844 StartEmbeddedServer();
1846 // Do an initial navigation and capture objects we expect to be cleaned up
1847 // on cross-process navigation.
1848 GURL start_url
= embedded_test_server()->GetURL("/title1.html");
1849 NavigateToURL(shell(), start_url
);
1851 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1854 int32 orig_site_instance_id
=
1855 root
->current_frame_host()->GetSiteInstance()->GetId();
1856 int initial_process_id
=
1857 root
->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1858 int initial_rfh_id
= root
->current_frame_host()->GetRoutingID();
1859 int initial_rvh_id
=
1860 root
->current_frame_host()->render_view_host()->GetRoutingID();
1862 // Navigate cross-process and ensure that cleanup is performed as expected.
1863 GURL cross_site_url
=
1864 embedded_test_server()->GetURL("foo.com", "/title2.html");
1865 RenderFrameHostDestructionObserver
rfh_observer(root
->current_frame_host());
1866 NavigateToURL(shell(), cross_site_url
);
1867 rfh_observer
.Wait();
1869 EXPECT_NE(orig_site_instance_id
,
1870 root
->current_frame_host()->GetSiteInstance()->GetId());
1871 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id
, initial_rfh_id
));
1872 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id
, initial_rvh_id
));
1875 // Ensure that the opener chain proxies and RVHs are properly reinitialized if
1876 // a tab crashes and reloads. See https://crbug.com/505090.
1877 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1878 ReinitializeOpenerChainAfterCrashAndReload
) {
1879 StartEmbeddedServer();
1881 GURL main_url
= embedded_test_server()->GetURL("/title1.html");
1882 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1884 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1888 scoped_refptr
<SiteInstance
> orig_site_instance(
1889 shell()->web_contents()->GetSiteInstance());
1890 EXPECT_TRUE(orig_site_instance
);
1892 // Open a popup and navigate it cross-site.
1894 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL
), "foo");
1895 EXPECT_TRUE(new_shell
);
1896 FrameTreeNode
* popup_root
=
1897 static_cast<WebContentsImpl
*>(new_shell
->web_contents())
1901 GURL cross_site_url
=
1902 embedded_test_server()->GetURL("foo.com", "/title2.html");
1903 EXPECT_TRUE(NavigateToURL(new_shell
, cross_site_url
));
1905 scoped_refptr
<SiteInstance
> foo_site_instance(
1906 new_shell
->web_contents()->GetSiteInstance());
1907 EXPECT_NE(foo_site_instance
, orig_site_instance
);
1909 // Kill the popup's process.
1910 RenderProcessHost
* popup_process
=
1911 popup_root
->current_frame_host()->GetProcess();
1912 RenderProcessHostWatcher
crash_observer(
1913 popup_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1914 popup_process
->Shutdown(0, false);
1915 crash_observer
.Wait();
1916 EXPECT_FALSE(popup_root
->current_frame_host()->IsRenderFrameLive());
1918 popup_root
->current_frame_host()->render_view_host()->IsRenderViewLive());
1920 // The swapped-out RVH and proxy for the opener page in the foo.com
1921 // SiteInstance should not be live.
1922 RenderFrameHostManager
* opener_manager
= root
->render_manager();
1923 RenderViewHostImpl
* opener_rvh
=
1924 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get());
1925 EXPECT_TRUE(opener_rvh
);
1926 EXPECT_FALSE(opener_rvh
->IsRenderViewLive());
1927 RenderFrameProxyHost
* opener_rfph
=
1928 opener_manager
->GetRenderFrameProxyHost(foo_site_instance
.get());
1929 EXPECT_TRUE(opener_rfph
);
1930 EXPECT_FALSE(opener_rfph
->is_render_frame_proxy_live());
1932 // Re-navigate the popup to the same URL and check that this recreates the
1933 // opener's swapped out RVH and proxy in the foo.com SiteInstance.
1934 EXPECT_TRUE(NavigateToURL(new_shell
, cross_site_url
));
1935 EXPECT_TRUE(opener_rvh
->IsRenderViewLive());
1936 EXPECT_TRUE(opener_rfph
->is_render_frame_proxy_live());
1939 } // namespace content