1 // Copyright (c) 2012 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.
5 #include "base/json/json_reader.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/path_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/values.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/browser/site_instance_impl.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/common/content_constants_internal.h"
14 #include "content/public/browser/navigation_controller.h"
15 #include "content/public/browser/navigation_entry.h"
16 #include "content/public/browser/notification_details.h"
17 #include "content/public/browser/notification_observer.h"
18 #include "content/public/browser/notification_registrar.h"
19 #include "content/public/browser/notification_types.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host_observer.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/common/url_constants.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "content/public/test/test_navigation_observer.h"
27 #include "content/public/test/test_utils.h"
28 #include "content/shell/shell.h"
29 #include "content/test/content_browser_test.h"
30 #include "content/test/content_browser_test_utils.h"
31 #include "net/base/net_util.h"
32 #include "net/test/spawned_test_server/spawned_test_server.h"
36 class RenderViewHostManagerTest
: public ContentBrowserTest
{
38 RenderViewHostManagerTest() {}
40 static bool GetFilePathWithHostAndPortReplacement(
41 const std::string
& original_file_path
,
42 const net::HostPortPair
& host_port_pair
,
43 std::string
* replacement_path
) {
44 std::vector
<net::SpawnedTestServer::StringPair
> replacement_text
;
45 replacement_text
.push_back(
46 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
47 return net::SpawnedTestServer::GetFilePathWithReplacements(
48 original_file_path
, replacement_text
, replacement_path
);
52 // Web pages should not have script access to the swapped out page.
53 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, NoScriptAccessAfterSwapOut
) {
54 // Start two servers with different sites.
55 ASSERT_TRUE(test_server()->Start());
56 net::SpawnedTestServer
https_server(
57 net::SpawnedTestServer::TYPE_HTTPS
,
58 net::SpawnedTestServer::kLocalhost
,
59 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
60 ASSERT_TRUE(https_server
.Start());
62 // Load a page with links that open in a new window.
63 std::string replacement_path
;
64 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
65 "files/click-noreferrer-links.html",
66 https_server
.host_port_pair(),
68 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
70 // Get the original SiteInstance for later comparison.
71 scoped_refptr
<SiteInstance
> orig_site_instance(
72 shell()->web_contents()->GetSiteInstance());
73 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
75 // Open a same-site link in a new window.
76 ShellAddedObserver new_shell_observer
;
78 EXPECT_TRUE(ExecuteScriptAndExtractBool(
79 shell()->web_contents(),
80 "window.domAutomationController.send(clickSameSiteTargetedLink());",
83 Shell
* new_shell
= new_shell_observer
.GetShell();
85 // Wait for the navigation in the new window to finish, if it hasn't.
86 WaitForLoadStop(new_shell
->web_contents());
87 EXPECT_EQ("/files/navigate_opener.html",
88 new_shell
->web_contents()->GetURL().path());
90 // Should have the same SiteInstance.
91 scoped_refptr
<SiteInstance
> blank_site_instance(
92 new_shell
->web_contents()->GetSiteInstance());
93 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
95 // We should have access to the opened window's location.
97 EXPECT_TRUE(ExecuteScriptAndExtractBool(
98 shell()->web_contents(),
99 "window.domAutomationController.send(testScriptAccessToWindow());",
101 EXPECT_TRUE(success
);
103 // Now navigate the new window to a different site.
104 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
105 scoped_refptr
<SiteInstance
> new_site_instance(
106 new_shell
->web_contents()->GetSiteInstance());
107 EXPECT_NE(orig_site_instance
, new_site_instance
);
109 // We should no longer have script access to the opened window's location.
111 EXPECT_TRUE(ExecuteScriptAndExtractBool(
112 shell()->web_contents(),
113 "window.domAutomationController.send(testScriptAccessToWindow());",
115 EXPECT_FALSE(success
);
118 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
119 // and target=_blank should create a new SiteInstance.
120 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
121 SwapProcessWithRelNoreferrerAndTargetBlank
) {
122 // Start two servers with different sites.
123 ASSERT_TRUE(test_server()->Start());
124 net::SpawnedTestServer
https_server(
125 net::SpawnedTestServer::TYPE_HTTPS
,
126 net::SpawnedTestServer::kLocalhost
,
127 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
128 ASSERT_TRUE(https_server
.Start());
130 // Load a page with links that open in a new window.
131 std::string replacement_path
;
132 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
133 "files/click-noreferrer-links.html",
134 https_server
.host_port_pair(),
136 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
138 // Get the original SiteInstance for later comparison.
139 scoped_refptr
<SiteInstance
> orig_site_instance(
140 shell()->web_contents()->GetSiteInstance());
141 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
143 // Test clicking a rel=noreferrer + target=blank link.
144 ShellAddedObserver new_shell_observer
;
145 bool success
= false;
146 EXPECT_TRUE(ExecuteScriptAndExtractBool(
147 shell()->web_contents(),
148 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
150 EXPECT_TRUE(success
);
152 // Wait for the window to open.
153 Shell
* new_shell
= new_shell_observer
.GetShell();
155 EXPECT_EQ("/files/title2.html", new_shell
->web_contents()->GetURL().path());
157 // Wait for the cross-site transition in the new tab to finish.
158 WaitForLoadStop(new_shell
->web_contents());
159 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
160 new_shell
->web_contents());
161 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
162 pending_render_view_host());
164 // Should have a new SiteInstance.
165 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
166 new_shell
->web_contents()->GetSiteInstance());
167 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
170 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
171 // for rel=noreferrer links in new windows, even to same site pages and named
173 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
174 SwapProcessWithSameSiteRelNoreferrer
) {
175 // Start two servers with different sites.
176 ASSERT_TRUE(test_server()->Start());
177 net::SpawnedTestServer
https_server(
178 net::SpawnedTestServer::TYPE_HTTPS
,
179 net::SpawnedTestServer::kLocalhost
,
180 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
181 ASSERT_TRUE(https_server
.Start());
183 // Load a page with links that open in a new window.
184 std::string replacement_path
;
185 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
186 "files/click-noreferrer-links.html",
187 https_server
.host_port_pair(),
189 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
191 // Get the original SiteInstance for later comparison.
192 scoped_refptr
<SiteInstance
> orig_site_instance(
193 shell()->web_contents()->GetSiteInstance());
194 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
196 // Test clicking a same-site rel=noreferrer + target=foo link.
197 ShellAddedObserver new_shell_observer
;
198 bool success
= false;
199 EXPECT_TRUE(ExecuteScriptAndExtractBool(
200 shell()->web_contents(),
201 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
203 EXPECT_TRUE(success
);
205 // Wait for the window to open.
206 Shell
* new_shell
= new_shell_observer
.GetShell();
208 // Opens in new window.
209 EXPECT_EQ("/files/title2.html", new_shell
->web_contents()->GetURL().path());
211 // Wait for the cross-site transition in the new tab to finish.
212 WaitForLoadStop(new_shell
->web_contents());
213 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
214 new_shell
->web_contents());
215 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
216 pending_render_view_host());
218 // Should have a new SiteInstance (in a new BrowsingInstance).
219 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
220 new_shell
->web_contents()->GetSiteInstance());
221 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
224 // Test for crbug.com/24447. Following a cross-site link with just
225 // target=_blank should not create a new SiteInstance.
226 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
227 DontSwapProcessWithOnlyTargetBlank
) {
228 // Start two servers with different sites.
229 ASSERT_TRUE(test_server()->Start());
230 net::SpawnedTestServer
https_server(
231 net::SpawnedTestServer::TYPE_HTTPS
,
232 net::SpawnedTestServer::kLocalhost
,
233 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
234 ASSERT_TRUE(https_server
.Start());
236 // Load a page with links that open in a new window.
237 std::string replacement_path
;
238 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
239 "files/click-noreferrer-links.html",
240 https_server
.host_port_pair(),
242 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
244 // Get the original SiteInstance for later comparison.
245 scoped_refptr
<SiteInstance
> orig_site_instance(
246 shell()->web_contents()->GetSiteInstance());
247 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
249 // Test clicking a target=blank link.
250 ShellAddedObserver new_shell_observer
;
251 bool success
= false;
252 EXPECT_TRUE(ExecuteScriptAndExtractBool(
253 shell()->web_contents(),
254 "window.domAutomationController.send(clickTargetBlankLink());",
256 EXPECT_TRUE(success
);
258 // Wait for the window to open.
259 Shell
* new_shell
= new_shell_observer
.GetShell();
261 // Wait for the cross-site transition in the new tab to finish.
262 WaitForLoadStop(new_shell
->web_contents());
263 EXPECT_EQ("/files/title2.html",
264 new_shell
->web_contents()->GetURL().path());
266 // Should have the same SiteInstance.
267 scoped_refptr
<SiteInstance
> blank_site_instance(
268 new_shell
->web_contents()->GetSiteInstance());
269 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
272 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
273 // and no target=_blank should not create a new SiteInstance.
274 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
275 DontSwapProcessWithOnlyRelNoreferrer
) {
276 // Start two servers with different sites.
277 ASSERT_TRUE(test_server()->Start());
278 net::SpawnedTestServer
https_server(
279 net::SpawnedTestServer::TYPE_HTTPS
,
280 net::SpawnedTestServer::kLocalhost
,
281 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
282 ASSERT_TRUE(https_server
.Start());
284 // Load a page with links that open in a new window.
285 std::string replacement_path
;
286 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
287 "files/click-noreferrer-links.html",
288 https_server
.host_port_pair(),
290 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
292 // Get the original SiteInstance for later comparison.
293 scoped_refptr
<SiteInstance
> orig_site_instance(
294 shell()->web_contents()->GetSiteInstance());
295 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
297 // Test clicking a rel=noreferrer link.
298 bool success
= false;
299 EXPECT_TRUE(ExecuteScriptAndExtractBool(
300 shell()->web_contents(),
301 "window.domAutomationController.send(clickNoRefLink());",
303 EXPECT_TRUE(success
);
305 // Wait for the cross-site transition in the current tab to finish.
306 WaitForLoadStop(shell()->web_contents());
308 // Opens in same window.
309 EXPECT_EQ(1u, Shell::windows().size());
310 EXPECT_EQ("/files/title2.html", shell()->web_contents()->GetURL().path());
312 // Should have the same SiteInstance.
313 scoped_refptr
<SiteInstance
> noref_site_instance(
314 shell()->web_contents()->GetSiteInstance());
315 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
320 class WebContentsDestroyedObserver
: public WebContentsObserver
{
322 WebContentsDestroyedObserver(WebContents
* web_contents
,
323 const base::Closure
& callback
)
324 : WebContentsObserver(web_contents
),
325 callback_(callback
) {
328 virtual void WebContentsDestroyed(WebContents
* web_contents
) OVERRIDE
{
333 base::Closure callback_
;
335 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedObserver
);
340 // Test for crbug.com/116192. Targeted links should still work after the
341 // named target window has swapped processes.
342 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
343 AllowTargetedNavigationsAfterSwap
) {
344 // Start two servers with different sites.
345 ASSERT_TRUE(test_server()->Start());
346 net::SpawnedTestServer
https_server(
347 net::SpawnedTestServer::TYPE_HTTPS
,
348 net::SpawnedTestServer::kLocalhost
,
349 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
350 ASSERT_TRUE(https_server
.Start());
352 // Load a page with links that open in a new window.
353 std::string replacement_path
;
354 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
355 "files/click-noreferrer-links.html",
356 https_server
.host_port_pair(),
358 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
360 // Get the original SiteInstance for later comparison.
361 scoped_refptr
<SiteInstance
> orig_site_instance(
362 shell()->web_contents()->GetSiteInstance());
363 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
365 // Test clicking a target=foo link.
366 ShellAddedObserver new_shell_observer
;
367 bool success
= false;
368 EXPECT_TRUE(ExecuteScriptAndExtractBool(
369 shell()->web_contents(),
370 "window.domAutomationController.send(clickSameSiteTargetedLink());",
372 EXPECT_TRUE(success
);
373 Shell
* new_shell
= new_shell_observer
.GetShell();
375 // Wait for the navigation in the new tab to finish, if it hasn't.
376 WaitForLoadStop(new_shell
->web_contents());
377 EXPECT_EQ("/files/navigate_opener.html",
378 new_shell
->web_contents()->GetURL().path());
380 // Should have the same SiteInstance.
381 scoped_refptr
<SiteInstance
> blank_site_instance(
382 new_shell
->web_contents()->GetSiteInstance());
383 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
385 // Now navigate the new tab to a different site.
386 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
387 scoped_refptr
<SiteInstance
> new_site_instance(
388 new_shell
->web_contents()->GetSiteInstance());
389 EXPECT_NE(orig_site_instance
, new_site_instance
);
391 // Clicking the original link in the first tab should cause us to swap back.
392 TestNavigationObserver
navigation_observer(new_shell
->web_contents());
393 EXPECT_TRUE(ExecuteScriptAndExtractBool(
394 shell()->web_contents(),
395 "window.domAutomationController.send(clickSameSiteTargetedLink());",
397 EXPECT_TRUE(success
);
398 navigation_observer
.Wait();
400 // Should have swapped back and shown the new window again.
401 scoped_refptr
<SiteInstance
> revisit_site_instance(
402 new_shell
->web_contents()->GetSiteInstance());
403 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
405 // If it navigates away to another process, the original window should
406 // still be able to close it (using a cross-process close message).
407 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
408 EXPECT_EQ(new_site_instance
,
409 new_shell
->web_contents()->GetSiteInstance());
410 scoped_refptr
<MessageLoopRunner
> loop_runner(new MessageLoopRunner
);
411 WebContentsDestroyedObserver
close_observer(new_shell
->web_contents(),
412 loop_runner
->QuitClosure());
413 EXPECT_TRUE(ExecuteScriptAndExtractBool(
414 shell()->web_contents(),
415 "window.domAutomationController.send(testCloseWindow());",
417 EXPECT_TRUE(success
);
421 // Test that setting the opener to null in a window affects cross-process
422 // navigations, including those to existing entries. http://crbug.com/156669.
423 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, DisownOpener
) {
424 // Start two servers with different sites.
425 ASSERT_TRUE(test_server()->Start());
426 net::SpawnedTestServer
https_server(
427 net::SpawnedTestServer::TYPE_HTTPS
,
428 net::SpawnedTestServer::kLocalhost
,
429 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
430 ASSERT_TRUE(https_server
.Start());
432 // Load a page with links that open in a new window.
433 std::string replacement_path
;
434 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
435 "files/click-noreferrer-links.html",
436 https_server
.host_port_pair(),
438 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
440 // Get the original SiteInstance for later comparison.
441 scoped_refptr
<SiteInstance
> orig_site_instance(
442 shell()->web_contents()->GetSiteInstance());
443 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
445 // Test clicking a target=_blank link.
446 ShellAddedObserver new_shell_observer
;
447 bool success
= false;
448 EXPECT_TRUE(ExecuteScriptAndExtractBool(
449 shell()->web_contents(),
450 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
452 EXPECT_TRUE(success
);
453 Shell
* new_shell
= new_shell_observer
.GetShell();
455 // Wait for the navigation in the new tab to finish, if it hasn't.
456 WaitForLoadStop(new_shell
->web_contents());
457 EXPECT_EQ("/files/title2.html",
458 new_shell
->web_contents()->GetURL().path());
460 // Should have the same SiteInstance.
461 scoped_refptr
<SiteInstance
> blank_site_instance(
462 new_shell
->web_contents()->GetSiteInstance());
463 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
465 // Now navigate the new tab to a different site.
466 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
467 scoped_refptr
<SiteInstance
> new_site_instance(
468 new_shell
->web_contents()->GetSiteInstance());
469 EXPECT_NE(orig_site_instance
, new_site_instance
);
471 // Now disown the opener.
472 EXPECT_TRUE(ExecuteScript(new_shell
->web_contents(),
473 "window.opener = null;"));
475 // Go back and ensure the opener is still null.
477 TestNavigationObserver
back_nav_load_observer(new_shell
->web_contents());
478 new_shell
->web_contents()->GetController().GoBack();
479 back_nav_load_observer
.Wait();
482 EXPECT_TRUE(ExecuteScriptAndExtractBool(
483 new_shell
->web_contents(),
484 "window.domAutomationController.send(window.opener == null);",
486 EXPECT_TRUE(success
);
488 // Now navigate forward again (creating a new process) and check opener.
489 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
491 EXPECT_TRUE(ExecuteScriptAndExtractBool(
492 new_shell
->web_contents(),
493 "window.domAutomationController.send(window.opener == null);",
495 EXPECT_TRUE(success
);
498 // Test that subframes can disown their openers. http://crbug.com/225528.
499 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, DisownSubframeOpener
) {
500 const GURL
frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
501 NavigateToURL(shell(), frame_url
);
503 // Give the frame an opener using window.open.
504 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
505 "window.open('about:blank','foo');"));
507 // Now disown the frame's opener. Shouldn't crash.
508 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
509 "window.frames[0].opener = null;"));
512 // Test for crbug.com/99202. PostMessage calls should still work after
513 // navigating the source and target windows to different sites.
515 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
516 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
517 // 3) Post a message from "foo" to opener, which replies back to "foo".
518 // 4) Post a message from _blank to "foo".
519 // 5) Post a message from "foo" to a subframe of opener, which replies back.
520 // 6) Post a message from _blank to a subframe of "foo".
521 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
522 SupportCrossProcessPostMessage
) {
523 // Start two servers with different sites.
524 ASSERT_TRUE(test_server()->Start());
525 net::SpawnedTestServer
https_server(
526 net::SpawnedTestServer::TYPE_HTTPS
,
527 net::SpawnedTestServer::kLocalhost
,
528 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
529 ASSERT_TRUE(https_server
.Start());
531 // Load a page with links that open in a new window.
532 std::string replacement_path
;
533 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
534 "files/click-noreferrer-links.html",
535 https_server
.host_port_pair(),
537 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
539 // Get the original SiteInstance and RVHM for later comparison.
540 WebContents
* opener_contents
= shell()->web_contents();
541 scoped_refptr
<SiteInstance
> orig_site_instance(
542 opener_contents
->GetSiteInstance());
543 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
544 RenderViewHostManager
* opener_manager
= static_cast<WebContentsImpl
*>(
545 opener_contents
)->GetRenderManagerForTesting();
547 // 1) Open two more windows, one named. These initially have openers but no
548 // reference to each other. We will later post a message between them.
550 // First, a named target=foo window.
551 ShellAddedObserver new_shell_observer
;
552 bool success
= false;
553 EXPECT_TRUE(ExecuteScriptAndExtractBool(
555 "window.domAutomationController.send(clickSameSiteTargetedLink());",
557 EXPECT_TRUE(success
);
558 Shell
* new_shell
= new_shell_observer
.GetShell();
560 // Wait for the navigation in the new window to finish, if it hasn't, then
561 // send it to post_message.html on a different site.
562 WebContents
* foo_contents
= new_shell
->web_contents();
563 WaitForLoadStop(foo_contents
);
564 EXPECT_EQ("/files/navigate_opener.html", foo_contents
->GetURL().path());
565 NavigateToURL(new_shell
, https_server
.GetURL("files/post_message.html"));
566 scoped_refptr
<SiteInstance
> foo_site_instance(
567 foo_contents
->GetSiteInstance());
568 EXPECT_NE(orig_site_instance
, foo_site_instance
);
570 // Second, a target=_blank window.
571 ShellAddedObserver new_shell_observer2
;
572 EXPECT_TRUE(ExecuteScriptAndExtractBool(
573 shell()->web_contents(),
574 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
576 EXPECT_TRUE(success
);
578 // Wait for the navigation in the new window to finish, if it hasn't, then
579 // send it to post_message.html on the original site.
580 Shell
* new_shell2
= new_shell_observer2
.GetShell();
581 WebContents
* new_contents
= new_shell2
->web_contents();
582 WaitForLoadStop(new_contents
);
583 EXPECT_EQ("/files/title2.html", new_contents
->GetURL().path());
584 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
585 EXPECT_EQ(orig_site_instance
, new_contents
->GetSiteInstance());
586 RenderViewHostManager
* new_manager
=
587 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
589 // We now have three windows. The opener should have a swapped out RVH
590 // for the new SiteInstance, but the _blank window should not.
591 EXPECT_EQ(3u, Shell::windows().size());
593 opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
595 new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
.get()));
597 // 2) Fail to post a message from the foo window to the opener if the target
598 // origin is wrong. We won't see an error, but we can check for the right
599 // number of received messages below.
600 EXPECT_TRUE(ExecuteScriptAndExtractBool(
602 "window.domAutomationController.send(postToOpener('msg',"
603 " 'http://google.com'));",
605 EXPECT_TRUE(success
);
607 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
609 // 3) Post a message from the foo window to the opener. The opener will
610 // reply, causing the foo window to update its own title.
611 WindowedNotificationObserver
title_observer(
612 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
,
613 Source
<WebContents
>(foo_contents
));
614 EXPECT_TRUE(ExecuteScriptAndExtractBool(
616 "window.domAutomationController.send(postToOpener('msg','*'));",
618 EXPECT_TRUE(success
);
620 opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
.get()));
621 title_observer
.Wait();
623 // We should have received only 1 message in the opener and "foo" tabs,
624 // and updated the title.
625 int opener_received_messages
= 0;
626 EXPECT_TRUE(ExecuteScriptAndExtractInt(
628 "window.domAutomationController.send(window.receivedMessages);",
629 &opener_received_messages
));
630 int foo_received_messages
= 0;
631 EXPECT_TRUE(ExecuteScriptAndExtractInt(
633 "window.domAutomationController.send(window.receivedMessages);",
634 &foo_received_messages
));
635 EXPECT_EQ(1, foo_received_messages
);
636 EXPECT_EQ(1, opener_received_messages
);
637 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
639 // 4) Now post a message from the _blank window to the foo window. The
640 // foo window will update its title and will not reply.
641 WindowedNotificationObserver
title_observer2(
642 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
,
643 Source
<WebContents
>(foo_contents
));
644 EXPECT_TRUE(ExecuteScriptAndExtractBool(
646 "window.domAutomationController.send(postToFoo('msg2'));",
648 EXPECT_TRUE(success
);
649 title_observer2
.Wait();
650 EXPECT_EQ(ASCIIToUTF16("msg2"), foo_contents
->GetTitle());
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/116192. Navigations to a window's opener should
662 // still work after a process swap.
663 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
664 AllowTargetedNavigationsInOpenerAfterSwap
) {
665 // Start two servers with different sites.
666 ASSERT_TRUE(test_server()->Start());
667 net::SpawnedTestServer
https_server(
668 net::SpawnedTestServer::TYPE_HTTPS
,
669 net::SpawnedTestServer::kLocalhost
,
670 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
671 ASSERT_TRUE(https_server
.Start());
673 // Load a page with links that open in a new window.
674 std::string replacement_path
;
675 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
676 "files/click-noreferrer-links.html",
677 https_server
.host_port_pair(),
679 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
681 // Get the original tab and SiteInstance for later comparison.
682 WebContents
* orig_contents
= shell()->web_contents();
683 scoped_refptr
<SiteInstance
> orig_site_instance(
684 orig_contents
->GetSiteInstance());
685 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
687 // Test clicking a target=foo link.
688 ShellAddedObserver new_shell_observer
;
689 bool success
= false;
690 EXPECT_TRUE(ExecuteScriptAndExtractBool(
692 "window.domAutomationController.send(clickSameSiteTargetedLink());",
694 EXPECT_TRUE(success
);
695 Shell
* new_shell
= new_shell_observer
.GetShell();
697 // Wait for the navigation in the new window to finish, if it hasn't.
698 WaitForLoadStop(new_shell
->web_contents());
699 EXPECT_EQ("/files/navigate_opener.html",
700 new_shell
->web_contents()->GetURL().path());
702 // Should have the same SiteInstance.
703 scoped_refptr
<SiteInstance
> blank_site_instance(
704 new_shell
->web_contents()->GetSiteInstance());
705 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
707 // Now navigate the original (opener) tab to a different site.
708 NavigateToURL(shell(), https_server
.GetURL("files/title1.html"));
709 scoped_refptr
<SiteInstance
> new_site_instance(
710 shell()->web_contents()->GetSiteInstance());
711 EXPECT_NE(orig_site_instance
, new_site_instance
);
713 // The opened tab should be able to navigate the opener back to its process.
714 TestNavigationObserver
navigation_observer(orig_contents
);
715 EXPECT_TRUE(ExecuteScriptAndExtractBool(
716 new_shell
->web_contents(),
717 "window.domAutomationController.send(navigateOpener());",
719 EXPECT_TRUE(success
);
720 navigation_observer
.Wait();
722 // Should have swapped back into this process.
723 scoped_refptr
<SiteInstance
> revisit_site_instance(
724 shell()->web_contents()->GetSiteInstance());
725 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
728 // Test that opening a new window in the same SiteInstance and then navigating
729 // both windows to a different SiteInstance allows the first process to exit.
730 // See http://crbug.com/126333.
731 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
732 ProcessExitWithSwappedOutViews
) {
733 // Start two servers with different sites.
734 ASSERT_TRUE(test_server()->Start());
735 net::SpawnedTestServer
https_server(
736 net::SpawnedTestServer::TYPE_HTTPS
,
737 net::SpawnedTestServer::kLocalhost
,
738 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
739 ASSERT_TRUE(https_server
.Start());
741 // Load a page with links that open in a new window.
742 std::string replacement_path
;
743 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
744 "files/click-noreferrer-links.html",
745 https_server
.host_port_pair(),
747 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
749 // Get the original SiteInstance for later comparison.
750 scoped_refptr
<SiteInstance
> orig_site_instance(
751 shell()->web_contents()->GetSiteInstance());
752 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
754 // Test clicking a target=foo link.
755 ShellAddedObserver new_shell_observer
;
756 bool success
= false;
757 EXPECT_TRUE(ExecuteScriptAndExtractBool(
758 shell()->web_contents(),
759 "window.domAutomationController.send(clickSameSiteTargetedLink());",
761 EXPECT_TRUE(success
);
762 Shell
* new_shell
= new_shell_observer
.GetShell();
764 // Wait for the navigation in the new window to finish, if it hasn't.
765 WaitForLoadStop(new_shell
->web_contents());
766 EXPECT_EQ("/files/navigate_opener.html",
767 new_shell
->web_contents()->GetURL().path());
769 // Should have the same SiteInstance.
770 scoped_refptr
<SiteInstance
> opened_site_instance(
771 new_shell
->web_contents()->GetSiteInstance());
772 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
774 // Now navigate the opened window to a different site.
775 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
776 scoped_refptr
<SiteInstance
> new_site_instance(
777 new_shell
->web_contents()->GetSiteInstance());
778 EXPECT_NE(orig_site_instance
, new_site_instance
);
780 // The original process should still be alive, since it is still used in the
782 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
783 EXPECT_TRUE(orig_process
->HasConnection());
785 // Navigate the first window to a different site as well. The original
786 // process should exit, since all of its views are now swapped out.
787 WindowedNotificationObserver
exit_observer(
788 NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
789 Source
<RenderProcessHost
>(orig_process
));
790 NavigateToURL(shell(), https_server
.GetURL("files/title1.html"));
791 exit_observer
.Wait();
792 scoped_refptr
<SiteInstance
> new_site_instance2(
793 shell()->web_contents()->GetSiteInstance());
794 EXPECT_EQ(new_site_instance
, new_site_instance2
);
797 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
798 // error should not make us ignore future renderer-initiated navigations.
799 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, ClickLinkAfter204Error
) {
800 // Start two servers with different sites.
801 ASSERT_TRUE(test_server()->Start());
802 net::SpawnedTestServer
https_server(
803 net::SpawnedTestServer::TYPE_HTTPS
,
804 net::SpawnedTestServer::kLocalhost
,
805 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
806 ASSERT_TRUE(https_server
.Start());
808 // Load a page with links that open in a new window.
809 // The links will point to the HTTPS server.
810 std::string replacement_path
;
811 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
812 "files/click-noreferrer-links.html",
813 https_server
.host_port_pair(),
815 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
817 // Get the original SiteInstance for later comparison.
818 scoped_refptr
<SiteInstance
> orig_site_instance(
819 shell()->web_contents()->GetSiteInstance());
820 EXPECT_TRUE(orig_site_instance
.get() != NULL
);
822 // Load a cross-site page that fails with a 204 error.
823 NavigateToURL(shell(), https_server
.GetURL("nocontent"));
825 // We should still be looking at the normal page. The typed URL will
826 // still be visible until the user clears it manually, but the last
827 // committed URL will be the previous page.
828 scoped_refptr
<SiteInstance
> post_nav_site_instance(
829 shell()->web_contents()->GetSiteInstance());
830 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
831 EXPECT_EQ("/nocontent", shell()->web_contents()->GetURL().path());
832 EXPECT_EQ("/files/click-noreferrer-links.html",
833 shell()->web_contents()->GetController().
834 GetLastCommittedEntry()->GetVirtualURL().path());
836 // Renderer-initiated navigations should work.
837 bool success
= false;
838 EXPECT_TRUE(ExecuteScriptAndExtractBool(
839 shell()->web_contents(),
840 "window.domAutomationController.send(clickNoRefLink());",
842 EXPECT_TRUE(success
);
844 // Wait for the cross-site transition in the current tab to finish.
845 WaitForLoadStop(shell()->web_contents());
847 // Opens in same tab.
848 EXPECT_EQ(1u, Shell::windows().size());
849 EXPECT_EQ("/files/title2.html", shell()->web_contents()->GetURL().path());
851 // Should have the same SiteInstance.
852 scoped_refptr
<SiteInstance
> noref_site_instance(
853 shell()->web_contents()->GetSiteInstance());
854 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
857 // Test for crbug.com/9682. We should show the URL for a pending renderer-
858 // initiated navigation in a new tab, until the content of the initial
859 // about:blank page is modified by another window. At that point, we should
860 // revert to showing about:blank to prevent a URL spoof.
861 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, ShowLoadingURLUntilSpoof
) {
862 ASSERT_TRUE(test_server()->Start());
864 // Load a page that can open a URL that won't commit in a new window.
866 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
867 WebContents
* orig_contents
= shell()->web_contents();
869 // Click a /nocontent link that opens in a new window but never commits.
870 ShellAddedObserver new_shell_observer
;
871 bool success
= false;
872 EXPECT_TRUE(ExecuteScriptAndExtractBool(
874 "window.domAutomationController.send(clickNoContentTargetedLink());",
876 EXPECT_TRUE(success
);
878 // Wait for the window to open.
879 Shell
* new_shell
= new_shell_observer
.GetShell();
881 // Ensure the destination URL is visible, because it is considered the
882 // initial navigation.
883 WebContents
* contents
= new_shell
->web_contents();
884 EXPECT_TRUE(contents
->GetController().IsInitialNavigation());
885 EXPECT_EQ("/nocontent",
886 contents
->GetController().GetVisibleEntry()->GetURL().path());
888 // Now modify the contents of the new window from the opener. This will also
889 // modify the title of the document to give us something to listen for.
890 WindowedNotificationObserver
title_observer(
891 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
,
892 Source
<WebContents
>(contents
));
894 EXPECT_TRUE(ExecuteScriptAndExtractBool(
896 "window.domAutomationController.send(modifyNewWindow());",
898 EXPECT_TRUE(success
);
899 title_observer
.Wait();
900 EXPECT_EQ(ASCIIToUTF16("Modified Title"), contents
->GetTitle());
902 // At this point, we should no longer be showing the destination URL.
903 // The visible entry should be null, resulting in about:blank in the address
905 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
908 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
909 // initiated navigation in a new tab if it is not the initial navigation. In
910 // this case, the renderer will not notify us of a modification, so we cannot
911 // show the pending URL without allowing a spoof.
912 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
913 DontShowLoadingURLIfNotInitialNav
) {
914 ASSERT_TRUE(test_server()->Start());
916 // Load a page that can open a URL that won't commit in a new window.
918 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
919 WebContents
* orig_contents
= shell()->web_contents();
921 // Click a /nocontent link that opens in a new window but never commits.
922 // By using an onclick handler that first creates the window, the slow
923 // navigation is not considered an initial navigation.
924 ShellAddedObserver new_shell_observer
;
925 bool success
= false;
926 EXPECT_TRUE(ExecuteScriptAndExtractBool(
928 "window.domAutomationController.send("
929 "clickNoContentScriptedTargetedLink());",
931 EXPECT_TRUE(success
);
933 // Wait for the window to open.
934 Shell
* new_shell
= new_shell_observer
.GetShell();
936 // Ensure the destination URL is not visible, because it is not the initial
938 WebContents
* contents
= new_shell
->web_contents();
939 EXPECT_FALSE(contents
->GetController().IsInitialNavigation());
940 EXPECT_FALSE(contents
->GetController().GetVisibleEntry());
943 // Test for http://crbug.com/93427. Ensure that cross-site navigations
944 // do not cause back/forward navigations to be considered stale by the
946 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, BackForwardNotStale
) {
947 NavigateToURL(shell(), GURL(kAboutBlankURL
));
949 // Start two servers with different sites.
950 ASSERT_TRUE(test_server()->Start());
951 net::SpawnedTestServer
https_server(
952 net::SpawnedTestServer::TYPE_HTTPS
,
953 net::SpawnedTestServer::kLocalhost
,
954 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
955 ASSERT_TRUE(https_server
.Start());
957 // Visit a page on first site.
958 std::string replacement_path_a1
;
959 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
961 test_server()->host_port_pair(),
962 &replacement_path_a1
));
963 NavigateToURL(shell(), test_server()->GetURL(replacement_path_a1
));
965 // Visit three pages on second site.
966 std::string replacement_path_b1
;
967 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
969 https_server
.host_port_pair(),
970 &replacement_path_b1
));
971 NavigateToURL(shell(), https_server
.GetURL(replacement_path_b1
));
972 std::string replacement_path_b2
;
973 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
975 https_server
.host_port_pair(),
976 &replacement_path_b2
));
977 NavigateToURL(shell(), https_server
.GetURL(replacement_path_b2
));
978 std::string replacement_path_b3
;
979 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
981 https_server
.host_port_pair(),
982 &replacement_path_b3
));
983 NavigateToURL(shell(), https_server
.GetURL(replacement_path_b3
));
985 // History is now [blank, A1, B1, B2, *B3].
986 WebContents
* contents
= shell()->web_contents();
987 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
989 // Open another window in same process to keep this process alive.
990 Shell
* new_shell
= CreateBrowser();
991 NavigateToURL(new_shell
, https_server
.GetURL(replacement_path_b1
));
993 // Go back three times to first site.
995 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
996 shell()->web_contents()->GetController().GoBack();
997 back_nav_load_observer
.Wait();
1000 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1001 shell()->web_contents()->GetController().GoBack();
1002 back_nav_load_observer
.Wait();
1005 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1006 shell()->web_contents()->GetController().GoBack();
1007 back_nav_load_observer
.Wait();
1010 // Now go forward twice to B2. Shouldn't be left spinning.
1012 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1013 shell()->web_contents()->GetController().GoForward();
1014 forward_nav_load_observer
.Wait();
1017 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1018 shell()->web_contents()->GetController().GoForward();
1019 forward_nav_load_observer
.Wait();
1022 // Go back twice to first site.
1024 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1025 shell()->web_contents()->GetController().GoBack();
1026 back_nav_load_observer
.Wait();
1029 TestNavigationObserver
back_nav_load_observer(shell()->web_contents());
1030 shell()->web_contents()->GetController().GoBack();
1031 back_nav_load_observer
.Wait();
1034 // Now go forward directly to B3. Shouldn't be left spinning.
1036 TestNavigationObserver
forward_nav_load_observer(shell()->web_contents());
1037 shell()->web_contents()->GetController().GoToIndex(4);
1038 forward_nav_load_observer
.Wait();
1042 // Test for http://crbug.com/130016.
1043 // Swapping out a render view should update its visiblity state.
1044 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
1045 SwappedOutViewHasCorrectVisibilityState
) {
1046 // Start two servers with different sites.
1047 ASSERT_TRUE(test_server()->Start());
1048 net::SpawnedTestServer
https_server(
1049 net::SpawnedTestServer::TYPE_HTTPS
,
1050 net::SpawnedTestServer::kLocalhost
,
1051 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1052 ASSERT_TRUE(https_server
.Start());
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",
1058 https_server
.host_port_pair(),
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()->GetURL().path());
1077 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
1079 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1081 "window.domAutomationController.send("
1082 " document.webkitVisibilityState == '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
, https_server
.GetURL("files/title1.html"));
1090 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1092 "window.domAutomationController.send("
1093 " document.webkitVisibilityState == '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()->GetURL().path());
1108 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
1110 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1112 "window.domAutomationController.send("
1113 " document.webkitVisibilityState == 'visible');",
1115 EXPECT_TRUE(success
);
1118 // This class holds onto RenderViewHostObservers for as long as their observed
1119 // RenderViewHosts are alive. This allows us to confirm that all hosts have
1120 // properly been shutdown.
1121 class RenderViewHostObserverArray
{
1123 ~RenderViewHostObserverArray() {
1124 // In case some would be left in there with a dead pointer to us.
1125 for (std::list
<RVHObserver
*>::iterator iter
= observers_
.begin();
1126 iter
!= observers_
.end(); ++iter
) {
1127 (*iter
)->ClearParent();
1130 void AddObserverToRVH(RenderViewHost
* rvh
) {
1131 observers_
.push_back(new RVHObserver(this, rvh
));
1133 size_t GetNumObservers() const {
1134 return observers_
.size();
1138 friend class RVHObserver
;
1139 class RVHObserver
: public RenderViewHostObserver
{
1141 RVHObserver(RenderViewHostObserverArray
* parent
, RenderViewHost
* rvh
)
1142 : RenderViewHostObserver(rvh
),
1145 virtual void RenderViewHostDestroyed(RenderViewHost
* rvh
) OVERRIDE
{
1147 parent_
->RemoveObserver(this);
1148 RenderViewHostObserver::RenderViewHostDestroyed(rvh
);
1150 void ClearParent() {
1154 RenderViewHostObserverArray
* parent_
;
1157 void RemoveObserver(RVHObserver
* observer
) {
1158 observers_
.remove(observer
);
1161 std::list
<RVHObserver
*> observers_
;
1164 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1165 // they may cause crashes or memory corruptions when trying to call dead
1166 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1167 // ensure that a separate SiteInstance is created when navigating to view-source
1168 // URLs, regardless of current URL.
1169 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, LeakingRenderViewHosts
) {
1170 // Start two servers with different sites.
1171 ASSERT_TRUE(test_server()->Start());
1172 net::SpawnedTestServer
https_server(
1173 net::SpawnedTestServer::TYPE_HTTPS
,
1174 net::SpawnedTestServer::kLocalhost
,
1175 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1176 ASSERT_TRUE(https_server
.Start());
1178 // Observe the created render_view_host's to make sure they will not leak.
1179 RenderViewHostObserverArray rvh_observers
;
1181 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1182 GURL
view_source_url(kViewSourceScheme
+ std::string(":") +
1183 navigated_url
.spec());
1185 // Let's ensure that when we start with a blank window, navigating away to a
1186 // view-source URL, we create a new SiteInstance.
1187 RenderViewHost
* blank_rvh
= shell()->web_contents()->GetRenderViewHost();
1188 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1189 EXPECT_EQ(shell()->web_contents()->GetURL(), GURL::EmptyGURL());
1190 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1191 rvh_observers
.AddObserverToRVH(blank_rvh
);
1193 // Now navigate to the view-source URL and ensure we got a different
1194 // SiteInstance and RenderViewHost.
1195 NavigateToURL(shell(), view_source_url
);
1196 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1197 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1198 GetRenderViewHost()->GetSiteInstance());
1199 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1201 // Load a random page and then navigate to view-source: of it.
1202 // This used to cause two RVH instances for the same SiteInstance, which
1203 // was a problem. This is no longer the case.
1204 NavigateToURL(shell(), navigated_url
);
1205 SiteInstance
* site_instance1
= shell()->web_contents()->
1206 GetRenderViewHost()->GetSiteInstance();
1207 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1209 NavigateToURL(shell(), view_source_url
);
1210 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1211 SiteInstance
* site_instance2
= shell()->web_contents()->
1212 GetRenderViewHost()->GetSiteInstance();
1214 // Ensure that view-source navigations force a new SiteInstance.
1215 EXPECT_NE(site_instance1
, site_instance2
);
1217 // Now navigate to a different instance so that we swap out again.
1218 NavigateToURL(shell(), https_server
.GetURL("files/title2.html"));
1219 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1221 // This used to leak a render view host.
1224 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1226 EXPECT_EQ(0U, rvh_observers
.GetNumObservers());
1229 // Test for crbug.com/143155. Frame tree updates during unload should not
1230 // interrupt the intended navigation and show swappedout:// instead.
1232 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1233 // 2) Send the second tab to a different HTTPS SiteInstance.
1234 // This creates a swapped out opener for the first tab in the HTTPS process.
1235 // 3) Navigate the first tab to the HTTPS SiteInstance, and have the first
1236 // tab's unload handler remove its frame.
1237 // This used to cause an update to the frame tree of the swapped out RV,
1238 // just as it was navigating to a real page. That pre-empted the real
1239 // navigation and visibly sent the tab to swappedout://.
1240 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
1241 DontPreemptNavigationWithFrameTreeUpdate
) {
1242 // Start two servers with different sites.
1243 ASSERT_TRUE(test_server()->Start());
1244 net::SpawnedTestServer
https_server(
1245 net::SpawnedTestServer::TYPE_HTTPS
,
1246 net::SpawnedTestServer::kLocalhost
,
1247 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1248 ASSERT_TRUE(https_server
.Start());
1250 // 1. Load a page that deletes its iframe during unload.
1251 NavigateToURL(shell(),
1252 test_server()->GetURL("files/remove_frame_on_unload.html"));
1254 // Get the original SiteInstance for later comparison.
1255 scoped_refptr
<SiteInstance
> orig_site_instance(
1256 shell()->web_contents()->GetSiteInstance());
1258 // Open a same-site page in a new window.
1259 ShellAddedObserver new_shell_observer
;
1260 bool success
= false;
1261 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1262 shell()->web_contents(),
1263 "window.domAutomationController.send(openWindow());",
1265 EXPECT_TRUE(success
);
1266 Shell
* new_shell
= new_shell_observer
.GetShell();
1268 // Wait for the navigation in the new window to finish, if it hasn't.
1269 WaitForLoadStop(new_shell
->web_contents());
1270 EXPECT_EQ("/files/title1.html",
1271 new_shell
->web_contents()->GetURL().path());
1273 // Should have the same SiteInstance.
1274 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
1276 // 2. Send the second tab to a different process.
1277 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
1278 scoped_refptr
<SiteInstance
> new_site_instance(
1279 new_shell
->web_contents()->GetSiteInstance());
1280 EXPECT_NE(orig_site_instance
, new_site_instance
);
1282 // 3. Send the first tab to the second tab's process.
1283 NavigateToURL(shell(), https_server
.GetURL("files/title1.html"));
1285 // Make sure it ends up at the right page.
1286 WaitForLoadStop(shell()->web_contents());
1287 EXPECT_EQ(https_server
.GetURL("files/title1.html"),
1288 shell()->web_contents()->GetURL());
1289 EXPECT_EQ(new_site_instance
, shell()->web_contents()->GetSiteInstance());
1292 } // namespace content