cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blob9ae4cb38692844d56eb5796aa90b596f492c1f40
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, unless we
257 // are running in --site-per-process mode.
258 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
259 DontSwapProcessWithOnlyTargetBlank) {
260 StartServer();
262 // Load a page with links that open in a new window.
263 std::string replacement_path;
264 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
265 "files/click-noreferrer-links.html",
266 foo_host_port_,
267 &replacement_path));
268 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
270 // Get the original SiteInstance for later comparison.
271 scoped_refptr<SiteInstance> orig_site_instance(
272 shell()->web_contents()->GetSiteInstance());
273 EXPECT_TRUE(orig_site_instance.get() != NULL);
275 // Test clicking a target=blank link.
276 ShellAddedObserver new_shell_observer;
277 bool success = false;
278 EXPECT_TRUE(ExecuteScriptAndExtractBool(
279 shell()->web_contents(),
280 "window.domAutomationController.send(clickTargetBlankLink());",
281 &success));
282 EXPECT_TRUE(success);
284 // Wait for the window to open.
285 Shell* new_shell = new_shell_observer.GetShell();
287 // Wait for the cross-site transition in the new tab to finish.
288 WaitForLoadStop(new_shell->web_contents());
289 EXPECT_EQ("/files/title2.html",
290 new_shell->web_contents()->GetLastCommittedURL().path());
292 // Should have the same SiteInstance unless we're in site-per-process mode.
293 scoped_refptr<SiteInstance> blank_site_instance(
294 new_shell->web_contents()->GetSiteInstance());
295 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
296 switches::kSitePerProcess))
297 EXPECT_EQ(orig_site_instance, blank_site_instance);
298 else
299 EXPECT_NE(orig_site_instance, blank_site_instance);
302 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
303 // and no target=_blank should not create a new SiteInstance.
304 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
305 DontSwapProcessWithOnlyRelNoreferrer) {
306 StartServer();
308 // Load a page with links that open in a new window.
309 std::string replacement_path;
310 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
311 "files/click-noreferrer-links.html",
312 foo_host_port_,
313 &replacement_path));
314 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
316 // Get the original SiteInstance for later comparison.
317 scoped_refptr<SiteInstance> orig_site_instance(
318 shell()->web_contents()->GetSiteInstance());
319 EXPECT_TRUE(orig_site_instance.get() != NULL);
321 // Test clicking a rel=noreferrer link.
322 bool success = false;
323 EXPECT_TRUE(ExecuteScriptAndExtractBool(
324 shell()->web_contents(),
325 "window.domAutomationController.send(clickNoRefLink());",
326 &success));
327 EXPECT_TRUE(success);
329 // Wait for the cross-site transition in the current tab to finish.
330 WaitForLoadStop(shell()->web_contents());
332 // Opens in same window.
333 EXPECT_EQ(1u, Shell::windows().size());
334 EXPECT_EQ("/files/title2.html",
335 shell()->web_contents()->GetLastCommittedURL().path());
337 // Should have the same SiteInstance.
338 scoped_refptr<SiteInstance> noref_site_instance(
339 shell()->web_contents()->GetSiteInstance());
340 EXPECT_EQ(orig_site_instance, noref_site_instance);
343 // Test for crbug.com/116192. Targeted links should still work after the
344 // named target window has swapped processes.
345 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
346 AllowTargetedNavigationsAfterSwap) {
347 StartServer();
349 // Load a page with links that open in a new window.
350 std::string replacement_path;
351 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
352 "files/click-noreferrer-links.html",
353 foo_host_port_,
354 &replacement_path));
355 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
357 // Get the original SiteInstance for later comparison.
358 scoped_refptr<SiteInstance> orig_site_instance(
359 shell()->web_contents()->GetSiteInstance());
360 EXPECT_TRUE(orig_site_instance.get() != NULL);
362 // Test clicking a target=foo link.
363 ShellAddedObserver new_shell_observer;
364 bool success = false;
365 EXPECT_TRUE(ExecuteScriptAndExtractBool(
366 shell()->web_contents(),
367 "window.domAutomationController.send(clickSameSiteTargetedLink());",
368 &success));
369 EXPECT_TRUE(success);
370 Shell* new_shell = new_shell_observer.GetShell();
372 // Wait for the navigation in the new tab to finish, if it hasn't.
373 WaitForLoadStop(new_shell->web_contents());
374 EXPECT_EQ("/files/navigate_opener.html",
375 new_shell->web_contents()->GetLastCommittedURL().path());
377 // Should have the same SiteInstance.
378 scoped_refptr<SiteInstance> blank_site_instance(
379 new_shell->web_contents()->GetSiteInstance());
380 EXPECT_EQ(orig_site_instance, blank_site_instance);
382 // Now navigate the new tab to a different site.
383 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
384 NavigateToURL(new_shell, cross_site_url);
385 scoped_refptr<SiteInstance> new_site_instance(
386 new_shell->web_contents()->GetSiteInstance());
387 EXPECT_NE(orig_site_instance, new_site_instance);
389 // Clicking the original link in the first tab should cause us to swap back.
390 TestNavigationObserver navigation_observer(new_shell->web_contents());
391 EXPECT_TRUE(ExecuteScriptAndExtractBool(
392 shell()->web_contents(),
393 "window.domAutomationController.send(clickSameSiteTargetedLink());",
394 &success));
395 EXPECT_TRUE(success);
396 navigation_observer.Wait();
398 // Should have swapped back and shown the new window again.
399 scoped_refptr<SiteInstance> revisit_site_instance(
400 new_shell->web_contents()->GetSiteInstance());
401 EXPECT_EQ(orig_site_instance, revisit_site_instance);
403 // If it navigates away to another process, the original window should
404 // still be able to close it (using a cross-process close message).
405 NavigateToURL(new_shell, cross_site_url);
406 EXPECT_EQ(new_site_instance.get(),
407 new_shell->web_contents()->GetSiteInstance());
408 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
409 EXPECT_TRUE(ExecuteScriptAndExtractBool(
410 shell()->web_contents(),
411 "window.domAutomationController.send(testCloseWindow());",
412 &success));
413 EXPECT_TRUE(success);
414 close_watcher.Wait();
417 // Test that setting the opener to null in a window affects cross-process
418 // navigations, including those to existing entries. http://crbug.com/156669.
419 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
420 #if defined(THREAD_SANITIZER)
421 #define MAYBE_DisownOpener DISABLED_DisownOpener
422 #else
423 #define MAYBE_DisownOpener DisownOpener
424 #endif
425 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
426 StartServer();
428 // Load a page with links that open in a new window.
429 std::string replacement_path;
430 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
431 "files/click-noreferrer-links.html",
432 foo_host_port_,
433 &replacement_path));
434 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
436 // Get the original SiteInstance for later comparison.
437 scoped_refptr<SiteInstance> orig_site_instance(
438 shell()->web_contents()->GetSiteInstance());
439 EXPECT_TRUE(orig_site_instance.get() != NULL);
441 // Test clicking a target=_blank link.
442 ShellAddedObserver new_shell_observer;
443 bool success = false;
444 EXPECT_TRUE(ExecuteScriptAndExtractBool(
445 shell()->web_contents(),
446 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
447 &success));
448 EXPECT_TRUE(success);
449 Shell* new_shell = new_shell_observer.GetShell();
450 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
452 // Wait for the navigation in the new tab to finish, if it hasn't.
453 WaitForLoadStop(new_shell->web_contents());
454 EXPECT_EQ("/files/title2.html",
455 new_shell->web_contents()->GetLastCommittedURL().path());
457 // Should have the same SiteInstance.
458 scoped_refptr<SiteInstance> blank_site_instance(
459 new_shell->web_contents()->GetSiteInstance());
460 EXPECT_EQ(orig_site_instance, blank_site_instance);
462 // Now navigate the new tab to a different site.
463 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
464 scoped_refptr<SiteInstance> new_site_instance(
465 new_shell->web_contents()->GetSiteInstance());
466 EXPECT_NE(orig_site_instance, new_site_instance);
467 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
469 // Now disown the opener.
470 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
471 "window.opener = null;"));
472 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
474 // Go back and ensure the opener is still null.
476 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
477 new_shell->web_contents()->GetController().GoBack();
478 back_nav_load_observer.Wait();
480 success = false;
481 EXPECT_TRUE(ExecuteScriptAndExtractBool(
482 new_shell->web_contents(),
483 "window.domAutomationController.send(window.opener == null);",
484 &success));
485 EXPECT_TRUE(success);
486 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
488 // Now navigate forward again (creating a new process) and check opener.
489 NavigateToURL(new_shell, GetCrossSiteURL("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);
496 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
499 // Test that subframes can disown their openers. http://crbug.com/225528.
500 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
501 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
502 NavigateToURL(shell(), frame_url);
504 // Give the frame an opener using window.open.
505 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
506 "window.open('about:blank','foo');"));
508 // Now disown the frame's opener. Shouldn't crash.
509 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
510 "window.frames[0].opener = null;"));
513 // Test for crbug.com/99202. PostMessage calls should still work after
514 // navigating the source and target windows to different sites.
515 // Specifically:
516 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
517 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
518 // 3) Post a message from "foo" to opener, which replies back to "foo".
519 // 4) Post a message from _blank to "foo".
520 // 5) Post a message from "foo" to a subframe of opener, which replies back.
521 // 6) Post a message from _blank to a subframe of "foo".
522 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
523 SupportCrossProcessPostMessage) {
524 StartServer();
526 // Load a page with links that open in a new window.
527 std::string replacement_path;
528 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
529 "files/click-noreferrer-links.html",
530 foo_host_port_,
531 &replacement_path));
532 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
534 // Get the original SiteInstance and RVHM for later comparison.
535 WebContents* opener_contents = shell()->web_contents();
536 scoped_refptr<SiteInstance> orig_site_instance(
537 opener_contents->GetSiteInstance());
538 EXPECT_TRUE(orig_site_instance.get() != NULL);
539 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
540 opener_contents)->GetRenderManagerForTesting();
542 // 1) Open two more windows, one named. These initially have openers but no
543 // reference to each other. We will later post a message between them.
545 // First, a named target=foo window.
546 ShellAddedObserver new_shell_observer;
547 bool success = false;
548 EXPECT_TRUE(ExecuteScriptAndExtractBool(
549 opener_contents,
550 "window.domAutomationController.send(clickSameSiteTargetedLink());",
551 &success));
552 EXPECT_TRUE(success);
553 Shell* new_shell = new_shell_observer.GetShell();
555 // Wait for the navigation in the new window to finish, if it hasn't, then
556 // send it to post_message.html on a different site.
557 WebContents* foo_contents = new_shell->web_contents();
558 WaitForLoadStop(foo_contents);
559 EXPECT_EQ("/files/navigate_opener.html",
560 foo_contents->GetLastCommittedURL().path());
561 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
562 scoped_refptr<SiteInstance> foo_site_instance(
563 foo_contents->GetSiteInstance());
564 EXPECT_NE(orig_site_instance, foo_site_instance);
566 // Second, a target=_blank window.
567 ShellAddedObserver new_shell_observer2;
568 EXPECT_TRUE(ExecuteScriptAndExtractBool(
569 shell()->web_contents(),
570 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
571 &success));
572 EXPECT_TRUE(success);
574 // Wait for the navigation in the new window to finish, if it hasn't, then
575 // send it to post_message.html on the original site.
576 Shell* new_shell2 = new_shell_observer2.GetShell();
577 WebContents* new_contents = new_shell2->web_contents();
578 WaitForLoadStop(new_contents);
579 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
580 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
581 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
582 RenderFrameHostManager* new_manager =
583 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
585 // We now have three windows. The opener should have a swapped out RVH
586 // for the new SiteInstance, but the _blank window should not.
587 EXPECT_EQ(3u, Shell::windows().size());
588 EXPECT_TRUE(
589 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
590 EXPECT_FALSE(
591 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
593 // 2) Fail to post a message from the foo window to the opener if the target
594 // origin is wrong. We won't see an error, but we can check for the right
595 // number of received messages below.
596 EXPECT_TRUE(ExecuteScriptAndExtractBool(
597 foo_contents,
598 "window.domAutomationController.send(postToOpener('msg',"
599 " 'http://google.com'));",
600 &success));
601 EXPECT_TRUE(success);
602 ASSERT_FALSE(
603 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
605 // 3) Post a message from the foo window to the opener. The opener will
606 // reply, causing the foo window to update its own title.
607 base::string16 expected_title = ASCIIToUTF16("msg");
608 TitleWatcher title_watcher(foo_contents, expected_title);
609 EXPECT_TRUE(ExecuteScriptAndExtractBool(
610 foo_contents,
611 "window.domAutomationController.send(postToOpener('msg','*'));",
612 &success));
613 EXPECT_TRUE(success);
614 ASSERT_FALSE(
615 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
616 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
618 // We should have received only 1 message in the opener and "foo" tabs,
619 // and updated the title.
620 int opener_received_messages = 0;
621 EXPECT_TRUE(ExecuteScriptAndExtractInt(
622 opener_contents,
623 "window.domAutomationController.send(window.receivedMessages);",
624 &opener_received_messages));
625 int foo_received_messages = 0;
626 EXPECT_TRUE(ExecuteScriptAndExtractInt(
627 foo_contents,
628 "window.domAutomationController.send(window.receivedMessages);",
629 &foo_received_messages));
630 EXPECT_EQ(1, foo_received_messages);
631 EXPECT_EQ(1, opener_received_messages);
632 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
634 // 4) Now post a message from the _blank window to the foo window. The
635 // foo window will update its title and will not reply.
636 expected_title = ASCIIToUTF16("msg2");
637 TitleWatcher title_watcher2(foo_contents, expected_title);
638 EXPECT_TRUE(ExecuteScriptAndExtractBool(
639 new_contents,
640 "window.domAutomationController.send(postToFoo('msg2'));",
641 &success));
642 EXPECT_TRUE(success);
643 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
645 // This postMessage should have created a swapped out RVH for the new
646 // SiteInstance in the target=_blank window.
647 EXPECT_TRUE(
648 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
650 // TODO(nasko): Test subframe targeting of postMessage once
651 // http://crbug.com/153701 is fixed.
654 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
655 // messages which contain Transferables and get intercepted by
656 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
657 // swapped out) should work.
658 // Specifically:
659 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
660 // 2) Post a message containing a message port from opener to "foo".
661 // 3) Post a message from "foo" back to opener via the passed message port.
662 // The test will be enabled when the feature implementation lands.
663 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
664 SupportCrossProcessPostMessageWithMessagePort) {
665 StartServer();
667 // Load a page with links that open in a new window.
668 std::string replacement_path;
669 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
670 "files/click-noreferrer-links.html",
671 foo_host_port_,
672 &replacement_path));
673 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
675 // Get the original SiteInstance and RVHM for later comparison.
676 WebContents* opener_contents = shell()->web_contents();
677 scoped_refptr<SiteInstance> orig_site_instance(
678 opener_contents->GetSiteInstance());
679 EXPECT_TRUE(orig_site_instance.get() != NULL);
680 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
681 opener_contents)->GetRenderManagerForTesting();
683 // 1) Open a named target=foo window. We will later post a message between the
684 // opener and the new window.
685 ShellAddedObserver new_shell_observer;
686 bool success = false;
687 EXPECT_TRUE(ExecuteScriptAndExtractBool(
688 opener_contents,
689 "window.domAutomationController.send(clickSameSiteTargetedLink());",
690 &success));
691 EXPECT_TRUE(success);
692 Shell* new_shell = new_shell_observer.GetShell();
694 // Wait for the navigation in the new window to finish, if it hasn't, then
695 // send it to post_message.html on a different site.
696 WebContents* foo_contents = new_shell->web_contents();
697 WaitForLoadStop(foo_contents);
698 EXPECT_EQ("/files/navigate_opener.html",
699 foo_contents->GetLastCommittedURL().path());
700 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
701 scoped_refptr<SiteInstance> foo_site_instance(
702 foo_contents->GetSiteInstance());
703 EXPECT_NE(orig_site_instance, foo_site_instance);
705 // We now have two windows. The opener should have a swapped out RVH
706 // for the new SiteInstance.
707 EXPECT_EQ(2u, Shell::windows().size());
708 EXPECT_TRUE(
709 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
711 // 2) Post a message containing a MessagePort from opener to the the foo
712 // window. The foo window will reply via the passed port, causing the opener
713 // to update its own title.
714 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
715 TitleWatcher title_observer(opener_contents, expected_title);
716 EXPECT_TRUE(ExecuteScriptAndExtractBool(
717 opener_contents,
718 "window.domAutomationController.send(postWithPortToFoo());",
719 &success));
720 EXPECT_TRUE(success);
721 ASSERT_FALSE(
722 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
723 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
725 // Check message counts.
726 int opener_received_messages_via_port = 0;
727 EXPECT_TRUE(ExecuteScriptAndExtractInt(
728 opener_contents,
729 "window.domAutomationController.send(window.receivedMessagesViaPort);",
730 &opener_received_messages_via_port));
731 int foo_received_messages = 0;
732 EXPECT_TRUE(ExecuteScriptAndExtractInt(
733 foo_contents,
734 "window.domAutomationController.send(window.receivedMessages);",
735 &foo_received_messages));
736 int foo_received_messages_with_port = 0;
737 EXPECT_TRUE(ExecuteScriptAndExtractInt(
738 foo_contents,
739 "window.domAutomationController.send(window.receivedMessagesWithPort);",
740 &foo_received_messages_with_port));
741 EXPECT_EQ(1, foo_received_messages);
742 EXPECT_EQ(1, foo_received_messages_with_port);
743 EXPECT_EQ(1, opener_received_messages_via_port);
744 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
745 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
748 // Test for crbug.com/116192. Navigations to a window's opener should
749 // still work after a process swap.
750 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
751 AllowTargetedNavigationsInOpenerAfterSwap) {
752 StartServer();
754 // Load a page with links that open in a new window.
755 std::string replacement_path;
756 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
757 "files/click-noreferrer-links.html",
758 foo_host_port_,
759 &replacement_path));
760 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
762 // Get the original tab and SiteInstance for later comparison.
763 WebContents* orig_contents = shell()->web_contents();
764 scoped_refptr<SiteInstance> orig_site_instance(
765 orig_contents->GetSiteInstance());
766 EXPECT_TRUE(orig_site_instance.get() != NULL);
768 // Test clicking a target=foo link.
769 ShellAddedObserver new_shell_observer;
770 bool success = false;
771 EXPECT_TRUE(ExecuteScriptAndExtractBool(
772 orig_contents,
773 "window.domAutomationController.send(clickSameSiteTargetedLink());",
774 &success));
775 EXPECT_TRUE(success);
776 Shell* new_shell = new_shell_observer.GetShell();
778 // Wait for the navigation in the new window to finish, if it hasn't.
779 WaitForLoadStop(new_shell->web_contents());
780 EXPECT_EQ("/files/navigate_opener.html",
781 new_shell->web_contents()->GetLastCommittedURL().path());
783 // Should have the same SiteInstance.
784 scoped_refptr<SiteInstance> blank_site_instance(
785 new_shell->web_contents()->GetSiteInstance());
786 EXPECT_EQ(orig_site_instance, blank_site_instance);
788 // Now navigate the original (opener) tab to a different site.
789 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
790 scoped_refptr<SiteInstance> new_site_instance(
791 shell()->web_contents()->GetSiteInstance());
792 EXPECT_NE(orig_site_instance, new_site_instance);
794 // The opened tab should be able to navigate the opener back to its process.
795 TestNavigationObserver navigation_observer(orig_contents);
796 EXPECT_TRUE(ExecuteScriptAndExtractBool(
797 new_shell->web_contents(),
798 "window.domAutomationController.send(navigateOpener());",
799 &success));
800 EXPECT_TRUE(success);
801 navigation_observer.Wait();
803 // Should have swapped back into this process.
804 scoped_refptr<SiteInstance> revisit_site_instance(
805 shell()->web_contents()->GetSiteInstance());
806 EXPECT_EQ(orig_site_instance, revisit_site_instance);
809 // Test that opening a new window in the same SiteInstance and then navigating
810 // both windows to a different SiteInstance allows the first process to exit.
811 // See http://crbug.com/126333.
812 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
813 ProcessExitWithSwappedOutViews) {
814 StartServer();
816 // Load a page with links that open in a new window.
817 std::string replacement_path;
818 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
819 "files/click-noreferrer-links.html",
820 foo_host_port_,
821 &replacement_path));
822 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
824 // Get the original SiteInstance for later comparison.
825 scoped_refptr<SiteInstance> orig_site_instance(
826 shell()->web_contents()->GetSiteInstance());
827 EXPECT_TRUE(orig_site_instance.get() != NULL);
829 // Test clicking a target=foo link.
830 ShellAddedObserver new_shell_observer;
831 bool success = false;
832 EXPECT_TRUE(ExecuteScriptAndExtractBool(
833 shell()->web_contents(),
834 "window.domAutomationController.send(clickSameSiteTargetedLink());",
835 &success));
836 EXPECT_TRUE(success);
837 Shell* new_shell = new_shell_observer.GetShell();
839 // Wait for the navigation in the new window to finish, if it hasn't.
840 WaitForLoadStop(new_shell->web_contents());
841 EXPECT_EQ("/files/navigate_opener.html",
842 new_shell->web_contents()->GetLastCommittedURL().path());
844 // Should have the same SiteInstance.
845 scoped_refptr<SiteInstance> opened_site_instance(
846 new_shell->web_contents()->GetSiteInstance());
847 EXPECT_EQ(orig_site_instance, opened_site_instance);
849 // Now navigate the opened window to a different site.
850 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
851 scoped_refptr<SiteInstance> new_site_instance(
852 new_shell->web_contents()->GetSiteInstance());
853 EXPECT_NE(orig_site_instance, new_site_instance);
855 // The original process should still be alive, since it is still used in the
856 // first window.
857 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
858 EXPECT_TRUE(orig_process->HasConnection());
860 // Navigate the first window to a different site as well. The original
861 // process should exit, since all of its views are now swapped out.
862 RenderProcessHostWatcher exit_observer(
863 orig_process,
864 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
865 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
866 exit_observer.Wait();
867 scoped_refptr<SiteInstance> new_site_instance2(
868 shell()->web_contents()->GetSiteInstance());
869 EXPECT_EQ(new_site_instance, new_site_instance2);
872 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
873 // error should not make us ignore future renderer-initiated navigations.
874 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
875 StartServer();
877 // Get the original SiteInstance for later comparison.
878 scoped_refptr<SiteInstance> orig_site_instance(
879 shell()->web_contents()->GetSiteInstance());
880 EXPECT_TRUE(orig_site_instance.get() != NULL);
882 // Load a cross-site page that fails with a 204 error.
883 NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
885 // We should still be looking at the normal page. Because we started from a
886 // blank new tab, the typed URL will still be visible until the user clears it
887 // manually. The last committed URL will be the previous page.
888 scoped_refptr<SiteInstance> post_nav_site_instance(
889 shell()->web_contents()->GetSiteInstance());
890 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
891 EXPECT_EQ("/nocontent",
892 shell()->web_contents()->GetVisibleURL().path());
893 EXPECT_FALSE(
894 shell()->web_contents()->GetController().GetLastCommittedEntry());
896 // Renderer-initiated navigations should work.
897 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
898 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
899 GURL url = test_server()->GetURL("files/title2.html");
900 EXPECT_TRUE(ExecuteScript(
901 shell()->web_contents(),
902 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
903 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
905 // Opens in same tab.
906 EXPECT_EQ(1u, Shell::windows().size());
907 EXPECT_EQ("/files/title2.html",
908 shell()->web_contents()->GetLastCommittedURL().path());
910 // Should have the same SiteInstance.
911 scoped_refptr<SiteInstance> new_site_instance(
912 shell()->web_contents()->GetSiteInstance());
913 EXPECT_EQ(orig_site_instance, new_site_instance);
916 // Test for crbug.com/9682. We should show the URL for a pending renderer-
917 // initiated navigation in a new tab, until the content of the initial
918 // about:blank page is modified by another window. At that point, we should
919 // revert to showing about:blank to prevent a URL spoof.
920 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
921 ASSERT_TRUE(test_server()->Start());
923 // Load a page that can open a URL that won't commit in a new window.
924 NavigateToURL(
925 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
926 WebContents* orig_contents = shell()->web_contents();
928 // Click a /nocontent link that opens in a new window but never commits.
929 ShellAddedObserver new_shell_observer;
930 bool success = false;
931 EXPECT_TRUE(ExecuteScriptAndExtractBool(
932 orig_contents,
933 "window.domAutomationController.send(clickNoContentTargetedLink());",
934 &success));
935 EXPECT_TRUE(success);
937 // Wait for the window to open.
938 Shell* new_shell = new_shell_observer.GetShell();
940 // Ensure the destination URL is visible, because it is considered the
941 // initial navigation.
942 WebContents* contents = new_shell->web_contents();
943 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
944 EXPECT_EQ("/nocontent",
945 contents->GetController().GetVisibleEntry()->GetURL().path());
947 // Now modify the contents of the new window from the opener. This will also
948 // modify the title of the document to give us something to listen for.
949 base::string16 expected_title = ASCIIToUTF16("Modified Title");
950 TitleWatcher title_watcher(contents, expected_title);
951 success = false;
952 EXPECT_TRUE(ExecuteScriptAndExtractBool(
953 orig_contents,
954 "window.domAutomationController.send(modifyNewWindow());",
955 &success));
956 EXPECT_TRUE(success);
957 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
959 // At this point, we should no longer be showing the destination URL.
960 // The visible entry should be null, resulting in about:blank in the address
961 // bar.
962 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
965 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
966 // initiated navigation in a new tab if it is not the initial navigation. In
967 // this case, the renderer will not notify us of a modification, so we cannot
968 // show the pending URL without allowing a spoof.
969 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
970 DontShowLoadingURLIfNotInitialNav) {
971 ASSERT_TRUE(test_server()->Start());
973 // Load a page that can open a URL that won't commit in a new window.
974 NavigateToURL(
975 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
976 WebContents* orig_contents = shell()->web_contents();
978 // Click a /nocontent link that opens in a new window but never commits.
979 // By using an onclick handler that first creates the window, the slow
980 // navigation is not considered an initial navigation.
981 ShellAddedObserver new_shell_observer;
982 bool success = false;
983 EXPECT_TRUE(ExecuteScriptAndExtractBool(
984 orig_contents,
985 "window.domAutomationController.send("
986 "clickNoContentScriptedTargetedLink());",
987 &success));
988 EXPECT_TRUE(success);
990 // Wait for the window to open.
991 Shell* new_shell = new_shell_observer.GetShell();
993 // Ensure the destination URL is not visible, because it is not the initial
994 // navigation.
995 WebContents* contents = new_shell->web_contents();
996 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
997 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1000 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1001 #if defined(THREAD_SANITIZER)
1002 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1003 #else
1004 #define MAYBE_BackForwardNotStale BackForwardNotStale
1005 #endif
1006 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1007 // do not cause back/forward navigations to be considered stale by the
1008 // renderer.
1009 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1010 StartServer();
1011 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1013 // Visit a page on first site.
1014 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1016 // Visit three pages on second site.
1017 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1018 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1019 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1021 // History is now [blank, A1, B1, B2, *B3].
1022 WebContents* contents = shell()->web_contents();
1023 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1025 // Open another window in same process to keep this process alive.
1026 Shell* new_shell = CreateBrowser();
1027 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1029 // Go back three times to first site.
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 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1042 shell()->web_contents()->GetController().GoBack();
1043 back_nav_load_observer.Wait();
1046 // Now go forward twice to B2. Shouldn't be left spinning.
1048 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1049 shell()->web_contents()->GetController().GoForward();
1050 forward_nav_load_observer.Wait();
1053 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1054 shell()->web_contents()->GetController().GoForward();
1055 forward_nav_load_observer.Wait();
1058 // Go back twice to first site.
1060 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1061 shell()->web_contents()->GetController().GoBack();
1062 back_nav_load_observer.Wait();
1065 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1066 shell()->web_contents()->GetController().GoBack();
1067 back_nav_load_observer.Wait();
1070 // Now go forward directly to B3. Shouldn't be left spinning.
1072 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1073 shell()->web_contents()->GetController().GoToIndex(4);
1074 forward_nav_load_observer.Wait();
1078 // Test for http://crbug.com/130016.
1079 // Swapping out a render view should update its visiblity state.
1080 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1081 SwappedOutViewHasCorrectVisibilityState) {
1082 StartServer();
1084 // Load a page with links that open in a new window.
1085 std::string replacement_path;
1086 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1087 "files/click-noreferrer-links.html",
1088 foo_host_port_,
1089 &replacement_path));
1090 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1092 // Open a same-site link in a new widnow.
1093 ShellAddedObserver new_shell_observer;
1094 bool success = false;
1095 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1096 shell()->web_contents(),
1097 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1098 &success));
1099 EXPECT_TRUE(success);
1100 Shell* new_shell = new_shell_observer.GetShell();
1102 // Wait for the navigation in the new tab to finish, if it hasn't.
1103 WaitForLoadStop(new_shell->web_contents());
1104 EXPECT_EQ("/files/navigate_opener.html",
1105 new_shell->web_contents()->GetLastCommittedURL().path());
1107 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1109 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1110 rvh,
1111 "window.domAutomationController.send("
1112 " document.visibilityState == 'visible');",
1113 &success));
1114 EXPECT_TRUE(success);
1116 // Now navigate the new window to a different site. This should swap out the
1117 // tab's existing RenderView, causing it become hidden.
1118 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1120 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1121 rvh,
1122 "window.domAutomationController.send("
1123 " document.visibilityState == 'hidden');",
1124 &success));
1125 EXPECT_TRUE(success);
1127 // Going back should make the previously swapped-out view to become visible
1128 // again.
1130 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1131 new_shell->web_contents()->GetController().GoBack();
1132 back_nav_load_observer.Wait();
1135 EXPECT_EQ("/files/navigate_opener.html",
1136 new_shell->web_contents()->GetLastCommittedURL().path());
1138 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1140 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1141 rvh,
1142 "window.domAutomationController.send("
1143 " document.visibilityState == 'visible');",
1144 &success));
1145 EXPECT_TRUE(success);
1148 // This class ensures that all the given RenderViewHosts have properly been
1149 // shutdown.
1150 class RenderViewHostDestructionObserver : public WebContentsObserver {
1151 public:
1152 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1153 : WebContentsObserver(web_contents) {}
1154 ~RenderViewHostDestructionObserver() override {}
1155 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1156 watched_render_view_hosts_.insert(rvh);
1158 size_t GetNumberOfWatchedRenderViewHosts() const {
1159 return watched_render_view_hosts_.size();
1162 private:
1163 // WebContentsObserver implementation:
1164 void RenderViewDeleted(RenderViewHost* rvh) override {
1165 watched_render_view_hosts_.erase(rvh);
1168 std::set<RenderViewHost*> watched_render_view_hosts_;
1171 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1172 #if defined(THREAD_SANITIZER)
1173 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1174 #else
1175 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1176 #endif
1177 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1178 // they may cause crashes or memory corruptions when trying to call dead
1179 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1180 // ensure that a separate SiteInstance is created when navigating to view-source
1181 // URLs, regardless of current URL.
1182 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1183 MAYBE_LeakingRenderViewHosts) {
1184 StartServer();
1186 // Observe the created render_view_host's to make sure they will not leak.
1187 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1189 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1190 GURL view_source_url(kViewSourceScheme + std::string(":") +
1191 navigated_url.spec());
1193 // Let's ensure that when we start with a blank window, navigating away to a
1194 // view-source URL, we create a new SiteInstance.
1195 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1196 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1197 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1198 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1199 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1201 // Now navigate to the view-source URL and ensure we got a different
1202 // SiteInstance and RenderViewHost.
1203 NavigateToURL(shell(), view_source_url);
1204 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1205 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1206 GetRenderViewHost()->GetSiteInstance());
1207 rvh_observers.EnsureRVHGetsDestructed(
1208 shell()->web_contents()->GetRenderViewHost());
1210 // Load a random page and then navigate to view-source: of it.
1211 // This used to cause two RVH instances for the same SiteInstance, which
1212 // was a problem. This is no longer the case.
1213 NavigateToURL(shell(), navigated_url);
1214 SiteInstance* site_instance1 = shell()->web_contents()->
1215 GetRenderViewHost()->GetSiteInstance();
1216 rvh_observers.EnsureRVHGetsDestructed(
1217 shell()->web_contents()->GetRenderViewHost());
1219 NavigateToURL(shell(), view_source_url);
1220 rvh_observers.EnsureRVHGetsDestructed(
1221 shell()->web_contents()->GetRenderViewHost());
1222 SiteInstance* site_instance2 = shell()->web_contents()->
1223 GetRenderViewHost()->GetSiteInstance();
1225 // Ensure that view-source navigations force a new SiteInstance.
1226 EXPECT_NE(site_instance1, site_instance2);
1228 // Now navigate to a different instance so that we swap out again.
1229 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1230 rvh_observers.EnsureRVHGetsDestructed(
1231 shell()->web_contents()->GetRenderViewHost());
1233 // This used to leak a render view host.
1234 shell()->Close();
1236 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1238 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1241 // Test for crbug.com/143155. Frame tree updates during unload should not
1242 // interrupt the intended navigation and show swappedout:// instead.
1243 // Specifically:
1244 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1245 // 2) Send the second tab to a different foo.com SiteInstance.
1246 // This creates a swapped out opener for the first tab in the foo process.
1247 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1248 // tab's unload handler remove its frame.
1249 // This used to cause an update to the frame tree of the swapped out RV,
1250 // just as it was navigating to a real page. That pre-empted the real
1251 // navigation and visibly sent the tab to swappedout://.
1252 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1253 DontPreemptNavigationWithFrameTreeUpdate) {
1254 StartServer();
1256 // 1. Load a page that deletes its iframe during unload.
1257 NavigateToURL(shell(),
1258 test_server()->GetURL("files/remove_frame_on_unload.html"));
1260 // Get the original SiteInstance for later comparison.
1261 scoped_refptr<SiteInstance> orig_site_instance(
1262 shell()->web_contents()->GetSiteInstance());
1264 // Open a same-site page in a new window.
1265 ShellAddedObserver new_shell_observer;
1266 bool success = false;
1267 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1268 shell()->web_contents(),
1269 "window.domAutomationController.send(openWindow());",
1270 &success));
1271 EXPECT_TRUE(success);
1272 Shell* new_shell = new_shell_observer.GetShell();
1274 // Wait for the navigation in the new window to finish, if it hasn't.
1275 WaitForLoadStop(new_shell->web_contents());
1276 EXPECT_EQ("/files/title1.html",
1277 new_shell->web_contents()->GetLastCommittedURL().path());
1279 // Should have the same SiteInstance.
1280 EXPECT_EQ(orig_site_instance.get(),
1281 new_shell->web_contents()->GetSiteInstance());
1283 // 2. Send the second tab to a different process.
1284 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1285 scoped_refptr<SiteInstance> new_site_instance(
1286 new_shell->web_contents()->GetSiteInstance());
1287 EXPECT_NE(orig_site_instance, new_site_instance);
1289 // 3. Send the first tab to the second tab's process.
1290 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1292 // Make sure it ends up at the right page.
1293 WaitForLoadStop(shell()->web_contents());
1294 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1295 shell()->web_contents()->GetLastCommittedURL());
1296 EXPECT_EQ(new_site_instance.get(),
1297 shell()->web_contents()->GetSiteInstance());
1300 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1301 // are meant to run in the current page. We had a bug where we expected a
1302 // BrowsingInstance swap to occur on pages like view-source and extensions,
1303 // which broke chrome://crash and javascript: URLs.
1304 // See http://crbug.com/335503.
1305 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1306 ASSERT_TRUE(test_server()->Start());
1308 GURL original_url(test_server()->GetURL("files/title2.html"));
1309 GURL view_source_url(kViewSourceScheme + std::string(":") +
1310 original_url.spec());
1312 NavigateToURL(shell(), view_source_url);
1314 // Check that javascript: URLs work.
1315 base::string16 expected_title = ASCIIToUTF16("msg");
1316 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1317 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1318 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1320 // Crash the renderer of the view-source page.
1321 RenderProcessHostWatcher crash_observer(
1322 shell()->web_contents(),
1323 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1324 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1325 crash_observer.Wait();
1328 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1329 // Otherwise, we might try to load an unprivileged about:blank page into a
1330 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1331 // See http://crbug.com/334214.
1332 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1333 IgnoreRendererDebugURLsWhenCrashed) {
1334 // Visit a WebUI page with bindings.
1335 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1336 std::string(kChromeUIGpuHost));
1337 NavigateToURL(shell(), webui_url);
1338 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1339 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1341 // Crash the renderer of the WebUI page.
1342 RenderProcessHostWatcher crash_observer(
1343 shell()->web_contents(),
1344 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1345 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1346 crash_observer.Wait();
1348 // Load the crash URL again but don't wait for any action. If it is not
1349 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1350 shell()->LoadURL(GURL(kChromeUICrashURL));
1352 // Ensure that such URLs can still work as the initial navigation of a tab.
1353 // We postpone the initial navigation of the tab using an empty GURL, so that
1354 // we can add a watcher for crashes.
1355 Shell* shell2 = Shell::CreateNewWindow(
1356 shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1357 MSG_ROUTING_NONE, gfx::Size());
1358 RenderProcessHostWatcher crash_observer2(
1359 shell2->web_contents(),
1360 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1361 NavigateToURL(shell2, GURL(kChromeUIKillURL));
1362 crash_observer2.Wait();
1365 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1366 // Otherwise it might get picked up by InitRenderView when granting bindings
1367 // to other RenderViewHosts. See http://crbug.com/330811.
1368 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) {
1369 // Visit a WebUI page with bindings.
1370 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1371 std::string(kChromeUIGpuHost)));
1372 NavigateToURL(shell(), webui_url);
1373 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1374 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1375 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1376 shell()->web_contents());
1377 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1378 EXPECT_TRUE(webui);
1379 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1381 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1382 // clear pending_web_ui() when it commits.
1383 GURL webui_url2(webui_url.spec() + "#foo");
1384 NavigateToURL(shell(), webui_url2);
1385 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1386 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1389 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1390 public:
1391 RFHMProcessPerTabTest() {}
1393 void SetUpCommandLine(CommandLine* command_line) override {
1394 command_line->AppendSwitch(switches::kProcessPerTab);
1398 // Test that we still swap processes for BrowsingInstance changes even in
1399 // --process-per-tab mode. See http://crbug.com/343017.
1400 // Disabled on Android: http://crbug.com/345873.
1401 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1402 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1403 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1404 #else
1405 #define MAYBE_BackFromWebUI BackFromWebUI
1406 #endif
1407 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1408 ASSERT_TRUE(test_server()->Start());
1409 GURL original_url(test_server()->GetURL("files/title2.html"));
1410 NavigateToURL(shell(), original_url);
1412 // Visit a WebUI page with bindings.
1413 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1414 std::string(kChromeUIGpuHost)));
1415 NavigateToURL(shell(), webui_url);
1416 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1417 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1419 // Go back and ensure we have no WebUI bindings.
1420 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1421 shell()->web_contents()->GetController().GoBack();
1422 back_nav_load_observer.Wait();
1423 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1424 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1425 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1428 // crbug.com/372360
1429 // The test loads url1, opens a link pointing to url2 in a new tab, and
1430 // navigates the new tab to url1.
1431 // The following is needed for the bug to happen:
1432 // - url1 must require webui bindings;
1433 // - navigating to url2 in the site instance of url1 should not swap
1434 // browsing instances, but should require a new site instance.
1435 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1436 GURL url1(std::string(kChromeUIScheme) + "://" +
1437 std::string(kChromeUIGpuHost));
1438 GURL url2(std::string(kChromeUIScheme) + "://" +
1439 std::string(kChromeUIAccessibilityHost));
1441 // Visit a WebUI page with bindings.
1442 NavigateToURL(shell(), url1);
1443 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1444 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1445 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1447 // Open a new tab. Initially it gets a render view in the original tab's
1448 // current site instance.
1449 TestNavigationObserver nav_observer(NULL);
1450 nav_observer.StartWatchingNewWebContents();
1451 ShellAddedObserver shao;
1452 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1453 nav_observer.Wait();
1454 Shell* new_shell = shao.GetShell();
1455 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1456 new_shell->web_contents());
1457 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1459 EXPECT_NE(site_instance2, site_instance1);
1460 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1461 RenderViewHost* initial_rvh = new_web_contents->
1462 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1463 ASSERT_TRUE(initial_rvh);
1464 // The following condition is what was causing the bug.
1465 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1467 // Navigate to url1 and check bindings.
1468 NavigateToURL(new_shell, url1);
1469 // The navigation should have used the first SiteInstance, otherwise
1470 // |initial_rvh| did not have a chance to be used.
1471 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1472 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1473 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1476 // crbug.com/424526
1477 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1478 // page and then to a regular page. The bug reproduces if blank page is visited
1479 // in between WebUI and regular page.
1480 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1481 ForceSwapAfterWebUIBindings) {
1482 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kProcessPerTab);
1483 ASSERT_TRUE(test_server()->Start());
1485 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1486 std::string(kChromeUIGpuHost));
1487 NavigateToURL(shell(), web_ui_url);
1488 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1489 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1491 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1493 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1494 NavigateToURL(shell(), regular_page_url);
1495 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1496 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1499 } // namespace content