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/file_util.h"
6 #include "base/json/json_reader.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/path_service.h"
9 #include "base/utf_string_conversions.h"
10 #include "content/common/content_constants_internal.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/site_instance_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.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/common/url_constants.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/test_utils.h"
26 #include "content/shell/shell.h"
27 #include "content/test/content_browser_test.h"
28 #include "content/test/content_browser_test_utils.h"
29 #include "net/base/net_util.h"
30 #include "net/test/test_server.h"
35 bool CompareTrees(base::DictionaryValue
* first
, base::DictionaryValue
* second
) {
38 if (!first
->GetString(kFrameTreeNodeNameKey
, &name1
) ||
39 !second
->GetString(kFrameTreeNodeNameKey
, &name2
))
46 if (!first
->GetInteger(kFrameTreeNodeIdKey
, &id1
) ||
47 !second
->GetInteger(kFrameTreeNodeIdKey
, &id2
)) {
53 ListValue
* subtree1
= NULL
;
54 ListValue
* subtree2
= NULL
;
55 bool result1
= first
->GetList(kFrameTreeNodeSubtreeKey
, &subtree1
);
56 bool result2
= second
->GetList(kFrameTreeNodeSubtreeKey
, &subtree2
);
57 if (!result1
&& !result2
)
59 if (!result1
|| !result2
)
62 if (subtree1
->GetSize() != subtree2
->GetSize())
65 base::DictionaryValue
* child1
= NULL
;
66 base::DictionaryValue
* child2
= NULL
;
67 for (size_t i
= 0; i
< subtree1
->GetSize(); ++i
) {
68 if (!subtree1
->GetDictionary(i
, &child1
) ||
69 !subtree2
->GetDictionary(i
, &child2
)) {
72 if (!CompareTrees(child1
, child2
))
79 base::DictionaryValue
* GetTree(RenderViewHostImpl
* rvh
) {
80 std::string frame_tree
= rvh
->frame_tree();
81 EXPECT_FALSE(frame_tree
.empty());
82 base::Value
* v
= base::JSONReader::Read(frame_tree
);
83 base::DictionaryValue
* tree
= NULL
;
84 EXPECT_TRUE(v
->IsType(base::Value::TYPE_DICTIONARY
));
85 EXPECT_TRUE(v
->GetAsDictionary(&tree
));
91 class RenderViewHostManagerTest
: public ContentBrowserTest
{
93 RenderViewHostManagerTest() {}
95 static bool GetFilePathWithHostAndPortReplacement(
96 const std::string
& original_file_path
,
97 const net::HostPortPair
& host_port_pair
,
98 std::string
* replacement_path
) {
99 std::vector
<net::TestServer::StringPair
> replacement_text
;
100 replacement_text
.push_back(
101 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair
.ToString()));
102 return net::TestServer::GetFilePathWithReplacements(
103 original_file_path
, replacement_text
, replacement_path
);
107 // Web pages should not have script access to the swapped out page.
108 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, NoScriptAccessAfterSwapOut
) {
109 // Start two servers with different sites.
110 ASSERT_TRUE(test_server()->Start());
111 net::TestServer
https_server(
112 net::TestServer::TYPE_HTTPS
,
113 net::TestServer::kLocalhost
,
114 FilePath(FILE_PATH_LITERAL("content/test/data")));
115 ASSERT_TRUE(https_server
.Start());
117 // Load a page with links that open in a new window.
118 std::string replacement_path
;
119 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
120 "files/click-noreferrer-links.html",
121 https_server
.host_port_pair(),
123 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
125 // Get the original SiteInstance for later comparison.
126 scoped_refptr
<SiteInstance
> orig_site_instance(
127 shell()->web_contents()->GetSiteInstance());
128 EXPECT_TRUE(orig_site_instance
!= NULL
);
130 // Open a same-site link in a new window.
131 ShellAddedObserver new_shell_observer
;
132 bool success
= false;
133 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
134 shell()->web_contents()->GetRenderViewHost(), L
"",
135 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
137 EXPECT_TRUE(success
);
138 Shell
* new_shell
= new_shell_observer
.GetShell();
140 // Wait for the navigation in the new window to finish, if it hasn't.
141 WaitForLoadStop(new_shell
->web_contents());
142 EXPECT_EQ("/files/navigate_opener.html",
143 new_shell
->web_contents()->GetURL().path());
145 // Should have the same SiteInstance.
146 scoped_refptr
<SiteInstance
> blank_site_instance(
147 new_shell
->web_contents()->GetSiteInstance());
148 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
150 // We should have access to the opened window's location.
152 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
153 shell()->web_contents()->GetRenderViewHost(), L
"",
154 L
"window.domAutomationController.send(testScriptAccessToWindow());",
156 EXPECT_TRUE(success
);
158 // Now navigate the new window to a different site.
159 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
160 scoped_refptr
<SiteInstance
> new_site_instance(
161 new_shell
->web_contents()->GetSiteInstance());
162 EXPECT_NE(orig_site_instance
, new_site_instance
);
164 // We should no longer have script access to the opened window's location.
166 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
167 shell()->web_contents()->GetRenderViewHost(), L
"",
168 L
"window.domAutomationController.send(testScriptAccessToWindow());",
170 EXPECT_FALSE(success
);
173 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
174 // and target=_blank should create a new SiteInstance.
175 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
176 SwapProcessWithRelNoreferrerAndTargetBlank
) {
177 // Start two servers with different sites.
178 ASSERT_TRUE(test_server()->Start());
179 net::TestServer
https_server(
180 net::TestServer::TYPE_HTTPS
,
181 net::TestServer::kLocalhost
,
182 FilePath(FILE_PATH_LITERAL("content/test/data")));
183 ASSERT_TRUE(https_server
.Start());
185 // Load a page with links that open in a new window.
186 std::string replacement_path
;
187 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
188 "files/click-noreferrer-links.html",
189 https_server
.host_port_pair(),
191 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
193 // Get the original SiteInstance for later comparison.
194 scoped_refptr
<SiteInstance
> orig_site_instance(
195 shell()->web_contents()->GetSiteInstance());
196 EXPECT_TRUE(orig_site_instance
!= NULL
);
198 // Test clicking a rel=noreferrer + target=blank link.
199 ShellAddedObserver new_shell_observer
;
200 bool success
= false;
201 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
202 shell()->web_contents()->GetRenderViewHost(), L
"",
203 L
"window.domAutomationController.send(clickNoRefTargetBlankLink());",
205 EXPECT_TRUE(success
);
207 // Wait for the window to open.
208 Shell
* new_shell
= new_shell_observer
.GetShell();
210 EXPECT_EQ("/files/title2.html", new_shell
->web_contents()->GetURL().path());
212 // Wait for the cross-site transition in the new tab to finish.
213 WaitForLoadStop(new_shell
->web_contents());
214 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
215 new_shell
->web_contents());
216 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
217 pending_render_view_host());
219 // Should have a new SiteInstance.
220 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
221 new_shell
->web_contents()->GetSiteInstance());
222 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
225 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
226 // for rel=noreferrer links in new windows, even to same site pages and named
228 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
229 SwapProcessWithSameSiteRelNoreferrer
) {
230 // Start two servers with different sites.
231 ASSERT_TRUE(test_server()->Start());
232 net::TestServer
https_server(
233 net::TestServer::TYPE_HTTPS
,
234 net::TestServer::kLocalhost
,
235 FilePath(FILE_PATH_LITERAL("content/test/data")));
236 ASSERT_TRUE(https_server
.Start());
238 // Load a page with links that open in a new window.
239 std::string replacement_path
;
240 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
241 "files/click-noreferrer-links.html",
242 https_server
.host_port_pair(),
244 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
246 // Get the original SiteInstance for later comparison.
247 scoped_refptr
<SiteInstance
> orig_site_instance(
248 shell()->web_contents()->GetSiteInstance());
249 EXPECT_TRUE(orig_site_instance
!= NULL
);
251 // Test clicking a same-site rel=noreferrer + target=foo link.
252 ShellAddedObserver new_shell_observer
;
253 bool success
= false;
254 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
255 shell()->web_contents()->GetRenderViewHost(), L
"",
256 L
"window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
258 EXPECT_TRUE(success
);
260 // Wait for the window to open.
261 Shell
* new_shell
= new_shell_observer
.GetShell();
263 // Opens in new window.
264 EXPECT_EQ("/files/title2.html", new_shell
->web_contents()->GetURL().path());
266 // Wait for the cross-site transition in the new tab to finish.
267 WaitForLoadStop(new_shell
->web_contents());
268 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
269 new_shell
->web_contents());
270 EXPECT_FALSE(web_contents
->GetRenderManagerForTesting()->
271 pending_render_view_host());
273 // Should have a new SiteInstance (in a new BrowsingInstance).
274 scoped_refptr
<SiteInstance
> noref_blank_site_instance(
275 new_shell
->web_contents()->GetSiteInstance());
276 EXPECT_NE(orig_site_instance
, noref_blank_site_instance
);
279 // Test for crbug.com/24447. Following a cross-site link with just
280 // target=_blank should not create a new SiteInstance.
281 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
282 DontSwapProcessWithOnlyTargetBlank
) {
283 // Start two servers with different sites.
284 ASSERT_TRUE(test_server()->Start());
285 net::TestServer
https_server(
286 net::TestServer::TYPE_HTTPS
,
287 net::TestServer::kLocalhost
,
288 FilePath(FILE_PATH_LITERAL("content/test/data")));
289 ASSERT_TRUE(https_server
.Start());
291 // Load a page with links that open in a new window.
292 std::string replacement_path
;
293 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
294 "files/click-noreferrer-links.html",
295 https_server
.host_port_pair(),
297 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
299 // Get the original SiteInstance for later comparison.
300 scoped_refptr
<SiteInstance
> orig_site_instance(
301 shell()->web_contents()->GetSiteInstance());
302 EXPECT_TRUE(orig_site_instance
!= NULL
);
304 // Test clicking a target=blank link.
305 ShellAddedObserver new_shell_observer
;
306 bool success
= false;
307 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
308 shell()->web_contents()->GetRenderViewHost(), L
"",
309 L
"window.domAutomationController.send(clickTargetBlankLink());",
311 EXPECT_TRUE(success
);
313 // Wait for the window to open.
314 Shell
* new_shell
= new_shell_observer
.GetShell();
316 // Wait for the cross-site transition in the new tab to finish.
317 WaitForLoadStop(new_shell
->web_contents());
318 EXPECT_EQ("/files/title2.html",
319 new_shell
->web_contents()->GetURL().path());
321 // Should have the same SiteInstance.
322 scoped_refptr
<SiteInstance
> blank_site_instance(
323 new_shell
->web_contents()->GetSiteInstance());
324 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
327 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
328 // and no target=_blank should not create a new SiteInstance.
329 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
330 DontSwapProcessWithOnlyRelNoreferrer
) {
331 // Start two servers with different sites.
332 ASSERT_TRUE(test_server()->Start());
333 net::TestServer
https_server(
334 net::TestServer::TYPE_HTTPS
,
335 net::TestServer::kLocalhost
,
336 FilePath(FILE_PATH_LITERAL("content/test/data")));
337 ASSERT_TRUE(https_server
.Start());
339 // Load a page with links that open in a new window.
340 std::string replacement_path
;
341 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
342 "files/click-noreferrer-links.html",
343 https_server
.host_port_pair(),
345 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
347 // Get the original SiteInstance for later comparison.
348 scoped_refptr
<SiteInstance
> orig_site_instance(
349 shell()->web_contents()->GetSiteInstance());
350 EXPECT_TRUE(orig_site_instance
!= NULL
);
352 // Test clicking a rel=noreferrer link.
353 bool success
= false;
354 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
355 shell()->web_contents()->GetRenderViewHost(), L
"",
356 L
"window.domAutomationController.send(clickNoRefLink());",
358 EXPECT_TRUE(success
);
360 // Wait for the cross-site transition in the current tab to finish.
361 WaitForLoadStop(shell()->web_contents());
363 // Opens in same window.
364 EXPECT_EQ(1u, Shell::windows().size());
365 EXPECT_EQ("/files/title2.html", shell()->web_contents()->GetURL().path());
367 // Should have the same SiteInstance.
368 scoped_refptr
<SiteInstance
> noref_site_instance(
369 shell()->web_contents()->GetSiteInstance());
370 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
373 // Test for crbug.com/116192. Targeted links should still work after the
374 // named target window has swapped processes.
375 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
376 AllowTargetedNavigationsAfterSwap
) {
377 // Start two servers with different sites.
378 ASSERT_TRUE(test_server()->Start());
379 net::TestServer
https_server(
380 net::TestServer::TYPE_HTTPS
,
381 net::TestServer::kLocalhost
,
382 FilePath(FILE_PATH_LITERAL("content/test/data")));
383 ASSERT_TRUE(https_server
.Start());
385 // Load a page with links that open in a new window.
386 std::string replacement_path
;
387 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
388 "files/click-noreferrer-links.html",
389 https_server
.host_port_pair(),
391 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
393 // Get the original SiteInstance for later comparison.
394 scoped_refptr
<SiteInstance
> orig_site_instance(
395 shell()->web_contents()->GetSiteInstance());
396 EXPECT_TRUE(orig_site_instance
!= NULL
);
398 // Test clicking a target=foo link.
399 ShellAddedObserver new_shell_observer
;
400 bool success
= false;
401 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
402 shell()->web_contents()->GetRenderViewHost(), L
"",
403 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
405 EXPECT_TRUE(success
);
406 Shell
* new_shell
= new_shell_observer
.GetShell();
408 // Wait for the navigation in the new tab to finish, if it hasn't.
409 WaitForLoadStop(new_shell
->web_contents());
410 EXPECT_EQ("/files/navigate_opener.html",
411 new_shell
->web_contents()->GetURL().path());
413 // Should have the same SiteInstance.
414 scoped_refptr
<SiteInstance
> blank_site_instance(
415 new_shell
->web_contents()->GetSiteInstance());
416 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
418 // Now navigate the new tab to a different site.
419 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
420 scoped_refptr
<SiteInstance
> new_site_instance(
421 new_shell
->web_contents()->GetSiteInstance());
422 EXPECT_NE(orig_site_instance
, new_site_instance
);
424 // Clicking the original link in the first tab should cause us to swap back.
425 WindowedNotificationObserver
navigation_observer(
426 NOTIFICATION_NAV_ENTRY_COMMITTED
,
427 Source
<NavigationController
>(
428 &new_shell
->web_contents()->GetController()));
429 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
430 shell()->web_contents()->GetRenderViewHost(), L
"",
431 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
433 EXPECT_TRUE(success
);
434 navigation_observer
.Wait();
436 // Should have swapped back and shown the new window again.
437 scoped_refptr
<SiteInstance
> revisit_site_instance(
438 new_shell
->web_contents()->GetSiteInstance());
439 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
441 // If it navigates away to another process, the original window should
442 // still be able to close it (using a cross-process close message).
443 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
444 EXPECT_EQ(new_site_instance
,
445 new_shell
->web_contents()->GetSiteInstance());
446 WindowedNotificationObserver
close_observer(
447 NOTIFICATION_WEB_CONTENTS_DESTROYED
,
448 Source
<WebContents
>(new_shell
->web_contents()));
449 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
450 shell()->web_contents()->GetRenderViewHost(), L
"",
451 L
"window.domAutomationController.send(testCloseWindow());",
453 EXPECT_TRUE(success
);
454 close_observer
.Wait();
457 // Test for crbug.com/99202. PostMessage calls should still work after
458 // navigating the source and target windows to different sites.
460 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
461 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
462 // 3) Post a message from "foo" to opener, which replies back to "foo".
463 // 4) Post a message from _blank to "foo".
464 // 5) Post a message from "foo" to a subframe of opener, which replies back.
465 // 6) Post a message from _blank to a subframe of "foo".
466 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
467 SupportCrossProcessPostMessage
) {
468 // Start two servers with different sites.
469 ASSERT_TRUE(test_server()->Start());
470 net::TestServer
https_server(
471 net::TestServer::TYPE_HTTPS
,
472 net::TestServer::kLocalhost
,
473 FilePath(FILE_PATH_LITERAL("content/test/data")));
474 ASSERT_TRUE(https_server
.Start());
476 // Load a page with links that open in a new window.
477 std::string replacement_path
;
478 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
479 "files/click-noreferrer-links.html",
480 https_server
.host_port_pair(),
482 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
484 // Get the original SiteInstance and RVHM for later comparison.
485 WebContents
* opener_contents
= shell()->web_contents();
486 scoped_refptr
<SiteInstance
> orig_site_instance(
487 opener_contents
->GetSiteInstance());
488 EXPECT_TRUE(orig_site_instance
!= NULL
);
489 RenderViewHostManager
* opener_manager
=
490 static_cast<WebContentsImpl
*>(opener_contents
)->
491 GetRenderManagerForTesting();
493 // 1) Open two more windows, one named. These initially have openers but no
494 // reference to each other. We will later post a message between them.
496 // First, a named target=foo window.
497 ShellAddedObserver new_shell_observer
;
498 bool success
= false;
499 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
500 opener_contents
->GetRenderViewHost(), L
"",
501 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
503 EXPECT_TRUE(success
);
504 Shell
* new_shell
= new_shell_observer
.GetShell();
506 // Wait for the navigation in the new window to finish, if it hasn't, then
507 // send it to post_message.html on a different site.
508 WebContents
* foo_contents
= new_shell
->web_contents();
509 WaitForLoadStop(foo_contents
);
510 EXPECT_EQ("/files/navigate_opener.html", foo_contents
->GetURL().path());
511 NavigateToURL(new_shell
, https_server
.GetURL("files/post_message.html"));
512 scoped_refptr
<SiteInstance
> foo_site_instance(
513 foo_contents
->GetSiteInstance());
514 EXPECT_NE(orig_site_instance
, foo_site_instance
);
516 // Second, a target=_blank window.
517 ShellAddedObserver new_shell_observer2
;
518 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
519 shell()->web_contents()->GetRenderViewHost(), L
"",
520 L
"window.domAutomationController.send(clickSameSiteTargetBlankLink());",
522 EXPECT_TRUE(success
);
524 // Wait for the navigation in the new window to finish, if it hasn't, then
525 // send it to post_message.html on the original site.
526 Shell
* new_shell2
= new_shell_observer2
.GetShell();
527 WebContents
* new_contents
= new_shell2
->web_contents();
528 WaitForLoadStop(new_contents
);
529 EXPECT_EQ("/files/title2.html", new_contents
->GetURL().path());
530 NavigateToURL(new_shell2
, test_server()->GetURL("files/post_message.html"));
531 EXPECT_EQ(orig_site_instance
, new_contents
->GetSiteInstance());
532 RenderViewHostManager
* new_manager
=
533 static_cast<WebContentsImpl
*>(new_contents
)->GetRenderManagerForTesting();
535 // We now have three windows. The opener should have a swapped out RVH
536 // for the new SiteInstance, but the _blank window should not.
537 EXPECT_EQ(3u, Shell::windows().size());
538 EXPECT_TRUE(opener_manager
->GetSwappedOutRenderViewHost(foo_site_instance
));
539 EXPECT_FALSE(new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
));
541 // 2) Fail to post a message from the foo window to the opener if the target
542 // origin is wrong. We won't see an error, but we can check for the right
543 // number of received messages below.
544 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
545 foo_contents
->GetRenderViewHost(), L
"",
546 L
"window.domAutomationController.send(postToOpener('msg',"
547 L
"'http://google.com'));",
549 EXPECT_TRUE(success
);
550 ASSERT_FALSE(opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
));
552 // 3) Post a message from the foo window to the opener. The opener will
553 // reply, causing the foo window to update its own title.
554 WindowedNotificationObserver
title_observer(
555 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
,
556 Source
<WebContents
>(foo_contents
));
557 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
558 foo_contents
->GetRenderViewHost(), L
"",
559 L
"window.domAutomationController.send(postToOpener('msg','*'));",
561 EXPECT_TRUE(success
);
562 ASSERT_FALSE(opener_manager
->GetSwappedOutRenderViewHost(orig_site_instance
));
563 title_observer
.Wait();
565 // We should have received only 1 message in the opener and "foo" tabs,
566 // and updated the title.
567 int opener_received_messages
= 0;
568 EXPECT_TRUE(ExecuteJavaScriptAndExtractInt(
569 opener_contents
->GetRenderViewHost(), L
"",
570 L
"window.domAutomationController.send(window.receivedMessages);",
571 &opener_received_messages
));
572 int foo_received_messages
= 0;
573 EXPECT_TRUE(ExecuteJavaScriptAndExtractInt(
574 foo_contents
->GetRenderViewHost(), L
"",
575 L
"window.domAutomationController.send(window.receivedMessages);",
576 &foo_received_messages
));
577 EXPECT_EQ(1, foo_received_messages
);
578 EXPECT_EQ(1, opener_received_messages
);
579 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents
->GetTitle());
581 // 4) Now post a message from the _blank window to the foo window. The
582 // foo window will update its title and will not reply.
583 WindowedNotificationObserver
title_observer2(
584 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED
,
585 Source
<WebContents
>(foo_contents
));
586 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
587 new_contents
->GetRenderViewHost(), L
"",
588 L
"window.domAutomationController.send(postToFoo('msg2'));",
590 EXPECT_TRUE(success
);
591 title_observer2
.Wait();
592 EXPECT_EQ(ASCIIToUTF16("msg2"), foo_contents
->GetTitle());
594 // This postMessage should have created a swapped out RVH for the new
595 // SiteInstance in the target=_blank window.
596 EXPECT_TRUE(new_manager
->GetSwappedOutRenderViewHost(foo_site_instance
));
598 // TODO(nasko): Test subframe targeting of postMessage once
599 // http://crbug.com/153701 is fixed.
602 // Test for crbug.com/116192. Navigations to a window's opener should
603 // still work after a process swap.
604 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
605 AllowTargetedNavigationsInOpenerAfterSwap
) {
606 // Start two servers with different sites.
607 ASSERT_TRUE(test_server()->Start());
608 net::TestServer
https_server(
609 net::TestServer::TYPE_HTTPS
,
610 net::TestServer::kLocalhost
,
611 FilePath(FILE_PATH_LITERAL("content/test/data")));
612 ASSERT_TRUE(https_server
.Start());
614 // Load a page with links that open in a new window.
615 std::string replacement_path
;
616 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
617 "files/click-noreferrer-links.html",
618 https_server
.host_port_pair(),
620 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
622 // Get the original tab and SiteInstance for later comparison.
623 WebContents
* orig_contents
= shell()->web_contents();
624 scoped_refptr
<SiteInstance
> orig_site_instance(
625 orig_contents
->GetSiteInstance());
626 EXPECT_TRUE(orig_site_instance
!= NULL
);
628 // Test clicking a target=foo link.
629 ShellAddedObserver new_shell_observer
;
630 bool success
= false;
631 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
632 orig_contents
->GetRenderViewHost(), L
"",
633 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
635 EXPECT_TRUE(success
);
636 Shell
* new_shell
= new_shell_observer
.GetShell();
638 // Wait for the navigation in the new window to finish, if it hasn't.
639 WaitForLoadStop(new_shell
->web_contents());
640 EXPECT_EQ("/files/navigate_opener.html",
641 new_shell
->web_contents()->GetURL().path());
643 // Should have the same SiteInstance.
644 scoped_refptr
<SiteInstance
> blank_site_instance(
645 new_shell
->web_contents()->GetSiteInstance());
646 EXPECT_EQ(orig_site_instance
, blank_site_instance
);
648 // Now navigate the original (opener) tab to a different site.
649 NavigateToURL(shell(), https_server
.GetURL("files/title1.html"));
650 scoped_refptr
<SiteInstance
> new_site_instance(
651 shell()->web_contents()->GetSiteInstance());
652 EXPECT_NE(orig_site_instance
, new_site_instance
);
654 // The opened tab should be able to navigate the opener back to its process.
655 WindowedNotificationObserver
navigation_observer(
656 NOTIFICATION_NAV_ENTRY_COMMITTED
,
657 Source
<NavigationController
>(
658 &orig_contents
->GetController()));
659 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
660 new_shell
->web_contents()->GetRenderViewHost(), L
"",
661 L
"window.domAutomationController.send(navigateOpener());",
663 EXPECT_TRUE(success
);
664 navigation_observer
.Wait();
666 // Should have swapped back into this process.
667 scoped_refptr
<SiteInstance
> revisit_site_instance(
668 shell()->web_contents()->GetSiteInstance());
669 EXPECT_EQ(orig_site_instance
, revisit_site_instance
);
672 // Test that opening a new window in the same SiteInstance and then navigating
673 // both windows to a different SiteInstance allows the first process to exit.
674 // See http://crbug.com/126333.
675 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
676 ProcessExitWithSwappedOutViews
) {
677 // Start two servers with different sites.
678 ASSERT_TRUE(test_server()->Start());
679 net::TestServer
https_server(
680 net::TestServer::TYPE_HTTPS
,
681 net::TestServer::kLocalhost
,
682 FilePath(FILE_PATH_LITERAL("content/test/data")));
683 ASSERT_TRUE(https_server
.Start());
685 // Load a page with links that open in a new window.
686 std::string replacement_path
;
687 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
688 "files/click-noreferrer-links.html",
689 https_server
.host_port_pair(),
691 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
693 // Get the original SiteInstance for later comparison.
694 scoped_refptr
<SiteInstance
> orig_site_instance(
695 shell()->web_contents()->GetSiteInstance());
696 EXPECT_TRUE(orig_site_instance
!= NULL
);
698 // Test clicking a target=foo link.
699 ShellAddedObserver new_shell_observer
;
700 bool success
= false;
701 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
702 shell()->web_contents()->GetRenderViewHost(), L
"",
703 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
705 EXPECT_TRUE(success
);
706 Shell
* new_shell
= new_shell_observer
.GetShell();
708 // Wait for the navigation in the new window to finish, if it hasn't.
709 WaitForLoadStop(new_shell
->web_contents());
710 EXPECT_EQ("/files/navigate_opener.html",
711 new_shell
->web_contents()->GetURL().path());
713 // Should have the same SiteInstance.
714 scoped_refptr
<SiteInstance
> opened_site_instance(
715 new_shell
->web_contents()->GetSiteInstance());
716 EXPECT_EQ(orig_site_instance
, opened_site_instance
);
718 // Now navigate the opened window to a different site.
719 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
720 scoped_refptr
<SiteInstance
> new_site_instance(
721 new_shell
->web_contents()->GetSiteInstance());
722 EXPECT_NE(orig_site_instance
, new_site_instance
);
724 // The original process should still be alive, since it is still used in the
726 RenderProcessHost
* orig_process
= orig_site_instance
->GetProcess();
727 EXPECT_TRUE(orig_process
->HasConnection());
729 // Navigate the first window to a different site as well. The original
730 // process should exit, since all of its views are now swapped out.
731 WindowedNotificationObserver
exit_observer(
732 NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
733 Source
<RenderProcessHost
>(orig_process
));
734 NavigateToURL(shell(), https_server
.GetURL("files/title1.html"));
735 exit_observer
.Wait();
736 scoped_refptr
<SiteInstance
> new_site_instance2(
737 shell()->web_contents()->GetSiteInstance());
738 EXPECT_EQ(new_site_instance
, new_site_instance2
);
741 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
742 // error should not make us ignore future renderer-initiated navigations.
743 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, ClickLinkAfter204Error
) {
744 // Start two servers with different sites.
745 ASSERT_TRUE(test_server()->Start());
746 net::TestServer
https_server(
747 net::TestServer::TYPE_HTTPS
,
748 net::TestServer::kLocalhost
,
749 FilePath(FILE_PATH_LITERAL("content/test/data")));
750 ASSERT_TRUE(https_server
.Start());
752 // Load a page with links that open in a new window.
753 // The links will point to the HTTPS server.
754 std::string replacement_path
;
755 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
756 "files/click-noreferrer-links.html",
757 https_server
.host_port_pair(),
759 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
761 // Get the original SiteInstance for later comparison.
762 scoped_refptr
<SiteInstance
> orig_site_instance(
763 shell()->web_contents()->GetSiteInstance());
764 EXPECT_TRUE(orig_site_instance
!= NULL
);
766 // Load a cross-site page that fails with a 204 error.
767 NavigateToURL(shell(), https_server
.GetURL("nocontent"));
769 // We should still be looking at the normal page. The typed URL will
770 // still be visible until the user clears it manually, but the last
771 // committed URL will be the previous page.
772 scoped_refptr
<SiteInstance
> post_nav_site_instance(
773 shell()->web_contents()->GetSiteInstance());
774 EXPECT_EQ(orig_site_instance
, post_nav_site_instance
);
775 EXPECT_EQ("/nocontent", shell()->web_contents()->GetURL().path());
776 EXPECT_EQ("/files/click-noreferrer-links.html",
777 shell()->web_contents()->GetController().
778 GetLastCommittedEntry()->GetVirtualURL().path());
780 // Renderer-initiated navigations should work.
781 bool success
= false;
782 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
783 shell()->web_contents()->GetRenderViewHost(), L
"",
784 L
"window.domAutomationController.send(clickNoRefLink());",
786 EXPECT_TRUE(success
);
788 // Wait for the cross-site transition in the current tab to finish.
789 WaitForLoadStop(shell()->web_contents());
791 // Opens in same tab.
792 EXPECT_EQ(1u, Shell::windows().size());
793 EXPECT_EQ("/files/title2.html", shell()->web_contents()->GetURL().path());
795 // Should have the same SiteInstance.
796 scoped_refptr
<SiteInstance
> noref_site_instance(
797 shell()->web_contents()->GetSiteInstance());
798 EXPECT_EQ(orig_site_instance
, noref_site_instance
);
801 // Test for http://crbug.com/93427. Ensure that cross-site navigations
802 // do not cause back/forward navigations to be considered stale by the
804 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, BackForwardNotStale
) {
805 NavigateToURL(shell(), GURL(chrome::kAboutBlankURL
));
807 // Start two servers with different sites.
808 ASSERT_TRUE(test_server()->Start());
809 net::TestServer
https_server(
810 net::TestServer::TYPE_HTTPS
,
811 net::TestServer::kLocalhost
,
812 FilePath(FILE_PATH_LITERAL("content/test/data")));
813 ASSERT_TRUE(https_server
.Start());
815 // Visit a page on first site.
816 std::string replacement_path_a1
;
817 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
819 test_server()->host_port_pair(),
820 &replacement_path_a1
));
821 NavigateToURL(shell(), test_server()->GetURL(replacement_path_a1
));
823 // Visit three pages on second site.
824 std::string replacement_path_b1
;
825 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
827 https_server
.host_port_pair(),
828 &replacement_path_b1
));
829 NavigateToURL(shell(), https_server
.GetURL(replacement_path_b1
));
830 std::string replacement_path_b2
;
831 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
833 https_server
.host_port_pair(),
834 &replacement_path_b2
));
835 NavigateToURL(shell(), https_server
.GetURL(replacement_path_b2
));
836 std::string replacement_path_b3
;
837 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
839 https_server
.host_port_pair(),
840 &replacement_path_b3
));
841 NavigateToURL(shell(), https_server
.GetURL(replacement_path_b3
));
843 // History is now [blank, A1, B1, B2, *B3].
844 WebContents
* contents
= shell()->web_contents();
845 EXPECT_EQ(5, contents
->GetController().GetEntryCount());
847 // Open another window in same process to keep this process alive.
848 Shell
* new_shell
= CreateBrowser();
849 NavigateToURL(new_shell
, https_server
.GetURL(replacement_path_b1
));
851 // Go back three times to first site.
853 WindowedNotificationObserver
back_nav_load_observer(
854 NOTIFICATION_NAV_ENTRY_COMMITTED
,
855 Source
<NavigationController
>(
856 &contents
->GetController()));
857 shell()->web_contents()->GetController().GoBack();
858 back_nav_load_observer
.Wait();
861 WindowedNotificationObserver
back_nav_load_observer(
862 NOTIFICATION_NAV_ENTRY_COMMITTED
,
863 Source
<NavigationController
>(
864 &contents
->GetController()));
865 shell()->web_contents()->GetController().GoBack();
866 back_nav_load_observer
.Wait();
869 WindowedNotificationObserver
back_nav_load_observer(
870 NOTIFICATION_NAV_ENTRY_COMMITTED
,
871 Source
<NavigationController
>(&contents
->GetController()));
872 shell()->web_contents()->GetController().GoBack();
873 back_nav_load_observer
.Wait();
876 // Now go forward twice to B2. Shouldn't be left spinning.
878 WindowedNotificationObserver
forward_nav_load_observer(
879 NOTIFICATION_NAV_ENTRY_COMMITTED
,
880 Source
<NavigationController
>(&contents
->GetController()));
881 shell()->web_contents()->GetController().GoForward();
882 forward_nav_load_observer
.Wait();
885 WindowedNotificationObserver
forward_nav_load_observer(
886 NOTIFICATION_NAV_ENTRY_COMMITTED
,
887 Source
<NavigationController
>(&contents
->GetController()));
888 shell()->web_contents()->GetController().GoForward();
889 forward_nav_load_observer
.Wait();
892 // Go back twice to first site.
894 WindowedNotificationObserver
back_nav_load_observer(
895 NOTIFICATION_NAV_ENTRY_COMMITTED
,
896 Source
<NavigationController
>(&contents
->GetController()));
897 shell()->web_contents()->GetController().GoBack();
898 back_nav_load_observer
.Wait();
901 WindowedNotificationObserver
back_nav_load_observer(
902 NOTIFICATION_NAV_ENTRY_COMMITTED
,
903 Source
<NavigationController
>(&contents
->GetController()));
904 shell()->web_contents()->GetController().GoBack();
905 back_nav_load_observer
.Wait();
908 // Now go forward directly to B3. Shouldn't be left spinning.
910 WindowedNotificationObserver
forward_nav_load_observer(
911 NOTIFICATION_NAV_ENTRY_COMMITTED
,
912 Source
<NavigationController
>(&contents
->GetController()));
913 shell()->web_contents()->GetController().GoToIndex(4);
914 forward_nav_load_observer
.Wait();
918 // Test for http://crbug.com/130016.
919 // Swapping out a render view should update its visiblity state.
920 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
921 SwappedOutViewHasCorrectVisibilityState
) {
922 // Start two servers with different sites.
923 ASSERT_TRUE(test_server()->Start());
924 net::TestServer
https_server(
925 net::TestServer::TYPE_HTTPS
,
926 net::TestServer::kLocalhost
,
927 FilePath(FILE_PATH_LITERAL("content/test/data")));
928 ASSERT_TRUE(https_server
.Start());
930 // Load a page with links that open in a new window.
931 std::string replacement_path
;
932 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
933 "files/click-noreferrer-links.html",
934 https_server
.host_port_pair(),
936 NavigateToURL(shell(), test_server()->GetURL(replacement_path
));
938 // Open a same-site link in a new widnow.
939 ShellAddedObserver new_shell_observer
;
940 bool success
= false;
941 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
942 shell()->web_contents()->GetRenderViewHost(), L
"",
943 L
"window.domAutomationController.send(clickSameSiteTargetedLink());",
945 EXPECT_TRUE(success
);
946 Shell
* new_shell
= new_shell_observer
.GetShell();
948 // Wait for the navigation in the new tab to finish, if it hasn't.
949 WaitForLoadStop(new_shell
->web_contents());
950 EXPECT_EQ("/files/navigate_opener.html",
951 new_shell
->web_contents()->GetURL().path());
953 RenderViewHost
* rvh
= new_shell
->web_contents()->GetRenderViewHost();
954 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
956 L
"window.domAutomationController.send("
957 L
"document.webkitVisibilityState == 'visible');",
959 EXPECT_TRUE(success
);
961 // Now navigate the new window to a different site. This should swap out the
962 // tab's existing RenderView, causing it become hidden.
963 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
965 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
967 L
"window.domAutomationController.send("
968 L
"document.webkitVisibilityState == 'hidden');",
970 EXPECT_TRUE(success
);
972 // Going back should make the previously swapped-out view to become visible
975 WindowedNotificationObserver
back_nav_load_observer(
976 NOTIFICATION_NAV_ENTRY_COMMITTED
,
977 Source
<NavigationController
>(
978 &new_shell
->web_contents()->GetController()));
979 new_shell
->web_contents()->GetController().GoBack();
980 back_nav_load_observer
.Wait();
984 EXPECT_EQ("/files/navigate_opener.html",
985 new_shell
->web_contents()->GetURL().path());
987 EXPECT_EQ(rvh
, new_shell
->web_contents()->GetRenderViewHost());
989 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
991 L
"window.domAutomationController.send("
992 L
"document.webkitVisibilityState == 'visible');",
994 EXPECT_TRUE(success
);
997 // This class holds onto RenderViewHostObservers for as long as their observed
998 // RenderViewHosts are alive. This allows us to confirm that all hosts have
999 // properly been shutdown.
1000 class RenderViewHostObserverArray
{
1002 ~RenderViewHostObserverArray() {
1003 // In case some would be left in there with a dead pointer to us.
1004 for (std::list
<RVHObserver
*>::iterator iter
= observers_
.begin();
1005 iter
!= observers_
.end(); ++iter
) {
1006 (*iter
)->ClearParent();
1009 void AddObserverToRVH(RenderViewHost
* rvh
) {
1010 observers_
.push_back(new RVHObserver(this, rvh
));
1012 size_t GetNumObservers() const {
1013 return observers_
.size();
1016 friend class RVHObserver
;
1017 class RVHObserver
: public RenderViewHostObserver
{
1019 RVHObserver(RenderViewHostObserverArray
* parent
, RenderViewHost
* rvh
)
1020 : RenderViewHostObserver(rvh
),
1023 virtual void RenderViewHostDestroyed(RenderViewHost
* rvh
) OVERRIDE
{
1025 parent_
->RemoveObserver(this);
1026 RenderViewHostObserver::RenderViewHostDestroyed(rvh
);
1028 void ClearParent() {
1032 RenderViewHostObserverArray
* parent_
;
1035 void RemoveObserver(RVHObserver
* observer
) {
1036 observers_
.remove(observer
);
1039 std::list
<RVHObserver
*> observers_
;
1042 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1043 // they may cause crashes or memory corruptions when trying to call dead
1044 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1045 // ensure that a separate SiteInstance is created when navigating to view-source
1046 // URLs, regardless of current URL.
1047 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, LeakingRenderViewHosts
) {
1048 // Start two servers with different sites.
1049 ASSERT_TRUE(test_server()->Start());
1050 net::TestServer
https_server(
1051 net::TestServer::TYPE_HTTPS
,
1052 net::TestServer::kLocalhost
,
1053 FilePath(FILE_PATH_LITERAL("content/test/data")));
1054 ASSERT_TRUE(https_server
.Start());
1056 // Observe the created render_view_host's to make sure they will not leak.
1057 RenderViewHostObserverArray rvh_observers
;
1059 GURL
navigated_url(test_server()->GetURL("files/title2.html"));
1060 GURL
view_source_url(chrome::kViewSourceScheme
+ std::string(":") +
1061 navigated_url
.spec());
1063 // Let's ensure that when we start with a blank window, navigating away to a
1064 // view-source URL, we create a new SiteInstance.
1065 RenderViewHost
* blank_rvh
= shell()->web_contents()->
1066 GetRenderViewHost();
1067 SiteInstance
* blank_site_instance
= blank_rvh
->GetSiteInstance();
1068 EXPECT_EQ(shell()->web_contents()->GetURL(), GURL::EmptyGURL());
1069 EXPECT_EQ(blank_site_instance
->GetSiteURL(), GURL::EmptyGURL());
1070 rvh_observers
.AddObserverToRVH(blank_rvh
);
1072 // Now navigate to the view-source URL and ensure we got a different
1073 // SiteInstance and RenderViewHost.
1074 NavigateToURL(shell(), view_source_url
);
1075 EXPECT_NE(blank_rvh
, shell()->web_contents()->GetRenderViewHost());
1076 EXPECT_NE(blank_site_instance
, shell()->web_contents()->
1077 GetRenderViewHost()->GetSiteInstance());
1078 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1080 // Load a random page and then navigate to view-source: of it.
1081 // This used to cause two RVH instances for the same SiteInstance, which
1082 // was a problem. This is no longer the case.
1083 NavigateToURL(shell(), navigated_url
);
1084 SiteInstance
* site_instance1
= shell()->web_contents()->
1085 GetRenderViewHost()->GetSiteInstance();
1086 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1088 NavigateToURL(shell(), view_source_url
);
1089 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1090 SiteInstance
* site_instance2
= shell()->web_contents()->
1091 GetRenderViewHost()->GetSiteInstance();
1093 // Ensure that view-source navigations force a new SiteInstance.
1094 EXPECT_NE(site_instance1
, site_instance2
);
1096 // Now navigate to a different instance so that we swap out again.
1097 NavigateToURL(shell(), https_server
.GetURL("files/title2.html"));
1098 rvh_observers
.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
1100 // This used to leak a render view host.
1103 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1105 EXPECT_EQ(0U, rvh_observers
.GetNumObservers());
1108 // Test for correct propagation of the frame hierarchy across processes in the
1109 // same BrowsingInstance. The test starts by navigating to a page that has
1110 // multiple nested frames. It then opens two windows and navigates each one
1111 // to a separate site, so at the end we have 3 SiteInstances. The opened
1112 // windows have swapped out RenderViews corresponding to the opener, so those
1113 // swapped out views must have a matching frame hierarchy. The test checks
1114 // that frame hierarchies are kept in sync through navigations, reloading, and
1115 // JavaScript manipulation of the frame tree.
1117 // Disable the test until http://crbug.com/153701 is fixed.
1118 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
, DISABLED_FrameTreeUpdates
) {
1119 // Start two servers to allow using different sites.
1120 EXPECT_TRUE(test_server()->Start());
1121 net::TestServer
https_server(
1122 net::TestServer::TYPE_HTTPS
,
1123 net::TestServer::kLocalhost
,
1124 FilePath(FILE_PATH_LITERAL("content/test/data")));
1125 EXPECT_TRUE(https_server
.Start());
1127 GURL
frame_tree_url(test_server()->GetURL("files/frame_tree/top.html"));
1129 // Replace the 127.0.0.1 with localhost, which will give us a different
1131 GURL::Replacements replacements
;
1132 std::string
new_host("localhost");
1133 replacements
.SetHostStr(new_host
);
1134 GURL remote_frame
= test_server()->GetURL(
1135 "files/frame_tree/1-1.html").ReplaceComponents(replacements
);
1137 bool success
= false;
1138 base::DictionaryValue
* frames
= NULL
;
1139 base::ListValue
* subtree
= NULL
;
1141 // First navigate to a page with no frames and ensure the frame tree has no
1143 NavigateToURL(shell(), test_server()->GetURL("files/simple_page.html"));
1144 WebContents
* opener_contents
= shell()->web_contents();
1145 RenderViewHostManager
* opener_rvhm
= static_cast<WebContentsImpl
*>(
1146 opener_contents
)->GetRenderManagerForTesting();
1147 frames
= GetTree(opener_rvhm
->current_host());
1148 EXPECT_FALSE(frames
->GetList(kFrameTreeNodeSubtreeKey
, &subtree
));
1150 NavigateToURL(shell(), frame_tree_url
);
1151 frames
= GetTree(opener_rvhm
->current_host());
1152 EXPECT_TRUE(frames
->GetList(kFrameTreeNodeSubtreeKey
, &subtree
));
1153 EXPECT_TRUE(subtree
->GetSize() == 3);
1155 scoped_refptr
<SiteInstance
> orig_site_instance(
1156 opener_contents
->GetSiteInstance());
1157 EXPECT_TRUE(orig_site_instance
!= NULL
);
1159 ShellAddedObserver shell_observer1
;
1160 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
1161 opener_contents
->GetRenderViewHost(), L
"",
1162 L
"window.domAutomationController.send(openWindow('1-3.html'));",
1164 EXPECT_TRUE(success
);
1166 Shell
* shell1
= shell_observer1
.GetShell();
1167 WebContents
* contents1
= shell1
->web_contents();
1168 WaitForLoadStop(contents1
);
1169 RenderViewHostManager
* rvhm1
= static_cast<WebContentsImpl
*>(
1170 contents1
)->GetRenderManagerForTesting();
1171 EXPECT_EQ("/files/frame_tree/1-3.html", contents1
->GetURL().path());
1173 // Now navigate the new window to a different SiteInstance.
1174 NavigateToURL(shell1
, https_server
.GetURL("files/title1.html"));
1175 EXPECT_EQ("/files/title1.html", contents1
->GetURL().path());
1176 scoped_refptr
<SiteInstance
> site_instance1(
1177 contents1
->GetSiteInstance());
1178 EXPECT_NE(orig_site_instance
, site_instance1
);
1180 ShellAddedObserver shell_observer2
;
1181 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
1182 opener_contents
->GetRenderViewHost(), L
"",
1183 L
"window.domAutomationController.send(openWindow('../title2.html'));",
1185 EXPECT_TRUE(success
);
1187 Shell
* shell2
= shell_observer2
.GetShell();
1188 WebContents
* contents2
= shell2
->web_contents();
1189 WaitForLoadStop(contents2
);
1190 EXPECT_EQ("/files/title2.html", contents2
->GetURL().path());
1192 // Navigate the second new window to a different SiteInstance as well.
1193 NavigateToURL(shell2
, remote_frame
);
1194 EXPECT_EQ("/files/frame_tree/1-1.html", contents2
->GetURL().path());
1195 scoped_refptr
<SiteInstance
> site_instance2(
1196 contents2
->GetSiteInstance());
1197 EXPECT_NE(orig_site_instance
, site_instance2
);
1198 EXPECT_NE(site_instance1
, site_instance2
);
1200 RenderViewHostManager
* rvhm2
= static_cast<WebContentsImpl
*>(
1201 contents2
)->GetRenderManagerForTesting();
1203 EXPECT_TRUE(CompareTrees(
1204 GetTree(opener_rvhm
->current_host()),
1205 GetTree(opener_rvhm
->GetSwappedOutRenderViewHost(site_instance1
))));
1206 EXPECT_TRUE(CompareTrees(
1207 GetTree(opener_rvhm
->current_host()),
1208 GetTree(opener_rvhm
->GetSwappedOutRenderViewHost(site_instance2
))));
1210 EXPECT_TRUE(CompareTrees(
1211 GetTree(rvhm1
->current_host()),
1212 GetTree(rvhm1
->GetSwappedOutRenderViewHost(orig_site_instance
))));
1213 EXPECT_TRUE(CompareTrees(
1214 GetTree(rvhm2
->current_host()),
1215 GetTree(rvhm2
->GetSwappedOutRenderViewHost(orig_site_instance
))));
1217 // Verify that the frame trees from different windows aren't equal.
1218 EXPECT_FALSE(CompareTrees(
1219 GetTree(opener_rvhm
->current_host()), GetTree(rvhm1
->current_host())));
1220 EXPECT_FALSE(CompareTrees(
1221 GetTree(opener_rvhm
->current_host()), GetTree(rvhm2
->current_host())));
1223 // Reload the original page, which will cause subframe ids to change. This
1224 // will ensure that the ids are properly replicated across reload.
1225 NavigateToURL(shell(), frame_tree_url
);
1227 EXPECT_TRUE(CompareTrees(
1228 GetTree(opener_rvhm
->current_host()),
1229 GetTree(opener_rvhm
->GetSwappedOutRenderViewHost(site_instance1
))));
1230 EXPECT_TRUE(CompareTrees(
1231 GetTree(opener_rvhm
->current_host()),
1232 GetTree(opener_rvhm
->GetSwappedOutRenderViewHost(site_instance2
))));
1234 EXPECT_FALSE(CompareTrees(
1235 GetTree(opener_rvhm
->current_host()), GetTree(rvhm1
->current_host())));
1236 EXPECT_FALSE(CompareTrees(
1237 GetTree(opener_rvhm
->current_host()), GetTree(rvhm2
->current_host())));
1239 // Now let's ensure that using JS to add/remove frames results in proper
1241 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
1242 opener_contents
->GetRenderViewHost(), L
"",
1243 L
"window.domAutomationController.send(removeFrame());",
1245 EXPECT_TRUE(success
);
1246 frames
= GetTree(opener_rvhm
->current_host());
1247 EXPECT_TRUE(frames
->GetList(kFrameTreeNodeSubtreeKey
, &subtree
));
1248 EXPECT_EQ(subtree
->GetSize(), 2U);
1250 // Create a load observer for the iframe that will be created by the
1251 // JavaScript code we will execute.
1252 WindowedNotificationObserver
load_observer(
1253 NOTIFICATION_LOAD_STOP
,
1254 Source
<NavigationController
>(
1255 &opener_contents
->GetController()));
1256 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
1257 opener_contents
->GetRenderViewHost(), L
"",
1258 L
"window.domAutomationController.send(addFrame());",
1260 EXPECT_TRUE(success
);
1261 load_observer
.Wait();
1263 frames
= GetTree(opener_rvhm
->current_host());
1264 EXPECT_TRUE(frames
->GetList(kFrameTreeNodeSubtreeKey
, &subtree
));
1265 EXPECT_EQ(subtree
->GetSize(), 3U);
1267 EXPECT_TRUE(CompareTrees(
1268 GetTree(opener_rvhm
->current_host()),
1269 GetTree(opener_rvhm
->GetSwappedOutRenderViewHost(site_instance1
))));
1270 EXPECT_TRUE(CompareTrees(
1271 GetTree(opener_rvhm
->current_host()),
1272 GetTree(opener_rvhm
->GetSwappedOutRenderViewHost(site_instance2
))));
1275 // Test for crbug.com/143155. Frame tree updates during unload should not
1276 // interrupt the intended navigation and show swappedout:// instead.
1278 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1279 // 2) Send the second tab to a different HTTPS SiteInstance.
1280 // This creates a swapped out opener for the first tab in the HTTPS process.
1281 // 3) Navigate the first tab to the HTTPS SiteInstance, and have the first
1282 // tab's unload handler remove its frame.
1283 // This used to cause an update to the frame tree of the swapped out RV,
1284 // just as it was navigating to a real page. That pre-empted the real
1285 // navigation and visibly sent the tab to swappedout://.
1286 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest
,
1287 DontPreemptNavigationWithFrameTreeUpdate
) {
1288 // Start two servers with different sites.
1289 ASSERT_TRUE(test_server()->Start());
1290 net::TestServer
https_server(
1291 net::TestServer::TYPE_HTTPS
,
1292 net::TestServer::kLocalhost
,
1293 FilePath(FILE_PATH_LITERAL("content/test/data")));
1294 ASSERT_TRUE(https_server
.Start());
1296 // 1. Load a page that deletes its iframe during unload.
1297 NavigateToURL(shell(),
1298 test_server()->GetURL("files/remove_frame_on_unload.html"));
1300 // Get the original SiteInstance for later comparison.
1301 scoped_refptr
<SiteInstance
> orig_site_instance(
1302 shell()->web_contents()->GetSiteInstance());
1304 // Open a same-site page in a new window.
1305 ShellAddedObserver new_shell_observer
;
1306 bool success
= false;
1307 EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
1308 shell()->web_contents()->GetRenderViewHost(), L
"",
1309 L
"window.domAutomationController.send(openWindow());",
1311 EXPECT_TRUE(success
);
1312 Shell
* new_shell
= new_shell_observer
.GetShell();
1314 // Wait for the navigation in the new window to finish, if it hasn't.
1315 WaitForLoadStop(new_shell
->web_contents());
1316 EXPECT_EQ("/files/title1.html",
1317 new_shell
->web_contents()->GetURL().path());
1319 // Should have the same SiteInstance.
1320 EXPECT_EQ(orig_site_instance
, new_shell
->web_contents()->GetSiteInstance());
1322 // 2. Send the second tab to a different process.
1323 NavigateToURL(new_shell
, https_server
.GetURL("files/title1.html"));
1324 scoped_refptr
<SiteInstance
> new_site_instance(
1325 new_shell
->web_contents()->GetSiteInstance());
1326 EXPECT_NE(orig_site_instance
, new_site_instance
);
1328 // 3. Send the first tab to the second tab's process.
1329 NavigateToURL(shell(), https_server
.GetURL("files/title1.html"));
1331 // Make sure it ends up at the right page.
1332 WaitForLoadStop(shell()->web_contents());
1333 EXPECT_EQ(https_server
.GetURL("files/title1.html"),
1334 shell()->web_contents()->GetURL());
1335 EXPECT_EQ(new_site_instance
, shell()->web_contents()->GetSiteInstance());
1338 } // namespace content