DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blobf626fc7ee6d95bbc10ec8d7795e836adee7a9fe2
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/location.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/path_service.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/values.h"
16 #include "content/browser/child_process_security_policy_impl.h"
17 #include "content/browser/frame_host/render_frame_proxy_host.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/site_instance_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/browser/webui/web_ui_impl.h"
22 #include "content/common/content_constants_internal.h"
23 #include "content/public/browser/navigation_controller.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/common/bindings_policy.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/file_chooser_file_info.h"
31 #include "content/public/common/file_chooser_params.h"
32 #include "content/public/common/page_state.h"
33 #include "content/public/common/url_constants.h"
34 #include "content/public/test/browser_test_utils.h"
35 #include "content/public/test/content_browser_test.h"
36 #include "content/public/test/content_browser_test_utils.h"
37 #include "content/public/test/test_navigation_observer.h"
38 #include "content/public/test/test_utils.h"
39 #include "content/shell/browser/shell.h"
40 #include "net/base/net_util.h"
41 #include "net/dns/mock_host_resolver.h"
42 #include "net/test/embedded_test_server/embedded_test_server.h"
43 #include "net/test/spawned_test_server/spawned_test_server.h"
45 using base::ASCIIToUTF16;
47 namespace content {
49 namespace {
51 const char kOpenUrlViaClickTargetFunc[] =
52 "(function(url) {\n"
53 " var lnk = document.createElement(\"a\");\n"
54 " lnk.href = url;\n"
55 " lnk.target = \"_blank\";\n"
56 " document.body.appendChild(lnk);\n"
57 " lnk.click();\n"
58 "})";
60 // Adds a link with given url and target=_blank, and clicks on it.
61 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter,
62 const GURL& url) {
63 EXPECT_TRUE(ExecuteScript(adapter,
64 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
67 Shell* OpenPopup(const internal::ToRenderFrameHost& opener,
68 const std::string& name) {
69 ShellAddedObserver new_shell_observer;
70 bool success = false;
71 EXPECT_TRUE(ExecuteScriptAndExtractBool(
72 opener,
73 "window.domAutomationController.send(!!window.open('', '" + name + "'));",
74 &success));
75 EXPECT_TRUE(success);
76 Shell* new_shell = new_shell_observer.GetShell();
77 return new_shell;
80 } // anonymous namespace
82 class RenderFrameHostManagerTest : public ContentBrowserTest {
83 public:
84 RenderFrameHostManagerTest() : foo_com_("foo.com") {
85 replace_host_.SetHostStr(foo_com_);
88 static bool GetFilePathWithHostAndPortReplacement(
89 const std::string& original_file_path,
90 const net::HostPortPair& host_port_pair,
91 std::string* replacement_path) {
92 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
93 replacement_text.push_back(
94 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
95 return net::SpawnedTestServer::GetFilePathWithReplacements(
96 original_file_path, replacement_text, replacement_path);
99 void StartServer() {
100 // Support multiple sites on the test server.
101 host_resolver()->AddRule("*", "127.0.0.1");
102 ASSERT_TRUE(test_server()->Start());
104 foo_host_port_ = test_server()->host_port_pair();
105 foo_host_port_.set_host(foo_com_);
108 void StartEmbeddedServer() {
109 // Support multiple sites on the embedded test server.
110 host_resolver()->AddRule("*", "127.0.0.1");
111 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
112 SetupCrossSiteRedirector(embedded_test_server());
115 // Returns a URL on foo.com with the given path.
116 GURL GetCrossSiteURL(const std::string& path) {
117 GURL cross_site_url(test_server()->GetURL(path));
118 return cross_site_url.ReplaceComponents(replace_host_);
121 protected:
122 std::string foo_com_;
123 GURL::Replacements replace_host_;
124 net::HostPortPair foo_host_port_;
127 // Web pages should not have script access to the swapped out page.
128 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
129 StartServer();
131 // Load a page with links that open in a new window.
132 std::string replacement_path;
133 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
134 "files/click-noreferrer-links.html",
135 foo_host_port_,
136 &replacement_path));
137 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
139 // Get the original SiteInstance for later comparison.
140 scoped_refptr<SiteInstance> orig_site_instance(
141 shell()->web_contents()->GetSiteInstance());
142 EXPECT_TRUE(orig_site_instance.get() != NULL);
144 // Open a same-site link in a new window.
145 ShellAddedObserver new_shell_observer;
146 bool success = false;
147 EXPECT_TRUE(ExecuteScriptAndExtractBool(
148 shell()->web_contents(),
149 "window.domAutomationController.send(clickSameSiteTargetedLink());",
150 &success));
151 EXPECT_TRUE(success);
152 Shell* new_shell = new_shell_observer.GetShell();
154 // Wait for the navigation in the new window to finish, if it hasn't.
155 WaitForLoadStop(new_shell->web_contents());
156 EXPECT_EQ("/files/navigate_opener.html",
157 new_shell->web_contents()->GetLastCommittedURL().path());
159 // Should have the same SiteInstance.
160 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
162 // We should have access to the opened window's location.
163 success = false;
164 EXPECT_TRUE(ExecuteScriptAndExtractBool(
165 shell()->web_contents(),
166 "window.domAutomationController.send(testScriptAccessToWindow());",
167 &success));
168 EXPECT_TRUE(success);
170 // Now navigate the new window to a different site.
171 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
172 scoped_refptr<SiteInstance> new_site_instance(
173 new_shell->web_contents()->GetSiteInstance());
174 EXPECT_NE(orig_site_instance, new_site_instance);
176 // We should no longer have script access to the opened window's location.
177 success = false;
178 EXPECT_TRUE(ExecuteScriptAndExtractBool(
179 shell()->web_contents(),
180 "window.domAutomationController.send(testScriptAccessToWindow());",
181 &success));
182 EXPECT_FALSE(success);
184 // We now navigate the window to an about:blank page.
185 success = false;
186 EXPECT_TRUE(ExecuteScriptAndExtractBool(
187 shell()->web_contents(),
188 "window.domAutomationController.send(clickBlankTargetedLink());",
189 &success));
190 EXPECT_TRUE(success);
192 // Wait for the navigation in the new window to finish.
193 WaitForLoadStop(new_shell->web_contents());
194 GURL blank_url(url::kAboutBlankURL);
195 EXPECT_EQ(blank_url,
196 new_shell->web_contents()->GetLastCommittedURL());
197 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
199 // We should have access to the opened window's location.
200 success = false;
201 EXPECT_TRUE(ExecuteScriptAndExtractBool(
202 shell()->web_contents(),
203 "window.domAutomationController.send(testScriptAccessToWindow());",
204 &success));
205 EXPECT_TRUE(success);
208 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
209 // and target=_blank should create a new SiteInstance.
210 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
211 SwapProcessWithRelNoreferrerAndTargetBlank) {
212 StartServer();
214 // Load a page with links that open in a new window.
215 std::string replacement_path;
216 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
217 "files/click-noreferrer-links.html",
218 foo_host_port_,
219 &replacement_path));
220 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
222 // Get the original SiteInstance for later comparison.
223 scoped_refptr<SiteInstance> orig_site_instance(
224 shell()->web_contents()->GetSiteInstance());
225 EXPECT_TRUE(orig_site_instance.get() != NULL);
227 // Test clicking a rel=noreferrer + target=blank link.
228 ShellAddedObserver new_shell_observer;
229 bool success = false;
230 EXPECT_TRUE(ExecuteScriptAndExtractBool(
231 shell()->web_contents(),
232 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
233 &success));
234 EXPECT_TRUE(success);
236 // Wait for the window to open.
237 Shell* new_shell = new_shell_observer.GetShell();
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.
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 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
256 // for rel=noreferrer links in new windows, even to same site pages and named
257 // targets.
258 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
259 SwapProcessWithSameSiteRelNoreferrer) {
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 same-site rel=noreferrer + target=foo link.
276 ShellAddedObserver new_shell_observer;
277 bool success = false;
278 EXPECT_TRUE(ExecuteScriptAndExtractBool(
279 shell()->web_contents(),
280 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
281 &success));
282 EXPECT_TRUE(success);
284 // Wait for the window to open.
285 Shell* new_shell = new_shell_observer.GetShell();
287 // Opens in new window.
288 EXPECT_EQ("/files/title2.html",
289 new_shell->web_contents()->GetVisibleURL().path());
291 // Wait for the cross-site transition in the new tab to finish.
292 WaitForLoadStop(new_shell->web_contents());
293 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
294 new_shell->web_contents());
295 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
296 pending_render_view_host());
298 // Should have a new SiteInstance (in a new BrowsingInstance).
299 scoped_refptr<SiteInstance> noref_blank_site_instance(
300 new_shell->web_contents()->GetSiteInstance());
301 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
304 // Test for crbug.com/24447. Following a cross-site link with just
305 // target=_blank should not create a new SiteInstance, unless we
306 // are running in --site-per-process mode.
307 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
308 DontSwapProcessWithOnlyTargetBlank) {
309 StartServer();
311 // Load a page with links that open in a new window.
312 std::string replacement_path;
313 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
314 "files/click-noreferrer-links.html",
315 foo_host_port_,
316 &replacement_path));
317 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path)));
319 // Get the original SiteInstance for later comparison.
320 scoped_refptr<SiteInstance> orig_site_instance(
321 shell()->web_contents()->GetSiteInstance());
322 EXPECT_TRUE(orig_site_instance.get() != NULL);
324 // Test clicking a target=blank link.
325 ShellAddedObserver new_shell_observer;
326 bool success = false;
327 EXPECT_TRUE(ExecuteScriptAndExtractBool(
328 shell()->web_contents(),
329 "window.domAutomationController.send(clickTargetBlankLink());",
330 &success));
331 EXPECT_TRUE(success);
333 // Wait for the window to open.
334 Shell* new_shell = new_shell_observer.GetShell();
336 // Wait for the cross-site transition in the new tab to finish.
337 EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
338 EXPECT_EQ("/files/title2.html",
339 new_shell->web_contents()->GetLastCommittedURL().path());
341 // Should have the same SiteInstance unless we're in site-per-process mode.
342 scoped_refptr<SiteInstance> blank_site_instance(
343 new_shell->web_contents()->GetSiteInstance());
344 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
345 switches::kSitePerProcess))
346 EXPECT_EQ(orig_site_instance, blank_site_instance);
347 else
348 EXPECT_NE(orig_site_instance, blank_site_instance);
351 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
352 // and no target=_blank should not create a new SiteInstance.
353 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
354 DontSwapProcessWithOnlyRelNoreferrer) {
355 StartServer();
357 // Load a page with links that open in a new window.
358 std::string replacement_path;
359 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
360 "files/click-noreferrer-links.html",
361 foo_host_port_,
362 &replacement_path));
363 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
365 // Get the original SiteInstance for later comparison.
366 scoped_refptr<SiteInstance> orig_site_instance(
367 shell()->web_contents()->GetSiteInstance());
368 EXPECT_TRUE(orig_site_instance.get() != NULL);
370 // Test clicking a rel=noreferrer link.
371 bool success = false;
372 EXPECT_TRUE(ExecuteScriptAndExtractBool(
373 shell()->web_contents(),
374 "window.domAutomationController.send(clickNoRefLink());",
375 &success));
376 EXPECT_TRUE(success);
378 // Wait for the cross-site transition in the current tab to finish.
379 WaitForLoadStop(shell()->web_contents());
381 // Opens in same window.
382 EXPECT_EQ(1u, Shell::windows().size());
383 EXPECT_EQ("/files/title2.html",
384 shell()->web_contents()->GetLastCommittedURL().path());
386 // Should have the same SiteInstance unless we're in site-per-process mode.
387 scoped_refptr<SiteInstance> noref_site_instance(
388 shell()->web_contents()->GetSiteInstance());
389 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
390 switches::kSitePerProcess))
391 EXPECT_EQ(orig_site_instance, noref_site_instance);
392 else
393 EXPECT_NE(orig_site_instance, noref_site_instance);
396 // Test for crbug.com/116192. Targeted links should still work after the
397 // named target window has swapped processes.
398 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
399 AllowTargetedNavigationsAfterSwap) {
400 StartServer();
402 // Load a page with links that open in a new window.
403 std::string replacement_path;
404 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
405 "files/click-noreferrer-links.html",
406 foo_host_port_,
407 &replacement_path));
408 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
410 // Get the original SiteInstance for later comparison.
411 scoped_refptr<SiteInstance> orig_site_instance(
412 shell()->web_contents()->GetSiteInstance());
413 EXPECT_TRUE(orig_site_instance.get() != NULL);
415 // Test clicking a target=foo link.
416 ShellAddedObserver new_shell_observer;
417 bool success = false;
418 EXPECT_TRUE(ExecuteScriptAndExtractBool(
419 shell()->web_contents(),
420 "window.domAutomationController.send(clickSameSiteTargetedLink());",
421 &success));
422 EXPECT_TRUE(success);
423 Shell* new_shell = new_shell_observer.GetShell();
425 // Wait for the navigation in the new tab to finish, if it hasn't.
426 WaitForLoadStop(new_shell->web_contents());
427 EXPECT_EQ("/files/navigate_opener.html",
428 new_shell->web_contents()->GetLastCommittedURL().path());
430 // Should have the same SiteInstance.
431 scoped_refptr<SiteInstance> blank_site_instance(
432 new_shell->web_contents()->GetSiteInstance());
433 EXPECT_EQ(orig_site_instance, blank_site_instance);
435 // Now navigate the new tab to a different site.
436 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
437 NavigateToURL(new_shell, cross_site_url);
438 scoped_refptr<SiteInstance> new_site_instance(
439 new_shell->web_contents()->GetSiteInstance());
440 EXPECT_NE(orig_site_instance, new_site_instance);
442 // Clicking the original link in the first tab should cause us to swap back.
443 TestNavigationObserver navigation_observer(new_shell->web_contents());
444 EXPECT_TRUE(ExecuteScriptAndExtractBool(
445 shell()->web_contents(),
446 "window.domAutomationController.send(clickSameSiteTargetedLink());",
447 &success));
448 EXPECT_TRUE(success);
449 navigation_observer.Wait();
451 // Should have swapped back and shown the new window again.
452 scoped_refptr<SiteInstance> revisit_site_instance(
453 new_shell->web_contents()->GetSiteInstance());
454 EXPECT_EQ(orig_site_instance, revisit_site_instance);
456 // If it navigates away to another process, the original window should
457 // still be able to close it (using a cross-process close message).
458 NavigateToURL(new_shell, cross_site_url);
459 EXPECT_EQ(new_site_instance.get(),
460 new_shell->web_contents()->GetSiteInstance());
461 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
462 EXPECT_TRUE(ExecuteScriptAndExtractBool(
463 shell()->web_contents(),
464 "window.domAutomationController.send(testCloseWindow());",
465 &success));
466 EXPECT_TRUE(success);
467 close_watcher.Wait();
470 // Test that setting the opener to null in a window affects cross-process
471 // navigations, including those to existing entries. http://crbug.com/156669.
472 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
473 #if defined(THREAD_SANITIZER)
474 #define MAYBE_DisownOpener DISABLED_DisownOpener
475 #else
476 #define MAYBE_DisownOpener DisownOpener
477 #endif
478 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
479 StartServer();
481 // Load a page with links that open in a new window.
482 std::string replacement_path;
483 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
484 "files/click-noreferrer-links.html",
485 foo_host_port_,
486 &replacement_path));
487 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
489 // Get the original SiteInstance for later comparison.
490 scoped_refptr<SiteInstance> orig_site_instance(
491 shell()->web_contents()->GetSiteInstance());
492 EXPECT_TRUE(orig_site_instance.get() != NULL);
494 // Test clicking a target=_blank link.
495 ShellAddedObserver new_shell_observer;
496 bool success = false;
497 EXPECT_TRUE(ExecuteScriptAndExtractBool(
498 shell()->web_contents(),
499 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
500 &success));
501 EXPECT_TRUE(success);
502 Shell* new_shell = new_shell_observer.GetShell();
503 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
505 // Wait for the navigation in the new tab to finish, if it hasn't.
506 WaitForLoadStop(new_shell->web_contents());
507 EXPECT_EQ("/files/title2.html",
508 new_shell->web_contents()->GetLastCommittedURL().path());
510 // Should have the same SiteInstance.
511 scoped_refptr<SiteInstance> blank_site_instance(
512 new_shell->web_contents()->GetSiteInstance());
513 EXPECT_EQ(orig_site_instance, blank_site_instance);
515 // Now navigate the new tab to a different site.
516 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
517 scoped_refptr<SiteInstance> new_site_instance(
518 new_shell->web_contents()->GetSiteInstance());
519 EXPECT_NE(orig_site_instance, new_site_instance);
520 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
522 // Now disown the opener.
523 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
524 "window.opener = null;"));
525 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
527 // Go back and ensure the opener is still null.
529 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
530 new_shell->web_contents()->GetController().GoBack();
531 back_nav_load_observer.Wait();
533 success = false;
534 EXPECT_TRUE(ExecuteScriptAndExtractBool(
535 new_shell->web_contents(),
536 "window.domAutomationController.send(window.opener == null);",
537 &success));
538 EXPECT_TRUE(success);
539 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
541 // Now navigate forward again (creating a new process) and check opener.
542 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
543 success = false;
544 EXPECT_TRUE(ExecuteScriptAndExtractBool(
545 new_shell->web_contents(),
546 "window.domAutomationController.send(window.opener == null);",
547 &success));
548 EXPECT_TRUE(success);
549 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
552 // Test that subframes can disown their openers. http://crbug.com/225528.
553 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
554 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
555 NavigateToURL(shell(), frame_url);
557 // Give the frame an opener using window.open.
558 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
559 "window.open('about:blank','foo');"));
561 // Now disown the frame's opener. Shouldn't crash.
562 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
563 "window.frames[0].opener = null;"));
566 // Check that window.name is preserved for top frames when they navigate
567 // cross-process. See https://crbug.com/504164.
568 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
569 PreserveTopFrameWindowNameOnCrossProcessNavigations) {
570 StartEmbeddedServer();
572 GURL main_url(embedded_test_server()->GetURL("/title1.html"));
573 EXPECT_TRUE(NavigateToURL(shell(), main_url));
575 // Get the original SiteInstance for later comparison.
576 scoped_refptr<SiteInstance> orig_site_instance(
577 shell()->web_contents()->GetSiteInstance());
578 EXPECT_TRUE(orig_site_instance.get() != NULL);
580 // Open a popup using window.open with a 'foo' window.name.
581 Shell* new_shell = OpenPopup(shell()->web_contents(), "foo");
583 // The window.name for the new popup should be "foo".
584 std::string name;
585 EXPECT_TRUE(ExecuteScriptAndExtractString(
586 new_shell->web_contents(),
587 "window.domAutomationController.send(window.name);", &name));
588 EXPECT_EQ("foo", name);
590 // Now navigate the new tab to a different site.
591 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
592 EXPECT_TRUE(NavigateToURL(new_shell, foo_url));
593 scoped_refptr<SiteInstance> new_site_instance(
594 new_shell->web_contents()->GetSiteInstance());
595 EXPECT_NE(orig_site_instance, new_site_instance);
597 // window.name should still be "foo".
598 name = "";
599 EXPECT_TRUE(ExecuteScriptAndExtractString(
600 new_shell->web_contents(),
601 "window.domAutomationController.send(window.name);", &name));
602 EXPECT_EQ("foo", name);
604 // Open another popup from the 'foo' popup and navigate it cross-site.
605 Shell* new_shell2 = OpenPopup(new_shell->web_contents(), "bar");
606 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title3.html"));
607 EXPECT_TRUE(NavigateToURL(new_shell2, bar_url));
609 // Check that the new popup's window.opener has name "foo", which verifies
610 // that new swapped-out RenderViews also propagate window.name. This has to
611 // be done via window.open, since window.name isn't readable cross-origin.
612 bool success = false;
613 EXPECT_TRUE(ExecuteScriptAndExtractBool(
614 new_shell2->web_contents(),
615 "window.domAutomationController.send("
616 " window.opener === window.open('','foo'));",
617 &success));
618 EXPECT_TRUE(success);
621 // Test for crbug.com/99202. PostMessage calls should still work after
622 // navigating the source and target windows to different sites.
623 // Specifically:
624 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
625 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
626 // 3) Post a message from "foo" to opener, which replies back to "foo".
627 // 4) Post a message from _blank to "foo".
628 // 5) Post a message from "foo" to a subframe of opener, which replies back.
629 // 6) Post a message from _blank to a subframe of "foo".
630 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
631 SupportCrossProcessPostMessage) {
632 StartServer();
634 // Load a page with links that open in a new window.
635 std::string replacement_path;
636 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
637 "files/click-noreferrer-links.html",
638 foo_host_port_,
639 &replacement_path));
640 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
642 // Get the original SiteInstance and RVHM for later comparison.
643 WebContents* opener_contents = shell()->web_contents();
644 scoped_refptr<SiteInstance> orig_site_instance(
645 opener_contents->GetSiteInstance());
646 EXPECT_TRUE(orig_site_instance.get() != NULL);
647 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
648 opener_contents)->GetRenderManagerForTesting();
650 // 1) Open two more windows, one named. These initially have openers but no
651 // reference to each other. We will later post a message between them.
653 // First, a named target=foo window.
654 ShellAddedObserver new_shell_observer;
655 bool success = false;
656 EXPECT_TRUE(ExecuteScriptAndExtractBool(
657 opener_contents,
658 "window.domAutomationController.send(clickSameSiteTargetedLink());",
659 &success));
660 EXPECT_TRUE(success);
661 Shell* new_shell = new_shell_observer.GetShell();
663 // Wait for the navigation in the new window to finish, if it hasn't, then
664 // send it to post_message.html on a different site.
665 WebContents* foo_contents = new_shell->web_contents();
666 WaitForLoadStop(foo_contents);
667 EXPECT_EQ("/files/navigate_opener.html",
668 foo_contents->GetLastCommittedURL().path());
669 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
670 scoped_refptr<SiteInstance> foo_site_instance(
671 foo_contents->GetSiteInstance());
672 EXPECT_NE(orig_site_instance, foo_site_instance);
674 // Second, a target=_blank window.
675 ShellAddedObserver new_shell_observer2;
676 EXPECT_TRUE(ExecuteScriptAndExtractBool(
677 shell()->web_contents(),
678 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
679 &success));
680 EXPECT_TRUE(success);
682 // Wait for the navigation in the new window to finish, if it hasn't, then
683 // send it to post_message.html on the original site.
684 Shell* new_shell2 = new_shell_observer2.GetShell();
685 WebContents* new_contents = new_shell2->web_contents();
686 WaitForLoadStop(new_contents);
687 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
688 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
689 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
690 RenderFrameHostManager* new_manager =
691 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
693 // We now have three windows. The opener should have a swapped out RVH
694 // for the new SiteInstance, but the _blank window should not.
695 EXPECT_EQ(3u, Shell::windows().size());
696 EXPECT_TRUE(
697 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
698 EXPECT_FALSE(
699 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
701 // 2) Fail to post a message from the foo window to the opener if the target
702 // origin is wrong. We won't see an error, but we can check for the right
703 // number of received messages below.
704 EXPECT_TRUE(ExecuteScriptAndExtractBool(
705 foo_contents,
706 "window.domAutomationController.send(postToOpener('msg',"
707 " 'http://google.com'));",
708 &success));
709 EXPECT_TRUE(success);
710 ASSERT_FALSE(
711 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
713 // 3) Post a message from the foo window to the opener. The opener will
714 // reply, causing the foo window to update its own title.
715 base::string16 expected_title = ASCIIToUTF16("msg");
716 TitleWatcher title_watcher(foo_contents, expected_title);
717 EXPECT_TRUE(ExecuteScriptAndExtractBool(
718 foo_contents,
719 "window.domAutomationController.send(postToOpener('msg','*'));",
720 &success));
721 EXPECT_TRUE(success);
722 ASSERT_FALSE(
723 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
724 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
726 // We should have received only 1 message in the opener and "foo" tabs,
727 // and updated the title.
728 int opener_received_messages = 0;
729 EXPECT_TRUE(ExecuteScriptAndExtractInt(
730 opener_contents,
731 "window.domAutomationController.send(window.receivedMessages);",
732 &opener_received_messages));
733 int foo_received_messages = 0;
734 EXPECT_TRUE(ExecuteScriptAndExtractInt(
735 foo_contents,
736 "window.domAutomationController.send(window.receivedMessages);",
737 &foo_received_messages));
738 EXPECT_EQ(1, foo_received_messages);
739 EXPECT_EQ(1, opener_received_messages);
740 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
742 // 4) Now post a message from the _blank window to the foo window. The
743 // foo window will update its title and will not reply.
744 expected_title = ASCIIToUTF16("msg2");
745 TitleWatcher title_watcher2(foo_contents, expected_title);
746 EXPECT_TRUE(ExecuteScriptAndExtractBool(
747 new_contents,
748 "window.domAutomationController.send(postToFoo('msg2'));",
749 &success));
750 EXPECT_TRUE(success);
751 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
753 // This postMessage should have created a swapped out RVH for the new
754 // SiteInstance in the target=_blank window.
755 EXPECT_TRUE(
756 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
758 // TODO(nasko): Test subframe targeting of postMessage once
759 // http://crbug.com/153701 is fixed.
762 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
763 // messages which contain Transferables and get intercepted by
764 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
765 // swapped out) should work.
766 // Specifically:
767 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
768 // 2) Post a message containing a message port from opener to "foo".
769 // 3) Post a message from "foo" back to opener via the passed message port.
770 // The test will be enabled when the feature implementation lands.
771 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
772 SupportCrossProcessPostMessageWithMessagePort) {
773 StartServer();
775 // Load a page with links that open in a new window.
776 std::string replacement_path;
777 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
778 "files/click-noreferrer-links.html",
779 foo_host_port_,
780 &replacement_path));
781 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
783 // Get the original SiteInstance and RVHM for later comparison.
784 WebContents* opener_contents = shell()->web_contents();
785 scoped_refptr<SiteInstance> orig_site_instance(
786 opener_contents->GetSiteInstance());
787 EXPECT_TRUE(orig_site_instance.get() != NULL);
788 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
789 opener_contents)->GetRenderManagerForTesting();
791 // 1) Open a named target=foo window. We will later post a message between the
792 // opener and the new window.
793 ShellAddedObserver new_shell_observer;
794 bool success = false;
795 EXPECT_TRUE(ExecuteScriptAndExtractBool(
796 opener_contents,
797 "window.domAutomationController.send(clickSameSiteTargetedLink());",
798 &success));
799 EXPECT_TRUE(success);
800 Shell* new_shell = new_shell_observer.GetShell();
802 // Wait for the navigation in the new window to finish, if it hasn't, then
803 // send it to post_message.html on a different site.
804 WebContents* foo_contents = new_shell->web_contents();
805 WaitForLoadStop(foo_contents);
806 EXPECT_EQ("/files/navigate_opener.html",
807 foo_contents->GetLastCommittedURL().path());
808 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
809 scoped_refptr<SiteInstance> foo_site_instance(
810 foo_contents->GetSiteInstance());
811 EXPECT_NE(orig_site_instance, foo_site_instance);
813 // We now have two windows. The opener should have a swapped out RVH
814 // for the new SiteInstance.
815 EXPECT_EQ(2u, Shell::windows().size());
816 EXPECT_TRUE(
817 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
819 // 2) Post a message containing a MessagePort from opener to the the foo
820 // window. The foo window will reply via the passed port, causing the opener
821 // to update its own title.
822 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
823 TitleWatcher title_observer(opener_contents, expected_title);
824 EXPECT_TRUE(ExecuteScriptAndExtractBool(
825 opener_contents,
826 "window.domAutomationController.send(postWithPortToFoo());",
827 &success));
828 EXPECT_TRUE(success);
829 ASSERT_FALSE(
830 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
831 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
833 // Check message counts.
834 int opener_received_messages_via_port = 0;
835 EXPECT_TRUE(ExecuteScriptAndExtractInt(
836 opener_contents,
837 "window.domAutomationController.send(window.receivedMessagesViaPort);",
838 &opener_received_messages_via_port));
839 int foo_received_messages = 0;
840 EXPECT_TRUE(ExecuteScriptAndExtractInt(
841 foo_contents,
842 "window.domAutomationController.send(window.receivedMessages);",
843 &foo_received_messages));
844 int foo_received_messages_with_port = 0;
845 EXPECT_TRUE(ExecuteScriptAndExtractInt(
846 foo_contents,
847 "window.domAutomationController.send(window.receivedMessagesWithPort);",
848 &foo_received_messages_with_port));
849 EXPECT_EQ(1, foo_received_messages);
850 EXPECT_EQ(1, foo_received_messages_with_port);
851 EXPECT_EQ(1, opener_received_messages_via_port);
852 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
853 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
856 // Test for crbug.com/116192. Navigations to a window's opener should
857 // still work after a process swap.
858 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
859 AllowTargetedNavigationsInOpenerAfterSwap) {
860 StartServer();
862 // Load a page with links that open in a new window.
863 std::string replacement_path;
864 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
865 "files/click-noreferrer-links.html",
866 foo_host_port_,
867 &replacement_path));
868 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
870 // Get the original tab and SiteInstance for later comparison.
871 WebContents* orig_contents = shell()->web_contents();
872 scoped_refptr<SiteInstance> orig_site_instance(
873 orig_contents->GetSiteInstance());
874 EXPECT_TRUE(orig_site_instance.get() != NULL);
876 // Test clicking a target=foo link.
877 ShellAddedObserver new_shell_observer;
878 bool success = false;
879 EXPECT_TRUE(ExecuteScriptAndExtractBool(
880 orig_contents,
881 "window.domAutomationController.send(clickSameSiteTargetedLink());",
882 &success));
883 EXPECT_TRUE(success);
884 Shell* new_shell = new_shell_observer.GetShell();
886 // Wait for the navigation in the new window to finish, if it hasn't.
887 WaitForLoadStop(new_shell->web_contents());
888 EXPECT_EQ("/files/navigate_opener.html",
889 new_shell->web_contents()->GetLastCommittedURL().path());
891 // Should have the same SiteInstance.
892 scoped_refptr<SiteInstance> blank_site_instance(
893 new_shell->web_contents()->GetSiteInstance());
894 EXPECT_EQ(orig_site_instance, blank_site_instance);
896 // Now navigate the original (opener) tab to a different site.
897 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
898 scoped_refptr<SiteInstance> new_site_instance(
899 shell()->web_contents()->GetSiteInstance());
900 EXPECT_NE(orig_site_instance, new_site_instance);
902 // The opened tab should be able to navigate the opener back to its process.
903 TestNavigationObserver navigation_observer(orig_contents);
904 EXPECT_TRUE(ExecuteScriptAndExtractBool(
905 new_shell->web_contents(),
906 "window.domAutomationController.send(navigateOpener());",
907 &success));
908 EXPECT_TRUE(success);
909 navigation_observer.Wait();
911 // Should have swapped back into this process.
912 scoped_refptr<SiteInstance> revisit_site_instance(
913 shell()->web_contents()->GetSiteInstance());
914 EXPECT_EQ(orig_site_instance, revisit_site_instance);
917 // Test that subframes do not crash when sending a postMessage to the top frame
918 // from an unload handler while the top frame is being swapped out as part of
919 // navigating cross-process. https://crbug.com/475651.
920 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
921 PostMessageFromSubframeUnloadHandler) {
922 StartServer();
924 GURL frame_url(test_server()->GetURL("files/post_message.html"));
925 GURL main_url("data:text/html,<iframe name='foo' src='" + frame_url.spec() +
926 "'></iframe>");
927 EXPECT_TRUE(NavigateToURL(shell(), main_url));
929 // Get the original SiteInstance for later comparison.
930 scoped_refptr<SiteInstance> orig_site_instance(
931 shell()->web_contents()->GetSiteInstance());
932 EXPECT_NE(nullptr, orig_site_instance.get());
934 // It is safe to obtain the root frame tree node here, as it doesn't change.
935 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
936 ->GetFrameTree()
937 ->root();
938 ASSERT_EQ(1U, root->child_count());
939 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
941 // Register an unload handler that sends a postMessage to the top frame.
942 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
943 "registerUnload();"));
945 // Navigate the top frame cross-site. This will cause the top frame to be
946 // swapped out and run unload handlers, and the original renderer process
947 // should then terminate since it's not rendering any other frames.
948 RenderProcessHostWatcher exit_observer(
949 root->current_frame_host()->GetProcess(),
950 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
951 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
952 scoped_refptr<SiteInstance> new_site_instance(
953 shell()->web_contents()->GetSiteInstance());
954 EXPECT_NE(orig_site_instance, new_site_instance);
956 // Ensure that the original renderer process exited cleanly without crashing.
957 exit_observer.Wait();
958 EXPECT_EQ(true, exit_observer.did_exit_normally());
961 // Test that opening a new window in the same SiteInstance and then navigating
962 // both windows to a different SiteInstance allows the first process to exit.
963 // See http://crbug.com/126333.
964 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
965 ProcessExitWithSwappedOutViews) {
966 StartServer();
968 // Load a page with links that open in a new window.
969 std::string replacement_path;
970 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
971 "files/click-noreferrer-links.html",
972 foo_host_port_,
973 &replacement_path));
974 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
976 // Get the original SiteInstance for later comparison.
977 scoped_refptr<SiteInstance> orig_site_instance(
978 shell()->web_contents()->GetSiteInstance());
979 EXPECT_TRUE(orig_site_instance.get() != NULL);
981 // Test clicking a target=foo link.
982 ShellAddedObserver new_shell_observer;
983 bool success = false;
984 EXPECT_TRUE(ExecuteScriptAndExtractBool(
985 shell()->web_contents(),
986 "window.domAutomationController.send(clickSameSiteTargetedLink());",
987 &success));
988 EXPECT_TRUE(success);
989 Shell* new_shell = new_shell_observer.GetShell();
991 // Wait for the navigation in the new window to finish, if it hasn't.
992 WaitForLoadStop(new_shell->web_contents());
993 EXPECT_EQ("/files/navigate_opener.html",
994 new_shell->web_contents()->GetLastCommittedURL().path());
996 // Should have the same SiteInstance.
997 scoped_refptr<SiteInstance> opened_site_instance(
998 new_shell->web_contents()->GetSiteInstance());
999 EXPECT_EQ(orig_site_instance, opened_site_instance);
1001 // Now navigate the opened window to a different site.
1002 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1003 scoped_refptr<SiteInstance> new_site_instance(
1004 new_shell->web_contents()->GetSiteInstance());
1005 EXPECT_NE(orig_site_instance, new_site_instance);
1007 // The original process should still be alive, since it is still used in the
1008 // first window.
1009 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
1010 EXPECT_TRUE(orig_process->HasConnection());
1012 // Navigate the first window to a different site as well. The original
1013 // process should exit, since all of its views are now swapped out.
1014 RenderProcessHostWatcher exit_observer(
1015 orig_process,
1016 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1017 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1018 exit_observer.Wait();
1019 scoped_refptr<SiteInstance> new_site_instance2(
1020 shell()->web_contents()->GetSiteInstance());
1021 EXPECT_EQ(new_site_instance, new_site_instance2);
1024 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
1025 // error should not make us ignore future renderer-initiated navigations.
1026 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
1027 StartServer();
1029 // Get the original SiteInstance for later comparison.
1030 scoped_refptr<SiteInstance> orig_site_instance(
1031 shell()->web_contents()->GetSiteInstance());
1032 EXPECT_TRUE(orig_site_instance.get() != NULL);
1034 // Load a cross-site page that fails with a 204 error.
1035 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
1036 GetCrossSiteURL("nocontent")));
1038 // We should still be looking at the normal page. Because we started from a
1039 // blank new tab, the typed URL will still be visible until the user clears it
1040 // manually. The last committed URL will be the previous page.
1041 scoped_refptr<SiteInstance> post_nav_site_instance(
1042 shell()->web_contents()->GetSiteInstance());
1043 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
1044 EXPECT_EQ("/nocontent",
1045 shell()->web_contents()->GetVisibleURL().path());
1046 EXPECT_FALSE(
1047 shell()->web_contents()->GetController().GetLastCommittedEntry());
1049 // Renderer-initiated navigations should work.
1050 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
1051 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1052 GURL url = test_server()->GetURL("files/title2.html");
1053 EXPECT_TRUE(ExecuteScript(
1054 shell()->web_contents(),
1055 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
1056 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1058 // Opens in same tab.
1059 EXPECT_EQ(1u, Shell::windows().size());
1060 EXPECT_EQ("/files/title2.html",
1061 shell()->web_contents()->GetLastCommittedURL().path());
1063 // Should have the same SiteInstance.
1064 scoped_refptr<SiteInstance> new_site_instance(
1065 shell()->web_contents()->GetSiteInstance());
1066 EXPECT_EQ(orig_site_instance, new_site_instance);
1069 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1070 // initiated navigation in a new tab, until the content of the initial
1071 // about:blank page is modified by another window. At that point, we should
1072 // revert to showing about:blank to prevent a URL spoof.
1073 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
1074 ASSERT_TRUE(test_server()->Start());
1076 // Load a page that can open a URL that won't commit in a new window.
1077 NavigateToURL(
1078 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1079 WebContents* orig_contents = shell()->web_contents();
1081 // Click a /nocontent link that opens in a new window but never commits.
1082 ShellAddedObserver new_shell_observer;
1083 bool success = false;
1084 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1085 orig_contents,
1086 "window.domAutomationController.send(clickNoContentTargetedLink());",
1087 &success));
1088 EXPECT_TRUE(success);
1090 // Wait for the window to open.
1091 Shell* new_shell = new_shell_observer.GetShell();
1093 // Ensure the destination URL is visible, because it is considered the
1094 // initial navigation.
1095 WebContents* contents = new_shell->web_contents();
1096 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
1097 EXPECT_EQ("/nocontent",
1098 contents->GetController().GetVisibleEntry()->GetURL().path());
1100 // Now modify the contents of the new window from the opener. This will also
1101 // modify the title of the document to give us something to listen for.
1102 base::string16 expected_title = ASCIIToUTF16("Modified Title");
1103 TitleWatcher title_watcher(contents, expected_title);
1104 success = false;
1105 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1106 orig_contents,
1107 "window.domAutomationController.send(modifyNewWindow());",
1108 &success));
1109 EXPECT_TRUE(success);
1110 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1112 // At this point, we should no longer be showing the destination URL.
1113 // The visible entry should be null, resulting in about:blank in the address
1114 // bar.
1115 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1118 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1119 // initiated navigation in a new tab if it is not the initial navigation. In
1120 // this case, the renderer will not notify us of a modification, so we cannot
1121 // show the pending URL without allowing a spoof.
1122 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1123 DontShowLoadingURLIfNotInitialNav) {
1124 ASSERT_TRUE(test_server()->Start());
1126 // Load a page that can open a URL that won't commit in a new window.
1127 NavigateToURL(
1128 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1129 WebContents* orig_contents = shell()->web_contents();
1131 // Click a /nocontent link that opens in a new window but never commits.
1132 // By using an onclick handler that first creates the window, the slow
1133 // navigation is not considered an initial navigation.
1134 ShellAddedObserver new_shell_observer;
1135 bool success = false;
1136 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1137 orig_contents,
1138 "window.domAutomationController.send("
1139 "clickNoContentScriptedTargetedLink());",
1140 &success));
1141 EXPECT_TRUE(success);
1143 // Wait for the window to open.
1144 Shell* new_shell = new_shell_observer.GetShell();
1146 // Ensure the destination URL is not visible, because it is not the initial
1147 // navigation.
1148 WebContents* contents = new_shell->web_contents();
1149 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1150 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1153 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1154 #if defined(THREAD_SANITIZER)
1155 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1156 #else
1157 #define MAYBE_BackForwardNotStale BackForwardNotStale
1158 #endif
1159 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1160 // do not cause back/forward navigations to be considered stale by the
1161 // renderer.
1162 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1163 StartServer();
1164 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1166 // Visit a page on first site.
1167 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1169 // Visit three pages on second site.
1170 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1171 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1172 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1174 // History is now [blank, A1, B1, B2, *B3].
1175 WebContents* contents = shell()->web_contents();
1176 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1178 // Open another window in same process to keep this process alive.
1179 Shell* new_shell = CreateBrowser();
1180 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1182 // Go back three times to first site.
1184 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1185 shell()->web_contents()->GetController().GoBack();
1186 back_nav_load_observer.Wait();
1189 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1190 shell()->web_contents()->GetController().GoBack();
1191 back_nav_load_observer.Wait();
1194 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1195 shell()->web_contents()->GetController().GoBack();
1196 back_nav_load_observer.Wait();
1199 // Now go forward twice to B2. Shouldn't be left spinning.
1201 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1202 shell()->web_contents()->GetController().GoForward();
1203 forward_nav_load_observer.Wait();
1206 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1207 shell()->web_contents()->GetController().GoForward();
1208 forward_nav_load_observer.Wait();
1211 // Go back twice to first site.
1213 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1214 shell()->web_contents()->GetController().GoBack();
1215 back_nav_load_observer.Wait();
1218 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1219 shell()->web_contents()->GetController().GoBack();
1220 back_nav_load_observer.Wait();
1223 // Now go forward directly to B3. Shouldn't be left spinning.
1225 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1226 shell()->web_contents()->GetController().GoToIndex(4);
1227 forward_nav_load_observer.Wait();
1231 // Test for http://crbug.com/130016.
1232 // Swapping out a render view should update its visiblity state.
1233 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1234 SwappedOutViewHasCorrectVisibilityState) {
1235 // This test is invalid in --site-per-process mode, as swapped-out is no
1236 // longer used.
1237 if (RenderFrameHostManager::IsSwappedOutStateForbidden())
1238 return;
1239 StartServer();
1241 // Load a page with links that open in a new window.
1242 std::string replacement_path;
1243 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1244 "files/click-noreferrer-links.html",
1245 foo_host_port_,
1246 &replacement_path));
1247 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1249 // Open a same-site link in a new widnow.
1250 ShellAddedObserver new_shell_observer;
1251 bool success = false;
1252 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1253 shell()->web_contents(),
1254 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1255 &success));
1256 EXPECT_TRUE(success);
1257 Shell* new_shell = new_shell_observer.GetShell();
1259 // Wait for the navigation in the new tab to finish, if it hasn't.
1260 WaitForLoadStop(new_shell->web_contents());
1261 EXPECT_EQ("/files/navigate_opener.html",
1262 new_shell->web_contents()->GetLastCommittedURL().path());
1264 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1266 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1267 rvh,
1268 "window.domAutomationController.send("
1269 " document.visibilityState == 'visible');",
1270 &success));
1271 EXPECT_TRUE(success);
1273 // Now navigate the new window to a different site. This should swap out the
1274 // tab's existing RenderView, causing it become hidden.
1275 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1277 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1278 rvh,
1279 "window.domAutomationController.send("
1280 " document.visibilityState == 'hidden');",
1281 &success));
1282 EXPECT_TRUE(success);
1284 // Going back should make the previously swapped-out view to become visible
1285 // again.
1287 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1288 new_shell->web_contents()->GetController().GoBack();
1289 back_nav_load_observer.Wait();
1292 EXPECT_EQ("/files/navigate_opener.html",
1293 new_shell->web_contents()->GetLastCommittedURL().path());
1295 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1297 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1298 rvh,
1299 "window.domAutomationController.send("
1300 " document.visibilityState == 'visible');",
1301 &success));
1302 EXPECT_TRUE(success);
1305 // This class ensures that all the given RenderViewHosts have properly been
1306 // shutdown.
1307 class RenderViewHostDestructionObserver : public WebContentsObserver {
1308 public:
1309 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1310 : WebContentsObserver(web_contents) {}
1311 ~RenderViewHostDestructionObserver() override {}
1312 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1313 watched_render_view_hosts_.insert(rvh);
1315 size_t GetNumberOfWatchedRenderViewHosts() const {
1316 return watched_render_view_hosts_.size();
1319 private:
1320 // WebContentsObserver implementation:
1321 void RenderViewDeleted(RenderViewHost* rvh) override {
1322 watched_render_view_hosts_.erase(rvh);
1325 std::set<RenderViewHost*> watched_render_view_hosts_;
1328 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1329 #if defined(THREAD_SANITIZER)
1330 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1331 #else
1332 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1333 #endif
1334 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1335 // they may cause crashes or memory corruptions when trying to call dead
1336 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1337 // ensure that a separate SiteInstance is created when navigating to view-source
1338 // URLs, regardless of current URL.
1339 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1340 MAYBE_LeakingRenderViewHosts) {
1341 StartServer();
1343 // Observe the created render_view_host's to make sure they will not leak.
1344 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1346 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1347 GURL view_source_url(kViewSourceScheme + std::string(":") +
1348 navigated_url.spec());
1350 // Let's ensure that when we start with a blank window, navigating away to a
1351 // view-source URL, we create a new SiteInstance.
1352 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1353 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1354 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1355 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1356 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1358 // Now navigate to the view-source URL and ensure we got a different
1359 // SiteInstance and RenderViewHost.
1360 NavigateToURL(shell(), view_source_url);
1361 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1362 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1363 GetRenderViewHost()->GetSiteInstance());
1364 rvh_observers.EnsureRVHGetsDestructed(
1365 shell()->web_contents()->GetRenderViewHost());
1367 // Load a random page and then navigate to view-source: of it.
1368 // This used to cause two RVH instances for the same SiteInstance, which
1369 // was a problem. This is no longer the case.
1370 NavigateToURL(shell(), navigated_url);
1371 SiteInstance* site_instance1 = shell()->web_contents()->
1372 GetRenderViewHost()->GetSiteInstance();
1373 rvh_observers.EnsureRVHGetsDestructed(
1374 shell()->web_contents()->GetRenderViewHost());
1376 NavigateToURL(shell(), view_source_url);
1377 rvh_observers.EnsureRVHGetsDestructed(
1378 shell()->web_contents()->GetRenderViewHost());
1379 SiteInstance* site_instance2 = shell()->web_contents()->
1380 GetRenderViewHost()->GetSiteInstance();
1382 // Ensure that view-source navigations force a new SiteInstance.
1383 EXPECT_NE(site_instance1, site_instance2);
1385 // Now navigate to a different instance so that we swap out again.
1386 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1387 rvh_observers.EnsureRVHGetsDestructed(
1388 shell()->web_contents()->GetRenderViewHost());
1390 // This used to leak a render view host.
1391 shell()->Close();
1393 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1395 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1398 // Test for crbug.com/143155. Frame tree updates during unload should not
1399 // interrupt the intended navigation and show swappedout:// instead.
1400 // Specifically:
1401 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1402 // 2) Send the second tab to a different foo.com SiteInstance.
1403 // This creates a swapped out opener for the first tab in the foo process.
1404 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1405 // tab's unload handler remove its frame.
1406 // This used to cause an update to the frame tree of the swapped out RV,
1407 // just as it was navigating to a real page. That pre-empted the real
1408 // navigation and visibly sent the tab to swappedout://.
1409 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1410 DontPreemptNavigationWithFrameTreeUpdate) {
1411 StartServer();
1413 // 1. Load a page that deletes its iframe during unload.
1414 NavigateToURL(shell(),
1415 test_server()->GetURL("files/remove_frame_on_unload.html"));
1417 // Get the original SiteInstance for later comparison.
1418 scoped_refptr<SiteInstance> orig_site_instance(
1419 shell()->web_contents()->GetSiteInstance());
1421 // Open a same-site page in a new window.
1422 ShellAddedObserver new_shell_observer;
1423 bool success = false;
1424 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1425 shell()->web_contents(),
1426 "window.domAutomationController.send(openWindow());",
1427 &success));
1428 EXPECT_TRUE(success);
1429 Shell* new_shell = new_shell_observer.GetShell();
1431 // Wait for the navigation in the new window to finish, if it hasn't.
1432 WaitForLoadStop(new_shell->web_contents());
1433 EXPECT_EQ("/files/title1.html",
1434 new_shell->web_contents()->GetLastCommittedURL().path());
1436 // Should have the same SiteInstance.
1437 EXPECT_EQ(orig_site_instance.get(),
1438 new_shell->web_contents()->GetSiteInstance());
1440 // 2. Send the second tab to a different process.
1441 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1442 scoped_refptr<SiteInstance> new_site_instance(
1443 new_shell->web_contents()->GetSiteInstance());
1444 EXPECT_NE(orig_site_instance, new_site_instance);
1446 // 3. Send the first tab to the second tab's process.
1447 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1449 // Make sure it ends up at the right page.
1450 WaitForLoadStop(shell()->web_contents());
1451 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1452 shell()->web_contents()->GetLastCommittedURL());
1453 EXPECT_EQ(new_site_instance.get(),
1454 shell()->web_contents()->GetSiteInstance());
1457 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1458 // are meant to run in the current page. We had a bug where we expected a
1459 // BrowsingInstance swap to occur on pages like view-source and extensions,
1460 // which broke chrome://crash and javascript: URLs.
1461 // See http://crbug.com/335503.
1462 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1463 ASSERT_TRUE(test_server()->Start());
1465 GURL original_url(test_server()->GetURL("files/title2.html"));
1466 GURL view_source_url(kViewSourceScheme + std::string(":") +
1467 original_url.spec());
1469 NavigateToURL(shell(), view_source_url);
1471 // Check that javascript: URLs work.
1472 base::string16 expected_title = ASCIIToUTF16("msg");
1473 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1474 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1475 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1477 // Crash the renderer of the view-source page.
1478 RenderProcessHostWatcher crash_observer(
1479 shell()->web_contents(),
1480 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1481 EXPECT_TRUE(
1482 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1483 crash_observer.Wait();
1486 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1487 // Otherwise, we might try to load an unprivileged about:blank page into a
1488 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1489 // See http://crbug.com/334214.
1490 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1491 IgnoreRendererDebugURLsWhenCrashed) {
1492 // Visit a WebUI page with bindings.
1493 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1494 std::string(kChromeUIGpuHost));
1495 NavigateToURL(shell(), webui_url);
1496 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1497 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1499 // Crash the renderer of the WebUI page.
1500 RenderProcessHostWatcher crash_observer(
1501 shell()->web_contents(),
1502 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1503 EXPECT_TRUE(
1504 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1505 crash_observer.Wait();
1507 // Load the crash URL again but don't wait for any action. If it is not
1508 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1509 shell()->LoadURL(GURL(kChromeUICrashURL));
1511 // Ensure that such URLs can still work as the initial navigation of a tab.
1512 // We postpone the initial navigation of the tab using an empty GURL, so that
1513 // we can add a watcher for crashes.
1514 Shell* shell2 = Shell::CreateNewWindow(
1515 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, gfx::Size());
1516 RenderProcessHostWatcher crash_observer2(
1517 shell2->web_contents(),
1518 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1519 EXPECT_TRUE(
1520 NavigateToURLAndExpectNoCommit(shell2, GURL(kChromeUIKillURL)));
1521 crash_observer2.Wait();
1524 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1525 // See http://crbug.com/428329.
1526 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1527 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1528 #else
1529 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1530 #endif
1531 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1532 // Otherwise it might get picked up by InitRenderView when granting bindings
1533 // to other RenderViewHosts. See http://crbug.com/330811.
1534 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1535 MAYBE_ClearPendingWebUIOnCommit) {
1536 // Visit a WebUI page with bindings.
1537 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1538 std::string(kChromeUIGpuHost)));
1539 NavigateToURL(shell(), webui_url);
1540 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1541 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1542 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1543 shell()->web_contents());
1544 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1545 EXPECT_TRUE(webui);
1546 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1548 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1549 // clear pending_web_ui() when it commits.
1550 GURL webui_url2(webui_url.spec() + "#foo");
1551 NavigateToURL(shell(), webui_url2);
1552 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1553 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1556 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1557 public:
1558 RFHMProcessPerTabTest() {}
1560 void SetUpCommandLine(base::CommandLine* command_line) override {
1561 command_line->AppendSwitch(switches::kProcessPerTab);
1565 // Test that we still swap processes for BrowsingInstance changes even in
1566 // --process-per-tab mode. See http://crbug.com/343017.
1567 // Disabled on Android: http://crbug.com/345873.
1568 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1569 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1570 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1571 #else
1572 #define MAYBE_BackFromWebUI BackFromWebUI
1573 #endif
1574 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1575 ASSERT_TRUE(test_server()->Start());
1576 GURL original_url(test_server()->GetURL("files/title2.html"));
1577 NavigateToURL(shell(), original_url);
1579 // Visit a WebUI page with bindings.
1580 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1581 std::string(kChromeUIGpuHost)));
1582 NavigateToURL(shell(), webui_url);
1583 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1584 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1586 // Go back and ensure we have no WebUI bindings.
1587 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1588 shell()->web_contents()->GetController().GoBack();
1589 back_nav_load_observer.Wait();
1590 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1591 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1592 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1595 // crbug.com/372360
1596 // The test loads url1, opens a link pointing to url2 in a new tab, and
1597 // navigates the new tab to url1.
1598 // The following is needed for the bug to happen:
1599 // - url1 must require webui bindings;
1600 // - navigating to url2 in the site instance of url1 should not swap
1601 // browsing instances, but should require a new site instance.
1602 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1603 GURL url1(std::string(kChromeUIScheme) + "://" +
1604 std::string(kChromeUIGpuHost));
1605 GURL url2(std::string(kChromeUIScheme) + "://" +
1606 std::string(kChromeUIAccessibilityHost));
1608 // Visit a WebUI page with bindings.
1609 NavigateToURL(shell(), url1);
1610 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1611 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1612 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1614 // Open a new tab. Initially it gets a render view in the original tab's
1615 // current site instance.
1616 TestNavigationObserver nav_observer(NULL);
1617 nav_observer.StartWatchingNewWebContents();
1618 ShellAddedObserver shao;
1619 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1620 nav_observer.Wait();
1621 Shell* new_shell = shao.GetShell();
1622 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1623 new_shell->web_contents());
1624 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1626 EXPECT_NE(site_instance2, site_instance1);
1627 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1628 RenderViewHost* initial_rvh = new_web_contents->
1629 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1630 ASSERT_TRUE(initial_rvh);
1631 // The following condition is what was causing the bug.
1632 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1634 // Navigate to url1 and check bindings.
1635 NavigateToURL(new_shell, url1);
1636 // The navigation should have used the first SiteInstance, otherwise
1637 // |initial_rvh| did not have a chance to be used.
1638 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1639 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1640 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1643 // crbug.com/424526
1644 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1645 // page and then to a regular page. The bug reproduces if blank page is visited
1646 // in between WebUI and regular page.
1647 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1648 ForceSwapAfterWebUIBindings) {
1649 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1650 switches::kProcessPerTab);
1651 ASSERT_TRUE(test_server()->Start());
1653 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1654 std::string(kChromeUIGpuHost));
1655 NavigateToURL(shell(), web_ui_url);
1656 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1657 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1659 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1661 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1662 NavigateToURL(shell(), regular_page_url);
1663 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1664 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1667 class FileChooserDelegate : public WebContentsDelegate {
1668 public:
1669 FileChooserDelegate(const base::FilePath& file)
1670 : file_(file), file_chosen_(false) {}
1672 void RunFileChooser(WebContents* web_contents,
1673 const FileChooserParams& params) override {
1674 // Send the selected file to the renderer process.
1675 FileChooserFileInfo file_info;
1676 file_info.file_path = file_;
1677 std::vector<FileChooserFileInfo> files;
1678 files.push_back(file_info);
1679 web_contents->GetRenderViewHost()->FilesSelectedInChooser(
1680 files, FileChooserParams::Open);
1682 file_chosen_ = true;
1685 bool file_chosen() { return file_chosen_; }
1687 private:
1688 base::FilePath file_;
1689 bool file_chosen_;
1692 // Test for http://crbug.com/262948.
1693 // Flaky on Mac. http://crbug.com/452018
1694 #if defined(OS_MACOSX)
1695 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1696 DISABLED_RestoreFileAccessForHistoryNavigation
1697 #else
1698 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1699 RestoreFileAccessForHistoryNavigation
1700 #endif
1701 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1702 MAYBE_RestoreFileAccessForHistoryNavigation) {
1703 StartServer();
1704 base::FilePath file;
1705 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1706 file = file.AppendASCII("bar");
1708 // Navigate to url and get it to reference a file in its PageState.
1709 GURL url1(test_server()->GetURL("files/file_input.html"));
1710 NavigateToURL(shell(), url1);
1711 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1712 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1713 shell()->web_contents()->SetDelegate(delegate.get());
1714 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1715 "document.getElementById('fileinput').click();"));
1716 EXPECT_TRUE(delegate->file_chosen());
1717 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1718 process_id, file));
1720 // Navigate to a different process without access to the file, and wait for
1721 // the old process to exit.
1722 RenderProcessHostWatcher exit_observer(
1723 shell()->web_contents()->GetRenderProcessHost(),
1724 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1725 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1726 exit_observer.Wait();
1727 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1728 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1730 // Ensure that the file ended up in the PageState of the previous entry.
1731 NavigationEntry* prev_entry =
1732 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1733 EXPECT_EQ(url1, prev_entry->GetURL());
1734 const std::vector<base::FilePath>& files =
1735 prev_entry->GetPageState().GetReferencedFiles();
1736 ASSERT_EQ(1U, files.size());
1737 EXPECT_EQ(file, files.at(0));
1739 // Go back, ending up in a different RenderProcessHost than before.
1740 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1741 shell()->web_contents()->GetController().GoBack();
1742 back_nav_load_observer.Wait();
1743 EXPECT_NE(process_id,
1744 shell()->web_contents()->GetRenderProcessHost()->GetID());
1746 // Ensure that the file access still exists in the new process ID.
1747 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1748 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1750 // Navigate to a same site page to trigger a PageState update and ensure the
1751 // renderer is not killed.
1752 EXPECT_TRUE(
1753 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1756 // Test for http://crbug.com/441966.
1757 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1758 RestoreSubframeFileAccessForHistoryNavigation) {
1759 StartServer();
1760 base::FilePath file;
1761 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1762 file = file.AppendASCII("bar");
1764 // Navigate to url and get it to reference a file in its PageState.
1765 GURL url1(test_server()->GetURL("files/file_input_subframe.html"));
1766 NavigateToURL(shell(), url1);
1767 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
1768 FrameTreeNode* root = wc->GetFrameTree()->root();
1769 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1770 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1771 shell()->web_contents()->SetDelegate(delegate.get());
1772 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1773 "document.getElementById('fileinput').click();"));
1774 EXPECT_TRUE(delegate->file_chosen());
1775 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1776 process_id, file));
1778 // Navigate to a different process without access to the file, and wait for
1779 // the old process to exit.
1780 RenderProcessHostWatcher exit_observer(
1781 shell()->web_contents()->GetRenderProcessHost(),
1782 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1783 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1784 exit_observer.Wait();
1785 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1786 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1788 // Ensure that the file ended up in the PageState of the previous entry.
1789 NavigationEntry* prev_entry =
1790 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1791 EXPECT_EQ(url1, prev_entry->GetURL());
1792 const std::vector<base::FilePath>& files =
1793 prev_entry->GetPageState().GetReferencedFiles();
1794 ASSERT_EQ(1U, files.size());
1795 EXPECT_EQ(file, files.at(0));
1797 // Go back, ending up in a different RenderProcessHost than before.
1798 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1799 shell()->web_contents()->GetController().GoBack();
1800 back_nav_load_observer.Wait();
1801 EXPECT_NE(process_id,
1802 shell()->web_contents()->GetRenderProcessHost()->GetID());
1804 // Ensure that the file access still exists in the new process ID.
1805 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1806 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1809 // This class implements waiting for RenderFrameHost destruction. It relies on
1810 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1811 // destroyed.
1812 // Note: RenderFrameDeleted is also fired when the process associated with the
1813 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1814 // is expected.
1815 class RenderFrameHostDestructionObserver : public WebContentsObserver {
1816 public:
1817 explicit RenderFrameHostDestructionObserver(RenderFrameHost* rfh)
1818 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
1819 message_loop_runner_(new MessageLoopRunner),
1820 deleted_(false),
1821 render_frame_host_(rfh) {}
1822 ~RenderFrameHostDestructionObserver() override {}
1824 void Wait() {
1825 if (deleted_)
1826 return;
1828 message_loop_runner_->Run();
1831 // WebContentsObserver implementation:
1832 void RenderFrameDeleted(RenderFrameHost* rfh) override {
1833 if (rfh == render_frame_host_) {
1834 CHECK(!deleted_);
1835 deleted_ = true;
1838 if (deleted_ && message_loop_runner_->loop_running()) {
1839 base::ThreadTaskRunnerHandle::Get()->PostTask(
1840 FROM_HERE, message_loop_runner_->QuitClosure());
1844 private:
1845 scoped_refptr<MessageLoopRunner> message_loop_runner_;
1846 bool deleted_;
1847 RenderFrameHost* render_frame_host_;
1850 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1851 // doing a simple cross-process navigation.
1852 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1853 CleanupOnCrossProcessNavigation) {
1854 StartEmbeddedServer();
1856 // Do an initial navigation and capture objects we expect to be cleaned up
1857 // on cross-process navigation.
1858 GURL start_url = embedded_test_server()->GetURL("/title1.html");
1859 NavigateToURL(shell(), start_url);
1861 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1862 ->GetFrameTree()
1863 ->root();
1864 int32 orig_site_instance_id =
1865 root->current_frame_host()->GetSiteInstance()->GetId();
1866 int initial_process_id =
1867 root->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1868 int initial_rfh_id = root->current_frame_host()->GetRoutingID();
1869 int initial_rvh_id =
1870 root->current_frame_host()->render_view_host()->GetRoutingID();
1872 // Navigate cross-process and ensure that cleanup is performed as expected.
1873 GURL cross_site_url =
1874 embedded_test_server()->GetURL("foo.com", "/title2.html");
1875 RenderFrameHostDestructionObserver rfh_observer(root->current_frame_host());
1876 NavigateToURL(shell(), cross_site_url);
1877 rfh_observer.Wait();
1879 EXPECT_NE(orig_site_instance_id,
1880 root->current_frame_host()->GetSiteInstance()->GetId());
1881 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id, initial_rfh_id));
1882 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id, initial_rvh_id));
1885 // Ensure that the opener chain proxies and RVHs are properly reinitialized if
1886 // a tab crashes and reloads. See https://crbug.com/505090.
1887 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1888 ReinitializeOpenerChainAfterCrashAndReload) {
1889 StartEmbeddedServer();
1891 GURL main_url = embedded_test_server()->GetURL("/title1.html");
1892 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1894 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1895 ->GetFrameTree()
1896 ->root();
1898 scoped_refptr<SiteInstance> orig_site_instance(
1899 shell()->web_contents()->GetSiteInstance());
1900 EXPECT_TRUE(orig_site_instance);
1902 // Open a popup and navigate it cross-site.
1903 Shell* new_shell = OpenPopup(shell()->web_contents(), "foo");
1904 FrameTreeNode* popup_root =
1905 static_cast<WebContentsImpl*>(new_shell->web_contents())
1906 ->GetFrameTree()
1907 ->root();
1909 GURL cross_site_url =
1910 embedded_test_server()->GetURL("foo.com", "/title2.html");
1911 EXPECT_TRUE(NavigateToURL(new_shell, cross_site_url));
1913 scoped_refptr<SiteInstance> foo_site_instance(
1914 new_shell->web_contents()->GetSiteInstance());
1915 EXPECT_NE(foo_site_instance, orig_site_instance);
1917 // Kill the popup's process.
1918 RenderProcessHost* popup_process =
1919 popup_root->current_frame_host()->GetProcess();
1920 RenderProcessHostWatcher crash_observer(
1921 popup_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1922 popup_process->Shutdown(0, false);
1923 crash_observer.Wait();
1924 EXPECT_FALSE(popup_root->current_frame_host()->IsRenderFrameLive());
1925 EXPECT_FALSE(
1926 popup_root->current_frame_host()->render_view_host()->IsRenderViewLive());
1928 // The swapped-out RVH and proxy for the opener page in the foo.com
1929 // SiteInstance should not be live.
1930 RenderFrameHostManager* opener_manager = root->render_manager();
1931 RenderViewHostImpl* opener_rvh =
1932 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get());
1933 EXPECT_TRUE(opener_rvh);
1934 EXPECT_FALSE(opener_rvh->IsRenderViewLive());
1935 RenderFrameProxyHost* opener_rfph =
1936 opener_manager->GetRenderFrameProxyHost(foo_site_instance.get());
1937 EXPECT_TRUE(opener_rfph);
1938 EXPECT_FALSE(opener_rfph->is_render_frame_proxy_live());
1940 // Re-navigate the popup to the same URL and check that this recreates the
1941 // opener's swapped out RVH and proxy in the foo.com SiteInstance.
1942 EXPECT_TRUE(NavigateToURL(new_shell, cross_site_url));
1943 EXPECT_TRUE(opener_rvh->IsRenderViewLive());
1944 EXPECT_TRUE(opener_rfph->is_render_frame_proxy_live());
1947 } // namespace content