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/content_switches.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/content_browser_test.h"
28 #include "content/public/test/content_browser_test_utils.h"
29 #include "content/public/test/test_navigation_observer.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "net/base/net_util.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "net/test/spawned_test_server/spawned_test_server.h"
36 using base::ASCIIToUTF16
;
40 class RenderFrameHostManagerTest
: public ContentBrowserTest
{
42 RenderFrameHostManagerTest() : foo_com_("foo.com") {
43 replace_host_
.SetHostStr(foo_com_
);
46 static bool GetFilePathWithHostAndPortReplacement(
47 const std::string
& original_file_path
,
48 const net::HostPortPair
& host_port_pair
,
49 std::string
* replacement_path
) {
50 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
51 replacement_text
.push_back(
52 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
53 return net::SpawnedTestServer::GetFilePathWithReplacements(
54 original_file_path
, replacement_text
, replacement_path
);
58 // Support multiple sites on the test server.
59 host_resolver()->AddRule("*", "127.0.0.1");
60 ASSERT_TRUE(test_server()->Start());
62 foo_host_port_
= test_server()->host_port_pair();
63 foo_host_port_
.set_host(foo_com_
);
66 // Returns a URL on foo.com with the given path.
67 GURL
GetCrossSiteURL(const std::string
& path
) {
68 GURL
cross_site_url(test_server()->GetURL(path
));
69 return cross_site_url
.ReplaceComponents(replace_host_
);
74 GURL::Replacements replace_host_
;
75 net::HostPortPair foo_host_port_
;
78 // Web pages should not have script access to the swapped out page.
79 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, NoScriptAccessAfterSwapOut
) {
82 // Load a page with links that open in a new window.
83 std::string replacement_path
;
84 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
85 "files/click-noreferrer-links.html",
88 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
90 // Get the original SiteInstance for later comparison.
91 scoped_refptr
<SiteInstance
> orig_site_instance(
92 shell()->web_contents()->GetSiteInstance());
93 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
95 // Open a same-site link in a new window.
96 ShellAddedObserver new_shell_observer
;
98 EXPECT_TRUE(ExecuteScriptAndExtractBool(
99 shell()->web_contents(),
100 "window.domAutomationController.send(clickSameSiteTargetedLink());",
102 EXPECT_TRUE(success
);
103 Shell
* new_shell
= new_shell_observer
.GetShell();
105 // Wait for the navigation in the new window to finish, if it hasn't.
106 WaitForLoadStop(new_shell
->web_contents());
107 EXPECT_EQ("/files/navigate_opener.html",
108 new_shell
->web_contents()->GetLastCommittedURL().path());
110 // Should have the same SiteInstance.
111 scoped_refptr
<SiteInstance
> blank_site_instance(
112 new_shell
->web_contents()->GetSiteInstance());
113 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
115 // We should have access to the opened window's location.
117 EXPECT_TRUE(ExecuteScriptAndExtractBool(
118 shell()->web_contents(),
119 "window.domAutomationController.send(testScriptAccessToWindow());",
121 EXPECT_TRUE(success
);
123 // Now navigate the new window to a different site.
124 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
125 scoped_refptr
<SiteInstance
> new_site_instance(
126 new_shell
->web_contents()->GetSiteInstance());
127 EXPECT_NE(orig_site_instance
, new_site_instance
);
129 // We should no longer have script access to the opened window's location.
131 EXPECT_TRUE(ExecuteScriptAndExtractBool(
132 shell()->web_contents(),
133 "window.domAutomationController.send(testScriptAccessToWindow());",
135 EXPECT_FALSE(success
);
138 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
139 // and target=_blank should create a new SiteInstance.
140 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
141 SwapProcessWithRelNoreferrerAndTargetBlank
) {
144 // Load a page with links that open in a new window.
145 std::string replacement_path
;
146 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
147 "files/click-noreferrer-links.html",
150 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
152 // Get the original SiteInstance for later comparison.
153 scoped_refptr
<SiteInstance
> orig_site_instance(
154 shell()->web_contents()->GetSiteInstance());
155 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
157 // Test clicking a rel=noreferrer + target=blank link.
158 ShellAddedObserver new_shell_observer
;
159 bool success
= false;
160 EXPECT_TRUE(ExecuteScriptAndExtractBool(
161 shell()->web_contents(),
162 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
164 EXPECT_TRUE(success
);
166 // Wait for the window to open.
167 Shell
* new_shell
= new_shell_observer
.GetShell();
169 EXPECT_EQ("/files/title2.html",
170 new_shell
->web_contents()->GetVisibleURL().path());
172 // Wait for the cross-site transition in the new tab to finish.
173 WaitForLoadStop(new_shell
->web_contents());
174 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
175 new_shell
->web_contents());
176 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
177 pending_render_view_host());
179 // Should have a new SiteInstance.
180 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
181 new_shell
->web_contents()->GetSiteInstance());
182 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
185 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
186 // for rel=noreferrer links in new windows, even to same site pages and named
188 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
189 SwapProcessWithSameSiteRelNoreferrer
) {
192 // Load a page with links that open in a new window.
193 std::string replacement_path
;
194 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
195 "files/click-noreferrer-links.html",
198 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
200 // Get the original SiteInstance for later comparison.
201 scoped_refptr
<SiteInstance
> orig_site_instance(
202 shell()->web_contents()->GetSiteInstance());
203 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
205 // Test clicking a same-site rel=noreferrer + target=foo link.
206 ShellAddedObserver new_shell_observer
;
207 bool success
= false;
208 EXPECT_TRUE(ExecuteScriptAndExtractBool(
209 shell()->web_contents(),
210 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
212 EXPECT_TRUE(success
);
214 // Wait for the window to open.
215 Shell
* new_shell
= new_shell_observer
.GetShell();
217 // Opens in new window.
218 EXPECT_EQ("/files/title2.html",
219 new_shell
->web_contents()->GetVisibleURL().path());
221 // Wait for the cross-site transition in the new tab to finish.
222 WaitForLoadStop(new_shell
->web_contents());
223 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
224 new_shell
->web_contents());
225 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
226 pending_render_view_host());
228 // Should have a new SiteInstance (in a new BrowsingInstance).
229 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
230 new_shell
->web_contents()->GetSiteInstance());
231 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
234 // Test for crbug.com/24447. Following a cross-site link with just
235 // target=_blank should not create a new SiteInstance.
236 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
237 DontSwapProcessWithOnlyTargetBlank
) {
240 // Load a page with links that open in a new window.
241 std::string replacement_path
;
242 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
243 "files/click-noreferrer-links.html",
246 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
248 // Get the original SiteInstance for later comparison.
249 scoped_refptr
<SiteInstance
> orig_site_instance(
250 shell()->web_contents()->GetSiteInstance());
251 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
253 // Test clicking a target=blank link.
254 ShellAddedObserver new_shell_observer
;
255 bool success
= false;
256 EXPECT_TRUE(ExecuteScriptAndExtractBool(
257 shell()->web_contents(),
258 "window.domAutomationController.send(clickTargetBlankLink());",
260 EXPECT_TRUE(success
);
262 // Wait for the window to open.
263 Shell
* new_shell
= new_shell_observer
.GetShell();
265 // Wait for the cross-site transition in the new tab to finish.
266 WaitForLoadStop(new_shell
->web_contents());
267 EXPECT_EQ("/files/title2.html",
268 new_shell
->web_contents()->GetLastCommittedURL().path());
270 // Should have the same SiteInstance.
271 scoped_refptr
<SiteInstance
> blank_site_instance(
272 new_shell
->web_contents()->GetSiteInstance());
273 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
276 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
277 // and no target=_blank should not create a new SiteInstance.
278 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
279 DontSwapProcessWithOnlyRelNoreferrer
) {
282 // Load a page with links that open in a new window.
283 std::string replacement_path
;
284 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
285 "files/click-noreferrer-links.html",
288 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
290 // Get the original SiteInstance for later comparison.
291 scoped_refptr
<SiteInstance
> orig_site_instance(
292 shell()->web_contents()->GetSiteInstance());
293 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
295 // Test clicking a rel=noreferrer link.
296 bool success
= false;
297 EXPECT_TRUE(ExecuteScriptAndExtractBool(
298 shell()->web_contents(),
299 "window.domAutomationController.send(clickNoRefLink());",
301 EXPECT_TRUE(success
);
303 // Wait for the cross-site transition in the current tab to finish.
304 WaitForLoadStop(shell()->web_contents());
306 // Opens in same window.
307 EXPECT_EQ(1u, Shell::windows().size());
308 EXPECT_EQ("/files/title2.html",
309 shell()->web_contents()->GetLastCommittedURL().path());
311 // Should have the same SiteInstance.
312 scoped_refptr
<SiteInstance
> noref_site_instance(
313 shell()->web_contents()->GetSiteInstance());
314 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
317 // Test for crbug.com/116192. Targeted links should still work after the
318 // named target window has swapped processes.
319 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
320 AllowTargetedNavigationsAfterSwap
) {
323 // Load a page with links that open in a new window.
324 std::string replacement_path
;
325 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
326 "files/click-noreferrer-links.html",
329 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
331 // Get the original SiteInstance for later comparison.
332 scoped_refptr
<SiteInstance
> orig_site_instance(
333 shell()->web_contents()->GetSiteInstance());
334 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
336 // Test clicking a target=foo link.
337 ShellAddedObserver new_shell_observer
;
338 bool success
= false;
339 EXPECT_TRUE(ExecuteScriptAndExtractBool(
340 shell()->web_contents(),
341 "window.domAutomationController.send(clickSameSiteTargetedLink());",
343 EXPECT_TRUE(success
);
344 Shell
* new_shell
= new_shell_observer
.GetShell();
346 // Wait for the navigation in the new tab to finish, if it hasn't.
347 WaitForLoadStop(new_shell
->web_contents());
348 EXPECT_EQ("/files/navigate_opener.html",
349 new_shell
->web_contents()->GetLastCommittedURL().path());
351 // Should have the same SiteInstance.
352 scoped_refptr
<SiteInstance
> blank_site_instance(
353 new_shell
->web_contents()->GetSiteInstance());
354 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
356 // Now navigate the new tab to a different site.
357 GURL
cross_site_url(GetCrossSiteURL("files/title1.html"));
358 NavigateToURL(new_shell
, cross_site_url
);
359 scoped_refptr
<SiteInstance
> new_site_instance(
360 new_shell
->web_contents()->GetSiteInstance());
361 EXPECT_NE(orig_site_instance
, new_site_instance
);
363 // Clicking the original link in the first tab should cause us to swap back.
364 TestNavigationObserver
navigation_observer(new_shell
->web_contents());
365 EXPECT_TRUE(ExecuteScriptAndExtractBool(
366 shell()->web_contents(),
367 "window.domAutomationController.send(clickSameSiteTargetedLink());",
369 EXPECT_TRUE(success
);
370 navigation_observer
.Wait();
372 // Should have swapped back and shown the new window again.
373 scoped_refptr
<SiteInstance
> revisit_site_instance(
374 new_shell
->web_contents()->GetSiteInstance());
375 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
377 // If it navigates away to another process, the original window should
378 // still be able to close it (using a cross-process close message).
379 NavigateToURL(new_shell
, cross_site_url
);
380 EXPECT_EQ(new_site_instance
,
381 new_shell
->web_contents()->GetSiteInstance());
382 WebContentsDestroyedWatcher
close_watcher(new_shell
->web_contents());
383 EXPECT_TRUE(ExecuteScriptAndExtractBool(
384 shell()->web_contents(),
385 "window.domAutomationController.send(testCloseWindow());",
387 EXPECT_TRUE(success
);
388 close_watcher
.Wait();
391 // Test that setting the opener to null in a window affects cross-process
392 // navigations, including those to existing entries. http://crbug.com/156669.
393 // Flaky on windows: http://crbug.com/291249
394 // This test also crashes under ThreadSanitizer, http://crbug.com/356758.
395 #if defined(OS_WIN) || defined(THREAD_SANITIZER)
396 #define MAYBE_DisownOpener DISABLED_DisownOpener
398 #define MAYBE_DisownOpener DisownOpener
400 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_DisownOpener
) {
403 // Load a page with links that open in a new window.
404 std::string replacement_path
;
405 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
406 "files/click-noreferrer-links.html",
409 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
411 // Get the original SiteInstance for later comparison.
412 scoped_refptr
<SiteInstance
> orig_site_instance(
413 shell()->web_contents()->GetSiteInstance());
414 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
416 // Test clicking a target=_blank link.
417 ShellAddedObserver new_shell_observer
;
418 bool success
= false;
419 EXPECT_TRUE(ExecuteScriptAndExtractBool(
420 shell()->web_contents(),
421 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
423 EXPECT_TRUE(success
);
424 Shell
* new_shell
= new_shell_observer
.GetShell();
426 // Wait for the navigation in the new tab to finish, if it hasn't.
427 WaitForLoadStop(new_shell
->web_contents());
428 EXPECT_EQ("/files/title2.html",
429 new_shell
->web_contents()->GetLastCommittedURL().path());
431 // Should have the same SiteInstance.
432 scoped_refptr
<SiteInstance
> blank_site_instance(
433 new_shell
->web_contents()->GetSiteInstance());
434 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
436 // Now navigate the new tab to a different site.
437 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
438 scoped_refptr
<SiteInstance
> new_site_instance(
439 new_shell
->web_contents()->GetSiteInstance());
440 EXPECT_NE(orig_site_instance
, new_site_instance
);
442 // Now disown the opener.
443 EXPECT_TRUE(ExecuteScript(new_shell
->web_contents(),
444 "window.opener = null;"));
446 // Go back and ensure the opener is still null.
448 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
449 new_shell
->web_contents()->GetController().GoBack();
450 back_nav_load_observer
.Wait();
453 EXPECT_TRUE(ExecuteScriptAndExtractBool(
454 new_shell
->web_contents(),
455 "window.domAutomationController.send(window.opener == null);",
457 EXPECT_TRUE(success
);
459 // Now navigate forward again (creating a new process) and check opener.
460 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
462 EXPECT_TRUE(ExecuteScriptAndExtractBool(
463 new_shell
->web_contents(),
464 "window.domAutomationController.send(window.opener == null);",
466 EXPECT_TRUE(success
);
469 // Test that subframes can disown their openers. http://crbug.com/225528.
470 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, DisownSubframeOpener
) {
471 const GURL
frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
472 NavigateToURL(shell(), frame_url
);
474 // Give the frame an opener using window.open.
475 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
476 "window.open('about:blank','foo');"));
478 // Now disown the frame's opener. Shouldn't crash.
479 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
480 "window.frames[0].opener = null;"));
483 // Test for crbug.com/99202. PostMessage calls should still work after
484 // navigating the source and target windows to different sites.
486 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
487 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
488 // 3) Post a message from "foo" to opener, which replies back to "foo".
489 // 4) Post a message from _blank to "foo".
490 // 5) Post a message from "foo" to a subframe of opener, which replies back.
491 // 6) Post a message from _blank to a subframe of "foo".
492 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
493 SupportCrossProcessPostMessage
) {
496 // Load a page with links that open in a new window.
497 std::string replacement_path
;
498 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
499 "files/click-noreferrer-links.html",
502 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
504 // Get the original SiteInstance and RVHM for later comparison.
505 WebContents
* opener_contents
= shell()->web_contents();
506 scoped_refptr
<SiteInstance
> orig_site_instance(
507 opener_contents
->GetSiteInstance());
508 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
509 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
510 opener_contents
)->GetRenderManagerForTesting();
512 // 1) Open two more windows, one named. These initially have openers but no
513 // reference to each other. We will later post a message between them.
515 // First, a named target=foo window.
516 ShellAddedObserver new_shell_observer
;
517 bool success
= false;
518 EXPECT_TRUE(ExecuteScriptAndExtractBool(
520 "window.domAutomationController.send(clickSameSiteTargetedLink());",
522 EXPECT_TRUE(success
);
523 Shell
* new_shell
= new_shell_observer
.GetShell();
525 // Wait for the navigation in the new window to finish, if it hasn't, then
526 // send it to post_message.html on a different site.
527 WebContents
* foo_contents
= new_shell
->web_contents();
528 WaitForLoadStop(foo_contents
);
529 EXPECT_EQ("/files/navigate_opener.html",
530 foo_contents
->GetLastCommittedURL().path());
531 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
532 scoped_refptr
<SiteInstance
> foo_site_instance(
533 foo_contents
->GetSiteInstance());
534 EXPECT_NE(orig_site_instance
, foo_site_instance
);
536 // Second, a target=_blank window.
537 ShellAddedObserver new_shell_observer2
;
538 EXPECT_TRUE(ExecuteScriptAndExtractBool(
539 shell()->web_contents(),
540 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
542 EXPECT_TRUE(success
);
544 // Wait for the navigation in the new window to finish, if it hasn't, then
545 // send it to post_message.html on the original site.
546 Shell
* new_shell2
= new_shell_observer2
.GetShell();
547 WebContents
* new_contents
= new_shell2
->web_contents();
548 WaitForLoadStop(new_contents
);
549 EXPECT_EQ("/files/title2.html", new_contents
->GetLastCommittedURL().path());
550 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
551 EXPECT_EQ(orig_site_instance
, new_contents
->GetSiteInstance());
552 RenderFrameHostManager
* new_manager
=
553 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
555 // We now have three windows. The opener should have a swapped out RVH
556 // for the new SiteInstance, but the _blank window should not.
557 EXPECT_EQ(3u, Shell::windows().size());
559 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
561 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
563 // 2) Fail to post a message from the foo window to the opener if the target
564 // origin is wrong. We won't see an error, but we can check for the right
565 // number of received messages below.
566 EXPECT_TRUE(ExecuteScriptAndExtractBool(
568 "window.domAutomationController.send(postToOpener('msg',"
569 " 'http://google.com'));",
571 EXPECT_TRUE(success
);
573 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
575 // 3) Post a message from the foo window to the opener. The opener will
576 // reply, causing the foo window to update its own title.
577 base::string16 expected_title
= ASCIIToUTF16("msg");
578 TitleWatcher
title_watcher(foo_contents
, expected_title
);
579 EXPECT_TRUE(ExecuteScriptAndExtractBool(
581 "window.domAutomationController.send(postToOpener('msg','*'));",
583 EXPECT_TRUE(success
);
585 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
586 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
588 // We should have received only 1 message in the opener and "foo" tabs,
589 // and updated the title.
590 int opener_received_messages
= 0;
591 EXPECT_TRUE(ExecuteScriptAndExtractInt(
593 "window.domAutomationController.send(window.receivedMessages);",
594 &opener_received_messages
));
595 int foo_received_messages
= 0;
596 EXPECT_TRUE(ExecuteScriptAndExtractInt(
598 "window.domAutomationController.send(window.receivedMessages);",
599 &foo_received_messages
));
600 EXPECT_EQ(1, foo_received_messages
);
601 EXPECT_EQ(1, opener_received_messages
);
602 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
604 // 4) Now post a message from the _blank window to the foo window. The
605 // foo window will update its title and will not reply.
606 expected_title
= ASCIIToUTF16("msg2");
607 TitleWatcher
title_watcher2(foo_contents
, expected_title
);
608 EXPECT_TRUE(ExecuteScriptAndExtractBool(
610 "window.domAutomationController.send(postToFoo('msg2'));",
612 EXPECT_TRUE(success
);
613 ASSERT_EQ(expected_title
, title_watcher2
.WaitAndGetTitle());
615 // This postMessage should have created a swapped out RVH for the new
616 // SiteInstance in the target=_blank window.
618 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
620 // TODO(nasko): Test subframe targeting of postMessage once
621 // http://crbug.com/153701 is fixed.
624 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
625 // messages which contain Transferables and get intercepted by
626 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
627 // swapped out) should work.
629 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
630 // 2) Post a message containing a message port from opener to "foo".
631 // 3) Post a message from "foo" back to opener via the passed message port.
632 // The test will be enabled when the feature implementation lands.
633 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
634 SupportCrossProcessPostMessageWithMessagePort
) {
637 // Load a page with links that open in a new window.
638 std::string replacement_path
;
639 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
640 "files/click-noreferrer-links.html",
643 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
645 // Get the original SiteInstance and RVHM for later comparison.
646 WebContents
* opener_contents
= shell()->web_contents();
647 scoped_refptr
<SiteInstance
> orig_site_instance(
648 opener_contents
->GetSiteInstance());
649 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
650 RenderFrameHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
651 opener_contents
)->GetRenderManagerForTesting();
653 // 1) Open a named target=foo window. We will later post a message between the
654 // opener and the new window.
655 ShellAddedObserver new_shell_observer
;
656 bool success
= false;
657 EXPECT_TRUE(ExecuteScriptAndExtractBool(
659 "window.domAutomationController.send(clickSameSiteTargetedLink());",
661 EXPECT_TRUE(success
);
662 Shell
* new_shell
= new_shell_observer
.GetShell();
664 // Wait for the navigation in the new window to finish, if it hasn't, then
665 // send it to post_message.html on a different site.
666 WebContents
* foo_contents
= new_shell
->web_contents();
667 WaitForLoadStop(foo_contents
);
668 EXPECT_EQ("/files/navigate_opener.html",
669 foo_contents
->GetLastCommittedURL().path());
670 NavigateToURL(new_shell
, GetCrossSiteURL("files/post_message.html"));
671 scoped_refptr
<SiteInstance
> foo_site_instance(
672 foo_contents
->GetSiteInstance());
673 EXPECT_NE(orig_site_instance
, foo_site_instance
);
675 // We now have two windows. The opener should have a swapped out RVH
676 // for the new SiteInstance.
677 EXPECT_EQ(2u, Shell::windows().size());
679 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
681 // 2) Post a message containing a MessagePort from opener to the the foo
682 // window. The foo window will reply via the passed port, causing the opener
683 // to update its own title.
684 base::string16 expected_title
= ASCIIToUTF16("msg-back-via-port");
685 TitleWatcher
title_observer(opener_contents
, expected_title
);
686 EXPECT_TRUE(ExecuteScriptAndExtractBool(
688 "window.domAutomationController.send(postWithPortToFoo());",
690 EXPECT_TRUE(success
);
692 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
693 ASSERT_EQ(expected_title
, title_observer
.WaitAndGetTitle());
695 // Check message counts.
696 int opener_received_messages_via_port
= 0;
697 EXPECT_TRUE(ExecuteScriptAndExtractInt(
699 "window.domAutomationController.send(window.receivedMessagesViaPort);",
700 &opener_received_messages_via_port
));
701 int foo_received_messages
= 0;
702 EXPECT_TRUE(ExecuteScriptAndExtractInt(
704 "window.domAutomationController.send(window.receivedMessages);",
705 &foo_received_messages
));
706 int foo_received_messages_with_port
= 0;
707 EXPECT_TRUE(ExecuteScriptAndExtractInt(
709 "window.domAutomationController.send(window.receivedMessagesWithPort);",
710 &foo_received_messages_with_port
));
711 EXPECT_EQ(1, foo_received_messages
);
712 EXPECT_EQ(1, foo_received_messages_with_port
);
713 EXPECT_EQ(1, opener_received_messages_via_port
);
714 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents
->GetTitle());
715 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents
->GetTitle());
718 // Test for crbug.com/116192. Navigations to a window's opener should
719 // still work after a process swap.
720 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
721 AllowTargetedNavigationsInOpenerAfterSwap
) {
724 // Load a page with links that open in a new window.
725 std::string replacement_path
;
726 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
727 "files/click-noreferrer-links.html",
730 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
732 // Get the original tab and SiteInstance for later comparison.
733 WebContents
* orig_contents
= shell()->web_contents();
734 scoped_refptr
<SiteInstance
> orig_site_instance(
735 orig_contents
->GetSiteInstance());
736 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
738 // Test clicking a target=foo link.
739 ShellAddedObserver new_shell_observer
;
740 bool success
= false;
741 EXPECT_TRUE(ExecuteScriptAndExtractBool(
743 "window.domAutomationController.send(clickSameSiteTargetedLink());",
745 EXPECT_TRUE(success
);
746 Shell
* new_shell
= new_shell_observer
.GetShell();
748 // Wait for the navigation in the new window to finish, if it hasn't.
749 WaitForLoadStop(new_shell
->web_contents());
750 EXPECT_EQ("/files/navigate_opener.html",
751 new_shell
->web_contents()->GetLastCommittedURL().path());
753 // Should have the same SiteInstance.
754 scoped_refptr
<SiteInstance
> blank_site_instance(
755 new_shell
->web_contents()->GetSiteInstance());
756 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
758 // Now navigate the original (opener) tab to a different site.
759 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
760 scoped_refptr
<SiteInstance
> new_site_instance(
761 shell()->web_contents()->GetSiteInstance());
762 EXPECT_NE(orig_site_instance
, new_site_instance
);
764 // The opened tab should be able to navigate the opener back to its process.
765 TestNavigationObserver
navigation_observer(orig_contents
);
766 EXPECT_TRUE(ExecuteScriptAndExtractBool(
767 new_shell
->web_contents(),
768 "window.domAutomationController.send(navigateOpener());",
770 EXPECT_TRUE(success
);
771 navigation_observer
.Wait();
773 // Should have swapped back into this process.
774 scoped_refptr
<SiteInstance
> revisit_site_instance(
775 shell()->web_contents()->GetSiteInstance());
776 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
779 // Test that opening a new window in the same SiteInstance and then navigating
780 // both windows to a different SiteInstance allows the first process to exit.
781 // See http://crbug.com/126333.
782 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
783 ProcessExitWithSwappedOutViews
) {
786 // Load a page with links that open in a new window.
787 std::string replacement_path
;
788 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
789 "files/click-noreferrer-links.html",
792 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
794 // Get the original SiteInstance for later comparison.
795 scoped_refptr
<SiteInstance
> orig_site_instance(
796 shell()->web_contents()->GetSiteInstance());
797 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
799 // Test clicking a target=foo link.
800 ShellAddedObserver new_shell_observer
;
801 bool success
= false;
802 EXPECT_TRUE(ExecuteScriptAndExtractBool(
803 shell()->web_contents(),
804 "window.domAutomationController.send(clickSameSiteTargetedLink());",
806 EXPECT_TRUE(success
);
807 Shell
* new_shell
= new_shell_observer
.GetShell();
809 // Wait for the navigation in the new window to finish, if it hasn't.
810 WaitForLoadStop(new_shell
->web_contents());
811 EXPECT_EQ("/files/navigate_opener.html",
812 new_shell
->web_contents()->GetLastCommittedURL().path());
814 // Should have the same SiteInstance.
815 scoped_refptr
<SiteInstance
> opened_site_instance(
816 new_shell
->web_contents()->GetSiteInstance());
817 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
819 // Now navigate the opened window to a different site.
820 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
821 scoped_refptr
<SiteInstance
> new_site_instance(
822 new_shell
->web_contents()->GetSiteInstance());
823 EXPECT_NE(orig_site_instance
, new_site_instance
);
825 // The original process should still be alive, since it is still used in the
827 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
828 EXPECT_TRUE(orig_process
->HasConnection());
830 // Navigate the first window to a different site as well. The original
831 // process should exit, since all of its views are now swapped out.
832 RenderProcessHostWatcher
exit_observer(
834 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION
);
835 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
836 exit_observer
.Wait();
837 scoped_refptr
<SiteInstance
> new_site_instance2(
838 shell()->web_contents()->GetSiteInstance());
839 EXPECT_EQ(new_site_instance
, new_site_instance2
);
842 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
843 // error should not make us ignore future renderer-initiated navigations.
844 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ClickLinkAfter204Error
) {
847 // Get the original SiteInstance for later comparison.
848 scoped_refptr
<SiteInstance
> orig_site_instance(
849 shell()->web_contents()->GetSiteInstance());
850 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
852 // Load a cross-site page that fails with a 204 error.
853 NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
855 // We should still be looking at the normal page. Because we started from a
856 // blank new tab, the typed URL will still be visible until the user clears it
857 // manually. The last committed URL will be the previous page.
858 scoped_refptr
<SiteInstance
> post_nav_site_instance(
859 shell()->web_contents()->GetSiteInstance());
860 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
861 EXPECT_EQ("/nocontent",
862 shell()->web_contents()->GetVisibleURL().path());
864 shell()->web_contents()->GetController().GetLastCommittedEntry());
866 // Renderer-initiated navigations should work.
867 base::string16 expected_title
= ASCIIToUTF16("Title Of Awesomeness");
868 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
869 GURL url
= test_server()->GetURL("files/title2.html");
870 EXPECT_TRUE(ExecuteScript(
871 shell()->web_contents(),
872 base::StringPrintf("location.href = '%s'", url
.spec().c_str())));
873 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
875 // Opens in same tab.
876 EXPECT_EQ(1u, Shell::windows().size());
877 EXPECT_EQ("/files/title2.html",
878 shell()->web_contents()->GetLastCommittedURL().path());
880 // Should have the same SiteInstance.
881 scoped_refptr
<SiteInstance
> new_site_instance(
882 shell()->web_contents()->GetSiteInstance());
883 EXPECT_EQ(orig_site_instance
, new_site_instance
);
886 // Test for crbug.com/9682. We should show the URL for a pending renderer-
887 // initiated navigation in a new tab, until the content of the initial
888 // about:blank page is modified by another window. At that point, we should
889 // revert to showing about:blank to prevent a URL spoof.
890 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ShowLoadingURLUntilSpoof
) {
891 ASSERT_TRUE(test_server()->Start());
893 // Load a page that can open a URL that won't commit in a new window.
895 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
896 WebContents
* orig_contents
= shell()->web_contents();
898 // Click a /nocontent link that opens in a new window but never commits.
899 ShellAddedObserver new_shell_observer
;
900 bool success
= false;
901 EXPECT_TRUE(ExecuteScriptAndExtractBool(
903 "window.domAutomationController.send(clickNoContentTargetedLink());",
905 EXPECT_TRUE(success
);
907 // Wait for the window to open.
908 Shell
* new_shell
= new_shell_observer
.GetShell();
910 // Ensure the destination URL is visible, because it is considered the
911 // initial navigation.
912 WebContents
* contents
= new_shell
->web_contents();
913 EXPECT_TRUE(contents
->GetController().IsInitialNavigation());
914 EXPECT_EQ("/nocontent",
915 contents
->GetController().GetVisibleEntry()->GetURL().path());
917 // Now modify the contents of the new window from the opener. This will also
918 // modify the title of the document to give us something to listen for.
919 base::string16 expected_title
= ASCIIToUTF16("Modified Title");
920 TitleWatcher
title_watcher(contents
, expected_title
);
922 EXPECT_TRUE(ExecuteScriptAndExtractBool(
924 "window.domAutomationController.send(modifyNewWindow());",
926 EXPECT_TRUE(success
);
927 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
929 // At this point, we should no longer be showing the destination URL.
930 // The visible entry should be null, resulting in about:blank in the address
932 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
935 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
936 // initiated navigation in a new tab if it is not the initial navigation. In
937 // this case, the renderer will not notify us of a modification, so we cannot
938 // show the pending URL without allowing a spoof.
939 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
940 DontShowLoadingURLIfNotInitialNav
) {
941 ASSERT_TRUE(test_server()->Start());
943 // Load a page that can open a URL that won't commit in a new window.
945 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
946 WebContents
* orig_contents
= shell()->web_contents();
948 // Click a /nocontent link that opens in a new window but never commits.
949 // By using an onclick handler that first creates the window, the slow
950 // navigation is not considered an initial navigation.
951 ShellAddedObserver new_shell_observer
;
952 bool success
= false;
953 EXPECT_TRUE(ExecuteScriptAndExtractBool(
955 "window.domAutomationController.send("
956 "clickNoContentScriptedTargetedLink());",
958 EXPECT_TRUE(success
);
960 // Wait for the window to open.
961 Shell
* new_shell
= new_shell_observer
.GetShell();
963 // Ensure the destination URL is not visible, because it is not the initial
965 WebContents
* contents
= new_shell
->web_contents();
966 EXPECT_FALSE(contents
->GetController().IsInitialNavigation());
967 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
970 // Crashes under ThreadSanitizer, http://crbug.com/356758.
971 #if defined(THREAD_SANITIZER)
972 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
974 #define MAYBE_BackForwardNotStale BackForwardNotStale
976 // Test for http://crbug.com/93427. Ensure that cross-site navigations
977 // do not cause back/forward navigations to be considered stale by the
979 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, MAYBE_BackForwardNotStale
) {
981 NavigateToURL(shell(), GURL(kAboutBlankURL
));
983 // Visit a page on first site.
984 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
986 // Visit three pages on second site.
987 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
988 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
989 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
991 // History is now [blank, A1, B1, B2, *B3].
992 WebContents
* contents
= shell()->web_contents();
993 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
995 // Open another window in same process to keep this process alive.
996 Shell
* new_shell
= CreateBrowser();
997 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
999 // Go back three times to first site.
1001 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1002 shell()->web_contents()->GetController().GoBack();
1003 back_nav_load_observer
.Wait();
1006 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1007 shell()->web_contents()->GetController().GoBack();
1008 back_nav_load_observer
.Wait();
1011 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1012 shell()->web_contents()->GetController().GoBack();
1013 back_nav_load_observer
.Wait();
1016 // Now go forward twice to B2. Shouldn't be left spinning.
1018 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1019 shell()->web_contents()->GetController().GoForward();
1020 forward_nav_load_observer
.Wait();
1023 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1024 shell()->web_contents()->GetController().GoForward();
1025 forward_nav_load_observer
.Wait();
1028 // Go back twice to first site.
1030 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1031 shell()->web_contents()->GetController().GoBack();
1032 back_nav_load_observer
.Wait();
1035 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1036 shell()->web_contents()->GetController().GoBack();
1037 back_nav_load_observer
.Wait();
1040 // Now go forward directly to B3. Shouldn't be left spinning.
1042 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1043 shell()->web_contents()->GetController().GoToIndex(4);
1044 forward_nav_load_observer
.Wait();
1048 // Test for http://crbug.com/130016.
1049 // Swapping out a render view should update its visiblity state.
1050 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1051 SwappedOutViewHasCorrectVisibilityState
) {
1054 // Load a page with links that open in a new window.
1055 std::string replacement_path
;
1056 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1057 "files/click-noreferrer-links.html",
1059 &replacement_path
));
1060 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
1062 // Open a same-site link in a new widnow.
1063 ShellAddedObserver new_shell_observer
;
1064 bool success
= false;
1065 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1066 shell()->web_contents(),
1067 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1069 EXPECT_TRUE(success
);
1070 Shell
* new_shell
= new_shell_observer
.GetShell();
1072 // Wait for the navigation in the new tab to finish, if it hasn't.
1073 WaitForLoadStop(new_shell
->web_contents());
1074 EXPECT_EQ("/files/navigate_opener.html",
1075 new_shell
->web_contents()->GetLastCommittedURL().path());
1077 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
1079 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1081 "window.domAutomationController.send("
1082 " document.visibilityState == 'visible');",
1084 EXPECT_TRUE(success
);
1086 // Now navigate the new window to a different site. This should swap out the
1087 // tab's existing RenderView, causing it become hidden.
1088 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1090 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1092 "window.domAutomationController.send("
1093 " document.visibilityState == 'hidden');",
1095 EXPECT_TRUE(success
);
1097 // Going back should make the previously swapped-out view to become visible
1100 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
1101 new_shell
->web_contents()->GetController().GoBack();
1102 back_nav_load_observer
.Wait();
1105 EXPECT_EQ("/files/navigate_opener.html",
1106 new_shell
->web_contents()->GetLastCommittedURL().path());
1108 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
1110 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1112 "window.domAutomationController.send("
1113 " document.visibilityState == 'visible');",
1115 EXPECT_TRUE(success
);
1118 // This class ensures that all the given RenderViewHosts have properly been
1120 class RenderViewHostDestructionObserver
: public WebContentsObserver
{
1122 explicit RenderViewHostDestructionObserver(WebContents
* web_contents
)
1123 : WebContentsObserver(web_contents
) {}
1124 virtual ~RenderViewHostDestructionObserver() {}
1125 void EnsureRVHGetsDestructed(RenderViewHost
* rvh
) {
1126 watched_render_view_hosts_
.insert(rvh
);
1128 size_t GetNumberOfWatchedRenderViewHosts() const {
1129 return watched_render_view_hosts_
.size();
1133 // WebContentsObserver implementation:
1134 virtual void RenderViewDeleted(RenderViewHost
* rvh
) OVERRIDE
{
1135 watched_render_view_hosts_
.erase(rvh
);
1138 std::set
<RenderViewHost
*> watched_render_view_hosts_
;
1141 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1142 #if defined(THREAD_SANITIZER)
1143 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1145 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1147 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1148 // they may cause crashes or memory corruptions when trying to call dead
1149 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1150 // ensure that a separate SiteInstance is created when navigating to view-source
1151 // URLs, regardless of current URL.
1152 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1153 MAYBE_LeakingRenderViewHosts
) {
1156 // Observe the created render_view_host's to make sure they will not leak.
1157 RenderViewHostDestructionObserver
rvh_observers(shell()->web_contents());
1159 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1160 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1161 navigated_url
.spec());
1163 // Let's ensure that when we start with a blank window, navigating away to a
1164 // view-source URL, we create a new SiteInstance.
1165 RenderViewHost
* blank_rvh
= shell()->web_contents()->GetRenderViewHost();
1166 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1167 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1168 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1169 rvh_observers
.EnsureRVHGetsDestructed(blank_rvh
);
1171 // Now navigate to the view-source URL and ensure we got a different
1172 // SiteInstance and RenderViewHost.
1173 NavigateToURL(shell(), view_source_url
);
1174 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1175 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1176 GetRenderViewHost()->GetSiteInstance());
1177 rvh_observers
.EnsureRVHGetsDestructed(
1178 shell()->web_contents()->GetRenderViewHost());
1180 // Load a random page and then navigate to view-source: of it.
1181 // This used to cause two RVH instances for the same SiteInstance, which
1182 // was a problem. This is no longer the case.
1183 NavigateToURL(shell(), navigated_url
);
1184 SiteInstance
* site_instance1
= shell()->web_contents()->
1185 GetRenderViewHost()->GetSiteInstance();
1186 rvh_observers
.EnsureRVHGetsDestructed(
1187 shell()->web_contents()->GetRenderViewHost());
1189 NavigateToURL(shell(), view_source_url
);
1190 rvh_observers
.EnsureRVHGetsDestructed(
1191 shell()->web_contents()->GetRenderViewHost());
1192 SiteInstance
* site_instance2
= shell()->web_contents()->
1193 GetRenderViewHost()->GetSiteInstance();
1195 // Ensure that view-source navigations force a new SiteInstance.
1196 EXPECT_NE(site_instance1
, site_instance2
);
1198 // Now navigate to a different instance so that we swap out again.
1199 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1200 rvh_observers
.EnsureRVHGetsDestructed(
1201 shell()->web_contents()->GetRenderViewHost());
1203 // This used to leak a render view host.
1206 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1208 EXPECT_EQ(0U, rvh_observers
.GetNumberOfWatchedRenderViewHosts());
1211 // Test for crbug.com/143155. Frame tree updates during unload should not
1212 // interrupt the intended navigation and show swappedout:// instead.
1214 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1215 // 2) Send the second tab to a different foo.com SiteInstance.
1216 // This creates a swapped out opener for the first tab in the foo process.
1217 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1218 // tab's unload handler remove its frame.
1219 // This used to cause an update to the frame tree of the swapped out RV,
1220 // just as it was navigating to a real page. That pre-empted the real
1221 // navigation and visibly sent the tab to swappedout://.
1222 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1223 DontPreemptNavigationWithFrameTreeUpdate
) {
1226 // 1. Load a page that deletes its iframe during unload.
1227 NavigateToURL(shell(),
1228 test_server()->GetURL("files/remove_frame_on_unload.html"));
1230 // Get the original SiteInstance for later comparison.
1231 scoped_refptr
<SiteInstance
> orig_site_instance(
1232 shell()->web_contents()->GetSiteInstance());
1234 // Open a same-site page in a new window.
1235 ShellAddedObserver new_shell_observer
;
1236 bool success
= false;
1237 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1238 shell()->web_contents(),
1239 "window.domAutomationController.send(openWindow());",
1241 EXPECT_TRUE(success
);
1242 Shell
* new_shell
= new_shell_observer
.GetShell();
1244 // Wait for the navigation in the new window to finish, if it hasn't.
1245 WaitForLoadStop(new_shell
->web_contents());
1246 EXPECT_EQ("/files/title1.html",
1247 new_shell
->web_contents()->GetLastCommittedURL().path());
1249 // Should have the same SiteInstance.
1250 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
1252 // 2. Send the second tab to a different process.
1253 NavigateToURL(new_shell
, GetCrossSiteURL("files/title1.html"));
1254 scoped_refptr
<SiteInstance
> new_site_instance(
1255 new_shell
->web_contents()->GetSiteInstance());
1256 EXPECT_NE(orig_site_instance
, new_site_instance
);
1258 // 3. Send the first tab to the second tab's process.
1259 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1261 // Make sure it ends up at the right page.
1262 WaitForLoadStop(shell()->web_contents());
1263 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1264 shell()->web_contents()->GetLastCommittedURL());
1265 EXPECT_EQ(new_site_instance
, shell()->web_contents()->GetSiteInstance());
1268 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1269 // are meant to run in the current page. We had a bug where we expected a
1270 // BrowsingInstance swap to occur on pages like view-source and extensions,
1271 // which broke chrome://crash and javascript: URLs.
1272 // See http://crbug.com/335503.
1273 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, RendererDebugURLsDontSwap
) {
1274 ASSERT_TRUE(test_server()->Start());
1276 GURL
original_url(test_server()->GetURL("files/title2.html"));
1277 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1278 original_url
.spec());
1280 NavigateToURL(shell(), view_source_url
);
1282 // Check that javascript: URLs work.
1283 base::string16 expected_title
= ASCIIToUTF16("msg");
1284 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1285 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1286 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
1288 // Crash the renderer of the view-source page.
1289 RenderProcessHostWatcher
crash_observer(
1290 shell()->web_contents(),
1291 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1292 NavigateToURL(shell(), GURL(kChromeUICrashURL
));
1293 crash_observer
.Wait();
1296 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1297 // Otherwise, we might try to load an unprivileged about:blank page into a
1298 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1299 // See http://crbug.com/334214.
1300 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
,
1301 IgnoreRendererDebugURLsWhenCrashed
) {
1302 // Visit a WebUI page with bindings.
1303 GURL webui_url
= GURL(std::string(kChromeUIScheme
) + "://" +
1304 std::string(kChromeUIGpuHost
));
1305 NavigateToURL(shell(), webui_url
);
1306 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1307 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1309 // Crash the renderer of the WebUI page.
1310 RenderProcessHostWatcher
crash_observer(
1311 shell()->web_contents(),
1312 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1313 NavigateToURL(shell(), GURL(kChromeUICrashURL
));
1314 crash_observer
.Wait();
1316 // Load the crash URL again but don't wait for any action. If it is not
1317 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1318 shell()->LoadURL(GURL(kChromeUICrashURL
));
1320 // Ensure that such URLs can still work as the initial navigation of a tab.
1321 // We postpone the initial navigation of the tab using an empty GURL, so that
1322 // we can add a watcher for crashes.
1323 Shell
* shell2
= Shell::CreateNewWindow(
1324 shell()->web_contents()->GetBrowserContext(), GURL(), NULL
,
1325 MSG_ROUTING_NONE
, gfx::Size());
1326 RenderProcessHostWatcher
crash_observer2(
1327 shell2
->web_contents(),
1328 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1329 NavigateToURL(shell2
, GURL(kChromeUIKillURL
));
1330 crash_observer2
.Wait();
1333 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1334 // Otherwise it might get picked up by InitRenderView when granting bindings
1335 // to other RenderViewHosts. See http://crbug.com/330811.
1336 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest
, ClearPendingWebUIOnCommit
) {
1337 // Visit a WebUI page with bindings.
1338 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1339 std::string(kChromeUIGpuHost
)));
1340 NavigateToURL(shell(), webui_url
);
1341 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1342 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1343 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1344 shell()->web_contents());
1345 WebUIImpl
* webui
= web_contents
->GetRenderManagerForTesting()->web_ui();
1347 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1349 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1350 // clear pending_web_ui() when it commits.
1351 GURL
webui_url2(webui_url
.spec() + "#foo");
1352 NavigateToURL(shell(), webui_url2
);
1353 EXPECT_EQ(webui
, web_contents
->GetRenderManagerForTesting()->web_ui());
1354 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->pending_web_ui());
1357 class RFHMProcessPerTabTest
: public RenderFrameHostManagerTest
{
1359 RFHMProcessPerTabTest() {}
1361 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
1362 command_line
->AppendSwitch(switches::kProcessPerTab
);
1366 // Test that we still swap processes for BrowsingInstance changes even in
1367 // --process-per-tab mode. See http://crbug.com/343017.
1368 // Disabled on Android: http://crbug.com/345873.
1369 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1370 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1371 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1373 #define MAYBE_BackFromWebUI BackFromWebUI
1375 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest
, MAYBE_BackFromWebUI
) {
1376 ASSERT_TRUE(test_server()->Start());
1377 GURL
original_url(test_server()->GetURL("files/title2.html"));
1378 NavigateToURL(shell(), original_url
);
1380 // Visit a WebUI page with bindings.
1381 GURL
webui_url(GURL(std::string(kChromeUIScheme
) + "://" +
1382 std::string(kChromeUIGpuHost
)));
1383 NavigateToURL(shell(), webui_url
);
1384 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1385 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1387 // Go back and ensure we have no WebUI bindings.
1388 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1389 shell()->web_contents()->GetController().GoBack();
1390 back_nav_load_observer
.Wait();
1391 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
1392 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1393 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1396 } // namespace content