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 "content/test/content_browser_test_utils_internal.h"
41 #include "net/base/net_util.h"
42 #include "net/dns/mock_host_resolver.h"
43 #include "net/test/embedded_test_server/embedded_test_server.h"
44 #include "net/test/spawned_test_server/spawned_test_server.h"
46 using base::ASCIIToUTF16
;
52 const char kOpenUrlViaClickTargetFunc
[] =
54 " var lnk = document.createElement(\"a\");\n"
56 " lnk.target = \"_blank\";\n"
57 " document.body.appendChild(lnk);\n"
61 // Adds a link with given url and target=_blank, and clicks on it.
62 void OpenUrlViaClickTarget(const ToRenderFrameHost
& adapter
, const GURL
& url
) {
63 EXPECT_TRUE(ExecuteScript(adapter
,
64 std::string(kOpenUrlViaClickTargetFunc
) + "(\"" + url
.spec() + "\");"));
67 } // anonymous namespace
69 class RenderFrameHostManagerTest
: public ContentBrowserTest
{
71 RenderFrameHostManagerTest() : foo_com_("foo.com") {
72 replace_host_
.SetHostStr(foo_com_
);
75 static bool GetFilePathWithHostAndPortReplacement(
76 const std::string
& original_file_path
,
77 const net::HostPortPair
& host_port_pair
,
78 std::string
* replacement_path
) {
79 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
80 replacement_text
.push_back(
81 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
82 return net::SpawnedTestServer::GetFilePathWithReplacements(
83 original_file_path
, replacement_text
, replacement_path
);
87 // Support multiple sites on the test server.
88 host_resolver()->AddRule("*", "127.0.0.1");
89 ASSERT_TRUE(test_server()->Start());
91 foo_host_port_
= test_server()->host_port_pair();
92 foo_host_port_
.set_host(foo_com_
);
95 void StartEmbeddedServer() {
96 // Support multiple sites on the embedded test server.
97 host_resolver()->AddRule("*", "127.0.0.1");
98 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
99 SetupCrossSiteRedirector(embedded_test_server());
102 // Returns a URL on foo.com with the given path.
103 GURL
GetCrossSiteURL(const std::string
& path
) {
104 GURL
cross_site_url(test_server()->GetURL(path
));
105 return cross_site_url
.ReplaceComponents(replace_host_
);
109 std::string foo_com_
;
110 GURL::Replacements replace_host_
;
111 net::HostPortPair foo_host_port_
;
114 // Web pages should not have script access to the swapped out page.
115 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, NoScriptAccessAfterSwapOut
) {
118 // Load a page with links that open in a new window.
119 std::string replacement_path
;
120 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
121 "files/click-noreferrer-links.html",
124 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
126 // Get the original SiteInstance for later comparison.
127 scoped_refptr
<SiteInstance
> orig_site_instance(
128 shell()->web_contents()->GetSiteInstance());
129 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
131 // Open a same-site link in a new window.
132 ShellAddedObserver new_shell_observer
;
133 bool success
= false;
134 EXPECT_TRUE(ExecuteScriptAndExtractBool(
135 shell()->web_contents(),
136 "window.domAutomationController.send(clickSameSiteTargetedLink());",
138 EXPECT_TRUE(success
);
139 Shell
* new_shell
= new_shell_observer
.GetShell();
141 // Wait for the navigation in the new window to finish, if it hasn't.
142 WaitForLoadStop(new_shell
->web_contents());
143 EXPECT_EQ("/files/navigate_opener.html",
144 new_shell
->web_contents()->GetLastCommittedURL().path());
146 // Should have the same SiteInstance.
147 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
149 // We should have access to the opened window's location.
151 EXPECT_TRUE(ExecuteScriptAndExtractBool(
152 shell()->web_contents(),
153 "window.domAutomationController.send(testScriptAccessToWindow());",
155 EXPECT_TRUE(success
);
157 // Now navigate the new window to a different site.
158 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
159 scoped_refptr
<SiteInstance
> new_site_instance(
160 new_shell
->web_contents()->GetSiteInstance());
161 EXPECT_NE(orig_site_instance
, new_site_instance
);
163 // We should no longer have script access to the opened window's location.
165 EXPECT_TRUE(ExecuteScriptAndExtractBool(
166 shell()->web_contents(),
167 "window.domAutomationController.send(testScriptAccessToWindow());",
169 EXPECT_FALSE(success
);
171 // We now navigate the window to an about:blank page.
173 EXPECT_TRUE(ExecuteScriptAndExtractBool(
174 shell()->web_contents(),
175 "window.domAutomationController.send(clickBlankTargetedLink());",
177 EXPECT_TRUE(success
);
179 // Wait for the navigation in the new window to finish.
180 WaitForLoadStop(new_shell
->web_contents());
181 GURL
blank_url(url::kAboutBlankURL
);
183 new_shell
->web_contents()->GetLastCommittedURL());
184 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
186 // We should have access to the opened window's location.
188 EXPECT_TRUE(ExecuteScriptAndExtractBool(
189 shell()->web_contents(),
190 "window.domAutomationController.send(testScriptAccessToWindow());",
192 EXPECT_TRUE(success
);
195 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
196 // and target=_blank should create a new SiteInstance.
197 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
198 SwapProcessWithRelNoreferrerAndTargetBlank
) {
201 // Load a page with links that open in a new window.
202 std::string replacement_path
;
203 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
204 "files/click-noreferrer-links.html",
207 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
209 // Get the original SiteInstance for later comparison.
210 scoped_refptr
<SiteInstance
> orig_site_instance(
211 shell()->web_contents()->GetSiteInstance());
212 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
214 // Test clicking a rel=noreferrer + target=blank link.
215 ShellAddedObserver new_shell_observer
;
216 bool success
= false;
217 EXPECT_TRUE(ExecuteScriptAndExtractBool(
218 shell()->web_contents(),
219 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
221 EXPECT_TRUE(success
);
223 // Wait for the window to open.
224 Shell
* new_shell
= new_shell_observer
.GetShell();
226 EXPECT_EQ("/files/title2.html",
227 new_shell
->web_contents()->GetVisibleURL().path());
229 // Wait for the cross-site transition in the new tab to finish.
230 WaitForLoadStop(new_shell
->web_contents());
231 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
232 new_shell
->web_contents());
233 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
234 pending_render_view_host());
236 // Should have a new SiteInstance.
237 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
238 new_shell
->web_contents()->GetSiteInstance());
239 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
242 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
243 // for rel=noreferrer links in new windows, even to same site pages and named
245 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
246 SwapProcessWithSameSiteRelNoreferrer
) {
249 // Load a page with links that open in a new window.
250 std::string replacement_path
;
251 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
252 "files/click-noreferrer-links.html",
255 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
257 // Get the original SiteInstance for later comparison.
258 scoped_refptr
<SiteInstance
> orig_site_instance(
259 shell()->web_contents()->GetSiteInstance());
260 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
262 // Test clicking a same-site rel=noreferrer + target=foo link.
263 ShellAddedObserver new_shell_observer
;
264 bool success
= false;
265 EXPECT_TRUE(ExecuteScriptAndExtractBool(
266 shell()->web_contents(),
267 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
269 EXPECT_TRUE(success
);
271 // Wait for the window to open.
272 Shell
* new_shell
= new_shell_observer
.GetShell();
274 // Opens in new window.
275 EXPECT_EQ("/files/title2.html",
276 new_shell
->web_contents()->GetVisibleURL().path());
278 // Wait for the cross-site transition in the new tab to finish.
279 WaitForLoadStop(new_shell
->web_contents());
280 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
281 new_shell
->web_contents());
282 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
283 pending_render_view_host());
285 // Should have a new SiteInstance (in a new BrowsingInstance).
286 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
287 new_shell
->web_contents()->GetSiteInstance());
288 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
291 // Test for crbug.com/24447. Following a cross-site link with just
292 // target=_blank should not create a new SiteInstance, unless we
293 // are running in --site-per-process mode.
294 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
295 DontSwapProcessWithOnlyTargetBlank
) {
298 // Load a page with links that open in a new window.
299 std::string replacement_path
;
300 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
301 "files/click-noreferrer-links.html",
304 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path
)));
306 // Get the original SiteInstance for later comparison.
307 scoped_refptr
<SiteInstance
> orig_site_instance(
308 shell()->web_contents()->GetSiteInstance());
309 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
311 // Test clicking a target=blank link.
312 ShellAddedObserver new_shell_observer
;
313 bool success
= false;
314 EXPECT_TRUE(ExecuteScriptAndExtractBool(
315 shell()->web_contents(),
316 "window.domAutomationController.send(clickTargetBlankLink());",
318 EXPECT_TRUE(success
);
320 // Wait for the window to open.
321 Shell
* new_shell
= new_shell_observer
.GetShell();
323 // Wait for the cross-site transition in the new tab to finish.
324 EXPECT_TRUE(WaitForLoadStop(new_shell
->web_contents()));
325 EXPECT_EQ("/files/title2.html",
326 new_shell
->web_contents()->GetLastCommittedURL().path());
328 // Should have the same SiteInstance unless we're in site-per-process mode.
329 scoped_refptr
<SiteInstance
> blank_site_instance(
330 new_shell
->web_contents()->GetSiteInstance());
331 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
332 switches::kSitePerProcess
))
333 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
335 EXPECT_NE(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 (!base::CommandLine::ForCurrentProcess()->HasSwitch(
377 switches::kSitePerProcess
))
378 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
380 EXPECT_NE(orig_site_instance
, noref_site_instance
);
383 // Test for crbug.com/116192. Targeted links should still work after the
384 // named target window has swapped processes.
385 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
386 AllowTargetedNavigationsAfterSwap
) {
389 // Load a page with links that open in a new window.
390 std::string replacement_path
;
391 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
392 "files/click-noreferrer-links.html",
395 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
397 // Get the original SiteInstance for later comparison.
398 scoped_refptr
<SiteInstance
> orig_site_instance(
399 shell()->web_contents()->GetSiteInstance());
400 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
402 // Test clicking a target=foo link.
403 ShellAddedObserver new_shell_observer
;
404 bool success
= false;
405 EXPECT_TRUE(ExecuteScriptAndExtractBool(
406 shell()->web_contents(),
407 "window.domAutomationController.send(clickSameSiteTargetedLink());",
409 EXPECT_TRUE(success
);
410 Shell
* new_shell
= new_shell_observer
.GetShell();
412 // Wait for the navigation in the new tab to finish, if it hasn't.
413 WaitForLoadStop(new_shell
->web_contents());
414 EXPECT_EQ("/files/navigate_opener.html",
415 new_shell
->web_contents()->GetLastCommittedURL().path());
417 // Should have the same SiteInstance.
418 scoped_refptr
<SiteInstance
> blank_site_instance(
419 new_shell
->web_contents()->GetSiteInstance());
420 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
422 // Now navigate the new tab to a different site.
423 GURL
cross_site_url(GetCrossSiteURL("files/title1.html"));
424 NavigateToURL(new_shell
, cross_site_url
);
425 scoped_refptr
<SiteInstance
> new_site_instance(
426 new_shell
->web_contents()->GetSiteInstance());
427 EXPECT_NE(orig_site_instance
, new_site_instance
);
429 // Clicking the original link in the first tab should cause us to swap back.
430 TestNavigationObserver
navigation_observer(new_shell
->web_contents());
431 EXPECT_TRUE(ExecuteScriptAndExtractBool(
432 shell()->web_contents(),
433 "window.domAutomationController.send(clickSameSiteTargetedLink());",
435 EXPECT_TRUE(success
);
436 navigation_observer
.Wait();
438 // Should have swapped back and shown the new window again.
439 scoped_refptr
<SiteInstance
> revisit_site_instance(
440 new_shell
->web_contents()->GetSiteInstance());
441 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
443 // If it navigates away to another process, the original window should
444 // still be able to close it (using a cross-process close message).
445 NavigateToURL(new_shell
, cross_site_url
);
446 EXPECT_EQ(new_site_instance
.get(),
447 new_shell
->web_contents()->GetSiteInstance());
448 WebContentsDestroyedWatcher
close_watcher(new_shell
->web_contents());
449 EXPECT_TRUE(ExecuteScriptAndExtractBool(
450 shell()->web_contents(),
451 "window.domAutomationController.send(testCloseWindow());",
453 EXPECT_TRUE(success
);
454 close_watcher
.Wait();
457 // Test that setting the opener to null in a window affects cross-process
458 // navigations, including those to existing entries. http://crbug.com/156669.
459 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
460 #if defined(THREAD_SANITIZER)
461 #define MAYBE_DisownOpener DISABLED_DisownOpener
463 #define MAYBE_DisownOpener DisownOpener
465 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_DisownOpener
) {
468 // Load a page with links that open in a new window.
469 std::string replacement_path
;
470 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
471 "files/click-noreferrer-links.html",
474 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
476 // Get the original SiteInstance for later comparison.
477 scoped_refptr
<SiteInstance
> orig_site_instance(
478 shell()->web_contents()->GetSiteInstance());
479 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
481 // Test clicking a target=_blank link.
482 ShellAddedObserver new_shell_observer
;
483 bool success
= false;
484 EXPECT_TRUE(ExecuteScriptAndExtractBool(
485 shell()->web_contents(),
486 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
488 EXPECT_TRUE(success
);
489 Shell
* new_shell
= new_shell_observer
.GetShell();
490 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
492 // Wait for the navigation in the new tab to finish, if it hasn't.
493 WaitForLoadStop(new_shell
->web_contents());
494 EXPECT_EQ("/files/title2.html",
495 new_shell
->web_contents()->GetLastCommittedURL().path());
497 // Should have the same SiteInstance.
498 scoped_refptr
<SiteInstance
> blank_site_instance(
499 new_shell
->web_contents()->GetSiteInstance());
500 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
502 // Now navigate the new tab to a different site.
503 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
504 scoped_refptr
<SiteInstance
> new_site_instance(
505 new_shell
->web_contents()->GetSiteInstance());
506 EXPECT_NE(orig_site_instance
, new_site_instance
);
507 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
509 // Now disown the opener.
510 EXPECT_TRUE(ExecuteScript(new_shell
->web_contents(),
511 "window.opener = null;"));
512 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
514 // Go back and ensure the opener is still null.
516 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
517 new_shell
->web_contents()->GetController().GoBack();
518 back_nav_load_observer
.Wait();
521 EXPECT_TRUE(ExecuteScriptAndExtractBool(
522 new_shell
->web_contents(),
523 "window.domAutomationController.send(window.opener == null);",
525 EXPECT_TRUE(success
);
526 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
528 // Now navigate forward again (creating a new process) and check opener.
529 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
531 EXPECT_TRUE(ExecuteScriptAndExtractBool(
532 new_shell
->web_contents(),
533 "window.domAutomationController.send(window.opener == null);",
535 EXPECT_TRUE(success
);
536 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
539 // Test that subframes can disown their openers. http://crbug.com/225528.
540 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, DisownSubframeOpener
) {
541 const GURL
frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
542 NavigateToURL(shell(), frame_url
);
544 // Give the frame an opener using window.open.
545 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
546 "window.open('about:blank','foo');"));
548 // Now disown the frame's opener. Shouldn't crash.
549 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
550 "window.frames[0].opener = null;"));
553 // Check that window.name is preserved for top frames when they navigate
554 // cross-process. See https://crbug.com/504164.
555 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
556 PreserveTopFrameWindowNameOnCrossProcessNavigations
) {
557 StartEmbeddedServer();
559 GURL
main_url(embedded_test_server()->GetURL("/title1.html"));
560 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
562 // Get the original SiteInstance for later comparison.
563 scoped_refptr
<SiteInstance
> orig_site_instance(
564 shell()->web_contents()->GetSiteInstance());
565 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
567 // Open a popup using window.open with a 'foo' window.name.
569 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL
), "foo");
570 EXPECT_TRUE(new_shell
);
572 // The window.name for the new popup should be "foo".
574 EXPECT_TRUE(ExecuteScriptAndExtractString(
575 new_shell
->web_contents(),
576 "window.domAutomationController.send(window.name);", &name
));
577 EXPECT_EQ("foo", name
);
579 // Now navigate the new tab to a different site.
580 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
581 EXPECT_TRUE(NavigateToURL(new_shell
, foo_url
));
582 scoped_refptr
<SiteInstance
> new_site_instance(
583 new_shell
->web_contents()->GetSiteInstance());
584 EXPECT_NE(orig_site_instance
, new_site_instance
);
586 // window.name should still be "foo".
588 EXPECT_TRUE(ExecuteScriptAndExtractString(
589 new_shell
->web_contents(),
590 "window.domAutomationController.send(window.name);", &name
));
591 EXPECT_EQ("foo", name
);
593 // Open another popup from the 'foo' popup and navigate it cross-site.
595 OpenPopup(new_shell
->web_contents(), GURL(url::kAboutBlankURL
), "bar");
596 EXPECT_TRUE(new_shell2
);
597 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title3.html"));
598 EXPECT_TRUE(NavigateToURL(new_shell2
, bar_url
));
600 // Check that the new popup's window.opener has name "foo", which verifies
601 // that new swapped-out RenderViews also propagate window.name. This has to
602 // be done via window.open, since window.name isn't readable cross-origin.
603 bool success
= false;
604 EXPECT_TRUE(ExecuteScriptAndExtractBool(
605 new_shell2
->web_contents(),
606 "window.domAutomationController.send("
607 " window.opener === window.open('','foo'));",
609 EXPECT_TRUE(success
);
612 // Test for crbug.com/99202. PostMessage calls should still work after
613 // navigating the source and target windows to different sites.
615 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
616 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
617 // 3) Post a message from "foo" to opener, which replies back to "foo".
618 // 4) Post a message from _blank to "foo".
619 // 5) Post a message from "foo" to a subframe of opener, which replies back.
620 // 6) Post a message from _blank to a subframe of "foo".
621 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
622 SupportCrossProcessPostMessage
) {
625 // Load a page with links that open in a new window.
626 std::string replacement_path
;
627 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
628 "files/click-noreferrer-links.html",
631 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
633 // Get the original SiteInstance and RVHM for later comparison.
634 WebContents
* opener_contents
= shell()->web_contents();
635 scoped_refptr
<SiteInstance
> orig_site_instance(
636 opener_contents
->GetSiteInstance());
637 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
638 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
639 opener_contents
)->GetRenderManagerForTesting();
641 // 1) Open two more windows, one named. These initially have openers but no
642 // reference to each other. We will later post a message between them.
644 // First, a named target=foo window.
645 ShellAddedObserver new_shell_observer
;
646 bool success
= false;
647 EXPECT_TRUE(ExecuteScriptAndExtractBool(
649 "window.domAutomationController.send(clickSameSiteTargetedLink());",
651 EXPECT_TRUE(success
);
652 Shell
* new_shell
= new_shell_observer
.GetShell();
654 // Wait for the navigation in the new window to finish, if it hasn't, then
655 // send it to post_message.html on a different site.
656 WebContents
* foo_contents
= new_shell
->web_contents();
657 WaitForLoadStop(foo_contents
);
658 EXPECT_EQ("/files/navigate_opener.html",
659 foo_contents
->GetLastCommittedURL().path());
660 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
661 scoped_refptr
<SiteInstance
> foo_site_instance(
662 foo_contents
->GetSiteInstance());
663 EXPECT_NE(orig_site_instance
, foo_site_instance
);
665 // Second, a target=_blank window.
666 ShellAddedObserver new_shell_observer2
;
667 EXPECT_TRUE(ExecuteScriptAndExtractBool(
668 shell()->web_contents(),
669 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
671 EXPECT_TRUE(success
);
673 // Wait for the navigation in the new window to finish, if it hasn't, then
674 // send it to post_message.html on the original site.
675 Shell
* new_shell2
= new_shell_observer2
.GetShell();
676 WebContents
* new_contents
= new_shell2
->web_contents();
677 WaitForLoadStop(new_contents
);
678 EXPECT_EQ("/files/title2.html", new_contents
->GetLastCommittedURL().path());
679 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
680 EXPECT_EQ(orig_site_instance
.get(), new_contents
->GetSiteInstance());
681 RenderFrameHostManager
* new_manager
=
682 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
684 // We now have three windows. The opener should have a swapped out RVH
685 // for the new SiteInstance, but the _blank window should not.
686 EXPECT_EQ(3u, Shell::windows().size());
688 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
690 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
692 // 2) Fail to post a message from the foo window to the opener if the target
693 // origin is wrong. We won't see an error, but we can check for the right
694 // number of received messages below.
695 EXPECT_TRUE(ExecuteScriptAndExtractBool(
697 "window.domAutomationController.send(postToOpener('msg',"
698 " 'http://google.com'));",
700 EXPECT_TRUE(success
);
702 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
704 // 3) Post a message from the foo window to the opener. The opener will
705 // reply, causing the foo window to update its own title.
706 base::string16 expected_title
= ASCIIToUTF16("msg");
707 TitleWatcher
title_watcher(foo_contents
, expected_title
);
708 EXPECT_TRUE(ExecuteScriptAndExtractBool(
710 "window.domAutomationController.send(postToOpener('msg','*'));",
712 EXPECT_TRUE(success
);
714 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
715 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
717 // We should have received only 1 message in the opener and "foo" tabs,
718 // and updated the title.
719 int opener_received_messages
= 0;
720 EXPECT_TRUE(ExecuteScriptAndExtractInt(
722 "window.domAutomationController.send(window.receivedMessages);",
723 &opener_received_messages
));
724 int foo_received_messages
= 0;
725 EXPECT_TRUE(ExecuteScriptAndExtractInt(
727 "window.domAutomationController.send(window.receivedMessages);",
728 &foo_received_messages
));
729 EXPECT_EQ(1, foo_received_messages
);
730 EXPECT_EQ(1, opener_received_messages
);
731 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
733 // 4) Now post a message from the _blank window to the foo window. The
734 // foo window will update its title and will not reply.
735 expected_title
= ASCIIToUTF16("msg2");
736 TitleWatcher
title_watcher2(foo_contents
, expected_title
);
737 EXPECT_TRUE(ExecuteScriptAndExtractBool(
739 "window.domAutomationController.send(postToFoo('msg2'));",
741 EXPECT_TRUE(success
);
742 ASSERT_EQ(expected_title
, title_watcher2
.WaitAndGetTitle());
744 // This postMessage should have created a swapped out RVH for the new
745 // SiteInstance in the target=_blank window.
747 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
749 // TODO(nasko): Test subframe targeting of postMessage once
750 // http://crbug.com/153701 is fixed.
753 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
754 // messages which contain Transferables and get intercepted by
755 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
756 // swapped out) should work.
758 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
759 // 2) Post a message containing a message port from opener to "foo".
760 // 3) Post a message from "foo" back to opener via the passed message port.
761 // The test will be enabled when the feature implementation lands.
762 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
763 SupportCrossProcessPostMessageWithMessagePort
) {
766 // Load a page with links that open in a new window.
767 std::string replacement_path
;
768 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
769 "files/click-noreferrer-links.html",
772 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
774 // Get the original SiteInstance and RVHM for later comparison.
775 WebContents
* opener_contents
= shell()->web_contents();
776 scoped_refptr
<SiteInstance
> orig_site_instance(
777 opener_contents
->GetSiteInstance());
778 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
779 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
780 opener_contents
)->GetRenderManagerForTesting();
782 // 1) Open a named target=foo window. We will later post a message between the
783 // opener and the new window.
784 ShellAddedObserver new_shell_observer
;
785 bool success
= false;
786 EXPECT_TRUE(ExecuteScriptAndExtractBool(
788 "window.domAutomationController.send(clickSameSiteTargetedLink());",
790 EXPECT_TRUE(success
);
791 Shell
* new_shell
= new_shell_observer
.GetShell();
793 // Wait for the navigation in the new window to finish, if it hasn't, then
794 // send it to post_message.html on a different site.
795 WebContents
* foo_contents
= new_shell
->web_contents();
796 WaitForLoadStop(foo_contents
);
797 EXPECT_EQ("/files/navigate_opener.html",
798 foo_contents
->GetLastCommittedURL().path());
799 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
800 scoped_refptr
<SiteInstance
> foo_site_instance(
801 foo_contents
->GetSiteInstance());
802 EXPECT_NE(orig_site_instance
, foo_site_instance
);
804 // We now have two windows. The opener should have a swapped out RVH
805 // for the new SiteInstance.
806 EXPECT_EQ(2u, Shell::windows().size());
808 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
810 // 2) Post a message containing a MessagePort from opener to the the foo
811 // window. The foo window will reply via the passed port, causing the opener
812 // to update its own title.
813 base::string16 expected_title
= ASCIIToUTF16("msg-back-via-port");
814 TitleWatcher
title_observer(opener_contents
, expected_title
);
815 EXPECT_TRUE(ExecuteScriptAndExtractBool(
817 "window.domAutomationController.send(postWithPortToFoo());",
819 EXPECT_TRUE(success
);
821 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
822 ASSERT_EQ(expected_title
, title_observer
.WaitAndGetTitle());
824 // Check message counts.
825 int opener_received_messages_via_port
= 0;
826 EXPECT_TRUE(ExecuteScriptAndExtractInt(
828 "window.domAutomationController.send(window.receivedMessagesViaPort);",
829 &opener_received_messages_via_port
));
830 int foo_received_messages
= 0;
831 EXPECT_TRUE(ExecuteScriptAndExtractInt(
833 "window.domAutomationController.send(window.receivedMessages);",
834 &foo_received_messages
));
835 int foo_received_messages_with_port
= 0;
836 EXPECT_TRUE(ExecuteScriptAndExtractInt(
838 "window.domAutomationController.send(window.receivedMessagesWithPort);",
839 &foo_received_messages_with_port
));
840 EXPECT_EQ(1, foo_received_messages
);
841 EXPECT_EQ(1, foo_received_messages_with_port
);
842 EXPECT_EQ(1, opener_received_messages_via_port
);
843 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents
->GetTitle());
844 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents
->GetTitle());
847 // Test for crbug.com/116192. Navigations to a window's opener should
848 // still work after a process swap.
849 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
850 AllowTargetedNavigationsInOpenerAfterSwap
) {
853 // Load a page with links that open in a new window.
854 std::string replacement_path
;
855 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
856 "files/click-noreferrer-links.html",
859 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
861 // Get the original tab and SiteInstance for later comparison.
862 WebContents
* orig_contents
= shell()->web_contents();
863 scoped_refptr
<SiteInstance
> orig_site_instance(
864 orig_contents
->GetSiteInstance());
865 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
867 // Test clicking a target=foo link.
868 ShellAddedObserver new_shell_observer
;
869 bool success
= false;
870 EXPECT_TRUE(ExecuteScriptAndExtractBool(
872 "window.domAutomationController.send(clickSameSiteTargetedLink());",
874 EXPECT_TRUE(success
);
875 Shell
* new_shell
= new_shell_observer
.GetShell();
877 // Wait for the navigation in the new window to finish, if it hasn't.
878 WaitForLoadStop(new_shell
->web_contents());
879 EXPECT_EQ("/files/navigate_opener.html",
880 new_shell
->web_contents()->GetLastCommittedURL().path());
882 // Should have the same SiteInstance.
883 scoped_refptr
<SiteInstance
> blank_site_instance(
884 new_shell
->web_contents()->GetSiteInstance());
885 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
887 // Now navigate the original (opener) tab to a different site.
888 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
889 scoped_refptr
<SiteInstance
> new_site_instance(
890 shell()->web_contents()->GetSiteInstance());
891 EXPECT_NE(orig_site_instance
, new_site_instance
);
893 // The opened tab should be able to navigate the opener back to its process.
894 TestNavigationObserver
navigation_observer(orig_contents
);
895 EXPECT_TRUE(ExecuteScriptAndExtractBool(
896 new_shell
->web_contents(),
897 "window.domAutomationController.send(navigateOpener());",
899 EXPECT_TRUE(success
);
900 navigation_observer
.Wait();
902 // Should have swapped back into this process.
903 scoped_refptr
<SiteInstance
> revisit_site_instance(
904 shell()->web_contents()->GetSiteInstance());
905 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
908 // Test that subframes do not crash when sending a postMessage to the top frame
909 // from an unload handler while the top frame is being swapped out as part of
910 // navigating cross-process. https://crbug.com/475651.
911 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
912 PostMessageFromSubframeUnloadHandler
) {
915 GURL
frame_url(test_server()->GetURL("files/post_message.html"));
916 GURL
main_url("data:text/html,<iframe name='foo' src='" + frame_url
.spec() +
918 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
920 // Get the original SiteInstance for later comparison.
921 scoped_refptr
<SiteInstance
> orig_site_instance(
922 shell()->web_contents()->GetSiteInstance());
923 EXPECT_NE(nullptr, orig_site_instance
.get());
925 // It is safe to obtain the root frame tree node here, as it doesn't change.
926 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
929 ASSERT_EQ(1U, root
->child_count());
930 EXPECT_EQ(frame_url
, root
->child_at(0)->current_url());
932 // Register an unload handler that sends a postMessage to the top frame.
933 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
934 "registerUnload();"));
936 // Navigate the top frame cross-site. This will cause the top frame to be
937 // swapped out and run unload handlers, and the original renderer process
938 // should then terminate since it's not rendering any other frames.
939 RenderProcessHostWatcher
exit_observer(
940 root
->current_frame_host()->GetProcess(),
941 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
942 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
943 scoped_refptr
<SiteInstance
> new_site_instance(
944 shell()->web_contents()->GetSiteInstance());
945 EXPECT_NE(orig_site_instance
, new_site_instance
);
947 // Ensure that the original renderer process exited cleanly without crashing.
948 exit_observer
.Wait();
949 EXPECT_EQ(true, exit_observer
.did_exit_normally());
952 // Test that opening a new window in the same SiteInstance and then navigating
953 // both windows to a different SiteInstance allows the first process to exit.
954 // See http://crbug.com/126333.
955 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
956 ProcessExitWithSwappedOutViews
) {
959 // Load a page with links that open in a new window.
960 std::string replacement_path
;
961 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
962 "files/click-noreferrer-links.html",
965 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
967 // Get the original SiteInstance for later comparison.
968 scoped_refptr
<SiteInstance
> orig_site_instance(
969 shell()->web_contents()->GetSiteInstance());
970 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
972 // Test clicking a target=foo link.
973 ShellAddedObserver new_shell_observer
;
974 bool success
= false;
975 EXPECT_TRUE(ExecuteScriptAndExtractBool(
976 shell()->web_contents(),
977 "window.domAutomationController.send(clickSameSiteTargetedLink());",
979 EXPECT_TRUE(success
);
980 Shell
* new_shell
= new_shell_observer
.GetShell();
982 // Wait for the navigation in the new window to finish, if it hasn't.
983 WaitForLoadStop(new_shell
->web_contents());
984 EXPECT_EQ("/files/navigate_opener.html",
985 new_shell
->web_contents()->GetLastCommittedURL().path());
987 // Should have the same SiteInstance.
988 scoped_refptr
<SiteInstance
> opened_site_instance(
989 new_shell
->web_contents()->GetSiteInstance());
990 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
992 // Now navigate the opened window to a different site.
993 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
994 scoped_refptr
<SiteInstance
> new_site_instance(
995 new_shell
->web_contents()->GetSiteInstance());
996 EXPECT_NE(orig_site_instance
, new_site_instance
);
998 // The original process should still be alive, since it is still used in the
1000 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
1001 EXPECT_TRUE(orig_process
->HasConnection());
1003 // Navigate the first window to a different site as well. The original
1004 // process should exit, since all of its views are now swapped out.
1005 RenderProcessHostWatcher
exit_observer(
1007 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1008 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1009 exit_observer
.Wait();
1010 scoped_refptr
<SiteInstance
> new_site_instance2(
1011 shell()->web_contents()->GetSiteInstance());
1012 EXPECT_EQ(new_site_instance
, new_site_instance2
);
1015 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
1016 // error should not make us ignore future renderer-initiated navigations.
1017 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ClickLinkAfter204Error
) {
1020 // Get the original SiteInstance for later comparison.
1021 scoped_refptr
<SiteInstance
> orig_site_instance(
1022 shell()->web_contents()->GetSiteInstance());
1023 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
1025 // Load a cross-site page that fails with a 204 error.
1026 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
1027 GetCrossSiteURL("nocontent")));
1029 // We should still be looking at the normal page. Because we started from a
1030 // blank new tab, the typed URL will still be visible until the user clears it
1031 // manually. The last committed URL will be the previous page.
1032 scoped_refptr
<SiteInstance
> post_nav_site_instance(
1033 shell()->web_contents()->GetSiteInstance());
1034 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
1035 EXPECT_EQ("/nocontent",
1036 shell()->web_contents()->GetVisibleURL().path());
1038 shell()->web_contents()->GetController().GetLastCommittedEntry());
1040 // Renderer-initiated navigations should work.
1041 base::string16 expected_title
= ASCIIToUTF16("Title Of Awesomeness");
1042 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1043 GURL url
= test_server()->GetURL("files/title2.html");
1044 EXPECT_TRUE(ExecuteScript(
1045 shell()->web_contents(),
1046 base::StringPrintf("location.href = '%s'", url
.spec().c_str())));
1047 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1049 // Opens in same tab.
1050 EXPECT_EQ(1u, Shell::windows().size());
1051 EXPECT_EQ("/files/title2.html",
1052 shell()->web_contents()->GetLastCommittedURL().path());
1054 // Should have the same SiteInstance.
1055 scoped_refptr
<SiteInstance
> new_site_instance(
1056 shell()->web_contents()->GetSiteInstance());
1057 EXPECT_EQ(orig_site_instance
, new_site_instance
);
1060 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1061 // initiated navigation in a new tab, until the content of the initial
1062 // about:blank page is modified by another window. At that point, we should
1063 // revert to showing about:blank to prevent a URL spoof.
1064 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ShowLoadingURLUntilSpoof
) {
1065 ASSERT_TRUE(test_server()->Start());
1067 // Load a page that can open a URL that won't commit in a new window.
1069 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1070 WebContents
* orig_contents
= shell()->web_contents();
1072 // Click a /nocontent link that opens in a new window but never commits.
1073 ShellAddedObserver new_shell_observer
;
1074 bool success
= false;
1075 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1077 "window.domAutomationController.send(clickNoContentTargetedLink());",
1079 EXPECT_TRUE(success
);
1081 // Wait for the window to open.
1082 Shell
* new_shell
= new_shell_observer
.GetShell();
1084 // Ensure the destination URL is visible, because it is considered the
1085 // initial navigation.
1086 WebContents
* contents
= new_shell
->web_contents();
1087 EXPECT_TRUE(contents
->GetController().IsInitialNavigation());
1088 EXPECT_EQ("/nocontent",
1089 contents
->GetController().GetVisibleEntry()->GetURL().path());
1091 // Now modify the contents of the new window from the opener. This will also
1092 // modify the title of the document to give us something to listen for.
1093 base::string16 expected_title
= ASCIIToUTF16("Modified Title");
1094 TitleWatcher
title_watcher(contents
, expected_title
);
1096 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1098 "window.domAutomationController.send(modifyNewWindow());",
1100 EXPECT_TRUE(success
);
1101 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1103 // At this point, we should no longer be showing the destination URL.
1104 // The visible entry should be null, resulting in about:blank in the address
1106 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1109 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1110 // initiated navigation in a new tab if it is not the initial navigation. In
1111 // this case, the renderer will not notify us of a modification, so we cannot
1112 // show the pending URL without allowing a spoof.
1113 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1114 DontShowLoadingURLIfNotInitialNav
) {
1115 ASSERT_TRUE(test_server()->Start());
1117 // Load a page that can open a URL that won't commit in a new window.
1119 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1120 WebContents
* orig_contents
= shell()->web_contents();
1122 // Click a /nocontent link that opens in a new window but never commits.
1123 // By using an onclick handler that first creates the window, the slow
1124 // navigation is not considered an initial navigation.
1125 ShellAddedObserver new_shell_observer
;
1126 bool success
= false;
1127 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1129 "window.domAutomationController.send("
1130 "clickNoContentScriptedTargetedLink());",
1132 EXPECT_TRUE(success
);
1134 // Wait for the window to open.
1135 Shell
* new_shell
= new_shell_observer
.GetShell();
1137 // Ensure the destination URL is not visible, because it is not the initial
1139 WebContents
* contents
= new_shell
->web_contents();
1140 EXPECT_FALSE(contents
->GetController().IsInitialNavigation());
1141 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1144 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1145 #if defined(THREAD_SANITIZER)
1146 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1148 #define MAYBE_BackForwardNotStale BackForwardNotStale
1150 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1151 // do not cause back/forward navigations to be considered stale by the
1153 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_BackForwardNotStale
) {
1155 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1157 // Visit a page on first site.
1158 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1160 // Visit three pages on second site.
1161 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1162 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1163 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1165 // History is now [blank, A1, B1, B2, *B3].
1166 WebContents
* contents
= shell()->web_contents();
1167 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
1169 // Open another window in same process to keep this process alive.
1170 Shell
* new_shell
= CreateBrowser();
1171 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1173 // Go back three times to first site.
1175 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1176 shell()->web_contents()->GetController().GoBack();
1177 back_nav_load_observer
.Wait();
1180 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1181 shell()->web_contents()->GetController().GoBack();
1182 back_nav_load_observer
.Wait();
1185 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1186 shell()->web_contents()->GetController().GoBack();
1187 back_nav_load_observer
.Wait();
1190 // Now go forward twice to B2. Shouldn't be left spinning.
1192 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1193 shell()->web_contents()->GetController().GoForward();
1194 forward_nav_load_observer
.Wait();
1197 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1198 shell()->web_contents()->GetController().GoForward();
1199 forward_nav_load_observer
.Wait();
1202 // Go back twice to first site.
1204 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1205 shell()->web_contents()->GetController().GoBack();
1206 back_nav_load_observer
.Wait();
1209 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1210 shell()->web_contents()->GetController().GoBack();
1211 back_nav_load_observer
.Wait();
1214 // Now go forward directly to B3. Shouldn't be left spinning.
1216 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1217 shell()->web_contents()->GetController().GoToIndex(4);
1218 forward_nav_load_observer
.Wait();
1222 // Test for http://crbug.com/130016.
1223 // Swapping out a render view should update its visiblity state.
1224 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1225 SwappedOutViewHasCorrectVisibilityState
) {
1226 // This test is invalid in --site-per-process mode, as swapped-out is no
1228 if (RenderFrameHostManager::IsSwappedOutStateForbidden())
1232 // Load a page with links that open in a new window.
1233 std::string replacement_path
;
1234 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1235 "files/click-noreferrer-links.html",
1237 &replacement_path
));
1238 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
1240 // Open a same-site link in a new widnow.
1241 ShellAddedObserver new_shell_observer
;
1242 bool success
= false;
1243 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1244 shell()->web_contents(),
1245 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1247 EXPECT_TRUE(success
);
1248 Shell
* new_shell
= new_shell_observer
.GetShell();
1250 // Wait for the navigation in the new tab to finish, if it hasn't.
1251 WaitForLoadStop(new_shell
->web_contents());
1252 EXPECT_EQ("/files/navigate_opener.html",
1253 new_shell
->web_contents()->GetLastCommittedURL().path());
1255 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
1257 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1259 "window.domAutomationController.send("
1260 " document.visibilityState == 'visible');",
1262 EXPECT_TRUE(success
);
1264 // Now navigate the new window to a different site. This should swap out the
1265 // tab's existing RenderView, causing it become hidden.
1266 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1268 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1270 "window.domAutomationController.send("
1271 " document.visibilityState == 'hidden');",
1273 EXPECT_TRUE(success
);
1275 // Going back should make the previously swapped-out view to become visible
1278 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
1279 new_shell
->web_contents()->GetController().GoBack();
1280 back_nav_load_observer
.Wait();
1283 EXPECT_EQ("/files/navigate_opener.html",
1284 new_shell
->web_contents()->GetLastCommittedURL().path());
1286 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
1288 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1290 "window.domAutomationController.send("
1291 " document.visibilityState == 'visible');",
1293 EXPECT_TRUE(success
);
1296 // This class ensures that all the given RenderViewHosts have properly been
1298 class RenderViewHostDestructionObserver
: public WebContentsObserver
{
1300 explicit RenderViewHostDestructionObserver(WebContents
* web_contents
)
1301 : WebContentsObserver(web_contents
) {}
1302 ~RenderViewHostDestructionObserver() override
{}
1303 void EnsureRVHGetsDestructed(RenderViewHost
* rvh
) {
1304 watched_render_view_hosts_
.insert(rvh
);
1306 size_t GetNumberOfWatchedRenderViewHosts() const {
1307 return watched_render_view_hosts_
.size();
1311 // WebContentsObserver implementation:
1312 void RenderViewDeleted(RenderViewHost
* rvh
) override
{
1313 watched_render_view_hosts_
.erase(rvh
);
1316 std::set
<RenderViewHost
*> watched_render_view_hosts_
;
1319 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1320 #if defined(THREAD_SANITIZER)
1321 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1323 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1325 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1326 // they may cause crashes or memory corruptions when trying to call dead
1327 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1328 // ensure that a separate SiteInstance is created when navigating to view-source
1329 // URLs, regardless of current URL.
1330 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1331 MAYBE_LeakingRenderViewHosts
) {
1334 // Observe the created render_view_host's to make sure they will not leak.
1335 RenderViewHostDestructionObserver
rvh_observers(shell()->web_contents());
1337 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1338 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1339 navigated_url
.spec());
1341 // Let's ensure that when we start with a blank window, navigating away to a
1342 // view-source URL, we create a new SiteInstance.
1343 RenderViewHost
* blank_rvh
= shell()->web_contents()->GetRenderViewHost();
1344 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1345 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1346 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1347 rvh_observers
.EnsureRVHGetsDestructed(blank_rvh
);
1349 // Now navigate to the view-source URL and ensure we got a different
1350 // SiteInstance and RenderViewHost.
1351 NavigateToURL(shell(), view_source_url
);
1352 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1353 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1354 GetRenderViewHost()->GetSiteInstance());
1355 rvh_observers
.EnsureRVHGetsDestructed(
1356 shell()->web_contents()->GetRenderViewHost());
1358 // Load a random page and then navigate to view-source: of it.
1359 // This used to cause two RVH instances for the same SiteInstance, which
1360 // was a problem. This is no longer the case.
1361 NavigateToURL(shell(), navigated_url
);
1362 SiteInstance
* site_instance1
= shell()->web_contents()->
1363 GetRenderViewHost()->GetSiteInstance();
1364 rvh_observers
.EnsureRVHGetsDestructed(
1365 shell()->web_contents()->GetRenderViewHost());
1367 NavigateToURL(shell(), view_source_url
);
1368 rvh_observers
.EnsureRVHGetsDestructed(
1369 shell()->web_contents()->GetRenderViewHost());
1370 SiteInstance
* site_instance2
= shell()->web_contents()->
1371 GetRenderViewHost()->GetSiteInstance();
1373 // Ensure that view-source navigations force a new SiteInstance.
1374 EXPECT_NE(site_instance1
, site_instance2
);
1376 // Now navigate to a different instance so that we swap out again.
1377 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1378 rvh_observers
.EnsureRVHGetsDestructed(
1379 shell()->web_contents()->GetRenderViewHost());
1381 // This used to leak a render view host.
1384 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1386 EXPECT_EQ(0U, rvh_observers
.GetNumberOfWatchedRenderViewHosts());
1389 // Test for crbug.com/143155. Frame tree updates during unload should not
1390 // interrupt the intended navigation and show swappedout:// instead.
1392 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1393 // 2) Send the second tab to a different foo.com SiteInstance.
1394 // This creates a swapped out opener for the first tab in the foo process.
1395 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1396 // tab's unload handler remove its frame.
1397 // This used to cause an update to the frame tree of the swapped out RV,
1398 // just as it was navigating to a real page. That pre-empted the real
1399 // navigation and visibly sent the tab to swappedout://.
1400 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1401 DontPreemptNavigationWithFrameTreeUpdate
) {
1404 // 1. Load a page that deletes its iframe during unload.
1405 NavigateToURL(shell(),
1406 test_server()->GetURL("files/remove_frame_on_unload.html"));
1408 // Get the original SiteInstance for later comparison.
1409 scoped_refptr
<SiteInstance
> orig_site_instance(
1410 shell()->web_contents()->GetSiteInstance());
1412 // Open a same-site page in a new window.
1413 ShellAddedObserver new_shell_observer
;
1414 bool success
= false;
1415 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1416 shell()->web_contents(),
1417 "window.domAutomationController.send(openWindow());",
1419 EXPECT_TRUE(success
);
1420 Shell
* new_shell
= new_shell_observer
.GetShell();
1422 // Wait for the navigation in the new window to finish, if it hasn't.
1423 WaitForLoadStop(new_shell
->web_contents());
1424 EXPECT_EQ("/files/title1.html",
1425 new_shell
->web_contents()->GetLastCommittedURL().path());
1427 // Should have the same SiteInstance.
1428 EXPECT_EQ(orig_site_instance
.get(),
1429 new_shell
->web_contents()->GetSiteInstance());
1431 // 2. Send the second tab to a different process.
1432 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1433 scoped_refptr
<SiteInstance
> new_site_instance(
1434 new_shell
->web_contents()->GetSiteInstance());
1435 EXPECT_NE(orig_site_instance
, new_site_instance
);
1437 // 3. Send the first tab to the second tab's process.
1438 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1440 // Make sure it ends up at the right page.
1441 WaitForLoadStop(shell()->web_contents());
1442 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1443 shell()->web_contents()->GetLastCommittedURL());
1444 EXPECT_EQ(new_site_instance
.get(),
1445 shell()->web_contents()->GetSiteInstance());
1448 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1449 // are meant to run in the current page. We had a bug where we expected a
1450 // BrowsingInstance swap to occur on pages like view-source and extensions,
1451 // which broke chrome://crash and javascript: URLs.
1452 // See http://crbug.com/335503.
1453 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, RendererDebugURLsDontSwap
) {
1454 ASSERT_TRUE(test_server()->Start());
1456 GURL
original_url(test_server()->GetURL("files/title2.html"));
1457 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1458 original_url
.spec());
1460 NavigateToURL(shell(), view_source_url
);
1462 // Check that javascript: URLs work.
1463 base::string16 expected_title
= ASCIIToUTF16("msg");
1464 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1465 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1466 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1468 // Crash the renderer of the view-source page.
1469 RenderProcessHostWatcher
crash_observer(
1470 shell()->web_contents(),
1471 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1473 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1474 crash_observer
.Wait();
1477 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1478 // Otherwise, we might try to load an unprivileged about:blank page into a
1479 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1480 // See http://crbug.com/334214.
1481 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1482 IgnoreRendererDebugURLsWhenCrashed
) {
1483 // Visit a WebUI page with bindings.
1484 GURL webui_url
= GURL(std::string(kChromeUIScheme
) + "://" +
1485 std::string(kChromeUIGpuHost
));
1486 NavigateToURL(shell(), webui_url
);
1487 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1488 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1490 // Crash the renderer of the WebUI page.
1491 RenderProcessHostWatcher
crash_observer(
1492 shell()->web_contents(),
1493 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1495 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1496 crash_observer
.Wait();
1498 // Load the crash URL again but don't wait for any action. If it is not
1499 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1500 shell()->LoadURL(GURL(kChromeUICrashURL
));
1502 // Ensure that such URLs can still work as the initial navigation of a tab.
1503 // We postpone the initial navigation of the tab using an empty GURL, so that
1504 // we can add a watcher for crashes.
1505 Shell
* shell2
= Shell::CreateNewWindow(
1506 shell()->web_contents()->GetBrowserContext(), GURL(), NULL
, gfx::Size());
1507 RenderProcessHostWatcher
crash_observer2(
1508 shell2
->web_contents(),
1509 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1511 NavigateToURLAndExpectNoCommit(shell2
, GURL(kChromeUIKillURL
)));
1512 crash_observer2
.Wait();
1515 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1516 // See http://crbug.com/428329.
1517 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1518 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1520 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1522 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1523 // Otherwise it might get picked up by InitRenderView when granting bindings
1524 // to other RenderViewHosts. See http://crbug.com/330811.
1525 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1526 MAYBE_ClearPendingWebUIOnCommit
) {
1527 // Visit a WebUI page with bindings.
1528 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1529 std::string(kChromeUIGpuHost
)));
1530 NavigateToURL(shell(), webui_url
);
1531 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1532 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1533 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1534 shell()->web_contents());
1535 WebUIImpl
* webui
= web_contents
->GetRenderManagerForTesting()->web_ui();
1537 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1539 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1540 // clear pending_web_ui() when it commits.
1541 GURL
webui_url2(webui_url
.spec() + "#foo");
1542 NavigateToURL(shell(), webui_url2
);
1543 EXPECT_EQ(webui
, web_contents
->GetRenderManagerForTesting()->web_ui());
1544 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1547 class RFHMProcessPerTabTest
: public RenderFrameHostManagerTest
{
1549 RFHMProcessPerTabTest() {}
1551 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1552 command_line
->AppendSwitch(switches::kProcessPerTab
);
1556 // Test that we still swap processes for BrowsingInstance changes even in
1557 // --process-per-tab mode. See http://crbug.com/343017.
1558 // Disabled on Android: http://crbug.com/345873.
1559 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1560 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1561 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1563 #define MAYBE_BackFromWebUI BackFromWebUI
1565 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest
, MAYBE_BackFromWebUI
) {
1566 ASSERT_TRUE(test_server()->Start());
1567 GURL
original_url(test_server()->GetURL("files/title2.html"));
1568 NavigateToURL(shell(), original_url
);
1570 // Visit a WebUI page with bindings.
1571 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1572 std::string(kChromeUIGpuHost
)));
1573 NavigateToURL(shell(), webui_url
);
1574 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1575 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1577 // Go back and ensure we have no WebUI bindings.
1578 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1579 shell()->web_contents()->GetController().GoBack();
1580 back_nav_load_observer
.Wait();
1581 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
1582 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1583 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1587 // The test loads url1, opens a link pointing to url2 in a new tab, and
1588 // navigates the new tab to url1.
1589 // The following is needed for the bug to happen:
1590 // - url1 must require webui bindings;
1591 // - navigating to url2 in the site instance of url1 should not swap
1592 // browsing instances, but should require a new site instance.
1593 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, WebUIGetsBindings
) {
1594 GURL
url1(std::string(kChromeUIScheme
) + "://" +
1595 std::string(kChromeUIGpuHost
));
1596 GURL
url2(std::string(kChromeUIScheme
) + "://" +
1597 std::string(kChromeUIAccessibilityHost
));
1599 // Visit a WebUI page with bindings.
1600 NavigateToURL(shell(), url1
);
1601 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1602 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1603 SiteInstance
* site_instance1
= shell()->web_contents()->GetSiteInstance();
1605 // Open a new tab. Initially it gets a render view in the original tab's
1606 // current site instance.
1607 TestNavigationObserver
nav_observer(NULL
);
1608 nav_observer
.StartWatchingNewWebContents();
1609 ShellAddedObserver shao
;
1610 OpenUrlViaClickTarget(shell()->web_contents(), url2
);
1611 nav_observer
.Wait();
1612 Shell
* new_shell
= shao
.GetShell();
1613 WebContentsImpl
* new_web_contents
= static_cast<WebContentsImpl
*>(
1614 new_shell
->web_contents());
1615 SiteInstance
* site_instance2
= new_web_contents
->GetSiteInstance();
1617 EXPECT_NE(site_instance2
, site_instance1
);
1618 EXPECT_TRUE(site_instance2
->IsRelatedSiteInstance(site_instance1
));
1619 RenderViewHost
* initial_rvh
= new_web_contents
->
1620 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1
);
1621 ASSERT_TRUE(initial_rvh
);
1622 // The following condition is what was causing the bug.
1623 EXPECT_EQ(0, initial_rvh
->GetEnabledBindings());
1625 // Navigate to url1 and check bindings.
1626 NavigateToURL(new_shell
, url1
);
1627 // The navigation should have used the first SiteInstance, otherwise
1628 // |initial_rvh| did not have a chance to be used.
1629 EXPECT_EQ(new_web_contents
->GetSiteInstance(), site_instance1
);
1630 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
1631 new_web_contents
->GetRenderViewHost()->GetEnabledBindings());
1635 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1636 // page and then to a regular page. The bug reproduces if blank page is visited
1637 // in between WebUI and regular page.
1638 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1639 ForceSwapAfterWebUIBindings
) {
1640 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1641 switches::kProcessPerTab
);
1642 ASSERT_TRUE(test_server()->Start());
1644 const GURL
web_ui_url(std::string(kChromeUIScheme
) + "://" +
1645 std::string(kChromeUIGpuHost
));
1646 NavigateToURL(shell(), web_ui_url
);
1647 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1648 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1650 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1652 GURL
regular_page_url(test_server()->GetURL("files/title2.html"));
1653 NavigateToURL(shell(), regular_page_url
);
1654 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1655 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1658 class FileChooserDelegate
: public WebContentsDelegate
{
1660 FileChooserDelegate(const base::FilePath
& file
)
1661 : file_(file
), file_chosen_(false) {}
1663 void RunFileChooser(WebContents
* web_contents
,
1664 const FileChooserParams
& params
) override
{
1665 // Send the selected file to the renderer process.
1666 FileChooserFileInfo file_info
;
1667 file_info
.file_path
= file_
;
1668 std::vector
<FileChooserFileInfo
> files
;
1669 files
.push_back(file_info
);
1670 web_contents
->GetRenderViewHost()->FilesSelectedInChooser(
1671 files
, FileChooserParams::Open
);
1673 file_chosen_
= true;
1676 bool file_chosen() { return file_chosen_
; }
1679 base::FilePath file_
;
1683 // Test for http://crbug.com/262948.
1684 // Flaky on Mac. http://crbug.com/452018
1685 #if defined(OS_MACOSX)
1686 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1687 DISABLED_RestoreFileAccessForHistoryNavigation
1689 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1690 RestoreFileAccessForHistoryNavigation
1692 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1693 MAYBE_RestoreFileAccessForHistoryNavigation
) {
1695 base::FilePath file
;
1696 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file
));
1697 file
= file
.AppendASCII("bar");
1699 // Navigate to url and get it to reference a file in its PageState.
1700 GURL
url1(test_server()->GetURL("files/file_input.html"));
1701 NavigateToURL(shell(), url1
);
1702 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1703 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file
));
1704 shell()->web_contents()->SetDelegate(delegate
.get());
1705 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1706 "document.getElementById('fileinput').click();"));
1707 EXPECT_TRUE(delegate
->file_chosen());
1708 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1711 // Navigate to a different process without access to the file, and wait for
1712 // the old process to exit.
1713 RenderProcessHostWatcher
exit_observer(
1714 shell()->web_contents()->GetRenderProcessHost(),
1715 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1716 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1717 exit_observer
.Wait();
1718 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1719 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1721 // Ensure that the file ended up in the PageState of the previous entry.
1722 NavigationEntry
* prev_entry
=
1723 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1724 EXPECT_EQ(url1
, prev_entry
->GetURL());
1725 const std::vector
<base::FilePath
>& files
=
1726 prev_entry
->GetPageState().GetReferencedFiles();
1727 ASSERT_EQ(1U, files
.size());
1728 EXPECT_EQ(file
, files
.at(0));
1730 // Go back, ending up in a different RenderProcessHost than before.
1731 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1732 shell()->web_contents()->GetController().GoBack();
1733 back_nav_load_observer
.Wait();
1734 EXPECT_NE(process_id
,
1735 shell()->web_contents()->GetRenderProcessHost()->GetID());
1737 // Ensure that the file access still exists in the new process ID.
1738 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1739 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1741 // Navigate to a same site page to trigger a PageState update and ensure the
1742 // renderer is not killed.
1744 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1747 // Test for http://crbug.com/441966.
1748 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1749 RestoreSubframeFileAccessForHistoryNavigation
) {
1751 base::FilePath file
;
1752 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file
));
1753 file
= file
.AppendASCII("bar");
1755 // Navigate to url and get it to reference a file in its PageState.
1756 GURL
url1(test_server()->GetURL("files/file_input_subframe.html"));
1757 NavigateToURL(shell(), url1
);
1758 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
1759 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
1760 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1761 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file
));
1762 shell()->web_contents()->SetDelegate(delegate
.get());
1763 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
1764 "document.getElementById('fileinput').click();"));
1765 EXPECT_TRUE(delegate
->file_chosen());
1766 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1769 // Navigate to a different process without access to the file, and wait for
1770 // the old process to exit.
1771 RenderProcessHostWatcher
exit_observer(
1772 shell()->web_contents()->GetRenderProcessHost(),
1773 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1774 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1775 exit_observer
.Wait();
1776 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1777 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1779 // Ensure that the file ended up in the PageState of the previous entry.
1780 NavigationEntry
* prev_entry
=
1781 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1782 EXPECT_EQ(url1
, prev_entry
->GetURL());
1783 const std::vector
<base::FilePath
>& files
=
1784 prev_entry
->GetPageState().GetReferencedFiles();
1785 ASSERT_EQ(1U, files
.size());
1786 EXPECT_EQ(file
, files
.at(0));
1788 // Go back, ending up in a different RenderProcessHost than before.
1789 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1790 shell()->web_contents()->GetController().GoBack();
1791 back_nav_load_observer
.Wait();
1792 EXPECT_NE(process_id
,
1793 shell()->web_contents()->GetRenderProcessHost()->GetID());
1795 // Ensure that the file access still exists in the new process ID.
1796 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1797 shell()->web_contents()->GetRenderProcessHost()->GetID(), file
));
1800 // This class implements waiting for RenderFrameHost destruction. It relies on
1801 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1803 // Note: RenderFrameDeleted is also fired when the process associated with the
1804 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1806 class RenderFrameHostDestructionObserver
: public WebContentsObserver
{
1808 explicit RenderFrameHostDestructionObserver(RenderFrameHost
* rfh
)
1809 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh
)),
1810 message_loop_runner_(new MessageLoopRunner
),
1812 render_frame_host_(rfh
) {}
1813 ~RenderFrameHostDestructionObserver() override
{}
1819 message_loop_runner_
->Run();
1822 // WebContentsObserver implementation:
1823 void RenderFrameDeleted(RenderFrameHost
* rfh
) override
{
1824 if (rfh
== render_frame_host_
) {
1829 if (deleted_
&& message_loop_runner_
->loop_running()) {
1830 base::ThreadTaskRunnerHandle::Get()->PostTask(
1831 FROM_HERE
, message_loop_runner_
->QuitClosure());
1836 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
1838 RenderFrameHost
* render_frame_host_
;
1841 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1842 // doing a simple cross-process navigation.
1843 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1844 CleanupOnCrossProcessNavigation
) {
1845 StartEmbeddedServer();
1847 // Do an initial navigation and capture objects we expect to be cleaned up
1848 // on cross-process navigation.
1849 GURL start_url
= embedded_test_server()->GetURL("/title1.html");
1850 NavigateToURL(shell(), start_url
);
1852 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1855 int32 orig_site_instance_id
=
1856 root
->current_frame_host()->GetSiteInstance()->GetId();
1857 int initial_process_id
=
1858 root
->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1859 int initial_rfh_id
= root
->current_frame_host()->GetRoutingID();
1860 int initial_rvh_id
=
1861 root
->current_frame_host()->render_view_host()->GetRoutingID();
1863 // Navigate cross-process and ensure that cleanup is performed as expected.
1864 GURL cross_site_url
=
1865 embedded_test_server()->GetURL("foo.com", "/title2.html");
1866 RenderFrameHostDestructionObserver
rfh_observer(root
->current_frame_host());
1867 NavigateToURL(shell(), cross_site_url
);
1868 rfh_observer
.Wait();
1870 EXPECT_NE(orig_site_instance_id
,
1871 root
->current_frame_host()->GetSiteInstance()->GetId());
1872 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id
, initial_rfh_id
));
1873 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id
, initial_rvh_id
));
1876 // Ensure that the opener chain proxies and RVHs are properly reinitialized if
1877 // a tab crashes and reloads. See https://crbug.com/505090.
1878 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1879 ReinitializeOpenerChainAfterCrashAndReload
) {
1880 StartEmbeddedServer();
1882 GURL main_url
= embedded_test_server()->GetURL("/title1.html");
1883 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1885 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1889 scoped_refptr
<SiteInstance
> orig_site_instance(
1890 shell()->web_contents()->GetSiteInstance());
1891 EXPECT_TRUE(orig_site_instance
);
1893 // Open a popup and navigate it cross-site.
1895 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL
), "foo");
1896 EXPECT_TRUE(new_shell
);
1897 FrameTreeNode
* popup_root
=
1898 static_cast<WebContentsImpl
*>(new_shell
->web_contents())
1902 GURL cross_site_url
=
1903 embedded_test_server()->GetURL("foo.com", "/title2.html");
1904 EXPECT_TRUE(NavigateToURL(new_shell
, cross_site_url
));
1906 scoped_refptr
<SiteInstance
> foo_site_instance(
1907 new_shell
->web_contents()->GetSiteInstance());
1908 EXPECT_NE(foo_site_instance
, orig_site_instance
);
1910 // Kill the popup's process.
1911 RenderProcessHost
* popup_process
=
1912 popup_root
->current_frame_host()->GetProcess();
1913 RenderProcessHostWatcher
crash_observer(
1914 popup_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1915 popup_process
->Shutdown(0, false);
1916 crash_observer
.Wait();
1917 EXPECT_FALSE(popup_root
->current_frame_host()->IsRenderFrameLive());
1919 popup_root
->current_frame_host()->render_view_host()->IsRenderViewLive());
1921 // The swapped-out RVH and proxy for the opener page in the foo.com
1922 // SiteInstance should not be live.
1923 RenderFrameHostManager
* opener_manager
= root
->render_manager();
1924 RenderViewHostImpl
* opener_rvh
=
1925 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get());
1926 EXPECT_TRUE(opener_rvh
);
1927 EXPECT_FALSE(opener_rvh
->IsRenderViewLive());
1928 RenderFrameProxyHost
* opener_rfph
=
1929 opener_manager
->GetRenderFrameProxyHost(foo_site_instance
.get());
1930 EXPECT_TRUE(opener_rfph
);
1931 EXPECT_FALSE(opener_rfph
->is_render_frame_proxy_live());
1933 // Re-navigate the popup to the same URL and check that this recreates the
1934 // opener's swapped out RVH and proxy in the foo.com SiteInstance.
1935 EXPECT_TRUE(NavigateToURL(new_shell
, cross_site_url
));
1936 EXPECT_TRUE(opener_rvh
->IsRenderViewLive());
1937 EXPECT_TRUE(opener_rfph
->is_render_frame_proxy_live());
1940 } // namespace content