1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/path_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "content/browser/child_process_security_policy_impl.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/browser/webui/web_ui_impl.h"
18 #include "content/common/content_constants_internal.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/common/bindings_policy.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/file_chooser_file_info.h"
27 #include "content/public/common/file_chooser_params.h"
28 #include "content/public/common/page_state.h"
29 #include "content/public/common/url_constants.h"
30 #include "content/public/test/browser_test_utils.h"
31 #include "content/public/test/content_browser_test.h"
32 #include "content/public/test/content_browser_test_utils.h"
33 #include "content/public/test/test_navigation_observer.h"
34 #include "content/public/test/test_utils.h"
35 #include "content/shell/browser/shell.h"
36 #include "net/base/net_util.h"
37 #include "net/dns/mock_host_resolver.h"
38 #include "net/test/spawned_test_server/spawned_test_server.h"
40 using base::ASCIIToUTF16
;
46 const char kOpenUrlViaClickTargetFunc
[] =
48 " var lnk = document.createElement(\"a\");\n"
50 " lnk.target = \"_blank\";\n"
51 " document.body.appendChild(lnk);\n"
55 // Adds a link with given url and target=_blank, and clicks on it.
56 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost
& adapter
,
58 EXPECT_TRUE(ExecuteScript(adapter
,
59 std::string(kOpenUrlViaClickTargetFunc
) + "(\"" + url
.spec() + "\");"));
62 } // anonymous namespace
64 class RenderFrameHostManagerTest
: public ContentBrowserTest
{
66 RenderFrameHostManagerTest() : foo_com_("foo.com") {
67 replace_host_
.SetHostStr(foo_com_
);
70 static bool GetFilePathWithHostAndPortReplacement(
71 const std::string
& original_file_path
,
72 const net::HostPortPair
& host_port_pair
,
73 std::string
* replacement_path
) {
74 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
75 replacement_text
.push_back(
76 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
77 return net::SpawnedTestServer::GetFilePathWithReplacements(
78 original_file_path
, replacement_text
, replacement_path
);
82 // Support multiple sites on the test server.
83 host_resolver()->AddRule("*", "127.0.0.1");
84 ASSERT_TRUE(test_server()->Start());
86 foo_host_port_
= test_server()->host_port_pair();
87 foo_host_port_
.set_host(foo_com_
);
90 // Returns a URL on foo.com with the given path.
91 GURL
GetCrossSiteURL(const std::string
& path
) {
92 GURL
cross_site_url(test_server()->GetURL(path
));
93 return cross_site_url
.ReplaceComponents(replace_host_
);
98 GURL::Replacements replace_host_
;
99 net::HostPortPair foo_host_port_
;
102 // Web pages should not have script access to the swapped out page.
103 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, NoScriptAccessAfterSwapOut
) {
106 // Load a page with links that open in a new window.
107 std::string replacement_path
;
108 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
109 "files/click-noreferrer-links.html",
112 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
114 // Get the original SiteInstance for later comparison.
115 scoped_refptr
<SiteInstance
> orig_site_instance(
116 shell()->web_contents()->GetSiteInstance());
117 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
119 // Open a same-site link in a new window.
120 ShellAddedObserver new_shell_observer
;
121 bool success
= false;
122 EXPECT_TRUE(ExecuteScriptAndExtractBool(
123 shell()->web_contents(),
124 "window.domAutomationController.send(clickSameSiteTargetedLink());",
126 EXPECT_TRUE(success
);
127 Shell
* new_shell
= new_shell_observer
.GetShell();
129 // Wait for the navigation in the new window to finish, if it hasn't.
130 WaitForLoadStop(new_shell
->web_contents());
131 EXPECT_EQ("/files/navigate_opener.html",
132 new_shell
->web_contents()->GetLastCommittedURL().path());
134 // Should have the same SiteInstance.
135 scoped_refptr
<SiteInstance
> blank_site_instance(
136 new_shell
->web_contents()->GetSiteInstance());
137 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
139 // We should have access to the opened window's location.
141 EXPECT_TRUE(ExecuteScriptAndExtractBool(
142 shell()->web_contents(),
143 "window.domAutomationController.send(testScriptAccessToWindow());",
145 EXPECT_TRUE(success
);
147 // Now navigate the new window to a different site.
148 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
149 scoped_refptr
<SiteInstance
> new_site_instance(
150 new_shell
->web_contents()->GetSiteInstance());
151 EXPECT_NE(orig_site_instance
, new_site_instance
);
153 // We should no longer have script access to the opened window's location.
155 EXPECT_TRUE(ExecuteScriptAndExtractBool(
156 shell()->web_contents(),
157 "window.domAutomationController.send(testScriptAccessToWindow());",
159 EXPECT_FALSE(success
);
162 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
163 // and target=_blank should create a new SiteInstance.
164 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
165 SwapProcessWithRelNoreferrerAndTargetBlank
) {
168 // Load a page with links that open in a new window.
169 std::string replacement_path
;
170 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
171 "files/click-noreferrer-links.html",
174 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
176 // Get the original SiteInstance for later comparison.
177 scoped_refptr
<SiteInstance
> orig_site_instance(
178 shell()->web_contents()->GetSiteInstance());
179 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
181 // Test clicking a rel=noreferrer + target=blank link.
182 ShellAddedObserver new_shell_observer
;
183 bool success
= false;
184 EXPECT_TRUE(ExecuteScriptAndExtractBool(
185 shell()->web_contents(),
186 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
188 EXPECT_TRUE(success
);
190 // Wait for the window to open.
191 Shell
* new_shell
= new_shell_observer
.GetShell();
193 EXPECT_EQ("/files/title2.html",
194 new_shell
->web_contents()->GetVisibleURL().path());
196 // Wait for the cross-site transition in the new tab to finish.
197 WaitForLoadStop(new_shell
->web_contents());
198 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
199 new_shell
->web_contents());
200 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
201 pending_render_view_host());
203 // Should have a new SiteInstance.
204 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
205 new_shell
->web_contents()->GetSiteInstance());
206 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
209 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
210 // for rel=noreferrer links in new windows, even to same site pages and named
212 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
213 SwapProcessWithSameSiteRelNoreferrer
) {
216 // Load a page with links that open in a new window.
217 std::string replacement_path
;
218 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
219 "files/click-noreferrer-links.html",
222 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
224 // Get the original SiteInstance for later comparison.
225 scoped_refptr
<SiteInstance
> orig_site_instance(
226 shell()->web_contents()->GetSiteInstance());
227 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
229 // Test clicking a same-site rel=noreferrer + target=foo link.
230 ShellAddedObserver new_shell_observer
;
231 bool success
= false;
232 EXPECT_TRUE(ExecuteScriptAndExtractBool(
233 shell()->web_contents(),
234 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
236 EXPECT_TRUE(success
);
238 // Wait for the window to open.
239 Shell
* new_shell
= new_shell_observer
.GetShell();
241 // Opens in new window.
242 EXPECT_EQ("/files/title2.html",
243 new_shell
->web_contents()->GetVisibleURL().path());
245 // Wait for the cross-site transition in the new tab to finish.
246 WaitForLoadStop(new_shell
->web_contents());
247 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
248 new_shell
->web_contents());
249 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
250 pending_render_view_host());
252 // Should have a new SiteInstance (in a new BrowsingInstance).
253 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
254 new_shell
->web_contents()->GetSiteInstance());
255 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
258 // Test for crbug.com/24447. Following a cross-site link with just
259 // target=_blank should not create a new SiteInstance, unless we
260 // are running in --site-per-process mode.
261 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
262 DontSwapProcessWithOnlyTargetBlank
) {
265 // Load a page with links that open in a new window.
266 std::string replacement_path
;
267 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
268 "files/click-noreferrer-links.html",
271 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path
)));
273 // Get the original SiteInstance for later comparison.
274 scoped_refptr
<SiteInstance
> orig_site_instance(
275 shell()->web_contents()->GetSiteInstance());
276 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
278 // Test clicking a target=blank link.
279 ShellAddedObserver new_shell_observer
;
280 bool success
= false;
281 EXPECT_TRUE(ExecuteScriptAndExtractBool(
282 shell()->web_contents(),
283 "window.domAutomationController.send(clickTargetBlankLink());",
285 EXPECT_TRUE(success
);
287 // Wait for the window to open.
288 Shell
* new_shell
= new_shell_observer
.GetShell();
290 // Wait for the cross-site transition in the new tab to finish.
291 EXPECT_TRUE(WaitForLoadStop(new_shell
->web_contents()));
292 EXPECT_EQ("/files/title2.html",
293 new_shell
->web_contents()->GetLastCommittedURL().path());
295 // Should have the same SiteInstance unless we're in site-per-process mode.
296 scoped_refptr
<SiteInstance
> blank_site_instance(
297 new_shell
->web_contents()->GetSiteInstance());
298 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
299 switches::kSitePerProcess
))
300 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
302 EXPECT_NE(orig_site_instance
, blank_site_instance
);
305 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
306 // and no target=_blank should not create a new SiteInstance.
307 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
308 DontSwapProcessWithOnlyRelNoreferrer
) {
311 // Load a page with links that open in a new window.
312 std::string replacement_path
;
313 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
314 "files/click-noreferrer-links.html",
317 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
319 // Get the original SiteInstance for later comparison.
320 scoped_refptr
<SiteInstance
> orig_site_instance(
321 shell()->web_contents()->GetSiteInstance());
322 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
324 // Test clicking a rel=noreferrer link.
325 bool success
= false;
326 EXPECT_TRUE(ExecuteScriptAndExtractBool(
327 shell()->web_contents(),
328 "window.domAutomationController.send(clickNoRefLink());",
330 EXPECT_TRUE(success
);
332 // Wait for the cross-site transition in the current tab to finish.
333 WaitForLoadStop(shell()->web_contents());
335 // Opens in same window.
336 EXPECT_EQ(1u, Shell::windows().size());
337 EXPECT_EQ("/files/title2.html",
338 shell()->web_contents()->GetLastCommittedURL().path());
340 // Should have the same SiteInstance unless we're in site-per-process mode.
341 scoped_refptr
<SiteInstance
> noref_site_instance(
342 shell()->web_contents()->GetSiteInstance());
343 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
344 switches::kSitePerProcess
))
345 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
347 EXPECT_NE(orig_site_instance
, noref_site_instance
);
350 // Test for crbug.com/116192. Targeted links should still work after the
351 // named target window has swapped processes.
352 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
353 AllowTargetedNavigationsAfterSwap
) {
356 // Load a page with links that open in a new window.
357 std::string replacement_path
;
358 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
359 "files/click-noreferrer-links.html",
362 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
364 // Get the original SiteInstance for later comparison.
365 scoped_refptr
<SiteInstance
> orig_site_instance(
366 shell()->web_contents()->GetSiteInstance());
367 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
369 // Test clicking a target=foo link.
370 ShellAddedObserver new_shell_observer
;
371 bool success
= false;
372 EXPECT_TRUE(ExecuteScriptAndExtractBool(
373 shell()->web_contents(),
374 "window.domAutomationController.send(clickSameSiteTargetedLink());",
376 EXPECT_TRUE(success
);
377 Shell
* new_shell
= new_shell_observer
.GetShell();
379 // Wait for the navigation in the new tab to finish, if it hasn't.
380 WaitForLoadStop(new_shell
->web_contents());
381 EXPECT_EQ("/files/navigate_opener.html",
382 new_shell
->web_contents()->GetLastCommittedURL().path());
384 // Should have the same SiteInstance.
385 scoped_refptr
<SiteInstance
> blank_site_instance(
386 new_shell
->web_contents()->GetSiteInstance());
387 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
389 // Now navigate the new tab to a different site.
390 GURL
cross_site_url(GetCrossSiteURL("files/title1.html"));
391 NavigateToURL(new_shell
, cross_site_url
);
392 scoped_refptr
<SiteInstance
> new_site_instance(
393 new_shell
->web_contents()->GetSiteInstance());
394 EXPECT_NE(orig_site_instance
, new_site_instance
);
396 // Clicking the original link in the first tab should cause us to swap back.
397 TestNavigationObserver
navigation_observer(new_shell
->web_contents());
398 EXPECT_TRUE(ExecuteScriptAndExtractBool(
399 shell()->web_contents(),
400 "window.domAutomationController.send(clickSameSiteTargetedLink());",
402 EXPECT_TRUE(success
);
403 navigation_observer
.Wait();
405 // Should have swapped back and shown the new window again.
406 scoped_refptr
<SiteInstance
> revisit_site_instance(
407 new_shell
->web_contents()->GetSiteInstance());
408 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
410 // If it navigates away to another process, the original window should
411 // still be able to close it (using a cross-process close message).
412 NavigateToURL(new_shell
, cross_site_url
);
413 EXPECT_EQ(new_site_instance
.get(),
414 new_shell
->web_contents()->GetSiteInstance());
415 WebContentsDestroyedWatcher
close_watcher(new_shell
->web_contents());
416 EXPECT_TRUE(ExecuteScriptAndExtractBool(
417 shell()->web_contents(),
418 "window.domAutomationController.send(testCloseWindow());",
420 EXPECT_TRUE(success
);
421 close_watcher
.Wait();
424 // Test that setting the opener to null in a window affects cross-process
425 // navigations, including those to existing entries. http://crbug.com/156669.
426 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
427 #if defined(THREAD_SANITIZER)
428 #define MAYBE_DisownOpener DISABLED_DisownOpener
430 #define MAYBE_DisownOpener DisownOpener
432 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_DisownOpener
) {
435 // Load a page with links that open in a new window.
436 std::string replacement_path
;
437 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
438 "files/click-noreferrer-links.html",
441 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
443 // Get the original SiteInstance for later comparison.
444 scoped_refptr
<SiteInstance
> orig_site_instance(
445 shell()->web_contents()->GetSiteInstance());
446 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
448 // Test clicking a target=_blank link.
449 ShellAddedObserver new_shell_observer
;
450 bool success
= false;
451 EXPECT_TRUE(ExecuteScriptAndExtractBool(
452 shell()->web_contents(),
453 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
455 EXPECT_TRUE(success
);
456 Shell
* new_shell
= new_shell_observer
.GetShell();
457 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
459 // Wait for the navigation in the new tab to finish, if it hasn't.
460 WaitForLoadStop(new_shell
->web_contents());
461 EXPECT_EQ("/files/title2.html",
462 new_shell
->web_contents()->GetLastCommittedURL().path());
464 // Should have the same SiteInstance.
465 scoped_refptr
<SiteInstance
> blank_site_instance(
466 new_shell
->web_contents()->GetSiteInstance());
467 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
469 // Now navigate the new tab to a different site.
470 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
471 scoped_refptr
<SiteInstance
> new_site_instance(
472 new_shell
->web_contents()->GetSiteInstance());
473 EXPECT_NE(orig_site_instance
, new_site_instance
);
474 EXPECT_TRUE(new_shell
->web_contents()->HasOpener());
476 // Now disown the opener.
477 EXPECT_TRUE(ExecuteScript(new_shell
->web_contents(),
478 "window.opener = null;"));
479 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
481 // Go back and ensure the opener is still null.
483 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
484 new_shell
->web_contents()->GetController().GoBack();
485 back_nav_load_observer
.Wait();
488 EXPECT_TRUE(ExecuteScriptAndExtractBool(
489 new_shell
->web_contents(),
490 "window.domAutomationController.send(window.opener == null);",
492 EXPECT_TRUE(success
);
493 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
495 // Now navigate forward again (creating a new process) and check opener.
496 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
498 EXPECT_TRUE(ExecuteScriptAndExtractBool(
499 new_shell
->web_contents(),
500 "window.domAutomationController.send(window.opener == null);",
502 EXPECT_TRUE(success
);
503 EXPECT_FALSE(new_shell
->web_contents()->HasOpener());
506 // Test that subframes can disown their openers. http://crbug.com/225528.
507 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, DisownSubframeOpener
) {
508 const GURL
frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
509 NavigateToURL(shell(), frame_url
);
511 // Give the frame an opener using window.open.
512 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
513 "window.open('about:blank','foo');"));
515 // Now disown the frame's opener. Shouldn't crash.
516 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
517 "window.frames[0].opener = null;"));
520 // Test for crbug.com/99202. PostMessage calls should still work after
521 // navigating the source and target windows to different sites.
523 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
524 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
525 // 3) Post a message from "foo" to opener, which replies back to "foo".
526 // 4) Post a message from _blank to "foo".
527 // 5) Post a message from "foo" to a subframe of opener, which replies back.
528 // 6) Post a message from _blank to a subframe of "foo".
529 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
530 SupportCrossProcessPostMessage
) {
533 // Load a page with links that open in a new window.
534 std::string replacement_path
;
535 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
536 "files/click-noreferrer-links.html",
539 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
541 // Get the original SiteInstance and RVHM for later comparison.
542 WebContents
* opener_contents
= shell()->web_contents();
543 scoped_refptr
<SiteInstance
> orig_site_instance(
544 opener_contents
->GetSiteInstance());
545 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
546 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
547 opener_contents
)->GetRenderManagerForTesting();
549 // 1) Open two more windows, one named. These initially have openers but no
550 // reference to each other. We will later post a message between them.
552 // First, a named target=foo window.
553 ShellAddedObserver new_shell_observer
;
554 bool success
= false;
555 EXPECT_TRUE(ExecuteScriptAndExtractBool(
557 "window.domAutomationController.send(clickSameSiteTargetedLink());",
559 EXPECT_TRUE(success
);
560 Shell
* new_shell
= new_shell_observer
.GetShell();
562 // Wait for the navigation in the new window to finish, if it hasn't, then
563 // send it to post_message.html on a different site.
564 WebContents
* foo_contents
= new_shell
->web_contents();
565 WaitForLoadStop(foo_contents
);
566 EXPECT_EQ("/files/navigate_opener.html",
567 foo_contents
->GetLastCommittedURL().path());
568 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
569 scoped_refptr
<SiteInstance
> foo_site_instance(
570 foo_contents
->GetSiteInstance());
571 EXPECT_NE(orig_site_instance
, foo_site_instance
);
573 // Second, a target=_blank window.
574 ShellAddedObserver new_shell_observer2
;
575 EXPECT_TRUE(ExecuteScriptAndExtractBool(
576 shell()->web_contents(),
577 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
579 EXPECT_TRUE(success
);
581 // Wait for the navigation in the new window to finish, if it hasn't, then
582 // send it to post_message.html on the original site.
583 Shell
* new_shell2
= new_shell_observer2
.GetShell();
584 WebContents
* new_contents
= new_shell2
->web_contents();
585 WaitForLoadStop(new_contents
);
586 EXPECT_EQ("/files/title2.html", new_contents
->GetLastCommittedURL().path());
587 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
588 EXPECT_EQ(orig_site_instance
.get(), new_contents
->GetSiteInstance());
589 RenderFrameHostManager
* new_manager
=
590 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
592 // We now have three windows. The opener should have a swapped out RVH
593 // for the new SiteInstance, but the _blank window should not.
594 EXPECT_EQ(3u, Shell::windows().size());
596 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
598 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
600 // 2) Fail to post a message from the foo window to the opener if the target
601 // origin is wrong. We won't see an error, but we can check for the right
602 // number of received messages below.
603 EXPECT_TRUE(ExecuteScriptAndExtractBool(
605 "window.domAutomationController.send(postToOpener('msg',"
606 " 'http://google.com'));",
608 EXPECT_TRUE(success
);
610 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
612 // 3) Post a message from the foo window to the opener. The opener will
613 // reply, causing the foo window to update its own title.
614 base::string16 expected_title
= ASCIIToUTF16("msg");
615 TitleWatcher
title_watcher(foo_contents
, expected_title
);
616 EXPECT_TRUE(ExecuteScriptAndExtractBool(
618 "window.domAutomationController.send(postToOpener('msg','*'));",
620 EXPECT_TRUE(success
);
622 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
623 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
625 // We should have received only 1 message in the opener and "foo" tabs,
626 // and updated the title.
627 int opener_received_messages
= 0;
628 EXPECT_TRUE(ExecuteScriptAndExtractInt(
630 "window.domAutomationController.send(window.receivedMessages);",
631 &opener_received_messages
));
632 int foo_received_messages
= 0;
633 EXPECT_TRUE(ExecuteScriptAndExtractInt(
635 "window.domAutomationController.send(window.receivedMessages);",
636 &foo_received_messages
));
637 EXPECT_EQ(1, foo_received_messages
);
638 EXPECT_EQ(1, opener_received_messages
);
639 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
641 // 4) Now post a message from the _blank window to the foo window. The
642 // foo window will update its title and will not reply.
643 expected_title
= ASCIIToUTF16("msg2");
644 TitleWatcher
title_watcher2(foo_contents
, expected_title
);
645 EXPECT_TRUE(ExecuteScriptAndExtractBool(
647 "window.domAutomationController.send(postToFoo('msg2'));",
649 EXPECT_TRUE(success
);
650 ASSERT_EQ(expected_title
, title_watcher2
.WaitAndGetTitle());
652 // This postMessage should have created a swapped out RVH for the new
653 // SiteInstance in the target=_blank window.
655 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
657 // TODO(nasko): Test subframe targeting of postMessage once
658 // http://crbug.com/153701 is fixed.
661 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
662 // messages which contain Transferables and get intercepted by
663 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
664 // swapped out) should work.
666 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
667 // 2) Post a message containing a message port from opener to "foo".
668 // 3) Post a message from "foo" back to opener via the passed message port.
669 // The test will be enabled when the feature implementation lands.
670 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
671 SupportCrossProcessPostMessageWithMessagePort
) {
674 // Load a page with links that open in a new window.
675 std::string replacement_path
;
676 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
677 "files/click-noreferrer-links.html",
680 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
682 // Get the original SiteInstance and RVHM for later comparison.
683 WebContents
* opener_contents
= shell()->web_contents();
684 scoped_refptr
<SiteInstance
> orig_site_instance(
685 opener_contents
->GetSiteInstance());
686 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
687 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
688 opener_contents
)->GetRenderManagerForTesting();
690 // 1) Open a named target=foo window. We will later post a message between the
691 // opener and the new window.
692 ShellAddedObserver new_shell_observer
;
693 bool success
= false;
694 EXPECT_TRUE(ExecuteScriptAndExtractBool(
696 "window.domAutomationController.send(clickSameSiteTargetedLink());",
698 EXPECT_TRUE(success
);
699 Shell
* new_shell
= new_shell_observer
.GetShell();
701 // Wait for the navigation in the new window to finish, if it hasn't, then
702 // send it to post_message.html on a different site.
703 WebContents
* foo_contents
= new_shell
->web_contents();
704 WaitForLoadStop(foo_contents
);
705 EXPECT_EQ("/files/navigate_opener.html",
706 foo_contents
->GetLastCommittedURL().path());
707 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
708 scoped_refptr
<SiteInstance
> foo_site_instance(
709 foo_contents
->GetSiteInstance());
710 EXPECT_NE(orig_site_instance
, foo_site_instance
);
712 // We now have two windows. The opener should have a swapped out RVH
713 // for the new SiteInstance.
714 EXPECT_EQ(2u, Shell::windows().size());
716 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
718 // 2) Post a message containing a MessagePort from opener to the the foo
719 // window. The foo window will reply via the passed port, causing the opener
720 // to update its own title.
721 base::string16 expected_title
= ASCIIToUTF16("msg-back-via-port");
722 TitleWatcher
title_observer(opener_contents
, expected_title
);
723 EXPECT_TRUE(ExecuteScriptAndExtractBool(
725 "window.domAutomationController.send(postWithPortToFoo());",
727 EXPECT_TRUE(success
);
729 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
730 ASSERT_EQ(expected_title
, title_observer
.WaitAndGetTitle());
732 // Check message counts.
733 int opener_received_messages_via_port
= 0;
734 EXPECT_TRUE(ExecuteScriptAndExtractInt(
736 "window.domAutomationController.send(window.receivedMessagesViaPort);",
737 &opener_received_messages_via_port
));
738 int foo_received_messages
= 0;
739 EXPECT_TRUE(ExecuteScriptAndExtractInt(
741 "window.domAutomationController.send(window.receivedMessages);",
742 &foo_received_messages
));
743 int foo_received_messages_with_port
= 0;
744 EXPECT_TRUE(ExecuteScriptAndExtractInt(
746 "window.domAutomationController.send(window.receivedMessagesWithPort);",
747 &foo_received_messages_with_port
));
748 EXPECT_EQ(1, foo_received_messages
);
749 EXPECT_EQ(1, foo_received_messages_with_port
);
750 EXPECT_EQ(1, opener_received_messages_via_port
);
751 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents
->GetTitle());
752 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents
->GetTitle());
755 // Test for crbug.com/116192. Navigations to a window's opener should
756 // still work after a process swap.
757 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
758 AllowTargetedNavigationsInOpenerAfterSwap
) {
761 // Load a page with links that open in a new window.
762 std::string replacement_path
;
763 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
764 "files/click-noreferrer-links.html",
767 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
769 // Get the original tab and SiteInstance for later comparison.
770 WebContents
* orig_contents
= shell()->web_contents();
771 scoped_refptr
<SiteInstance
> orig_site_instance(
772 orig_contents
->GetSiteInstance());
773 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
775 // Test clicking a target=foo link.
776 ShellAddedObserver new_shell_observer
;
777 bool success
= false;
778 EXPECT_TRUE(ExecuteScriptAndExtractBool(
780 "window.domAutomationController.send(clickSameSiteTargetedLink());",
782 EXPECT_TRUE(success
);
783 Shell
* new_shell
= new_shell_observer
.GetShell();
785 // Wait for the navigation in the new window to finish, if it hasn't.
786 WaitForLoadStop(new_shell
->web_contents());
787 EXPECT_EQ("/files/navigate_opener.html",
788 new_shell
->web_contents()->GetLastCommittedURL().path());
790 // Should have the same SiteInstance.
791 scoped_refptr
<SiteInstance
> blank_site_instance(
792 new_shell
->web_contents()->GetSiteInstance());
793 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
795 // Now navigate the original (opener) tab to a different site.
796 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
797 scoped_refptr
<SiteInstance
> new_site_instance(
798 shell()->web_contents()->GetSiteInstance());
799 EXPECT_NE(orig_site_instance
, new_site_instance
);
801 // The opened tab should be able to navigate the opener back to its process.
802 TestNavigationObserver
navigation_observer(orig_contents
);
803 EXPECT_TRUE(ExecuteScriptAndExtractBool(
804 new_shell
->web_contents(),
805 "window.domAutomationController.send(navigateOpener());",
807 EXPECT_TRUE(success
);
808 navigation_observer
.Wait();
810 // Should have swapped back into this process.
811 scoped_refptr
<SiteInstance
> revisit_site_instance(
812 shell()->web_contents()->GetSiteInstance());
813 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
816 // Test that opening a new window in the same SiteInstance and then navigating
817 // both windows to a different SiteInstance allows the first process to exit.
818 // See http://crbug.com/126333.
819 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
820 ProcessExitWithSwappedOutViews
) {
823 // Load a page with links that open in a new window.
824 std::string replacement_path
;
825 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
826 "files/click-noreferrer-links.html",
829 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
831 // Get the original SiteInstance for later comparison.
832 scoped_refptr
<SiteInstance
> orig_site_instance(
833 shell()->web_contents()->GetSiteInstance());
834 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
836 // Test clicking a target=foo link.
837 ShellAddedObserver new_shell_observer
;
838 bool success
= false;
839 EXPECT_TRUE(ExecuteScriptAndExtractBool(
840 shell()->web_contents(),
841 "window.domAutomationController.send(clickSameSiteTargetedLink());",
843 EXPECT_TRUE(success
);
844 Shell
* new_shell
= new_shell_observer
.GetShell();
846 // Wait for the navigation in the new window to finish, if it hasn't.
847 WaitForLoadStop(new_shell
->web_contents());
848 EXPECT_EQ("/files/navigate_opener.html",
849 new_shell
->web_contents()->GetLastCommittedURL().path());
851 // Should have the same SiteInstance.
852 scoped_refptr
<SiteInstance
> opened_site_instance(
853 new_shell
->web_contents()->GetSiteInstance());
854 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
856 // Now navigate the opened window to a different site.
857 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
858 scoped_refptr
<SiteInstance
> new_site_instance(
859 new_shell
->web_contents()->GetSiteInstance());
860 EXPECT_NE(orig_site_instance
, new_site_instance
);
862 // The original process should still be alive, since it is still used in the
864 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
865 EXPECT_TRUE(orig_process
->HasConnection());
867 // Navigate the first window to a different site as well. The original
868 // process should exit, since all of its views are now swapped out.
869 RenderProcessHostWatcher
exit_observer(
871 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
872 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
873 exit_observer
.Wait();
874 scoped_refptr
<SiteInstance
> new_site_instance2(
875 shell()->web_contents()->GetSiteInstance());
876 EXPECT_EQ(new_site_instance
, new_site_instance2
);
879 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
880 // error should not make us ignore future renderer-initiated navigations.
881 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ClickLinkAfter204Error
) {
884 // Get the original SiteInstance for later comparison.
885 scoped_refptr
<SiteInstance
> orig_site_instance(
886 shell()->web_contents()->GetSiteInstance());
887 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
889 // Load a cross-site page that fails with a 204 error.
890 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
891 GetCrossSiteURL("nocontent")));
893 // We should still be looking at the normal page. Because we started from a
894 // blank new tab, the typed URL will still be visible until the user clears it
895 // manually. The last committed URL will be the previous page.
896 scoped_refptr
<SiteInstance
> post_nav_site_instance(
897 shell()->web_contents()->GetSiteInstance());
898 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
899 EXPECT_EQ("/nocontent",
900 shell()->web_contents()->GetVisibleURL().path());
902 shell()->web_contents()->GetController().GetLastCommittedEntry());
904 // Renderer-initiated navigations should work.
905 base::string16 expected_title
= ASCIIToUTF16("Title Of Awesomeness");
906 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
907 GURL url
= test_server()->GetURL("files/title2.html");
908 EXPECT_TRUE(ExecuteScript(
909 shell()->web_contents(),
910 base::StringPrintf("location.href = '%s'", url
.spec().c_str())));
911 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
913 // Opens in same tab.
914 EXPECT_EQ(1u, Shell::windows().size());
915 EXPECT_EQ("/files/title2.html",
916 shell()->web_contents()->GetLastCommittedURL().path());
918 // Should have the same SiteInstance.
919 scoped_refptr
<SiteInstance
> new_site_instance(
920 shell()->web_contents()->GetSiteInstance());
921 EXPECT_EQ(orig_site_instance
, new_site_instance
);
924 // Test for crbug.com/9682. We should show the URL for a pending renderer-
925 // initiated navigation in a new tab, until the content of the initial
926 // about:blank page is modified by another window. At that point, we should
927 // revert to showing about:blank to prevent a URL spoof.
928 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ShowLoadingURLUntilSpoof
) {
929 ASSERT_TRUE(test_server()->Start());
931 // Load a page that can open a URL that won't commit in a new window.
933 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
934 WebContents
* orig_contents
= shell()->web_contents();
936 // Click a /nocontent link that opens in a new window but never commits.
937 ShellAddedObserver new_shell_observer
;
938 bool success
= false;
939 EXPECT_TRUE(ExecuteScriptAndExtractBool(
941 "window.domAutomationController.send(clickNoContentTargetedLink());",
943 EXPECT_TRUE(success
);
945 // Wait for the window to open.
946 Shell
* new_shell
= new_shell_observer
.GetShell();
948 // Ensure the destination URL is visible, because it is considered the
949 // initial navigation.
950 WebContents
* contents
= new_shell
->web_contents();
951 EXPECT_TRUE(contents
->GetController().IsInitialNavigation());
952 EXPECT_EQ("/nocontent",
953 contents
->GetController().GetVisibleEntry()->GetURL().path());
955 // Now modify the contents of the new window from the opener. This will also
956 // modify the title of the document to give us something to listen for.
957 base::string16 expected_title
= ASCIIToUTF16("Modified Title");
958 TitleWatcher
title_watcher(contents
, expected_title
);
960 EXPECT_TRUE(ExecuteScriptAndExtractBool(
962 "window.domAutomationController.send(modifyNewWindow());",
964 EXPECT_TRUE(success
);
965 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
967 // At this point, we should no longer be showing the destination URL.
968 // The visible entry should be null, resulting in about:blank in the address
970 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
973 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
974 // initiated navigation in a new tab if it is not the initial navigation. In
975 // this case, the renderer will not notify us of a modification, so we cannot
976 // show the pending URL without allowing a spoof.
977 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
978 DontShowLoadingURLIfNotInitialNav
) {
979 ASSERT_TRUE(test_server()->Start());
981 // Load a page that can open a URL that won't commit in a new window.
983 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
984 WebContents
* orig_contents
= shell()->web_contents();
986 // Click a /nocontent link that opens in a new window but never commits.
987 // By using an onclick handler that first creates the window, the slow
988 // navigation is not considered an initial navigation.
989 ShellAddedObserver new_shell_observer
;
990 bool success
= false;
991 EXPECT_TRUE(ExecuteScriptAndExtractBool(
993 "window.domAutomationController.send("
994 "clickNoContentScriptedTargetedLink());",
996 EXPECT_TRUE(success
);
998 // Wait for the window to open.
999 Shell
* new_shell
= new_shell_observer
.GetShell();
1001 // Ensure the destination URL is not visible, because it is not the initial
1003 WebContents
* contents
= new_shell
->web_contents();
1004 EXPECT_FALSE(contents
->GetController().IsInitialNavigation());
1005 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
1008 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1009 #if defined(THREAD_SANITIZER)
1010 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1012 #define MAYBE_BackForwardNotStale BackForwardNotStale
1014 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1015 // do not cause back/forward navigations to be considered stale by the
1017 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_BackForwardNotStale
) {
1019 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1021 // Visit a page on first site.
1022 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1024 // Visit three pages on second site.
1025 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1026 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1027 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1029 // History is now [blank, A1, B1, B2, *B3].
1030 WebContents
* contents
= shell()->web_contents();
1031 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
1033 // Open another window in same process to keep this process alive.
1034 Shell
* new_shell
= CreateBrowser();
1035 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1037 // Go back three times to first site.
1039 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1040 shell()->web_contents()->GetController().GoBack();
1041 back_nav_load_observer
.Wait();
1044 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1045 shell()->web_contents()->GetController().GoBack();
1046 back_nav_load_observer
.Wait();
1049 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1050 shell()->web_contents()->GetController().GoBack();
1051 back_nav_load_observer
.Wait();
1054 // Now go forward twice to B2. Shouldn't be left spinning.
1056 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1057 shell()->web_contents()->GetController().GoForward();
1058 forward_nav_load_observer
.Wait();
1061 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1062 shell()->web_contents()->GetController().GoForward();
1063 forward_nav_load_observer
.Wait();
1066 // Go back twice to first site.
1068 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1069 shell()->web_contents()->GetController().GoBack();
1070 back_nav_load_observer
.Wait();
1073 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1074 shell()->web_contents()->GetController().GoBack();
1075 back_nav_load_observer
.Wait();
1078 // Now go forward directly to B3. Shouldn't be left spinning.
1080 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1081 shell()->web_contents()->GetController().GoToIndex(4);
1082 forward_nav_load_observer
.Wait();
1086 // Test for http://crbug.com/130016.
1087 // Swapping out a render view should update its visiblity state.
1088 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1089 SwappedOutViewHasCorrectVisibilityState
) {
1092 // Load a page with links that open in a new window.
1093 std::string replacement_path
;
1094 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1095 "files/click-noreferrer-links.html",
1097 &replacement_path
));
1098 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
1100 // Open a same-site link in a new widnow.
1101 ShellAddedObserver new_shell_observer
;
1102 bool success
= false;
1103 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1104 shell()->web_contents(),
1105 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1107 EXPECT_TRUE(success
);
1108 Shell
* new_shell
= new_shell_observer
.GetShell();
1110 // Wait for the navigation in the new tab to finish, if it hasn't.
1111 WaitForLoadStop(new_shell
->web_contents());
1112 EXPECT_EQ("/files/navigate_opener.html",
1113 new_shell
->web_contents()->GetLastCommittedURL().path());
1115 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
1117 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1119 "window.domAutomationController.send("
1120 " document.visibilityState == 'visible');",
1122 EXPECT_TRUE(success
);
1124 // Now navigate the new window to a different site. This should swap out the
1125 // tab's existing RenderView, causing it become hidden.
1126 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1128 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1130 "window.domAutomationController.send("
1131 " document.visibilityState == 'hidden');",
1133 EXPECT_TRUE(success
);
1135 // Going back should make the previously swapped-out view to become visible
1138 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
1139 new_shell
->web_contents()->GetController().GoBack();
1140 back_nav_load_observer
.Wait();
1143 EXPECT_EQ("/files/navigate_opener.html",
1144 new_shell
->web_contents()->GetLastCommittedURL().path());
1146 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
1148 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1150 "window.domAutomationController.send("
1151 " document.visibilityState == 'visible');",
1153 EXPECT_TRUE(success
);
1156 // This class ensures that all the given RenderViewHosts have properly been
1158 class RenderViewHostDestructionObserver
: public WebContentsObserver
{
1160 explicit RenderViewHostDestructionObserver(WebContents
* web_contents
)
1161 : WebContentsObserver(web_contents
) {}
1162 ~RenderViewHostDestructionObserver() override
{}
1163 void EnsureRVHGetsDestructed(RenderViewHost
* rvh
) {
1164 watched_render_view_hosts_
.insert(rvh
);
1166 size_t GetNumberOfWatchedRenderViewHosts() const {
1167 return watched_render_view_hosts_
.size();
1171 // WebContentsObserver implementation:
1172 void RenderViewDeleted(RenderViewHost
* rvh
) override
{
1173 watched_render_view_hosts_
.erase(rvh
);
1176 std::set
<RenderViewHost
*> watched_render_view_hosts_
;
1179 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1180 #if defined(THREAD_SANITIZER)
1181 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1183 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1185 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1186 // they may cause crashes or memory corruptions when trying to call dead
1187 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1188 // ensure that a separate SiteInstance is created when navigating to view-source
1189 // URLs, regardless of current URL.
1190 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1191 MAYBE_LeakingRenderViewHosts
) {
1194 // Observe the created render_view_host's to make sure they will not leak.
1195 RenderViewHostDestructionObserver
rvh_observers(shell()->web_contents());
1197 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1198 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1199 navigated_url
.spec());
1201 // Let's ensure that when we start with a blank window, navigating away to a
1202 // view-source URL, we create a new SiteInstance.
1203 RenderViewHost
* blank_rvh
= shell()->web_contents()->GetRenderViewHost();
1204 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1205 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1206 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1207 rvh_observers
.EnsureRVHGetsDestructed(blank_rvh
);
1209 // Now navigate to the view-source URL and ensure we got a different
1210 // SiteInstance and RenderViewHost.
1211 NavigateToURL(shell(), view_source_url
);
1212 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1213 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1214 GetRenderViewHost()->GetSiteInstance());
1215 rvh_observers
.EnsureRVHGetsDestructed(
1216 shell()->web_contents()->GetRenderViewHost());
1218 // Load a random page and then navigate to view-source: of it.
1219 // This used to cause two RVH instances for the same SiteInstance, which
1220 // was a problem. This is no longer the case.
1221 NavigateToURL(shell(), navigated_url
);
1222 SiteInstance
* site_instance1
= shell()->web_contents()->
1223 GetRenderViewHost()->GetSiteInstance();
1224 rvh_observers
.EnsureRVHGetsDestructed(
1225 shell()->web_contents()->GetRenderViewHost());
1227 NavigateToURL(shell(), view_source_url
);
1228 rvh_observers
.EnsureRVHGetsDestructed(
1229 shell()->web_contents()->GetRenderViewHost());
1230 SiteInstance
* site_instance2
= shell()->web_contents()->
1231 GetRenderViewHost()->GetSiteInstance();
1233 // Ensure that view-source navigations force a new SiteInstance.
1234 EXPECT_NE(site_instance1
, site_instance2
);
1236 // Now navigate to a different instance so that we swap out again.
1237 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1238 rvh_observers
.EnsureRVHGetsDestructed(
1239 shell()->web_contents()->GetRenderViewHost());
1241 // This used to leak a render view host.
1244 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1246 EXPECT_EQ(0U, rvh_observers
.GetNumberOfWatchedRenderViewHosts());
1249 // Test for crbug.com/143155. Frame tree updates during unload should not
1250 // interrupt the intended navigation and show swappedout:// instead.
1252 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1253 // 2) Send the second tab to a different foo.com SiteInstance.
1254 // This creates a swapped out opener for the first tab in the foo process.
1255 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1256 // tab's unload handler remove its frame.
1257 // This used to cause an update to the frame tree of the swapped out RV,
1258 // just as it was navigating to a real page. That pre-empted the real
1259 // navigation and visibly sent the tab to swappedout://.
1260 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1261 DontPreemptNavigationWithFrameTreeUpdate
) {
1264 // 1. Load a page that deletes its iframe during unload.
1265 NavigateToURL(shell(),
1266 test_server()->GetURL("files/remove_frame_on_unload.html"));
1268 // Get the original SiteInstance for later comparison.
1269 scoped_refptr
<SiteInstance
> orig_site_instance(
1270 shell()->web_contents()->GetSiteInstance());
1272 // Open a same-site page in a new window.
1273 ShellAddedObserver new_shell_observer
;
1274 bool success
= false;
1275 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1276 shell()->web_contents(),
1277 "window.domAutomationController.send(openWindow());",
1279 EXPECT_TRUE(success
);
1280 Shell
* new_shell
= new_shell_observer
.GetShell();
1282 // Wait for the navigation in the new window to finish, if it hasn't.
1283 WaitForLoadStop(new_shell
->web_contents());
1284 EXPECT_EQ("/files/title1.html",
1285 new_shell
->web_contents()->GetLastCommittedURL().path());
1287 // Should have the same SiteInstance.
1288 EXPECT_EQ(orig_site_instance
.get(),
1289 new_shell
->web_contents()->GetSiteInstance());
1291 // 2. Send the second tab to a different process.
1292 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1293 scoped_refptr
<SiteInstance
> new_site_instance(
1294 new_shell
->web_contents()->GetSiteInstance());
1295 EXPECT_NE(orig_site_instance
, new_site_instance
);
1297 // 3. Send the first tab to the second tab's process.
1298 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1300 // Make sure it ends up at the right page.
1301 WaitForLoadStop(shell()->web_contents());
1302 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1303 shell()->web_contents()->GetLastCommittedURL());
1304 EXPECT_EQ(new_site_instance
.get(),
1305 shell()->web_contents()->GetSiteInstance());
1308 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1309 // are meant to run in the current page. We had a bug where we expected a
1310 // BrowsingInstance swap to occur on pages like view-source and extensions,
1311 // which broke chrome://crash and javascript: URLs.
1312 // See http://crbug.com/335503.
1313 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, RendererDebugURLsDontSwap
) {
1314 ASSERT_TRUE(test_server()->Start());
1316 GURL
original_url(test_server()->GetURL("files/title2.html"));
1317 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1318 original_url
.spec());
1320 NavigateToURL(shell(), view_source_url
);
1322 // Check that javascript: URLs work.
1323 base::string16 expected_title
= ASCIIToUTF16("msg");
1324 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1325 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1326 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1328 // Crash the renderer of the view-source page.
1329 RenderProcessHostWatcher
crash_observer(
1330 shell()->web_contents(),
1331 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1333 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1334 crash_observer
.Wait();
1337 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1338 // Otherwise, we might try to load an unprivileged about:blank page into a
1339 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1340 // See http://crbug.com/334214.
1341 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1342 IgnoreRendererDebugURLsWhenCrashed
) {
1343 // Visit a WebUI page with bindings.
1344 GURL webui_url
= GURL(std::string(kChromeUIScheme
) + "://" +
1345 std::string(kChromeUIGpuHost
));
1346 NavigateToURL(shell(), webui_url
);
1347 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1348 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1350 // Crash the renderer of the WebUI page.
1351 RenderProcessHostWatcher
crash_observer(
1352 shell()->web_contents(),
1353 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1355 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL
)));
1356 crash_observer
.Wait();
1358 // Load the crash URL again but don't wait for any action. If it is not
1359 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1360 shell()->LoadURL(GURL(kChromeUICrashURL
));
1362 // Ensure that such URLs can still work as the initial navigation of a tab.
1363 // We postpone the initial navigation of the tab using an empty GURL, so that
1364 // we can add a watcher for crashes.
1365 Shell
* shell2
= Shell::CreateNewWindow(
1366 shell()->web_contents()->GetBrowserContext(), GURL(), NULL
,
1367 MSG_ROUTING_NONE
, gfx::Size());
1368 RenderProcessHostWatcher
crash_observer2(
1369 shell2
->web_contents(),
1370 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1372 NavigateToURLAndExpectNoCommit(shell2
, GURL(kChromeUIKillURL
)));
1373 crash_observer2
.Wait();
1376 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1377 // See http://crbug.com/428329.
1378 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1379 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1381 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1383 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1384 // Otherwise it might get picked up by InitRenderView when granting bindings
1385 // to other RenderViewHosts. See http://crbug.com/330811.
1386 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1387 MAYBE_ClearPendingWebUIOnCommit
) {
1388 // Visit a WebUI page with bindings.
1389 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1390 std::string(kChromeUIGpuHost
)));
1391 NavigateToURL(shell(), webui_url
);
1392 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1393 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1394 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1395 shell()->web_contents());
1396 WebUIImpl
* webui
= web_contents
->GetRenderManagerForTesting()->web_ui();
1398 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1400 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1401 // clear pending_web_ui() when it commits.
1402 GURL
webui_url2(webui_url
.spec() + "#foo");
1403 NavigateToURL(shell(), webui_url2
);
1404 EXPECT_EQ(webui
, web_contents
->GetRenderManagerForTesting()->web_ui());
1405 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1408 class RFHMProcessPerTabTest
: public RenderFrameHostManagerTest
{
1410 RFHMProcessPerTabTest() {}
1412 void SetUpCommandLine(CommandLine
* command_line
) override
{
1413 command_line
->AppendSwitch(switches::kProcessPerTab
);
1417 // Test that we still swap processes for BrowsingInstance changes even in
1418 // --process-per-tab mode. See http://crbug.com/343017.
1419 // Disabled on Android: http://crbug.com/345873.
1420 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1421 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1422 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1424 #define MAYBE_BackFromWebUI BackFromWebUI
1426 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest
, MAYBE_BackFromWebUI
) {
1427 ASSERT_TRUE(test_server()->Start());
1428 GURL
original_url(test_server()->GetURL("files/title2.html"));
1429 NavigateToURL(shell(), original_url
);
1431 // Visit a WebUI page with bindings.
1432 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1433 std::string(kChromeUIGpuHost
)));
1434 NavigateToURL(shell(), webui_url
);
1435 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1436 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1438 // Go back and ensure we have no WebUI bindings.
1439 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1440 shell()->web_contents()->GetController().GoBack();
1441 back_nav_load_observer
.Wait();
1442 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
1443 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1444 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1448 // The test loads url1, opens a link pointing to url2 in a new tab, and
1449 // navigates the new tab to url1.
1450 // The following is needed for the bug to happen:
1451 // - url1 must require webui bindings;
1452 // - navigating to url2 in the site instance of url1 should not swap
1453 // browsing instances, but should require a new site instance.
1454 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, WebUIGetsBindings
) {
1455 GURL
url1(std::string(kChromeUIScheme
) + "://" +
1456 std::string(kChromeUIGpuHost
));
1457 GURL
url2(std::string(kChromeUIScheme
) + "://" +
1458 std::string(kChromeUIAccessibilityHost
));
1460 // Visit a WebUI page with bindings.
1461 NavigateToURL(shell(), url1
);
1462 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1463 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1464 SiteInstance
* site_instance1
= shell()->web_contents()->GetSiteInstance();
1466 // Open a new tab. Initially it gets a render view in the original tab's
1467 // current site instance.
1468 TestNavigationObserver
nav_observer(NULL
);
1469 nav_observer
.StartWatchingNewWebContents();
1470 ShellAddedObserver shao
;
1471 OpenUrlViaClickTarget(shell()->web_contents(), url2
);
1472 nav_observer
.Wait();
1473 Shell
* new_shell
= shao
.GetShell();
1474 WebContentsImpl
* new_web_contents
= static_cast<WebContentsImpl
*>(
1475 new_shell
->web_contents());
1476 SiteInstance
* site_instance2
= new_web_contents
->GetSiteInstance();
1478 EXPECT_NE(site_instance2
, site_instance1
);
1479 EXPECT_TRUE(site_instance2
->IsRelatedSiteInstance(site_instance1
));
1480 RenderViewHost
* initial_rvh
= new_web_contents
->
1481 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1
);
1482 ASSERT_TRUE(initial_rvh
);
1483 // The following condition is what was causing the bug.
1484 EXPECT_EQ(0, initial_rvh
->GetEnabledBindings());
1486 // Navigate to url1 and check bindings.
1487 NavigateToURL(new_shell
, url1
);
1488 // The navigation should have used the first SiteInstance, otherwise
1489 // |initial_rvh| did not have a chance to be used.
1490 EXPECT_EQ(new_web_contents
->GetSiteInstance(), site_instance1
);
1491 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
1492 new_web_contents
->GetRenderViewHost()->GetEnabledBindings());
1496 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1497 // page and then to a regular page. The bug reproduces if blank page is visited
1498 // in between WebUI and regular page.
1499 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1500 ForceSwapAfterWebUIBindings
) {
1501 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kProcessPerTab
);
1502 ASSERT_TRUE(test_server()->Start());
1504 const GURL
web_ui_url(std::string(kChromeUIScheme
) + "://" +
1505 std::string(kChromeUIGpuHost
));
1506 NavigateToURL(shell(), web_ui_url
);
1507 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1508 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1510 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1512 GURL
regular_page_url(test_server()->GetURL("files/title2.html"));
1513 NavigateToURL(shell(), regular_page_url
);
1514 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1515 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1518 class FileChooserDelegate
: public WebContentsDelegate
{
1520 FileChooserDelegate(const base::FilePath
& file
)
1521 : file_(file
), file_chosen_(false) {}
1523 void RunFileChooser(WebContents
* web_contents
,
1524 const FileChooserParams
& params
) override
{
1525 // Send the selected file to the renderer process.
1526 FileChooserFileInfo file_info
;
1527 file_info
.file_path
= file_
;
1528 std::vector
<FileChooserFileInfo
> files
;
1529 files
.push_back(file_info
);
1530 web_contents
->GetRenderViewHost()->FilesSelectedInChooser(
1531 files
, FileChooserParams::Open
);
1533 file_chosen_
= true;
1536 bool file_chosen() { return file_chosen_
; }
1539 base::FilePath file_
;
1543 // Test for http://crbug.com/262948.
1544 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1545 RestoreFileAccessForHistoryNavigation
) {
1547 base::FilePath file_path
;
1548 EXPECT_TRUE(PathService::Get(base::DIR_TEMP
, &file_path
));
1549 file_path
= file_path
.AppendASCII("bar");
1551 // Navigate to url and get it to reference a file in its PageState.
1552 GURL
url1(test_server()->GetURL("files/file_input.html"));
1553 NavigateToURL(shell(), url1
);
1554 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
1555 scoped_ptr
<FileChooserDelegate
> delegate(new FileChooserDelegate(file_path
));
1556 shell()->web_contents()->SetDelegate(delegate
.get());
1557 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1558 "document.getElementById('fileinput').click();"));
1559 EXPECT_TRUE(delegate
->file_chosen());
1560 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1561 process_id
, file_path
));
1563 // Navigate to a different process without access to the file, and wait for
1564 // the old process to exit.
1565 RenderProcessHostWatcher
exit_observer(
1566 shell()->web_contents()->GetRenderProcessHost(),
1567 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
1568 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1569 exit_observer
.Wait();
1570 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1571 shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path
));
1573 // Ensure that the file ended up in the PageState of the previous entry.
1574 NavigationEntry
* prev_entry
=
1575 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1576 EXPECT_EQ(url1
, prev_entry
->GetURL());
1577 const std::vector
<base::FilePath
>& file_paths
=
1578 prev_entry
->GetPageState().GetReferencedFiles();
1579 ASSERT_EQ(1U, file_paths
.size());
1580 EXPECT_EQ(file_path
, file_paths
.at(0));
1582 // Go back, ending up in a different RenderProcessHost than before.
1583 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1584 shell()->web_contents()->GetController().GoBack();
1585 back_nav_load_observer
.Wait();
1586 EXPECT_NE(process_id
,
1587 shell()->web_contents()->GetRenderProcessHost()->GetID());
1589 // Ensure that the file access still exists in the new process ID.
1590 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1591 shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path
));
1593 // Navigate to a same site page to trigger a PageState update and ensure the
1594 // renderer is not killed.
1596 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1599 } // namespace content