Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / render_view_host_manager_browsertest.cc
blobdee6fb6f98b4ab78f27b52e0bf94c17dfd30fe9c
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"
34 namespace content {
36 class RenderViewHostManagerTest : public ContentBrowserTest {
37 public:
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(),
67 &replacement_path));
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;
77 bool success = false;
78 EXPECT_TRUE(ExecuteScriptAndExtractBool(
79 shell()->web_contents(),
80 "window.domAutomationController.send(clickSameSiteTargetedLink());",
81 &success));
82 EXPECT_TRUE(success);
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.
96 success = false;
97 EXPECT_TRUE(ExecuteScriptAndExtractBool(
98 shell()->web_contents(),
99 "window.domAutomationController.send(testScriptAccessToWindow());",
100 &success));
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.
110 success = false;
111 EXPECT_TRUE(ExecuteScriptAndExtractBool(
112 shell()->web_contents(),
113 "window.domAutomationController.send(testScriptAccessToWindow());",
114 &success));
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(),
135 &replacement_path));
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());",
149 &success));
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
172 // targets.
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(),
188 &replacement_path));
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());",
202 &success));
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(),
241 &replacement_path));
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());",
255 &success));
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(),
289 &replacement_path));
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());",
302 &success));
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);
318 namespace {
320 class WebContentsDestroyedObserver : public WebContentsObserver {
321 public:
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 {
329 callback_.Run();
332 private:
333 base::Closure callback_;
335 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedObserver);
338 } // namespace
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(),
357 &replacement_path));
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());",
371 &success));
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());",
396 &success));
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());",
416 &success));
417 EXPECT_TRUE(success);
418 loop_runner->Run();
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(),
437 &replacement_path));
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());",
451 &success));
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();
481 success = false;
482 EXPECT_TRUE(ExecuteScriptAndExtractBool(
483 new_shell->web_contents(),
484 "window.domAutomationController.send(window.opener == null);",
485 &success));
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"));
490 success = false;
491 EXPECT_TRUE(ExecuteScriptAndExtractBool(
492 new_shell->web_contents(),
493 "window.domAutomationController.send(window.opener == null);",
494 &success));
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.
514 // Specifically:
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(),
536 &replacement_path));
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(
554 opener_contents,
555 "window.domAutomationController.send(clickSameSiteTargetedLink());",
556 &success));
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());",
575 &success));
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());
592 EXPECT_TRUE(
593 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
594 EXPECT_FALSE(
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(
601 foo_contents,
602 "window.domAutomationController.send(postToOpener('msg',"
603 " 'http://google.com'));",
604 &success));
605 EXPECT_TRUE(success);
606 ASSERT_FALSE(
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(
615 foo_contents,
616 "window.domAutomationController.send(postToOpener('msg','*'));",
617 &success));
618 EXPECT_TRUE(success);
619 ASSERT_FALSE(
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(
627 opener_contents,
628 "window.domAutomationController.send(window.receivedMessages);",
629 &opener_received_messages));
630 int foo_received_messages = 0;
631 EXPECT_TRUE(ExecuteScriptAndExtractInt(
632 foo_contents,
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(
645 new_contents,
646 "window.domAutomationController.send(postToFoo('msg2'));",
647 &success));
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.
654 EXPECT_TRUE(
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(),
678 &replacement_path));
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(
691 orig_contents,
692 "window.domAutomationController.send(clickSameSiteTargetedLink());",
693 &success));
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());",
718 &success));
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(),
746 &replacement_path));
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());",
760 &success));
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
781 // first window.
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(),
814 &replacement_path));
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());",
841 &success));
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.
865 NavigateToURL(
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(
873 orig_contents,
874 "window.domAutomationController.send(clickNoContentTargetedLink());",
875 &success));
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));
893 success = false;
894 EXPECT_TRUE(ExecuteScriptAndExtractBool(
895 orig_contents,
896 "window.domAutomationController.send(modifyNewWindow());",
897 &success));
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
904 // bar.
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.
917 NavigateToURL(
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(
927 orig_contents,
928 "window.domAutomationController.send("
929 "clickNoContentScriptedTargetedLink());",
930 &success));
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
937 // navigation.
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
945 // renderer.
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(
960 "files/title1.html",
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(
968 "files/title1.html",
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(
974 "files/title2.html",
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(
980 "files/title3.html",
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());",
1068 &success));
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(
1080 rvh,
1081 "window.domAutomationController.send("
1082 " document.webkitVisibilityState == 'visible');",
1083 &success));
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(
1091 rvh,
1092 "window.domAutomationController.send("
1093 " document.webkitVisibilityState == 'hidden');",
1094 &success));
1095 EXPECT_TRUE(success);
1097 // Going back should make the previously swapped-out view to become visible
1098 // again.
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(
1111 rvh,
1112 "window.domAutomationController.send("
1113 " document.webkitVisibilityState == 'visible');",
1114 &success));
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 {
1122 public:
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();
1137 private:
1138 friend class RVHObserver;
1139 class RVHObserver : public RenderViewHostObserver {
1140 public:
1141 RVHObserver(RenderViewHostObserverArray* parent, RenderViewHost* rvh)
1142 : RenderViewHostObserver(rvh),
1143 parent_(parent) {
1145 virtual void RenderViewHostDestroyed(RenderViewHost* rvh) OVERRIDE {
1146 if (parent_)
1147 parent_->RemoveObserver(this);
1148 RenderViewHostObserver::RenderViewHostDestroyed(rvh);
1150 void ClearParent() {
1151 parent_ = NULL;
1153 private:
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.
1222 shell()->Close();
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.
1231 // Specifically:
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());",
1264 &success));
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