Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blob34021e7d12448523a1ef983e72df630651d9076e
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <set>
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/path_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "content/browser/child_process_security_policy_impl.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/browser/webui/web_ui_impl.h"
18 #include "content/common/content_constants_internal.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/common/bindings_policy.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/url_constants.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "content/public/test/content_browser_test.h"
29 #include "content/public/test/content_browser_test_utils.h"
30 #include "content/public/test/test_navigation_observer.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/shell/browser/shell.h"
33 #include "net/base/net_util.h"
34 #include "net/dns/mock_host_resolver.h"
35 #include "net/test/spawned_test_server/spawned_test_server.h"
37 using base::ASCIIToUTF16;
39 namespace content {
41 namespace {
43 const char kOpenUrlViaClickTargetFunc[] =
44 "(function(url) {\n"
45 " var lnk = document.createElement(\"a\");\n"
46 " lnk.href = url;\n"
47 " lnk.target = \"_blank\";\n"
48 " document.body.appendChild(lnk);\n"
49 " lnk.click();\n"
50 "})";
52 // Adds a link with given url and target=_blank, and clicks on it.
53 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter,
54 const GURL& url) {
55 EXPECT_TRUE(ExecuteScript(adapter,
56 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
59 } // anonymous namespace
61 class RenderFrameHostManagerTest : public ContentBrowserTest {
62 public:
63 RenderFrameHostManagerTest() : foo_com_("foo.com") {
64 replace_host_.SetHostStr(foo_com_);
67 static bool GetFilePathWithHostAndPortReplacement(
68 const std::string& original_file_path,
69 const net::HostPortPair& host_port_pair,
70 std::string* replacement_path) {
71 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
72 replacement_text.push_back(
73 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
74 return net::SpawnedTestServer::GetFilePathWithReplacements(
75 original_file_path, replacement_text, replacement_path);
78 void StartServer() {
79 // Support multiple sites on the test server.
80 host_resolver()->AddRule("*", "127.0.0.1");
81 ASSERT_TRUE(test_server()->Start());
83 foo_host_port_ = test_server()->host_port_pair();
84 foo_host_port_.set_host(foo_com_);
87 // Returns a URL on foo.com with the given path.
88 GURL GetCrossSiteURL(const std::string& path) {
89 GURL cross_site_url(test_server()->GetURL(path));
90 return cross_site_url.ReplaceComponents(replace_host_);
93 protected:
94 std::string foo_com_;
95 GURL::Replacements replace_host_;
96 net::HostPortPair foo_host_port_;
99 // Web pages should not have script access to the swapped out page.
100 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
101 StartServer();
103 // Load a page with links that open in a new window.
104 std::string replacement_path;
105 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
106 "files/click-noreferrer-links.html",
107 foo_host_port_,
108 &replacement_path));
109 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
111 // Get the original SiteInstance for later comparison.
112 scoped_refptr<SiteInstance> orig_site_instance(
113 shell()->web_contents()->GetSiteInstance());
114 EXPECT_TRUE(orig_site_instance.get() != NULL);
116 // Open a same-site link in a new window.
117 ShellAddedObserver new_shell_observer;
118 bool success = false;
119 EXPECT_TRUE(ExecuteScriptAndExtractBool(
120 shell()->web_contents(),
121 "window.domAutomationController.send(clickSameSiteTargetedLink());",
122 &success));
123 EXPECT_TRUE(success);
124 Shell* new_shell = new_shell_observer.GetShell();
126 // Wait for the navigation in the new window to finish, if it hasn't.
127 WaitForLoadStop(new_shell->web_contents());
128 EXPECT_EQ("/files/navigate_opener.html",
129 new_shell->web_contents()->GetLastCommittedURL().path());
131 // Should have the same SiteInstance.
132 scoped_refptr<SiteInstance> blank_site_instance(
133 new_shell->web_contents()->GetSiteInstance());
134 EXPECT_EQ(orig_site_instance, blank_site_instance);
136 // We should have access to the opened window's location.
137 success = false;
138 EXPECT_TRUE(ExecuteScriptAndExtractBool(
139 shell()->web_contents(),
140 "window.domAutomationController.send(testScriptAccessToWindow());",
141 &success));
142 EXPECT_TRUE(success);
144 // Now navigate the new window to a different site.
145 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
146 scoped_refptr<SiteInstance> new_site_instance(
147 new_shell->web_contents()->GetSiteInstance());
148 EXPECT_NE(orig_site_instance, new_site_instance);
150 // We should no longer have script access to the opened window's location.
151 success = false;
152 EXPECT_TRUE(ExecuteScriptAndExtractBool(
153 shell()->web_contents(),
154 "window.domAutomationController.send(testScriptAccessToWindow());",
155 &success));
156 EXPECT_FALSE(success);
159 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
160 // and target=_blank should create a new SiteInstance.
161 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
162 SwapProcessWithRelNoreferrerAndTargetBlank) {
163 StartServer();
165 // Load a page with links that open in a new window.
166 std::string replacement_path;
167 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
168 "files/click-noreferrer-links.html",
169 foo_host_port_,
170 &replacement_path));
171 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
173 // Get the original SiteInstance for later comparison.
174 scoped_refptr<SiteInstance> orig_site_instance(
175 shell()->web_contents()->GetSiteInstance());
176 EXPECT_TRUE(orig_site_instance.get() != NULL);
178 // Test clicking a rel=noreferrer + target=blank link.
179 ShellAddedObserver new_shell_observer;
180 bool success = false;
181 EXPECT_TRUE(ExecuteScriptAndExtractBool(
182 shell()->web_contents(),
183 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
184 &success));
185 EXPECT_TRUE(success);
187 // Wait for the window to open.
188 Shell* new_shell = new_shell_observer.GetShell();
190 EXPECT_EQ("/files/title2.html",
191 new_shell->web_contents()->GetVisibleURL().path());
193 // Wait for the cross-site transition in the new tab to finish.
194 WaitForLoadStop(new_shell->web_contents());
195 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
196 new_shell->web_contents());
197 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
198 pending_render_view_host());
200 // Should have a new SiteInstance.
201 scoped_refptr<SiteInstance> noref_blank_site_instance(
202 new_shell->web_contents()->GetSiteInstance());
203 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
206 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
207 // for rel=noreferrer links in new windows, even to same site pages and named
208 // targets.
209 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
210 SwapProcessWithSameSiteRelNoreferrer) {
211 StartServer();
213 // Load a page with links that open in a new window.
214 std::string replacement_path;
215 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
216 "files/click-noreferrer-links.html",
217 foo_host_port_,
218 &replacement_path));
219 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
221 // Get the original SiteInstance for later comparison.
222 scoped_refptr<SiteInstance> orig_site_instance(
223 shell()->web_contents()->GetSiteInstance());
224 EXPECT_TRUE(orig_site_instance.get() != NULL);
226 // Test clicking a same-site rel=noreferrer + target=foo link.
227 ShellAddedObserver new_shell_observer;
228 bool success = false;
229 EXPECT_TRUE(ExecuteScriptAndExtractBool(
230 shell()->web_contents(),
231 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
232 &success));
233 EXPECT_TRUE(success);
235 // Wait for the window to open.
236 Shell* new_shell = new_shell_observer.GetShell();
238 // Opens in new window.
239 EXPECT_EQ("/files/title2.html",
240 new_shell->web_contents()->GetVisibleURL().path());
242 // Wait for the cross-site transition in the new tab to finish.
243 WaitForLoadStop(new_shell->web_contents());
244 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
245 new_shell->web_contents());
246 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
247 pending_render_view_host());
249 // Should have a new SiteInstance (in a new BrowsingInstance).
250 scoped_refptr<SiteInstance> noref_blank_site_instance(
251 new_shell->web_contents()->GetSiteInstance());
252 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
255 // Test for crbug.com/24447. Following a cross-site link with just
256 // target=_blank should not create a new SiteInstance.
257 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
258 DontSwapProcessWithOnlyTargetBlank) {
259 StartServer();
261 // Load a page with links that open in a new window.
262 std::string replacement_path;
263 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
264 "files/click-noreferrer-links.html",
265 foo_host_port_,
266 &replacement_path));
267 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
269 // Get the original SiteInstance for later comparison.
270 scoped_refptr<SiteInstance> orig_site_instance(
271 shell()->web_contents()->GetSiteInstance());
272 EXPECT_TRUE(orig_site_instance.get() != NULL);
274 // Test clicking a target=blank link.
275 ShellAddedObserver new_shell_observer;
276 bool success = false;
277 EXPECT_TRUE(ExecuteScriptAndExtractBool(
278 shell()->web_contents(),
279 "window.domAutomationController.send(clickTargetBlankLink());",
280 &success));
281 EXPECT_TRUE(success);
283 // Wait for the window to open.
284 Shell* new_shell = new_shell_observer.GetShell();
286 // Wait for the cross-site transition in the new tab to finish.
287 WaitForLoadStop(new_shell->web_contents());
288 EXPECT_EQ("/files/title2.html",
289 new_shell->web_contents()->GetLastCommittedURL().path());
291 // Should have the same SiteInstance.
292 scoped_refptr<SiteInstance> blank_site_instance(
293 new_shell->web_contents()->GetSiteInstance());
294 EXPECT_EQ(orig_site_instance, blank_site_instance);
297 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
298 // and no target=_blank should not create a new SiteInstance.
299 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
300 DontSwapProcessWithOnlyRelNoreferrer) {
301 StartServer();
303 // Load a page with links that open in a new window.
304 std::string replacement_path;
305 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
306 "files/click-noreferrer-links.html",
307 foo_host_port_,
308 &replacement_path));
309 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
311 // Get the original SiteInstance for later comparison.
312 scoped_refptr<SiteInstance> orig_site_instance(
313 shell()->web_contents()->GetSiteInstance());
314 EXPECT_TRUE(orig_site_instance.get() != NULL);
316 // Test clicking a rel=noreferrer link.
317 bool success = false;
318 EXPECT_TRUE(ExecuteScriptAndExtractBool(
319 shell()->web_contents(),
320 "window.domAutomationController.send(clickNoRefLink());",
321 &success));
322 EXPECT_TRUE(success);
324 // Wait for the cross-site transition in the current tab to finish.
325 WaitForLoadStop(shell()->web_contents());
327 // Opens in same window.
328 EXPECT_EQ(1u, Shell::windows().size());
329 EXPECT_EQ("/files/title2.html",
330 shell()->web_contents()->GetLastCommittedURL().path());
332 // Should have the same SiteInstance.
333 scoped_refptr<SiteInstance> noref_site_instance(
334 shell()->web_contents()->GetSiteInstance());
335 EXPECT_EQ(orig_site_instance, noref_site_instance);
338 // Test for crbug.com/116192. Targeted links should still work after the
339 // named target window has swapped processes.
340 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
341 AllowTargetedNavigationsAfterSwap) {
342 StartServer();
344 // Load a page with links that open in a new window.
345 std::string replacement_path;
346 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
347 "files/click-noreferrer-links.html",
348 foo_host_port_,
349 &replacement_path));
350 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
352 // Get the original SiteInstance for later comparison.
353 scoped_refptr<SiteInstance> orig_site_instance(
354 shell()->web_contents()->GetSiteInstance());
355 EXPECT_TRUE(orig_site_instance.get() != NULL);
357 // Test clicking a target=foo link.
358 ShellAddedObserver new_shell_observer;
359 bool success = false;
360 EXPECT_TRUE(ExecuteScriptAndExtractBool(
361 shell()->web_contents(),
362 "window.domAutomationController.send(clickSameSiteTargetedLink());",
363 &success));
364 EXPECT_TRUE(success);
365 Shell* new_shell = new_shell_observer.GetShell();
367 // Wait for the navigation in the new tab to finish, if it hasn't.
368 WaitForLoadStop(new_shell->web_contents());
369 EXPECT_EQ("/files/navigate_opener.html",
370 new_shell->web_contents()->GetLastCommittedURL().path());
372 // Should have the same SiteInstance.
373 scoped_refptr<SiteInstance> blank_site_instance(
374 new_shell->web_contents()->GetSiteInstance());
375 EXPECT_EQ(orig_site_instance, blank_site_instance);
377 // Now navigate the new tab to a different site.
378 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
379 NavigateToURL(new_shell, cross_site_url);
380 scoped_refptr<SiteInstance> new_site_instance(
381 new_shell->web_contents()->GetSiteInstance());
382 EXPECT_NE(orig_site_instance, new_site_instance);
384 // Clicking the original link in the first tab should cause us to swap back.
385 TestNavigationObserver navigation_observer(new_shell->web_contents());
386 EXPECT_TRUE(ExecuteScriptAndExtractBool(
387 shell()->web_contents(),
388 "window.domAutomationController.send(clickSameSiteTargetedLink());",
389 &success));
390 EXPECT_TRUE(success);
391 navigation_observer.Wait();
393 // Should have swapped back and shown the new window again.
394 scoped_refptr<SiteInstance> revisit_site_instance(
395 new_shell->web_contents()->GetSiteInstance());
396 EXPECT_EQ(orig_site_instance, revisit_site_instance);
398 // If it navigates away to another process, the original window should
399 // still be able to close it (using a cross-process close message).
400 NavigateToURL(new_shell, cross_site_url);
401 EXPECT_EQ(new_site_instance.get(),
402 new_shell->web_contents()->GetSiteInstance());
403 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
404 EXPECT_TRUE(ExecuteScriptAndExtractBool(
405 shell()->web_contents(),
406 "window.domAutomationController.send(testCloseWindow());",
407 &success));
408 EXPECT_TRUE(success);
409 close_watcher.Wait();
412 // Test that setting the opener to null in a window affects cross-process
413 // navigations, including those to existing entries. http://crbug.com/156669.
414 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
415 #if defined(THREAD_SANITIZER)
416 #define MAYBE_DisownOpener DISABLED_DisownOpener
417 #else
418 #define MAYBE_DisownOpener DisownOpener
419 #endif
420 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
421 StartServer();
423 // Load a page with links that open in a new window.
424 std::string replacement_path;
425 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
426 "files/click-noreferrer-links.html",
427 foo_host_port_,
428 &replacement_path));
429 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
431 // Get the original SiteInstance for later comparison.
432 scoped_refptr<SiteInstance> orig_site_instance(
433 shell()->web_contents()->GetSiteInstance());
434 EXPECT_TRUE(orig_site_instance.get() != NULL);
436 // Test clicking a target=_blank link.
437 ShellAddedObserver new_shell_observer;
438 bool success = false;
439 EXPECT_TRUE(ExecuteScriptAndExtractBool(
440 shell()->web_contents(),
441 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
442 &success));
443 EXPECT_TRUE(success);
444 Shell* new_shell = new_shell_observer.GetShell();
445 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
447 // Wait for the navigation in the new tab to finish, if it hasn't.
448 WaitForLoadStop(new_shell->web_contents());
449 EXPECT_EQ("/files/title2.html",
450 new_shell->web_contents()->GetLastCommittedURL().path());
452 // Should have the same SiteInstance.
453 scoped_refptr<SiteInstance> blank_site_instance(
454 new_shell->web_contents()->GetSiteInstance());
455 EXPECT_EQ(orig_site_instance, blank_site_instance);
457 // Now navigate the new tab to a different site.
458 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
459 scoped_refptr<SiteInstance> new_site_instance(
460 new_shell->web_contents()->GetSiteInstance());
461 EXPECT_NE(orig_site_instance, new_site_instance);
462 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
464 // Now disown the opener.
465 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
466 "window.opener = null;"));
467 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
469 // Go back and ensure the opener is still null.
471 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
472 new_shell->web_contents()->GetController().GoBack();
473 back_nav_load_observer.Wait();
475 success = false;
476 EXPECT_TRUE(ExecuteScriptAndExtractBool(
477 new_shell->web_contents(),
478 "window.domAutomationController.send(window.opener == null);",
479 &success));
480 EXPECT_TRUE(success);
481 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
483 // Now navigate forward again (creating a new process) and check opener.
484 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
485 success = false;
486 EXPECT_TRUE(ExecuteScriptAndExtractBool(
487 new_shell->web_contents(),
488 "window.domAutomationController.send(window.opener == null);",
489 &success));
490 EXPECT_TRUE(success);
491 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
494 // Test that subframes can disown their openers. http://crbug.com/225528.
495 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
496 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
497 NavigateToURL(shell(), frame_url);
499 // Give the frame an opener using window.open.
500 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
501 "window.open('about:blank','foo');"));
503 // Now disown the frame's opener. Shouldn't crash.
504 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
505 "window.frames[0].opener = null;"));
508 // Test for crbug.com/99202. PostMessage calls should still work after
509 // navigating the source and target windows to different sites.
510 // Specifically:
511 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
512 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
513 // 3) Post a message from "foo" to opener, which replies back to "foo".
514 // 4) Post a message from _blank to "foo".
515 // 5) Post a message from "foo" to a subframe of opener, which replies back.
516 // 6) Post a message from _blank to a subframe of "foo".
517 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
518 SupportCrossProcessPostMessage) {
519 StartServer();
521 // Load a page with links that open in a new window.
522 std::string replacement_path;
523 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
524 "files/click-noreferrer-links.html",
525 foo_host_port_,
526 &replacement_path));
527 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
529 // Get the original SiteInstance and RVHM for later comparison.
530 WebContents* opener_contents = shell()->web_contents();
531 scoped_refptr<SiteInstance> orig_site_instance(
532 opener_contents->GetSiteInstance());
533 EXPECT_TRUE(orig_site_instance.get() != NULL);
534 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
535 opener_contents)->GetRenderManagerForTesting();
537 // 1) Open two more windows, one named. These initially have openers but no
538 // reference to each other. We will later post a message between them.
540 // First, a named target=foo window.
541 ShellAddedObserver new_shell_observer;
542 bool success = false;
543 EXPECT_TRUE(ExecuteScriptAndExtractBool(
544 opener_contents,
545 "window.domAutomationController.send(clickSameSiteTargetedLink());",
546 &success));
547 EXPECT_TRUE(success);
548 Shell* new_shell = new_shell_observer.GetShell();
550 // Wait for the navigation in the new window to finish, if it hasn't, then
551 // send it to post_message.html on a different site.
552 WebContents* foo_contents = new_shell->web_contents();
553 WaitForLoadStop(foo_contents);
554 EXPECT_EQ("/files/navigate_opener.html",
555 foo_contents->GetLastCommittedURL().path());
556 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
557 scoped_refptr<SiteInstance> foo_site_instance(
558 foo_contents->GetSiteInstance());
559 EXPECT_NE(orig_site_instance, foo_site_instance);
561 // Second, a target=_blank window.
562 ShellAddedObserver new_shell_observer2;
563 EXPECT_TRUE(ExecuteScriptAndExtractBool(
564 shell()->web_contents(),
565 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
566 &success));
567 EXPECT_TRUE(success);
569 // Wait for the navigation in the new window to finish, if it hasn't, then
570 // send it to post_message.html on the original site.
571 Shell* new_shell2 = new_shell_observer2.GetShell();
572 WebContents* new_contents = new_shell2->web_contents();
573 WaitForLoadStop(new_contents);
574 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
575 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
576 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
577 RenderFrameHostManager* new_manager =
578 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
580 // We now have three windows. The opener should have a swapped out RVH
581 // for the new SiteInstance, but the _blank window should not.
582 EXPECT_EQ(3u, Shell::windows().size());
583 EXPECT_TRUE(
584 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
585 EXPECT_FALSE(
586 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
588 // 2) Fail to post a message from the foo window to the opener if the target
589 // origin is wrong. We won't see an error, but we can check for the right
590 // number of received messages below.
591 EXPECT_TRUE(ExecuteScriptAndExtractBool(
592 foo_contents,
593 "window.domAutomationController.send(postToOpener('msg',"
594 " 'http://google.com'));",
595 &success));
596 EXPECT_TRUE(success);
597 ASSERT_FALSE(
598 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
600 // 3) Post a message from the foo window to the opener. The opener will
601 // reply, causing the foo window to update its own title.
602 base::string16 expected_title = ASCIIToUTF16("msg");
603 TitleWatcher title_watcher(foo_contents, expected_title);
604 EXPECT_TRUE(ExecuteScriptAndExtractBool(
605 foo_contents,
606 "window.domAutomationController.send(postToOpener('msg','*'));",
607 &success));
608 EXPECT_TRUE(success);
609 ASSERT_FALSE(
610 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
611 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
613 // We should have received only 1 message in the opener and "foo" tabs,
614 // and updated the title.
615 int opener_received_messages = 0;
616 EXPECT_TRUE(ExecuteScriptAndExtractInt(
617 opener_contents,
618 "window.domAutomationController.send(window.receivedMessages);",
619 &opener_received_messages));
620 int foo_received_messages = 0;
621 EXPECT_TRUE(ExecuteScriptAndExtractInt(
622 foo_contents,
623 "window.domAutomationController.send(window.receivedMessages);",
624 &foo_received_messages));
625 EXPECT_EQ(1, foo_received_messages);
626 EXPECT_EQ(1, opener_received_messages);
627 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
629 // 4) Now post a message from the _blank window to the foo window. The
630 // foo window will update its title and will not reply.
631 expected_title = ASCIIToUTF16("msg2");
632 TitleWatcher title_watcher2(foo_contents, expected_title);
633 EXPECT_TRUE(ExecuteScriptAndExtractBool(
634 new_contents,
635 "window.domAutomationController.send(postToFoo('msg2'));",
636 &success));
637 EXPECT_TRUE(success);
638 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
640 // This postMessage should have created a swapped out RVH for the new
641 // SiteInstance in the target=_blank window.
642 EXPECT_TRUE(
643 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
645 // TODO(nasko): Test subframe targeting of postMessage once
646 // http://crbug.com/153701 is fixed.
649 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
650 // messages which contain Transferables and get intercepted by
651 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
652 // swapped out) should work.
653 // Specifically:
654 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
655 // 2) Post a message containing a message port from opener to "foo".
656 // 3) Post a message from "foo" back to opener via the passed message port.
657 // The test will be enabled when the feature implementation lands.
658 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
659 SupportCrossProcessPostMessageWithMessagePort) {
660 StartServer();
662 // Load a page with links that open in a new window.
663 std::string replacement_path;
664 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
665 "files/click-noreferrer-links.html",
666 foo_host_port_,
667 &replacement_path));
668 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
670 // Get the original SiteInstance and RVHM for later comparison.
671 WebContents* opener_contents = shell()->web_contents();
672 scoped_refptr<SiteInstance> orig_site_instance(
673 opener_contents->GetSiteInstance());
674 EXPECT_TRUE(orig_site_instance.get() != NULL);
675 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
676 opener_contents)->GetRenderManagerForTesting();
678 // 1) Open a named target=foo window. We will later post a message between the
679 // opener and the new window.
680 ShellAddedObserver new_shell_observer;
681 bool success = false;
682 EXPECT_TRUE(ExecuteScriptAndExtractBool(
683 opener_contents,
684 "window.domAutomationController.send(clickSameSiteTargetedLink());",
685 &success));
686 EXPECT_TRUE(success);
687 Shell* new_shell = new_shell_observer.GetShell();
689 // Wait for the navigation in the new window to finish, if it hasn't, then
690 // send it to post_message.html on a different site.
691 WebContents* foo_contents = new_shell->web_contents();
692 WaitForLoadStop(foo_contents);
693 EXPECT_EQ("/files/navigate_opener.html",
694 foo_contents->GetLastCommittedURL().path());
695 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
696 scoped_refptr<SiteInstance> foo_site_instance(
697 foo_contents->GetSiteInstance());
698 EXPECT_NE(orig_site_instance, foo_site_instance);
700 // We now have two windows. The opener should have a swapped out RVH
701 // for the new SiteInstance.
702 EXPECT_EQ(2u, Shell::windows().size());
703 EXPECT_TRUE(
704 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
706 // 2) Post a message containing a MessagePort from opener to the the foo
707 // window. The foo window will reply via the passed port, causing the opener
708 // to update its own title.
709 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
710 TitleWatcher title_observer(opener_contents, expected_title);
711 EXPECT_TRUE(ExecuteScriptAndExtractBool(
712 opener_contents,
713 "window.domAutomationController.send(postWithPortToFoo());",
714 &success));
715 EXPECT_TRUE(success);
716 ASSERT_FALSE(
717 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
718 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
720 // Check message counts.
721 int opener_received_messages_via_port = 0;
722 EXPECT_TRUE(ExecuteScriptAndExtractInt(
723 opener_contents,
724 "window.domAutomationController.send(window.receivedMessagesViaPort);",
725 &opener_received_messages_via_port));
726 int foo_received_messages = 0;
727 EXPECT_TRUE(ExecuteScriptAndExtractInt(
728 foo_contents,
729 "window.domAutomationController.send(window.receivedMessages);",
730 &foo_received_messages));
731 int foo_received_messages_with_port = 0;
732 EXPECT_TRUE(ExecuteScriptAndExtractInt(
733 foo_contents,
734 "window.domAutomationController.send(window.receivedMessagesWithPort);",
735 &foo_received_messages_with_port));
736 EXPECT_EQ(1, foo_received_messages);
737 EXPECT_EQ(1, foo_received_messages_with_port);
738 EXPECT_EQ(1, opener_received_messages_via_port);
739 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
740 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
743 // Test for crbug.com/116192. Navigations to a window's opener should
744 // still work after a process swap.
745 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
746 AllowTargetedNavigationsInOpenerAfterSwap) {
747 StartServer();
749 // Load a page with links that open in a new window.
750 std::string replacement_path;
751 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
752 "files/click-noreferrer-links.html",
753 foo_host_port_,
754 &replacement_path));
755 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
757 // Get the original tab and SiteInstance for later comparison.
758 WebContents* orig_contents = shell()->web_contents();
759 scoped_refptr<SiteInstance> orig_site_instance(
760 orig_contents->GetSiteInstance());
761 EXPECT_TRUE(orig_site_instance.get() != NULL);
763 // Test clicking a target=foo link.
764 ShellAddedObserver new_shell_observer;
765 bool success = false;
766 EXPECT_TRUE(ExecuteScriptAndExtractBool(
767 orig_contents,
768 "window.domAutomationController.send(clickSameSiteTargetedLink());",
769 &success));
770 EXPECT_TRUE(success);
771 Shell* new_shell = new_shell_observer.GetShell();
773 // Wait for the navigation in the new window to finish, if it hasn't.
774 WaitForLoadStop(new_shell->web_contents());
775 EXPECT_EQ("/files/navigate_opener.html",
776 new_shell->web_contents()->GetLastCommittedURL().path());
778 // Should have the same SiteInstance.
779 scoped_refptr<SiteInstance> blank_site_instance(
780 new_shell->web_contents()->GetSiteInstance());
781 EXPECT_EQ(orig_site_instance, blank_site_instance);
783 // Now navigate the original (opener) tab to a different site.
784 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
785 scoped_refptr<SiteInstance> new_site_instance(
786 shell()->web_contents()->GetSiteInstance());
787 EXPECT_NE(orig_site_instance, new_site_instance);
789 // The opened tab should be able to navigate the opener back to its process.
790 TestNavigationObserver navigation_observer(orig_contents);
791 EXPECT_TRUE(ExecuteScriptAndExtractBool(
792 new_shell->web_contents(),
793 "window.domAutomationController.send(navigateOpener());",
794 &success));
795 EXPECT_TRUE(success);
796 navigation_observer.Wait();
798 // Should have swapped back into this process.
799 scoped_refptr<SiteInstance> revisit_site_instance(
800 shell()->web_contents()->GetSiteInstance());
801 EXPECT_EQ(orig_site_instance, revisit_site_instance);
804 // Test that opening a new window in the same SiteInstance and then navigating
805 // both windows to a different SiteInstance allows the first process to exit.
806 // See http://crbug.com/126333.
807 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
808 ProcessExitWithSwappedOutViews) {
809 StartServer();
811 // Load a page with links that open in a new window.
812 std::string replacement_path;
813 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
814 "files/click-noreferrer-links.html",
815 foo_host_port_,
816 &replacement_path));
817 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
819 // Get the original SiteInstance for later comparison.
820 scoped_refptr<SiteInstance> orig_site_instance(
821 shell()->web_contents()->GetSiteInstance());
822 EXPECT_TRUE(orig_site_instance.get() != NULL);
824 // Test clicking a target=foo link.
825 ShellAddedObserver new_shell_observer;
826 bool success = false;
827 EXPECT_TRUE(ExecuteScriptAndExtractBool(
828 shell()->web_contents(),
829 "window.domAutomationController.send(clickSameSiteTargetedLink());",
830 &success));
831 EXPECT_TRUE(success);
832 Shell* new_shell = new_shell_observer.GetShell();
834 // Wait for the navigation in the new window to finish, if it hasn't.
835 WaitForLoadStop(new_shell->web_contents());
836 EXPECT_EQ("/files/navigate_opener.html",
837 new_shell->web_contents()->GetLastCommittedURL().path());
839 // Should have the same SiteInstance.
840 scoped_refptr<SiteInstance> opened_site_instance(
841 new_shell->web_contents()->GetSiteInstance());
842 EXPECT_EQ(orig_site_instance, opened_site_instance);
844 // Now navigate the opened window to a different site.
845 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
846 scoped_refptr<SiteInstance> new_site_instance(
847 new_shell->web_contents()->GetSiteInstance());
848 EXPECT_NE(orig_site_instance, new_site_instance);
850 // The original process should still be alive, since it is still used in the
851 // first window.
852 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
853 EXPECT_TRUE(orig_process->HasConnection());
855 // Navigate the first window to a different site as well. The original
856 // process should exit, since all of its views are now swapped out.
857 RenderProcessHostWatcher exit_observer(
858 orig_process,
859 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
860 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
861 exit_observer.Wait();
862 scoped_refptr<SiteInstance> new_site_instance2(
863 shell()->web_contents()->GetSiteInstance());
864 EXPECT_EQ(new_site_instance, new_site_instance2);
867 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
868 // error should not make us ignore future renderer-initiated navigations.
869 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
870 StartServer();
872 // Get the original SiteInstance for later comparison.
873 scoped_refptr<SiteInstance> orig_site_instance(
874 shell()->web_contents()->GetSiteInstance());
875 EXPECT_TRUE(orig_site_instance.get() != NULL);
877 // Load a cross-site page that fails with a 204 error.
878 NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
880 // We should still be looking at the normal page. Because we started from a
881 // blank new tab, the typed URL will still be visible until the user clears it
882 // manually. The last committed URL will be the previous page.
883 scoped_refptr<SiteInstance> post_nav_site_instance(
884 shell()->web_contents()->GetSiteInstance());
885 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
886 EXPECT_EQ("/nocontent",
887 shell()->web_contents()->GetVisibleURL().path());
888 EXPECT_FALSE(
889 shell()->web_contents()->GetController().GetLastCommittedEntry());
891 // Renderer-initiated navigations should work.
892 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
893 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
894 GURL url = test_server()->GetURL("files/title2.html");
895 EXPECT_TRUE(ExecuteScript(
896 shell()->web_contents(),
897 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
898 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
900 // Opens in same tab.
901 EXPECT_EQ(1u, Shell::windows().size());
902 EXPECT_EQ("/files/title2.html",
903 shell()->web_contents()->GetLastCommittedURL().path());
905 // Should have the same SiteInstance.
906 scoped_refptr<SiteInstance> new_site_instance(
907 shell()->web_contents()->GetSiteInstance());
908 EXPECT_EQ(orig_site_instance, new_site_instance);
911 // Test for crbug.com/9682. We should show the URL for a pending renderer-
912 // initiated navigation in a new tab, until the content of the initial
913 // about:blank page is modified by another window. At that point, we should
914 // revert to showing about:blank to prevent a URL spoof.
915 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
916 ASSERT_TRUE(test_server()->Start());
918 // Load a page that can open a URL that won't commit in a new window.
919 NavigateToURL(
920 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
921 WebContents* orig_contents = shell()->web_contents();
923 // Click a /nocontent link that opens in a new window but never commits.
924 ShellAddedObserver new_shell_observer;
925 bool success = false;
926 EXPECT_TRUE(ExecuteScriptAndExtractBool(
927 orig_contents,
928 "window.domAutomationController.send(clickNoContentTargetedLink());",
929 &success));
930 EXPECT_TRUE(success);
932 // Wait for the window to open.
933 Shell* new_shell = new_shell_observer.GetShell();
935 // Ensure the destination URL is visible, because it is considered the
936 // initial navigation.
937 WebContents* contents = new_shell->web_contents();
938 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
939 EXPECT_EQ("/nocontent",
940 contents->GetController().GetVisibleEntry()->GetURL().path());
942 // Now modify the contents of the new window from the opener. This will also
943 // modify the title of the document to give us something to listen for.
944 base::string16 expected_title = ASCIIToUTF16("Modified Title");
945 TitleWatcher title_watcher(contents, expected_title);
946 success = false;
947 EXPECT_TRUE(ExecuteScriptAndExtractBool(
948 orig_contents,
949 "window.domAutomationController.send(modifyNewWindow());",
950 &success));
951 EXPECT_TRUE(success);
952 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
954 // At this point, we should no longer be showing the destination URL.
955 // The visible entry should be null, resulting in about:blank in the address
956 // bar.
957 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
960 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
961 // initiated navigation in a new tab if it is not the initial navigation. In
962 // this case, the renderer will not notify us of a modification, so we cannot
963 // show the pending URL without allowing a spoof.
964 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
965 DontShowLoadingURLIfNotInitialNav) {
966 ASSERT_TRUE(test_server()->Start());
968 // Load a page that can open a URL that won't commit in a new window.
969 NavigateToURL(
970 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
971 WebContents* orig_contents = shell()->web_contents();
973 // Click a /nocontent link that opens in a new window but never commits.
974 // By using an onclick handler that first creates the window, the slow
975 // navigation is not considered an initial navigation.
976 ShellAddedObserver new_shell_observer;
977 bool success = false;
978 EXPECT_TRUE(ExecuteScriptAndExtractBool(
979 orig_contents,
980 "window.domAutomationController.send("
981 "clickNoContentScriptedTargetedLink());",
982 &success));
983 EXPECT_TRUE(success);
985 // Wait for the window to open.
986 Shell* new_shell = new_shell_observer.GetShell();
988 // Ensure the destination URL is not visible, because it is not the initial
989 // navigation.
990 WebContents* contents = new_shell->web_contents();
991 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
992 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
995 // Crashes under ThreadSanitizer, http://crbug.com/356758.
996 #if defined(THREAD_SANITIZER)
997 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
998 #else
999 #define MAYBE_BackForwardNotStale BackForwardNotStale
1000 #endif
1001 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1002 // do not cause back/forward navigations to be considered stale by the
1003 // renderer.
1004 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1005 StartServer();
1006 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1008 // Visit a page on first site.
1009 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1011 // Visit three pages on second site.
1012 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1013 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1014 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1016 // History is now [blank, A1, B1, B2, *B3].
1017 WebContents* contents = shell()->web_contents();
1018 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1020 // Open another window in same process to keep this process alive.
1021 Shell* new_shell = CreateBrowser();
1022 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1024 // Go back three times to first site.
1026 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1027 shell()->web_contents()->GetController().GoBack();
1028 back_nav_load_observer.Wait();
1031 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1032 shell()->web_contents()->GetController().GoBack();
1033 back_nav_load_observer.Wait();
1036 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1037 shell()->web_contents()->GetController().GoBack();
1038 back_nav_load_observer.Wait();
1041 // Now go forward twice to B2. Shouldn't be left spinning.
1043 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1044 shell()->web_contents()->GetController().GoForward();
1045 forward_nav_load_observer.Wait();
1048 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1049 shell()->web_contents()->GetController().GoForward();
1050 forward_nav_load_observer.Wait();
1053 // Go back twice to first site.
1055 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1056 shell()->web_contents()->GetController().GoBack();
1057 back_nav_load_observer.Wait();
1060 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1061 shell()->web_contents()->GetController().GoBack();
1062 back_nav_load_observer.Wait();
1065 // Now go forward directly to B3. Shouldn't be left spinning.
1067 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1068 shell()->web_contents()->GetController().GoToIndex(4);
1069 forward_nav_load_observer.Wait();
1073 // Test for http://crbug.com/130016.
1074 // Swapping out a render view should update its visiblity state.
1075 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1076 SwappedOutViewHasCorrectVisibilityState) {
1077 StartServer();
1079 // Load a page with links that open in a new window.
1080 std::string replacement_path;
1081 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1082 "files/click-noreferrer-links.html",
1083 foo_host_port_,
1084 &replacement_path));
1085 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1087 // Open a same-site link in a new widnow.
1088 ShellAddedObserver new_shell_observer;
1089 bool success = false;
1090 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1091 shell()->web_contents(),
1092 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1093 &success));
1094 EXPECT_TRUE(success);
1095 Shell* new_shell = new_shell_observer.GetShell();
1097 // Wait for the navigation in the new tab to finish, if it hasn't.
1098 WaitForLoadStop(new_shell->web_contents());
1099 EXPECT_EQ("/files/navigate_opener.html",
1100 new_shell->web_contents()->GetLastCommittedURL().path());
1102 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1104 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1105 rvh,
1106 "window.domAutomationController.send("
1107 " document.visibilityState == 'visible');",
1108 &success));
1109 EXPECT_TRUE(success);
1111 // Now navigate the new window to a different site. This should swap out the
1112 // tab's existing RenderView, causing it become hidden.
1113 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1115 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1116 rvh,
1117 "window.domAutomationController.send("
1118 " document.visibilityState == 'hidden');",
1119 &success));
1120 EXPECT_TRUE(success);
1122 // Going back should make the previously swapped-out view to become visible
1123 // again.
1125 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1126 new_shell->web_contents()->GetController().GoBack();
1127 back_nav_load_observer.Wait();
1130 EXPECT_EQ("/files/navigate_opener.html",
1131 new_shell->web_contents()->GetLastCommittedURL().path());
1133 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1135 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1136 rvh,
1137 "window.domAutomationController.send("
1138 " document.visibilityState == 'visible');",
1139 &success));
1140 EXPECT_TRUE(success);
1143 // This class ensures that all the given RenderViewHosts have properly been
1144 // shutdown.
1145 class RenderViewHostDestructionObserver : public WebContentsObserver {
1146 public:
1147 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1148 : WebContentsObserver(web_contents) {}
1149 virtual ~RenderViewHostDestructionObserver() {}
1150 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1151 watched_render_view_hosts_.insert(rvh);
1153 size_t GetNumberOfWatchedRenderViewHosts() const {
1154 return watched_render_view_hosts_.size();
1157 private:
1158 // WebContentsObserver implementation:
1159 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
1160 watched_render_view_hosts_.erase(rvh);
1163 std::set<RenderViewHost*> watched_render_view_hosts_;
1166 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1167 #if defined(THREAD_SANITIZER)
1168 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1169 #else
1170 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1171 #endif
1172 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1173 // they may cause crashes or memory corruptions when trying to call dead
1174 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1175 // ensure that a separate SiteInstance is created when navigating to view-source
1176 // URLs, regardless of current URL.
1177 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1178 MAYBE_LeakingRenderViewHosts) {
1179 StartServer();
1181 // Observe the created render_view_host's to make sure they will not leak.
1182 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1184 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1185 GURL view_source_url(kViewSourceScheme + std::string(":") +
1186 navigated_url.spec());
1188 // Let's ensure that when we start with a blank window, navigating away to a
1189 // view-source URL, we create a new SiteInstance.
1190 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1191 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1192 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1193 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1194 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1196 // Now navigate to the view-source URL and ensure we got a different
1197 // SiteInstance and RenderViewHost.
1198 NavigateToURL(shell(), view_source_url);
1199 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1200 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1201 GetRenderViewHost()->GetSiteInstance());
1202 rvh_observers.EnsureRVHGetsDestructed(
1203 shell()->web_contents()->GetRenderViewHost());
1205 // Load a random page and then navigate to view-source: of it.
1206 // This used to cause two RVH instances for the same SiteInstance, which
1207 // was a problem. This is no longer the case.
1208 NavigateToURL(shell(), navigated_url);
1209 SiteInstance* site_instance1 = shell()->web_contents()->
1210 GetRenderViewHost()->GetSiteInstance();
1211 rvh_observers.EnsureRVHGetsDestructed(
1212 shell()->web_contents()->GetRenderViewHost());
1214 NavigateToURL(shell(), view_source_url);
1215 rvh_observers.EnsureRVHGetsDestructed(
1216 shell()->web_contents()->GetRenderViewHost());
1217 SiteInstance* site_instance2 = shell()->web_contents()->
1218 GetRenderViewHost()->GetSiteInstance();
1220 // Ensure that view-source navigations force a new SiteInstance.
1221 EXPECT_NE(site_instance1, site_instance2);
1223 // Now navigate to a different instance so that we swap out again.
1224 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1225 rvh_observers.EnsureRVHGetsDestructed(
1226 shell()->web_contents()->GetRenderViewHost());
1228 // This used to leak a render view host.
1229 shell()->Close();
1231 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1233 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1236 // Test for crbug.com/143155. Frame tree updates during unload should not
1237 // interrupt the intended navigation and show swappedout:// instead.
1238 // Specifically:
1239 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1240 // 2) Send the second tab to a different foo.com SiteInstance.
1241 // This creates a swapped out opener for the first tab in the foo process.
1242 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1243 // tab's unload handler remove its frame.
1244 // This used to cause an update to the frame tree of the swapped out RV,
1245 // just as it was navigating to a real page. That pre-empted the real
1246 // navigation and visibly sent the tab to swappedout://.
1247 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1248 DontPreemptNavigationWithFrameTreeUpdate) {
1249 StartServer();
1251 // 1. Load a page that deletes its iframe during unload.
1252 NavigateToURL(shell(),
1253 test_server()->GetURL("files/remove_frame_on_unload.html"));
1255 // Get the original SiteInstance for later comparison.
1256 scoped_refptr<SiteInstance> orig_site_instance(
1257 shell()->web_contents()->GetSiteInstance());
1259 // Open a same-site page in a new window.
1260 ShellAddedObserver new_shell_observer;
1261 bool success = false;
1262 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1263 shell()->web_contents(),
1264 "window.domAutomationController.send(openWindow());",
1265 &success));
1266 EXPECT_TRUE(success);
1267 Shell* new_shell = new_shell_observer.GetShell();
1269 // Wait for the navigation in the new window to finish, if it hasn't.
1270 WaitForLoadStop(new_shell->web_contents());
1271 EXPECT_EQ("/files/title1.html",
1272 new_shell->web_contents()->GetLastCommittedURL().path());
1274 // Should have the same SiteInstance.
1275 EXPECT_EQ(orig_site_instance.get(),
1276 new_shell->web_contents()->GetSiteInstance());
1278 // 2. Send the second tab to a different process.
1279 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1280 scoped_refptr<SiteInstance> new_site_instance(
1281 new_shell->web_contents()->GetSiteInstance());
1282 EXPECT_NE(orig_site_instance, new_site_instance);
1284 // 3. Send the first tab to the second tab's process.
1285 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1287 // Make sure it ends up at the right page.
1288 WaitForLoadStop(shell()->web_contents());
1289 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1290 shell()->web_contents()->GetLastCommittedURL());
1291 EXPECT_EQ(new_site_instance.get(),
1292 shell()->web_contents()->GetSiteInstance());
1295 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1296 // are meant to run in the current page. We had a bug where we expected a
1297 // BrowsingInstance swap to occur on pages like view-source and extensions,
1298 // which broke chrome://crash and javascript: URLs.
1299 // See http://crbug.com/335503.
1300 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1301 ASSERT_TRUE(test_server()->Start());
1303 GURL original_url(test_server()->GetURL("files/title2.html"));
1304 GURL view_source_url(kViewSourceScheme + std::string(":") +
1305 original_url.spec());
1307 NavigateToURL(shell(), view_source_url);
1309 // Check that javascript: URLs work.
1310 base::string16 expected_title = ASCIIToUTF16("msg");
1311 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1312 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1313 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1315 // Crash the renderer of the view-source page.
1316 RenderProcessHostWatcher crash_observer(
1317 shell()->web_contents(),
1318 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1319 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1320 crash_observer.Wait();
1323 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1324 // Otherwise, we might try to load an unprivileged about:blank page into a
1325 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1326 // See http://crbug.com/334214.
1327 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1328 IgnoreRendererDebugURLsWhenCrashed) {
1329 // Visit a WebUI page with bindings.
1330 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1331 std::string(kChromeUIGpuHost));
1332 NavigateToURL(shell(), webui_url);
1333 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1334 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1336 // Crash the renderer of the WebUI page.
1337 RenderProcessHostWatcher crash_observer(
1338 shell()->web_contents(),
1339 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1340 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1341 crash_observer.Wait();
1343 // Load the crash URL again but don't wait for any action. If it is not
1344 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1345 shell()->LoadURL(GURL(kChromeUICrashURL));
1347 // Ensure that such URLs can still work as the initial navigation of a tab.
1348 // We postpone the initial navigation of the tab using an empty GURL, so that
1349 // we can add a watcher for crashes.
1350 Shell* shell2 = Shell::CreateNewWindow(
1351 shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1352 MSG_ROUTING_NONE, gfx::Size());
1353 RenderProcessHostWatcher crash_observer2(
1354 shell2->web_contents(),
1355 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1356 NavigateToURL(shell2, GURL(kChromeUIKillURL));
1357 crash_observer2.Wait();
1360 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1361 // Otherwise it might get picked up by InitRenderView when granting bindings
1362 // to other RenderViewHosts. See http://crbug.com/330811.
1363 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) {
1364 // Visit a WebUI page with bindings.
1365 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1366 std::string(kChromeUIGpuHost)));
1367 NavigateToURL(shell(), webui_url);
1368 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1369 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1370 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1371 shell()->web_contents());
1372 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1373 EXPECT_TRUE(webui);
1374 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1376 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1377 // clear pending_web_ui() when it commits.
1378 GURL webui_url2(webui_url.spec() + "#foo");
1379 NavigateToURL(shell(), webui_url2);
1380 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1381 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1384 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1385 public:
1386 RFHMProcessPerTabTest() {}
1388 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1389 command_line->AppendSwitch(switches::kProcessPerTab);
1393 // Test that we still swap processes for BrowsingInstance changes even in
1394 // --process-per-tab mode. See http://crbug.com/343017.
1395 // Disabled on Android: http://crbug.com/345873.
1396 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1397 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1398 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1399 #else
1400 #define MAYBE_BackFromWebUI BackFromWebUI
1401 #endif
1402 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1403 ASSERT_TRUE(test_server()->Start());
1404 GURL original_url(test_server()->GetURL("files/title2.html"));
1405 NavigateToURL(shell(), original_url);
1407 // Visit a WebUI page with bindings.
1408 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1409 std::string(kChromeUIGpuHost)));
1410 NavigateToURL(shell(), webui_url);
1411 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1412 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1414 // Go back and ensure we have no WebUI bindings.
1415 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1416 shell()->web_contents()->GetController().GoBack();
1417 back_nav_load_observer.Wait();
1418 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1419 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1420 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1423 // crbug.com/372360
1424 // The test loads url1, opens a link pointing to url2 in a new tab, and
1425 // navigates the new tab to url1.
1426 // The following is needed for the bug to happen:
1427 // - url1 must require webui bindings;
1428 // - navigating to url2 in the site instance of url1 should not swap
1429 // browsing instances, but should require a new site instance.
1430 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1431 GURL url1(std::string(kChromeUIScheme) + "://" +
1432 std::string(kChromeUIGpuHost));
1433 GURL url2(std::string(kChromeUIScheme) + "://" +
1434 std::string(kChromeUIAccessibilityHost));
1436 // Visit a WebUI page with bindings.
1437 NavigateToURL(shell(), url1);
1438 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1439 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1440 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1442 // Open a new tab. Initially it gets a render view in the original tab's
1443 // current site instance.
1444 TestNavigationObserver nav_observer(NULL);
1445 nav_observer.StartWatchingNewWebContents();
1446 ShellAddedObserver shao;
1447 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1448 nav_observer.Wait();
1449 Shell* new_shell = shao.GetShell();
1450 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1451 new_shell->web_contents());
1452 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1454 EXPECT_NE(site_instance2, site_instance1);
1455 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1456 RenderViewHost* initial_rvh = new_web_contents->
1457 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1458 ASSERT_TRUE(initial_rvh);
1459 // The following condition is what was causing the bug.
1460 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1462 // Navigate to url1 and check bindings.
1463 NavigateToURL(new_shell, url1);
1464 // The navigation should have used the first SiteInstance, otherwise
1465 // |initial_rvh| did not have a chance to be used.
1466 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1467 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1468 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1471 } // namespace content