[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blob8ee53ea1bf7ad70aa44880c4a863895e4e223fb5
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/common/site_isolation_policy.h"
24 #include "content/public/browser/navigation_controller.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/common/bindings_policy.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/file_chooser_file_info.h"
32 #include "content/public/common/file_chooser_params.h"
33 #include "content/public/common/page_state.h"
34 #include "content/public/common/url_constants.h"
35 #include "content/public/test/browser_test_utils.h"
36 #include "content/public/test/content_browser_test.h"
37 #include "content/public/test/content_browser_test_utils.h"
38 #include "content/public/test/test_navigation_observer.h"
39 #include "content/public/test/test_utils.h"
40 #include "content/shell/browser/shell.h"
41 #include "content/test/content_browser_test_utils_internal.h"
42 #include "net/base/net_util.h"
43 #include "net/dns/mock_host_resolver.h"
44 #include "net/test/embedded_test_server/embedded_test_server.h"
45 #include "net/test/spawned_test_server/spawned_test_server.h"
47 using base::ASCIIToUTF16;
49 namespace content {
51 namespace {
53 const char kOpenUrlViaClickTargetFunc[] =
54 "(function(url) {\n"
55 " var lnk = document.createElement(\"a\");\n"
56 " lnk.href = url;\n"
57 " lnk.target = \"_blank\";\n"
58 " document.body.appendChild(lnk);\n"
59 " lnk.click();\n"
60 "})";
62 // Adds a link with given url and target=_blank, and clicks on it.
63 void OpenUrlViaClickTarget(const ToRenderFrameHost& adapter, const GURL& url) {
64 EXPECT_TRUE(ExecuteScript(adapter,
65 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
68 } // anonymous namespace
70 class RenderFrameHostManagerTest : public ContentBrowserTest {
71 public:
72 RenderFrameHostManagerTest() : foo_com_("foo.com") {
73 replace_host_.SetHostStr(foo_com_);
76 static bool GetFilePathWithHostAndPortReplacement(
77 const std::string& original_file_path,
78 const net::HostPortPair& host_port_pair,
79 std::string* replacement_path) {
80 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
81 replacement_text.push_back(
82 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
83 return net::SpawnedTestServer::GetFilePathWithReplacements(
84 original_file_path, replacement_text, replacement_path);
87 void StartServer() {
88 // Support multiple sites on the test server.
89 host_resolver()->AddRule("*", "127.0.0.1");
90 ASSERT_TRUE(test_server()->Start());
92 foo_host_port_ = test_server()->host_port_pair();
93 foo_host_port_.set_host(foo_com_);
96 void StartEmbeddedServer() {
97 // Support multiple sites on the embedded test server.
98 host_resolver()->AddRule("*", "127.0.0.1");
99 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
100 SetupCrossSiteRedirector(embedded_test_server());
103 // Returns a URL on foo.com with the given path.
104 GURL GetCrossSiteURL(const std::string& path) {
105 GURL cross_site_url(test_server()->GetURL(path));
106 return cross_site_url.ReplaceComponents(replace_host_);
109 protected:
110 std::string foo_com_;
111 GURL::Replacements replace_host_;
112 net::HostPortPair foo_host_port_;
115 // Web pages should not have script access to the swapped out page.
116 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
117 StartServer();
119 // Load a page with links that open in a new window.
120 std::string replacement_path;
121 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
122 "files/click-noreferrer-links.html",
123 foo_host_port_,
124 &replacement_path));
125 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
127 // Get the original SiteInstance for later comparison.
128 scoped_refptr<SiteInstance> orig_site_instance(
129 shell()->web_contents()->GetSiteInstance());
130 EXPECT_TRUE(orig_site_instance.get() != NULL);
132 // Open a same-site link in a new window.
133 ShellAddedObserver new_shell_observer;
134 bool success = false;
135 EXPECT_TRUE(ExecuteScriptAndExtractBool(
136 shell()->web_contents(),
137 "window.domAutomationController.send(clickSameSiteTargetedLink());",
138 &success));
139 EXPECT_TRUE(success);
140 Shell* new_shell = new_shell_observer.GetShell();
142 // Wait for the navigation in the new window to finish, if it hasn't.
143 WaitForLoadStop(new_shell->web_contents());
144 EXPECT_EQ("/files/navigate_opener.html",
145 new_shell->web_contents()->GetLastCommittedURL().path());
147 // Should have the same SiteInstance.
148 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
150 // We should have 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_TRUE(success);
158 // Now navigate the new window to a different site.
159 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
160 scoped_refptr<SiteInstance> new_site_instance(
161 new_shell->web_contents()->GetSiteInstance());
162 EXPECT_NE(orig_site_instance, new_site_instance);
164 // We should no longer have script access to the opened window's location.
165 success = false;
166 EXPECT_TRUE(ExecuteScriptAndExtractBool(
167 shell()->web_contents(),
168 "window.domAutomationController.send(testScriptAccessToWindow());",
169 &success));
170 EXPECT_FALSE(success);
172 // We now navigate the window to an about:blank page.
173 success = false;
174 EXPECT_TRUE(ExecuteScriptAndExtractBool(
175 shell()->web_contents(),
176 "window.domAutomationController.send(clickBlankTargetedLink());",
177 &success));
178 EXPECT_TRUE(success);
180 // Wait for the navigation in the new window to finish.
181 WaitForLoadStop(new_shell->web_contents());
182 GURL blank_url(url::kAboutBlankURL);
183 EXPECT_EQ(blank_url,
184 new_shell->web_contents()->GetLastCommittedURL());
185 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
187 // We should have access to the opened window's location.
188 success = false;
189 EXPECT_TRUE(ExecuteScriptAndExtractBool(
190 shell()->web_contents(),
191 "window.domAutomationController.send(testScriptAccessToWindow());",
192 &success));
193 EXPECT_TRUE(success);
196 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
197 // and target=_blank should create a new SiteInstance.
198 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
199 SwapProcessWithRelNoreferrerAndTargetBlank) {
200 StartServer();
202 // Load a page with links that open in a new window.
203 std::string replacement_path;
204 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
205 "files/click-noreferrer-links.html",
206 foo_host_port_,
207 &replacement_path));
208 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
210 // Get the original SiteInstance for later comparison.
211 scoped_refptr<SiteInstance> orig_site_instance(
212 shell()->web_contents()->GetSiteInstance());
213 EXPECT_TRUE(orig_site_instance.get() != NULL);
215 // Test clicking a rel=noreferrer + target=blank link.
216 ShellAddedObserver new_shell_observer;
217 bool success = false;
218 EXPECT_TRUE(ExecuteScriptAndExtractBool(
219 shell()->web_contents(),
220 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
221 &success));
222 EXPECT_TRUE(success);
224 // Wait for the window to open.
225 Shell* new_shell = new_shell_observer.GetShell();
227 EXPECT_EQ("/files/title2.html",
228 new_shell->web_contents()->GetVisibleURL().path());
230 // Wait for the cross-site transition in the new tab to finish.
231 WaitForLoadStop(new_shell->web_contents());
232 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
233 new_shell->web_contents());
234 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
235 pending_render_view_host());
237 // Should have a new SiteInstance.
238 scoped_refptr<SiteInstance> noref_blank_site_instance(
239 new_shell->web_contents()->GetSiteInstance());
240 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
243 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
244 // for rel=noreferrer links in new windows, even to same site pages and named
245 // targets.
246 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
247 SwapProcessWithSameSiteRelNoreferrer) {
248 StartServer();
250 // Load a page with links that open in a new window.
251 std::string replacement_path;
252 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
253 "files/click-noreferrer-links.html",
254 foo_host_port_,
255 &replacement_path));
256 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
258 // Get the original SiteInstance for later comparison.
259 scoped_refptr<SiteInstance> orig_site_instance(
260 shell()->web_contents()->GetSiteInstance());
261 EXPECT_TRUE(orig_site_instance.get() != NULL);
263 // Test clicking a same-site rel=noreferrer + target=foo link.
264 ShellAddedObserver new_shell_observer;
265 bool success = false;
266 EXPECT_TRUE(ExecuteScriptAndExtractBool(
267 shell()->web_contents(),
268 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
269 &success));
270 EXPECT_TRUE(success);
272 // Wait for the window to open.
273 Shell* new_shell = new_shell_observer.GetShell();
275 // Opens in new window.
276 EXPECT_EQ("/files/title2.html",
277 new_shell->web_contents()->GetVisibleURL().path());
279 // Wait for the cross-site transition in the new tab to finish.
280 WaitForLoadStop(new_shell->web_contents());
281 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
282 new_shell->web_contents());
283 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
284 pending_render_view_host());
286 // Should have a new SiteInstance (in a new BrowsingInstance).
287 scoped_refptr<SiteInstance> noref_blank_site_instance(
288 new_shell->web_contents()->GetSiteInstance());
289 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
292 // Test for crbug.com/24447. Following a cross-site link with just
293 // target=_blank should not create a new SiteInstance, unless we
294 // are running in --site-per-process mode.
295 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
296 DontSwapProcessWithOnlyTargetBlank) {
297 StartServer();
299 // Load a page with links that open in a new window.
300 std::string replacement_path;
301 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
302 "files/click-noreferrer-links.html",
303 foo_host_port_,
304 &replacement_path));
305 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path)));
307 // Get the original SiteInstance for later comparison.
308 scoped_refptr<SiteInstance> orig_site_instance(
309 shell()->web_contents()->GetSiteInstance());
310 EXPECT_TRUE(orig_site_instance.get() != NULL);
312 // Test clicking a target=blank link.
313 ShellAddedObserver new_shell_observer;
314 bool success = false;
315 EXPECT_TRUE(ExecuteScriptAndExtractBool(
316 shell()->web_contents(),
317 "window.domAutomationController.send(clickTargetBlankLink());",
318 &success));
319 EXPECT_TRUE(success);
321 // Wait for the window to open.
322 Shell* new_shell = new_shell_observer.GetShell();
324 // Wait for the cross-site transition in the new tab to finish.
325 EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
326 EXPECT_EQ("/files/title2.html",
327 new_shell->web_contents()->GetLastCommittedURL().path());
329 // Should have the same SiteInstance unless we're in site-per-process mode.
330 scoped_refptr<SiteInstance> blank_site_instance(
331 new_shell->web_contents()->GetSiteInstance());
332 if (AreAllSitesIsolatedForTesting())
333 EXPECT_NE(orig_site_instance, blank_site_instance);
334 else
335 EXPECT_EQ(orig_site_instance, blank_site_instance);
338 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
339 // and no target=_blank should not create a new SiteInstance.
340 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
341 DontSwapProcessWithOnlyRelNoreferrer) {
342 StartServer();
344 // Load a page with links that open in a new window.
345 std::string replacement_path;
346 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
347 "files/click-noreferrer-links.html",
348 foo_host_port_,
349 &replacement_path));
350 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
352 // Get the original SiteInstance for later comparison.
353 scoped_refptr<SiteInstance> orig_site_instance(
354 shell()->web_contents()->GetSiteInstance());
355 EXPECT_TRUE(orig_site_instance.get() != NULL);
357 // Test clicking a rel=noreferrer link.
358 bool success = false;
359 EXPECT_TRUE(ExecuteScriptAndExtractBool(
360 shell()->web_contents(),
361 "window.domAutomationController.send(clickNoRefLink());",
362 &success));
363 EXPECT_TRUE(success);
365 // Wait for the cross-site transition in the current tab to finish.
366 WaitForLoadStop(shell()->web_contents());
368 // Opens in same window.
369 EXPECT_EQ(1u, Shell::windows().size());
370 EXPECT_EQ("/files/title2.html",
371 shell()->web_contents()->GetLastCommittedURL().path());
373 // Should have the same SiteInstance unless we're in site-per-process mode.
374 scoped_refptr<SiteInstance> noref_site_instance(
375 shell()->web_contents()->GetSiteInstance());
376 if (AreAllSitesIsolatedForTesting())
377 EXPECT_NE(orig_site_instance, noref_site_instance);
378 else
379 EXPECT_EQ(orig_site_instance, noref_site_instance);
382 // Test for crbug.com/116192. Targeted links should still work after the
383 // named target window has swapped processes.
384 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
385 AllowTargetedNavigationsAfterSwap) {
386 StartServer();
388 // Load a page with links that open in a new window.
389 std::string replacement_path;
390 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
391 "files/click-noreferrer-links.html",
392 foo_host_port_,
393 &replacement_path));
394 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
396 // Get the original SiteInstance for later comparison.
397 scoped_refptr<SiteInstance> orig_site_instance(
398 shell()->web_contents()->GetSiteInstance());
399 EXPECT_TRUE(orig_site_instance.get() != NULL);
401 // Test clicking a target=foo link.
402 ShellAddedObserver new_shell_observer;
403 bool success = false;
404 EXPECT_TRUE(ExecuteScriptAndExtractBool(
405 shell()->web_contents(),
406 "window.domAutomationController.send(clickSameSiteTargetedLink());",
407 &success));
408 EXPECT_TRUE(success);
409 Shell* new_shell = new_shell_observer.GetShell();
411 // Wait for the navigation in the new tab to finish, if it hasn't.
412 WaitForLoadStop(new_shell->web_contents());
413 EXPECT_EQ("/files/navigate_opener.html",
414 new_shell->web_contents()->GetLastCommittedURL().path());
416 // Should have the same SiteInstance.
417 scoped_refptr<SiteInstance> blank_site_instance(
418 new_shell->web_contents()->GetSiteInstance());
419 EXPECT_EQ(orig_site_instance, blank_site_instance);
421 // Now navigate the new tab to a different site.
422 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
423 NavigateToURL(new_shell, cross_site_url);
424 scoped_refptr<SiteInstance> new_site_instance(
425 new_shell->web_contents()->GetSiteInstance());
426 EXPECT_NE(orig_site_instance, new_site_instance);
428 // Clicking the original link in the first tab should cause us to swap back.
429 TestNavigationObserver navigation_observer(new_shell->web_contents());
430 EXPECT_TRUE(ExecuteScriptAndExtractBool(
431 shell()->web_contents(),
432 "window.domAutomationController.send(clickSameSiteTargetedLink());",
433 &success));
434 EXPECT_TRUE(success);
435 navigation_observer.Wait();
437 // Should have swapped back and shown the new window again.
438 scoped_refptr<SiteInstance> revisit_site_instance(
439 new_shell->web_contents()->GetSiteInstance());
440 EXPECT_EQ(orig_site_instance, revisit_site_instance);
442 // If it navigates away to another process, the original window should
443 // still be able to close it (using a cross-process close message).
444 NavigateToURL(new_shell, cross_site_url);
445 EXPECT_EQ(new_site_instance.get(),
446 new_shell->web_contents()->GetSiteInstance());
447 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
448 EXPECT_TRUE(ExecuteScriptAndExtractBool(
449 shell()->web_contents(),
450 "window.domAutomationController.send(testCloseWindow());",
451 &success));
452 EXPECT_TRUE(success);
453 close_watcher.Wait();
456 // Test that setting the opener to null in a window affects cross-process
457 // navigations, including those to existing entries. http://crbug.com/156669.
458 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
459 #if defined(THREAD_SANITIZER)
460 #define MAYBE_DisownOpener DISABLED_DisownOpener
461 #else
462 #define MAYBE_DisownOpener DisownOpener
463 #endif
464 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
465 StartServer();
467 // Load a page with links that open in a new window.
468 std::string replacement_path;
469 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
470 "files/click-noreferrer-links.html",
471 foo_host_port_,
472 &replacement_path));
473 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
475 // Get the original SiteInstance for later comparison.
476 scoped_refptr<SiteInstance> orig_site_instance(
477 shell()->web_contents()->GetSiteInstance());
478 EXPECT_TRUE(orig_site_instance.get() != NULL);
480 // Test clicking a target=_blank link.
481 ShellAddedObserver new_shell_observer;
482 bool success = false;
483 EXPECT_TRUE(ExecuteScriptAndExtractBool(
484 shell()->web_contents(),
485 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
486 &success));
487 EXPECT_TRUE(success);
488 Shell* new_shell = new_shell_observer.GetShell();
489 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
491 // Wait for the navigation in the new tab to finish, if it hasn't.
492 WaitForLoadStop(new_shell->web_contents());
493 EXPECT_EQ("/files/title2.html",
494 new_shell->web_contents()->GetLastCommittedURL().path());
496 // Should have the same SiteInstance.
497 scoped_refptr<SiteInstance> blank_site_instance(
498 new_shell->web_contents()->GetSiteInstance());
499 EXPECT_EQ(orig_site_instance, blank_site_instance);
501 // Now navigate the new tab to a different site.
502 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
503 scoped_refptr<SiteInstance> new_site_instance(
504 new_shell->web_contents()->GetSiteInstance());
505 EXPECT_NE(orig_site_instance, new_site_instance);
506 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
508 // Now disown the opener.
509 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
510 "window.opener = null;"));
511 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
513 // Go back and ensure the opener is still null.
515 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
516 new_shell->web_contents()->GetController().GoBack();
517 back_nav_load_observer.Wait();
519 success = false;
520 EXPECT_TRUE(ExecuteScriptAndExtractBool(
521 new_shell->web_contents(),
522 "window.domAutomationController.send(window.opener == null);",
523 &success));
524 EXPECT_TRUE(success);
525 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
527 // Now navigate forward again (creating a new process) and check opener.
528 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
529 success = false;
530 EXPECT_TRUE(ExecuteScriptAndExtractBool(
531 new_shell->web_contents(),
532 "window.domAutomationController.send(window.opener == null);",
533 &success));
534 EXPECT_TRUE(success);
535 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
538 // Test that subframes can disown their openers. http://crbug.com/225528.
539 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
540 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
541 NavigateToURL(shell(), frame_url);
543 // Give the frame an opener using window.open.
544 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
545 "window.open('about:blank','foo');"));
547 // Check that the browser process updates the subframe's opener.
548 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
549 ->GetFrameTree()
550 ->root();
551 EXPECT_EQ(root, root->child_at(0)->opener());
553 // Now disown the frame's opener. Shouldn't crash.
554 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
555 "window.frames[0].opener = null;"));
557 // Check that the subframe's opener in the browser process is disowned.
558 EXPECT_EQ(nullptr, root->child_at(0)->opener());
561 // Check that window.name is preserved for top frames when they navigate
562 // cross-process. See https://crbug.com/504164.
563 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
564 PreserveTopFrameWindowNameOnCrossProcessNavigations) {
565 StartEmbeddedServer();
567 GURL main_url(embedded_test_server()->GetURL("/title1.html"));
568 EXPECT_TRUE(NavigateToURL(shell(), main_url));
570 // Get the original SiteInstance for later comparison.
571 scoped_refptr<SiteInstance> orig_site_instance(
572 shell()->web_contents()->GetSiteInstance());
573 EXPECT_TRUE(orig_site_instance.get() != NULL);
575 // Open a popup using window.open with a 'foo' window.name.
576 Shell* new_shell =
577 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
578 EXPECT_TRUE(new_shell);
580 // The window.name for the new popup should be "foo".
581 std::string name;
582 EXPECT_TRUE(ExecuteScriptAndExtractString(
583 new_shell->web_contents(),
584 "window.domAutomationController.send(window.name);", &name));
585 EXPECT_EQ("foo", name);
587 // Now navigate the new tab to a different site.
588 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
589 EXPECT_TRUE(NavigateToURL(new_shell, foo_url));
590 scoped_refptr<SiteInstance> new_site_instance(
591 new_shell->web_contents()->GetSiteInstance());
592 EXPECT_NE(orig_site_instance, new_site_instance);
594 // window.name should still be "foo".
595 name = "";
596 EXPECT_TRUE(ExecuteScriptAndExtractString(
597 new_shell->web_contents(),
598 "window.domAutomationController.send(window.name);", &name));
599 EXPECT_EQ("foo", name);
601 // Open another popup from the 'foo' popup and navigate it cross-site.
602 Shell* new_shell2 =
603 OpenPopup(new_shell->web_contents(), GURL(url::kAboutBlankURL), "bar");
604 EXPECT_TRUE(new_shell2);
605 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title3.html"));
606 EXPECT_TRUE(NavigateToURL(new_shell2, bar_url));
608 // Check that the new popup's window.opener has name "foo", which verifies
609 // that new swapped-out RenderViews also propagate window.name. This has to
610 // be done via window.open, since window.name isn't readable cross-origin.
611 bool success = false;
612 EXPECT_TRUE(ExecuteScriptAndExtractBool(
613 new_shell2->web_contents(),
614 "window.domAutomationController.send("
615 " window.opener === window.open('','foo'));",
616 &success));
617 EXPECT_TRUE(success);
620 // Test for crbug.com/99202. PostMessage calls should still work after
621 // navigating the source and target windows to different sites.
622 // Specifically:
623 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
624 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
625 // 3) Post a message from "foo" to opener, which replies back to "foo".
626 // 4) Post a message from _blank to "foo".
627 // 5) Post a message from "foo" to a subframe of opener, which replies back.
628 // 6) Post a message from _blank to a subframe of "foo".
629 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
630 SupportCrossProcessPostMessage) {
631 StartServer();
633 // Load a page with links that open in a new window.
634 std::string replacement_path;
635 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
636 "files/click-noreferrer-links.html",
637 foo_host_port_,
638 &replacement_path));
639 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
641 // Get the original SiteInstance and RVHM for later comparison.
642 WebContents* opener_contents = shell()->web_contents();
643 scoped_refptr<SiteInstance> orig_site_instance(
644 opener_contents->GetSiteInstance());
645 EXPECT_TRUE(orig_site_instance.get() != NULL);
646 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
647 opener_contents)->GetRenderManagerForTesting();
649 // 1) Open two more windows, one named. These initially have openers but no
650 // reference to each other. We will later post a message between them.
652 // First, a named target=foo window.
653 ShellAddedObserver new_shell_observer;
654 bool success = false;
655 EXPECT_TRUE(ExecuteScriptAndExtractBool(
656 opener_contents,
657 "window.domAutomationController.send(clickSameSiteTargetedLink());",
658 &success));
659 EXPECT_TRUE(success);
660 Shell* new_shell = new_shell_observer.GetShell();
662 // Wait for the navigation in the new window to finish, if it hasn't, then
663 // send it to post_message.html on a different site.
664 WebContents* foo_contents = new_shell->web_contents();
665 WaitForLoadStop(foo_contents);
666 EXPECT_EQ("/files/navigate_opener.html",
667 foo_contents->GetLastCommittedURL().path());
668 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
669 scoped_refptr<SiteInstance> foo_site_instance(
670 foo_contents->GetSiteInstance());
671 EXPECT_NE(orig_site_instance, foo_site_instance);
673 // Second, a target=_blank window.
674 ShellAddedObserver new_shell_observer2;
675 EXPECT_TRUE(ExecuteScriptAndExtractBool(
676 shell()->web_contents(),
677 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
678 &success));
679 EXPECT_TRUE(success);
681 // Wait for the navigation in the new window to finish, if it hasn't, then
682 // send it to post_message.html on the original site.
683 Shell* new_shell2 = new_shell_observer2.GetShell();
684 WebContents* new_contents = new_shell2->web_contents();
685 WaitForLoadStop(new_contents);
686 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
687 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
688 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
689 RenderFrameHostManager* new_manager =
690 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
692 // We now have three windows. The opener should have a swapped out RVH
693 // for the new SiteInstance, but the _blank window should not.
694 EXPECT_EQ(3u, Shell::windows().size());
695 EXPECT_TRUE(
696 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
697 EXPECT_FALSE(
698 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
700 // 2) Fail to post a message from the foo window to the opener if the target
701 // origin is wrong. We won't see an error, but we can check for the right
702 // number of received messages below.
703 EXPECT_TRUE(ExecuteScriptAndExtractBool(
704 foo_contents,
705 "window.domAutomationController.send(postToOpener('msg',"
706 " 'http://google.com'));",
707 &success));
708 EXPECT_TRUE(success);
709 ASSERT_FALSE(
710 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
712 // 3) Post a message from the foo window to the opener. The opener will
713 // reply, causing the foo window to update its own title.
714 base::string16 expected_title = ASCIIToUTF16("msg");
715 TitleWatcher title_watcher(foo_contents, expected_title);
716 EXPECT_TRUE(ExecuteScriptAndExtractBool(
717 foo_contents,
718 "window.domAutomationController.send(postToOpener('msg','*'));",
719 &success));
720 EXPECT_TRUE(success);
721 ASSERT_FALSE(
722 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
723 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
725 // We should have received only 1 message in the opener and "foo" tabs,
726 // and updated the title.
727 int opener_received_messages = 0;
728 EXPECT_TRUE(ExecuteScriptAndExtractInt(
729 opener_contents,
730 "window.domAutomationController.send(window.receivedMessages);",
731 &opener_received_messages));
732 int foo_received_messages = 0;
733 EXPECT_TRUE(ExecuteScriptAndExtractInt(
734 foo_contents,
735 "window.domAutomationController.send(window.receivedMessages);",
736 &foo_received_messages));
737 EXPECT_EQ(1, foo_received_messages);
738 EXPECT_EQ(1, opener_received_messages);
739 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
741 // 4) Now post a message from the _blank window to the foo window. The
742 // foo window will update its title and will not reply.
743 expected_title = ASCIIToUTF16("msg2");
744 TitleWatcher title_watcher2(foo_contents, expected_title);
745 EXPECT_TRUE(ExecuteScriptAndExtractBool(
746 new_contents,
747 "window.domAutomationController.send(postToFoo('msg2'));",
748 &success));
749 EXPECT_TRUE(success);
750 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
752 // This postMessage should have created a swapped out RVH for the new
753 // SiteInstance in the target=_blank window.
754 EXPECT_TRUE(
755 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
757 // TODO(nasko): Test subframe targeting of postMessage once
758 // http://crbug.com/153701 is fixed.
761 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
762 // messages which contain Transferables and get intercepted by
763 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
764 // swapped out) should work.
765 // Specifically:
766 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
767 // 2) Post a message containing a message port from opener to "foo".
768 // 3) Post a message from "foo" back to opener via the passed message port.
769 // The test will be enabled when the feature implementation lands.
770 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
771 SupportCrossProcessPostMessageWithMessagePort) {
772 StartServer();
774 // Load a page with links that open in a new window.
775 std::string replacement_path;
776 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
777 "files/click-noreferrer-links.html",
778 foo_host_port_,
779 &replacement_path));
780 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
782 // Get the original SiteInstance and RVHM for later comparison.
783 WebContents* opener_contents = shell()->web_contents();
784 scoped_refptr<SiteInstance> orig_site_instance(
785 opener_contents->GetSiteInstance());
786 EXPECT_TRUE(orig_site_instance.get() != NULL);
787 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
788 opener_contents)->GetRenderManagerForTesting();
790 // 1) Open a named target=foo window. We will later post a message between the
791 // opener and the new window.
792 ShellAddedObserver new_shell_observer;
793 bool success = false;
794 EXPECT_TRUE(ExecuteScriptAndExtractBool(
795 opener_contents,
796 "window.domAutomationController.send(clickSameSiteTargetedLink());",
797 &success));
798 EXPECT_TRUE(success);
799 Shell* new_shell = new_shell_observer.GetShell();
801 // Wait for the navigation in the new window to finish, if it hasn't, then
802 // send it to post_message.html on a different site.
803 WebContents* foo_contents = new_shell->web_contents();
804 WaitForLoadStop(foo_contents);
805 EXPECT_EQ("/files/navigate_opener.html",
806 foo_contents->GetLastCommittedURL().path());
807 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
808 scoped_refptr<SiteInstance> foo_site_instance(
809 foo_contents->GetSiteInstance());
810 EXPECT_NE(orig_site_instance, foo_site_instance);
812 // We now have two windows. The opener should have a swapped out RVH
813 // for the new SiteInstance.
814 EXPECT_EQ(2u, Shell::windows().size());
815 EXPECT_TRUE(
816 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
818 // 2) Post a message containing a MessagePort from opener to the the foo
819 // window. The foo window will reply via the passed port, causing the opener
820 // to update its own title.
821 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
822 TitleWatcher title_observer(opener_contents, expected_title);
823 EXPECT_TRUE(ExecuteScriptAndExtractBool(
824 opener_contents,
825 "window.domAutomationController.send(postWithPortToFoo());",
826 &success));
827 EXPECT_TRUE(success);
828 ASSERT_FALSE(
829 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
830 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
832 // Check message counts.
833 int opener_received_messages_via_port = 0;
834 EXPECT_TRUE(ExecuteScriptAndExtractInt(
835 opener_contents,
836 "window.domAutomationController.send(window.receivedMessagesViaPort);",
837 &opener_received_messages_via_port));
838 int foo_received_messages = 0;
839 EXPECT_TRUE(ExecuteScriptAndExtractInt(
840 foo_contents,
841 "window.domAutomationController.send(window.receivedMessages);",
842 &foo_received_messages));
843 int foo_received_messages_with_port = 0;
844 EXPECT_TRUE(ExecuteScriptAndExtractInt(
845 foo_contents,
846 "window.domAutomationController.send(window.receivedMessagesWithPort);",
847 &foo_received_messages_with_port));
848 EXPECT_EQ(1, foo_received_messages);
849 EXPECT_EQ(1, foo_received_messages_with_port);
850 EXPECT_EQ(1, opener_received_messages_via_port);
851 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
852 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
855 // Test for crbug.com/116192. Navigations to a window's opener should
856 // still work after a process swap.
857 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
858 AllowTargetedNavigationsInOpenerAfterSwap) {
859 StartServer();
861 // Load a page with links that open in a new window.
862 std::string replacement_path;
863 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
864 "files/click-noreferrer-links.html",
865 foo_host_port_,
866 &replacement_path));
867 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
869 // Get the original tab and SiteInstance for later comparison.
870 WebContents* orig_contents = shell()->web_contents();
871 scoped_refptr<SiteInstance> orig_site_instance(
872 orig_contents->GetSiteInstance());
873 EXPECT_TRUE(orig_site_instance.get() != NULL);
875 // Test clicking a target=foo link.
876 ShellAddedObserver new_shell_observer;
877 bool success = false;
878 EXPECT_TRUE(ExecuteScriptAndExtractBool(
879 orig_contents,
880 "window.domAutomationController.send(clickSameSiteTargetedLink());",
881 &success));
882 EXPECT_TRUE(success);
883 Shell* new_shell = new_shell_observer.GetShell();
885 // Wait for the navigation in the new window to finish, if it hasn't.
886 WaitForLoadStop(new_shell->web_contents());
887 EXPECT_EQ("/files/navigate_opener.html",
888 new_shell->web_contents()->GetLastCommittedURL().path());
890 // Should have the same SiteInstance.
891 scoped_refptr<SiteInstance> blank_site_instance(
892 new_shell->web_contents()->GetSiteInstance());
893 EXPECT_EQ(orig_site_instance, blank_site_instance);
895 // Now navigate the original (opener) tab to a different site.
896 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
897 scoped_refptr<SiteInstance> new_site_instance(
898 shell()->web_contents()->GetSiteInstance());
899 EXPECT_NE(orig_site_instance, new_site_instance);
901 // The opened tab should be able to navigate the opener back to its process.
902 TestNavigationObserver navigation_observer(orig_contents);
903 EXPECT_TRUE(ExecuteScriptAndExtractBool(
904 new_shell->web_contents(),
905 "window.domAutomationController.send(navigateOpener());",
906 &success));
907 EXPECT_TRUE(success);
908 navigation_observer.Wait();
910 // Should have swapped back into this process.
911 scoped_refptr<SiteInstance> revisit_site_instance(
912 shell()->web_contents()->GetSiteInstance());
913 EXPECT_EQ(orig_site_instance, revisit_site_instance);
916 // Test that subframes do not crash when sending a postMessage to the top frame
917 // from an unload handler while the top frame is being swapped out as part of
918 // navigating cross-process. https://crbug.com/475651.
919 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
920 PostMessageFromSubframeUnloadHandler) {
921 StartServer();
923 GURL frame_url(test_server()->GetURL("files/post_message.html"));
924 GURL main_url("data:text/html,<iframe name='foo' src='" + frame_url.spec() +
925 "'></iframe>");
926 EXPECT_TRUE(NavigateToURL(shell(), main_url));
928 // Get the original SiteInstance for later comparison.
929 scoped_refptr<SiteInstance> orig_site_instance(
930 shell()->web_contents()->GetSiteInstance());
931 EXPECT_NE(nullptr, orig_site_instance.get());
933 // It is safe to obtain the root frame tree node here, as it doesn't change.
934 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
935 ->GetFrameTree()
936 ->root();
937 ASSERT_EQ(1U, root->child_count());
938 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
940 // Register an unload handler that sends a postMessage to the top frame.
941 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
942 "registerUnload();"));
944 // Navigate the top frame cross-site. This will cause the top frame to be
945 // swapped out and run unload handlers, and the original renderer process
946 // should then terminate since it's not rendering any other frames.
947 RenderProcessHostWatcher exit_observer(
948 root->current_frame_host()->GetProcess(),
949 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
950 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
951 scoped_refptr<SiteInstance> new_site_instance(
952 shell()->web_contents()->GetSiteInstance());
953 EXPECT_NE(orig_site_instance, new_site_instance);
955 // Ensure that the original renderer process exited cleanly without crashing.
956 exit_observer.Wait();
957 EXPECT_EQ(true, exit_observer.did_exit_normally());
960 // Test that opening a new window in the same SiteInstance and then navigating
961 // both windows to a different SiteInstance allows the first process to exit.
962 // See http://crbug.com/126333.
963 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
964 ProcessExitWithSwappedOutViews) {
965 StartServer();
967 // Load a page with links that open in a new window.
968 std::string replacement_path;
969 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
970 "files/click-noreferrer-links.html",
971 foo_host_port_,
972 &replacement_path));
973 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
975 // Get the original SiteInstance for later comparison.
976 scoped_refptr<SiteInstance> orig_site_instance(
977 shell()->web_contents()->GetSiteInstance());
978 EXPECT_TRUE(orig_site_instance.get() != NULL);
980 // Test clicking a target=foo link.
981 ShellAddedObserver new_shell_observer;
982 bool success = false;
983 EXPECT_TRUE(ExecuteScriptAndExtractBool(
984 shell()->web_contents(),
985 "window.domAutomationController.send(clickSameSiteTargetedLink());",
986 &success));
987 EXPECT_TRUE(success);
988 Shell* new_shell = new_shell_observer.GetShell();
990 // Wait for the navigation in the new window to finish, if it hasn't.
991 WaitForLoadStop(new_shell->web_contents());
992 EXPECT_EQ("/files/navigate_opener.html",
993 new_shell->web_contents()->GetLastCommittedURL().path());
995 // Should have the same SiteInstance.
996 scoped_refptr<SiteInstance> opened_site_instance(
997 new_shell->web_contents()->GetSiteInstance());
998 EXPECT_EQ(orig_site_instance, opened_site_instance);
1000 // Now navigate the opened window to a different site.
1001 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1002 scoped_refptr<SiteInstance> new_site_instance(
1003 new_shell->web_contents()->GetSiteInstance());
1004 EXPECT_NE(orig_site_instance, new_site_instance);
1006 // The original process should still be alive, since it is still used in the
1007 // first window.
1008 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
1009 EXPECT_TRUE(orig_process->HasConnection());
1011 // Navigate the first window to a different site as well. The original
1012 // process should exit, since all of its views are now swapped out.
1013 RenderProcessHostWatcher exit_observer(
1014 orig_process,
1015 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1016 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1017 exit_observer.Wait();
1018 scoped_refptr<SiteInstance> new_site_instance2(
1019 shell()->web_contents()->GetSiteInstance());
1020 EXPECT_EQ(new_site_instance, new_site_instance2);
1023 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
1024 // error should not make us ignore future renderer-initiated navigations.
1025 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
1026 StartServer();
1028 // Get the original SiteInstance for later comparison.
1029 scoped_refptr<SiteInstance> orig_site_instance(
1030 shell()->web_contents()->GetSiteInstance());
1031 EXPECT_TRUE(orig_site_instance.get() != NULL);
1033 // Load a cross-site page that fails with a 204 error.
1034 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
1035 GetCrossSiteURL("nocontent")));
1037 // We should still be looking at the normal page. Because we started from a
1038 // blank new tab, the typed URL will still be visible until the user clears it
1039 // manually. The last committed URL will be the previous page.
1040 scoped_refptr<SiteInstance> post_nav_site_instance(
1041 shell()->web_contents()->GetSiteInstance());
1042 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
1043 EXPECT_EQ("/nocontent",
1044 shell()->web_contents()->GetVisibleURL().path());
1045 EXPECT_FALSE(
1046 shell()->web_contents()->GetController().GetLastCommittedEntry());
1048 // Renderer-initiated navigations should work.
1049 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
1050 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1051 GURL url = test_server()->GetURL("files/title2.html");
1052 EXPECT_TRUE(ExecuteScript(
1053 shell()->web_contents(),
1054 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
1055 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1057 // Opens in same tab.
1058 EXPECT_EQ(1u, Shell::windows().size());
1059 EXPECT_EQ("/files/title2.html",
1060 shell()->web_contents()->GetLastCommittedURL().path());
1062 // Should have the same SiteInstance.
1063 scoped_refptr<SiteInstance> new_site_instance(
1064 shell()->web_contents()->GetSiteInstance());
1065 EXPECT_EQ(orig_site_instance, new_site_instance);
1068 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1069 // initiated navigation in a new tab, until the content of the initial
1070 // about:blank page is modified by another window. At that point, we should
1071 // revert to showing about:blank to prevent a URL spoof.
1072 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
1073 ASSERT_TRUE(test_server()->Start());
1075 // Load a page that can open a URL that won't commit in a new window.
1076 NavigateToURL(
1077 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1078 WebContents* orig_contents = shell()->web_contents();
1080 // Click a /nocontent link that opens in a new window but never commits.
1081 ShellAddedObserver new_shell_observer;
1082 bool success = false;
1083 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1084 orig_contents,
1085 "window.domAutomationController.send(clickNoContentTargetedLink());",
1086 &success));
1087 EXPECT_TRUE(success);
1089 // Wait for the window to open.
1090 Shell* new_shell = new_shell_observer.GetShell();
1092 // Ensure the destination URL is visible, because it is considered the
1093 // initial navigation.
1094 WebContents* contents = new_shell->web_contents();
1095 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
1096 EXPECT_EQ("/nocontent",
1097 contents->GetController().GetVisibleEntry()->GetURL().path());
1099 // Now modify the contents of the new window from the opener. This will also
1100 // modify the title of the document to give us something to listen for.
1101 base::string16 expected_title = ASCIIToUTF16("Modified Title");
1102 TitleWatcher title_watcher(contents, expected_title);
1103 success = false;
1104 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1105 orig_contents,
1106 "window.domAutomationController.send(modifyNewWindow());",
1107 &success));
1108 EXPECT_TRUE(success);
1109 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1111 // At this point, we should no longer be showing the destination URL.
1112 // The visible entry should be null, resulting in about:blank in the address
1113 // bar.
1114 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1117 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1118 // initiated navigation in a new tab if it is not the initial navigation. In
1119 // this case, the renderer will not notify us of a modification, so we cannot
1120 // show the pending URL without allowing a spoof.
1121 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1122 DontShowLoadingURLIfNotInitialNav) {
1123 ASSERT_TRUE(test_server()->Start());
1125 // Load a page that can open a URL that won't commit in a new window.
1126 NavigateToURL(
1127 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1128 WebContents* orig_contents = shell()->web_contents();
1130 // Click a /nocontent link that opens in a new window but never commits.
1131 // By using an onclick handler that first creates the window, the slow
1132 // navigation is not considered an initial navigation.
1133 ShellAddedObserver new_shell_observer;
1134 bool success = false;
1135 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1136 orig_contents,
1137 "window.domAutomationController.send("
1138 "clickNoContentScriptedTargetedLink());",
1139 &success));
1140 EXPECT_TRUE(success);
1142 // Wait for the window to open.
1143 Shell* new_shell = new_shell_observer.GetShell();
1145 // Ensure the destination URL is not visible, because it is not the initial
1146 // navigation.
1147 WebContents* contents = new_shell->web_contents();
1148 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1149 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1152 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1153 #if defined(THREAD_SANITIZER)
1154 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1155 #else
1156 #define MAYBE_BackForwardNotStale BackForwardNotStale
1157 #endif
1158 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1159 // do not cause back/forward navigations to be considered stale by the
1160 // renderer.
1161 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1162 StartServer();
1163 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1165 // Visit a page on first site.
1166 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1168 // Visit three pages on second site.
1169 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1170 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1171 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1173 // History is now [blank, A1, B1, B2, *B3].
1174 WebContents* contents = shell()->web_contents();
1175 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1177 // Open another window in same process to keep this process alive.
1178 Shell* new_shell = CreateBrowser();
1179 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1181 // Go back three times to first site.
1183 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1184 shell()->web_contents()->GetController().GoBack();
1185 back_nav_load_observer.Wait();
1188 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1189 shell()->web_contents()->GetController().GoBack();
1190 back_nav_load_observer.Wait();
1193 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1194 shell()->web_contents()->GetController().GoBack();
1195 back_nav_load_observer.Wait();
1198 // Now go forward twice to B2. Shouldn't be left spinning.
1200 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1201 shell()->web_contents()->GetController().GoForward();
1202 forward_nav_load_observer.Wait();
1205 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1206 shell()->web_contents()->GetController().GoForward();
1207 forward_nav_load_observer.Wait();
1210 // Go back twice to first site.
1212 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1213 shell()->web_contents()->GetController().GoBack();
1214 back_nav_load_observer.Wait();
1217 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1218 shell()->web_contents()->GetController().GoBack();
1219 back_nav_load_observer.Wait();
1222 // Now go forward directly to B3. Shouldn't be left spinning.
1224 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1225 shell()->web_contents()->GetController().GoToIndex(4);
1226 forward_nav_load_observer.Wait();
1230 // Test for http://crbug.com/130016.
1231 // Swapping out a render view should update its visiblity state.
1232 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1233 SwappedOutViewHasCorrectVisibilityState) {
1234 // This test is invalid in --site-per-process mode, as swapped-out is no
1235 // longer used.
1236 if (SiteIsolationPolicy::IsSwappedOutStateForbidden())
1237 return;
1238 StartServer();
1240 // Load a page with links that open in a new window.
1241 std::string replacement_path;
1242 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1243 "files/click-noreferrer-links.html",
1244 foo_host_port_,
1245 &replacement_path));
1246 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1248 // Open a same-site link in a new widnow.
1249 ShellAddedObserver new_shell_observer;
1250 bool success = false;
1251 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1252 shell()->web_contents(),
1253 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1254 &success));
1255 EXPECT_TRUE(success);
1256 Shell* new_shell = new_shell_observer.GetShell();
1258 // Wait for the navigation in the new tab to finish, if it hasn't.
1259 WaitForLoadStop(new_shell->web_contents());
1260 EXPECT_EQ("/files/navigate_opener.html",
1261 new_shell->web_contents()->GetLastCommittedURL().path());
1263 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1265 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1266 rvh,
1267 "window.domAutomationController.send("
1268 " document.visibilityState == 'visible');",
1269 &success));
1270 EXPECT_TRUE(success);
1272 // Now navigate the new window to a different site. This should swap out the
1273 // tab's existing RenderView, causing it become hidden.
1274 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1276 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1277 rvh,
1278 "window.domAutomationController.send("
1279 " document.visibilityState == 'hidden');",
1280 &success));
1281 EXPECT_TRUE(success);
1283 // Going back should make the previously swapped-out view to become visible
1284 // again.
1286 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1287 new_shell->web_contents()->GetController().GoBack();
1288 back_nav_load_observer.Wait();
1291 EXPECT_EQ("/files/navigate_opener.html",
1292 new_shell->web_contents()->GetLastCommittedURL().path());
1294 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1296 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1297 rvh,
1298 "window.domAutomationController.send("
1299 " document.visibilityState == 'visible');",
1300 &success));
1301 EXPECT_TRUE(success);
1304 // This class ensures that all the given RenderViewHosts have properly been
1305 // shutdown.
1306 class RenderViewHostDestructionObserver : public WebContentsObserver {
1307 public:
1308 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1309 : WebContentsObserver(web_contents) {}
1310 ~RenderViewHostDestructionObserver() override {}
1311 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1312 watched_render_view_hosts_.insert(rvh);
1314 size_t GetNumberOfWatchedRenderViewHosts() const {
1315 return watched_render_view_hosts_.size();
1318 private:
1319 // WebContentsObserver implementation:
1320 void RenderViewDeleted(RenderViewHost* rvh) override {
1321 watched_render_view_hosts_.erase(rvh);
1324 std::set<RenderViewHost*> watched_render_view_hosts_;
1327 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1328 #if defined(THREAD_SANITIZER)
1329 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1330 #else
1331 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1332 #endif
1333 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1334 // they may cause crashes or memory corruptions when trying to call dead
1335 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1336 // ensure that a separate SiteInstance is created when navigating to view-source
1337 // URLs, regardless of current URL.
1338 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1339 MAYBE_LeakingRenderViewHosts) {
1340 StartServer();
1342 // Observe the created render_view_host's to make sure they will not leak.
1343 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1345 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1346 GURL view_source_url(kViewSourceScheme + std::string(":") +
1347 navigated_url.spec());
1349 // Let's ensure that when we start with a blank window, navigating away to a
1350 // view-source URL, we create a new SiteInstance.
1351 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1352 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1353 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1354 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1355 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1357 // Now navigate to the view-source URL and ensure we got a different
1358 // SiteInstance and RenderViewHost.
1359 NavigateToURL(shell(), view_source_url);
1360 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1361 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1362 GetRenderViewHost()->GetSiteInstance());
1363 rvh_observers.EnsureRVHGetsDestructed(
1364 shell()->web_contents()->GetRenderViewHost());
1366 // Load a random page and then navigate to view-source: of it.
1367 // This used to cause two RVH instances for the same SiteInstance, which
1368 // was a problem. This is no longer the case.
1369 NavigateToURL(shell(), navigated_url);
1370 SiteInstance* site_instance1 = shell()->web_contents()->
1371 GetRenderViewHost()->GetSiteInstance();
1372 rvh_observers.EnsureRVHGetsDestructed(
1373 shell()->web_contents()->GetRenderViewHost());
1375 NavigateToURL(shell(), view_source_url);
1376 rvh_observers.EnsureRVHGetsDestructed(
1377 shell()->web_contents()->GetRenderViewHost());
1378 SiteInstance* site_instance2 = shell()->web_contents()->
1379 GetRenderViewHost()->GetSiteInstance();
1381 // Ensure that view-source navigations force a new SiteInstance.
1382 EXPECT_NE(site_instance1, site_instance2);
1384 // Now navigate to a different instance so that we swap out again.
1385 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1386 rvh_observers.EnsureRVHGetsDestructed(
1387 shell()->web_contents()->GetRenderViewHost());
1389 // This used to leak a render view host.
1390 shell()->Close();
1392 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1394 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1397 // Test for crbug.com/143155. Frame tree updates during unload should not
1398 // interrupt the intended navigation and show swappedout:// instead.
1399 // Specifically:
1400 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1401 // 2) Send the second tab to a different foo.com SiteInstance.
1402 // This creates a swapped out opener for the first tab in the foo process.
1403 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1404 // tab's unload handler remove its frame.
1405 // This used to cause an update to the frame tree of the swapped out RV,
1406 // just as it was navigating to a real page. That pre-empted the real
1407 // navigation and visibly sent the tab to swappedout://.
1408 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1409 DontPreemptNavigationWithFrameTreeUpdate) {
1410 StartServer();
1412 // 1. Load a page that deletes its iframe during unload.
1413 NavigateToURL(shell(),
1414 test_server()->GetURL("files/remove_frame_on_unload.html"));
1416 // Get the original SiteInstance for later comparison.
1417 scoped_refptr<SiteInstance> orig_site_instance(
1418 shell()->web_contents()->GetSiteInstance());
1420 // Open a same-site page in a new window.
1421 ShellAddedObserver new_shell_observer;
1422 bool success = false;
1423 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1424 shell()->web_contents(),
1425 "window.domAutomationController.send(openWindow());",
1426 &success));
1427 EXPECT_TRUE(success);
1428 Shell* new_shell = new_shell_observer.GetShell();
1430 // Wait for the navigation in the new window to finish, if it hasn't.
1431 WaitForLoadStop(new_shell->web_contents());
1432 EXPECT_EQ("/files/title1.html",
1433 new_shell->web_contents()->GetLastCommittedURL().path());
1435 // Should have the same SiteInstance.
1436 EXPECT_EQ(orig_site_instance.get(),
1437 new_shell->web_contents()->GetSiteInstance());
1439 // 2. Send the second tab to a different process.
1440 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1441 scoped_refptr<SiteInstance> new_site_instance(
1442 new_shell->web_contents()->GetSiteInstance());
1443 EXPECT_NE(orig_site_instance, new_site_instance);
1445 // 3. Send the first tab to the second tab's process.
1446 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1448 // Make sure it ends up at the right page.
1449 WaitForLoadStop(shell()->web_contents());
1450 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1451 shell()->web_contents()->GetLastCommittedURL());
1452 EXPECT_EQ(new_site_instance.get(),
1453 shell()->web_contents()->GetSiteInstance());
1456 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1457 // are meant to run in the current page. We had a bug where we expected a
1458 // BrowsingInstance swap to occur on pages like view-source and extensions,
1459 // which broke chrome://crash and javascript: URLs.
1460 // See http://crbug.com/335503.
1461 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1462 ASSERT_TRUE(test_server()->Start());
1464 GURL original_url(test_server()->GetURL("files/title2.html"));
1465 GURL view_source_url(kViewSourceScheme + std::string(":") +
1466 original_url.spec());
1468 NavigateToURL(shell(), view_source_url);
1470 // Check that javascript: URLs work.
1471 base::string16 expected_title = ASCIIToUTF16("msg");
1472 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1473 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1474 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1476 // Crash the renderer of the view-source page.
1477 RenderProcessHostWatcher crash_observer(
1478 shell()->web_contents(),
1479 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1480 EXPECT_TRUE(
1481 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1482 crash_observer.Wait();
1485 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1486 // Otherwise, we might try to load an unprivileged about:blank page into a
1487 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1488 // See http://crbug.com/334214.
1489 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1490 IgnoreRendererDebugURLsWhenCrashed) {
1491 // Visit a WebUI page with bindings.
1492 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1493 std::string(kChromeUIGpuHost));
1494 NavigateToURL(shell(), webui_url);
1495 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1496 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1498 // Crash the renderer of the WebUI page.
1499 RenderProcessHostWatcher crash_observer(
1500 shell()->web_contents(),
1501 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1502 EXPECT_TRUE(
1503 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1504 crash_observer.Wait();
1506 // Load the crash URL again but don't wait for any action. If it is not
1507 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1508 shell()->LoadURL(GURL(kChromeUICrashURL));
1510 // Ensure that such URLs can still work as the initial navigation of a tab.
1511 // We postpone the initial navigation of the tab using an empty GURL, so that
1512 // we can add a watcher for crashes.
1513 Shell* shell2 = Shell::CreateNewWindow(
1514 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, gfx::Size());
1515 RenderProcessHostWatcher crash_observer2(
1516 shell2->web_contents(),
1517 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1518 EXPECT_TRUE(
1519 NavigateToURLAndExpectNoCommit(shell2, GURL(kChromeUIKillURL)));
1520 crash_observer2.Wait();
1523 // Ensure that renderer-side debug URLs don't take effect on crashed renderers,
1524 // even when going back/forward.
1525 // See https://crbug.com/477606.
1526 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1527 IgnoreForwardToRendererDebugURLsWhenCrashed) {
1528 // Visit a WebUI page with bindings.
1529 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1530 std::string(kChromeUIGpuHost));
1531 NavigateToURL(shell(), webui_url);
1532 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1533 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1535 // Visit a debug URL that manages to commit, then go back.
1536 NavigateToURL(shell(), GURL(kChromeUIDumpURL));
1537 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1538 shell()->web_contents()->GetController().GoBack();
1539 back_nav_load_observer.Wait();
1541 // Crash the renderer of the WebUI page.
1542 RenderProcessHostWatcher crash_observer(
1543 shell()->web_contents(),
1544 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1545 EXPECT_TRUE(
1546 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1547 crash_observer.Wait();
1549 // Going forward with no live renderer should have no effect, and should not
1550 // crash.
1551 EXPECT_TRUE(shell()->web_contents()->GetController().CanGoForward());
1552 shell()->web_contents()->GetController().GoForward();
1553 EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
1554 EXPECT_TRUE(shell()->web_contents()->GetController().CanGoForward());
1557 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1558 // See http://crbug.com/428329.
1559 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1560 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1561 #else
1562 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1563 #endif
1564 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1565 // Otherwise it might get picked up by InitRenderView when granting bindings
1566 // to other RenderViewHosts. See http://crbug.com/330811.
1567 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1568 MAYBE_ClearPendingWebUIOnCommit) {
1569 // Visit a WebUI page with bindings.
1570 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1571 std::string(kChromeUIGpuHost)));
1572 NavigateToURL(shell(), webui_url);
1573 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1574 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1575 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1576 shell()->web_contents());
1577 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1578 EXPECT_TRUE(webui);
1579 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1581 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1582 // clear pending_web_ui() when it commits.
1583 GURL webui_url2(webui_url.spec() + "#foo");
1584 NavigateToURL(shell(), webui_url2);
1585 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1586 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1589 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1590 public:
1591 RFHMProcessPerTabTest() {}
1593 void SetUpCommandLine(base::CommandLine* command_line) override {
1594 command_line->AppendSwitch(switches::kProcessPerTab);
1598 // Test that we still swap processes for BrowsingInstance changes even in
1599 // --process-per-tab mode. See http://crbug.com/343017.
1600 // Disabled on Android: http://crbug.com/345873.
1601 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1602 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1603 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1604 #else
1605 #define MAYBE_BackFromWebUI BackFromWebUI
1606 #endif
1607 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1608 ASSERT_TRUE(test_server()->Start());
1609 GURL original_url(test_server()->GetURL("files/title2.html"));
1610 NavigateToURL(shell(), original_url);
1612 // Visit a WebUI page with bindings.
1613 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1614 std::string(kChromeUIGpuHost)));
1615 NavigateToURL(shell(), webui_url);
1616 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1617 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1619 // Go back and ensure we have no WebUI bindings.
1620 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1621 shell()->web_contents()->GetController().GoBack();
1622 back_nav_load_observer.Wait();
1623 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1624 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1625 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1628 // crbug.com/372360
1629 // The test loads url1, opens a link pointing to url2 in a new tab, and
1630 // navigates the new tab to url1.
1631 // The following is needed for the bug to happen:
1632 // - url1 must require webui bindings;
1633 // - navigating to url2 in the site instance of url1 should not swap
1634 // browsing instances, but should require a new site instance.
1635 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1636 GURL url1(std::string(kChromeUIScheme) + "://" +
1637 std::string(kChromeUIGpuHost));
1638 GURL url2(std::string(kChromeUIScheme) + "://" +
1639 std::string(kChromeUIAccessibilityHost));
1641 // Visit a WebUI page with bindings.
1642 NavigateToURL(shell(), url1);
1643 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1644 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1645 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1647 // Open a new tab. Initially it gets a render view in the original tab's
1648 // current site instance.
1649 TestNavigationObserver nav_observer(NULL);
1650 nav_observer.StartWatchingNewWebContents();
1651 ShellAddedObserver shao;
1652 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1653 nav_observer.Wait();
1654 Shell* new_shell = shao.GetShell();
1655 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1656 new_shell->web_contents());
1657 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1659 EXPECT_NE(site_instance2, site_instance1);
1660 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1661 RenderViewHost* initial_rvh = new_web_contents->
1662 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1663 ASSERT_TRUE(initial_rvh);
1664 // The following condition is what was causing the bug.
1665 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1667 // Navigate to url1 and check bindings.
1668 NavigateToURL(new_shell, url1);
1669 // The navigation should have used the first SiteInstance, otherwise
1670 // |initial_rvh| did not have a chance to be used.
1671 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1672 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1673 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1676 // crbug.com/424526
1677 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1678 // page and then to a regular page. The bug reproduces if blank page is visited
1679 // in between WebUI and regular page.
1680 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1681 ForceSwapAfterWebUIBindings) {
1682 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1683 switches::kProcessPerTab);
1684 ASSERT_TRUE(test_server()->Start());
1686 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1687 std::string(kChromeUIGpuHost));
1688 NavigateToURL(shell(), web_ui_url);
1689 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1690 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1692 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1694 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1695 NavigateToURL(shell(), regular_page_url);
1696 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1697 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1700 class FileChooserDelegate : public WebContentsDelegate {
1701 public:
1702 FileChooserDelegate(const base::FilePath& file)
1703 : file_(file), file_chosen_(false) {}
1705 void RunFileChooser(WebContents* web_contents,
1706 const FileChooserParams& params) override {
1707 // Send the selected file to the renderer process.
1708 FileChooserFileInfo file_info;
1709 file_info.file_path = file_;
1710 std::vector<FileChooserFileInfo> files;
1711 files.push_back(file_info);
1712 web_contents->GetRenderViewHost()->FilesSelectedInChooser(
1713 files, FileChooserParams::Open);
1715 file_chosen_ = true;
1718 bool file_chosen() { return file_chosen_; }
1720 private:
1721 base::FilePath file_;
1722 bool file_chosen_;
1725 // Test for http://crbug.com/262948.
1726 // Flaky on Mac. http://crbug.com/452018
1727 #if defined(OS_MACOSX)
1728 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1729 DISABLED_RestoreFileAccessForHistoryNavigation
1730 #else
1731 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1732 RestoreFileAccessForHistoryNavigation
1733 #endif
1734 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1735 MAYBE_RestoreFileAccessForHistoryNavigation) {
1736 StartServer();
1737 base::FilePath file;
1738 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1739 file = file.AppendASCII("bar");
1741 // Navigate to url and get it to reference a file in its PageState.
1742 GURL url1(test_server()->GetURL("files/file_input.html"));
1743 NavigateToURL(shell(), url1);
1744 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1745 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1746 shell()->web_contents()->SetDelegate(delegate.get());
1747 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1748 "document.getElementById('fileinput').click();"));
1749 EXPECT_TRUE(delegate->file_chosen());
1750 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1751 process_id, file));
1753 // Navigate to a different process without access to the file, and wait for
1754 // the old process to exit.
1755 RenderProcessHostWatcher exit_observer(
1756 shell()->web_contents()->GetRenderProcessHost(),
1757 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1758 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1759 exit_observer.Wait();
1760 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1761 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1763 // Ensure that the file ended up in the PageState of the previous entry.
1764 NavigationEntry* prev_entry =
1765 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1766 EXPECT_EQ(url1, prev_entry->GetURL());
1767 const std::vector<base::FilePath>& files =
1768 prev_entry->GetPageState().GetReferencedFiles();
1769 ASSERT_EQ(1U, files.size());
1770 EXPECT_EQ(file, files.at(0));
1772 // Go back, ending up in a different RenderProcessHost than before.
1773 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1774 shell()->web_contents()->GetController().GoBack();
1775 back_nav_load_observer.Wait();
1776 EXPECT_NE(process_id,
1777 shell()->web_contents()->GetRenderProcessHost()->GetID());
1779 // Ensure that the file access still exists in the new process ID.
1780 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1781 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1783 // Navigate to a same site page to trigger a PageState update and ensure the
1784 // renderer is not killed.
1785 EXPECT_TRUE(
1786 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1789 // Test for http://crbug.com/441966.
1790 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1791 RestoreSubframeFileAccessForHistoryNavigation) {
1792 StartServer();
1793 base::FilePath file;
1794 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1795 file = file.AppendASCII("bar");
1797 // Navigate to url and get it to reference a file in its PageState.
1798 GURL url1(test_server()->GetURL("files/file_input_subframe.html"));
1799 NavigateToURL(shell(), url1);
1800 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
1801 FrameTreeNode* root = wc->GetFrameTree()->root();
1802 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1803 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1804 shell()->web_contents()->SetDelegate(delegate.get());
1805 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1806 "document.getElementById('fileinput').click();"));
1807 EXPECT_TRUE(delegate->file_chosen());
1808 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1809 process_id, file));
1811 // Navigate to a different process without access to the file, and wait for
1812 // the old process to exit.
1813 RenderProcessHostWatcher exit_observer(
1814 shell()->web_contents()->GetRenderProcessHost(),
1815 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1816 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1817 exit_observer.Wait();
1818 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1819 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1821 // Ensure that the file ended up in the PageState of the previous entry.
1822 NavigationEntry* prev_entry =
1823 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1824 EXPECT_EQ(url1, prev_entry->GetURL());
1825 const std::vector<base::FilePath>& files =
1826 prev_entry->GetPageState().GetReferencedFiles();
1827 ASSERT_EQ(1U, files.size());
1828 EXPECT_EQ(file, files.at(0));
1830 // Go back, ending up in a different RenderProcessHost than before.
1831 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1832 shell()->web_contents()->GetController().GoBack();
1833 back_nav_load_observer.Wait();
1834 EXPECT_NE(process_id,
1835 shell()->web_contents()->GetRenderProcessHost()->GetID());
1837 // Ensure that the file access still exists in the new process ID.
1838 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1839 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1842 // This class implements waiting for RenderFrameHost destruction. It relies on
1843 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1844 // destroyed.
1845 // Note: RenderFrameDeleted is also fired when the process associated with the
1846 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1847 // is expected.
1848 class RenderFrameHostDestructionObserver : public WebContentsObserver {
1849 public:
1850 explicit RenderFrameHostDestructionObserver(RenderFrameHost* rfh)
1851 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
1852 message_loop_runner_(new MessageLoopRunner),
1853 deleted_(false),
1854 render_frame_host_(rfh) {}
1855 ~RenderFrameHostDestructionObserver() override {}
1857 void Wait() {
1858 if (deleted_)
1859 return;
1861 message_loop_runner_->Run();
1864 // WebContentsObserver implementation:
1865 void RenderFrameDeleted(RenderFrameHost* rfh) override {
1866 if (rfh == render_frame_host_) {
1867 CHECK(!deleted_);
1868 deleted_ = true;
1871 if (deleted_ && message_loop_runner_->loop_running()) {
1872 base::ThreadTaskRunnerHandle::Get()->PostTask(
1873 FROM_HERE, message_loop_runner_->QuitClosure());
1877 private:
1878 scoped_refptr<MessageLoopRunner> message_loop_runner_;
1879 bool deleted_;
1880 RenderFrameHost* render_frame_host_;
1883 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1884 // doing a simple cross-process navigation.
1885 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1886 CleanupOnCrossProcessNavigation) {
1887 StartEmbeddedServer();
1889 // Do an initial navigation and capture objects we expect to be cleaned up
1890 // on cross-process navigation.
1891 GURL start_url = embedded_test_server()->GetURL("/title1.html");
1892 NavigateToURL(shell(), start_url);
1894 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1895 ->GetFrameTree()
1896 ->root();
1897 int32 orig_site_instance_id =
1898 root->current_frame_host()->GetSiteInstance()->GetId();
1899 int initial_process_id =
1900 root->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1901 int initial_rfh_id = root->current_frame_host()->GetRoutingID();
1902 int initial_rvh_id =
1903 root->current_frame_host()->render_view_host()->GetRoutingID();
1905 // Navigate cross-process and ensure that cleanup is performed as expected.
1906 GURL cross_site_url =
1907 embedded_test_server()->GetURL("foo.com", "/title2.html");
1908 RenderFrameHostDestructionObserver rfh_observer(root->current_frame_host());
1909 NavigateToURL(shell(), cross_site_url);
1910 rfh_observer.Wait();
1912 EXPECT_NE(orig_site_instance_id,
1913 root->current_frame_host()->GetSiteInstance()->GetId());
1914 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id, initial_rfh_id));
1915 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id, initial_rvh_id));
1918 // Ensure that the opener chain proxies and RVHs are properly reinitialized if
1919 // a tab crashes and reloads. See https://crbug.com/505090.
1920 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1921 ReinitializeOpenerChainAfterCrashAndReload) {
1922 StartEmbeddedServer();
1924 GURL main_url = embedded_test_server()->GetURL("/title1.html");
1925 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1927 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1928 ->GetFrameTree()
1929 ->root();
1931 scoped_refptr<SiteInstance> orig_site_instance(
1932 shell()->web_contents()->GetSiteInstance());
1933 EXPECT_TRUE(orig_site_instance);
1935 // Open a popup and navigate it cross-site.
1936 Shell* new_shell =
1937 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
1938 EXPECT_TRUE(new_shell);
1939 FrameTreeNode* popup_root =
1940 static_cast<WebContentsImpl*>(new_shell->web_contents())
1941 ->GetFrameTree()
1942 ->root();
1944 GURL cross_site_url =
1945 embedded_test_server()->GetURL("foo.com", "/title2.html");
1946 EXPECT_TRUE(NavigateToURL(new_shell, cross_site_url));
1948 scoped_refptr<SiteInstance> foo_site_instance(
1949 new_shell->web_contents()->GetSiteInstance());
1950 EXPECT_NE(foo_site_instance, orig_site_instance);
1952 // Kill the popup's process.
1953 RenderProcessHost* popup_process =
1954 popup_root->current_frame_host()->GetProcess();
1955 RenderProcessHostWatcher crash_observer(
1956 popup_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1957 popup_process->Shutdown(0, false);
1958 crash_observer.Wait();
1959 EXPECT_FALSE(popup_root->current_frame_host()->IsRenderFrameLive());
1960 EXPECT_FALSE(
1961 popup_root->current_frame_host()->render_view_host()->IsRenderViewLive());
1963 // The swapped-out RVH and proxy for the opener page in the foo.com
1964 // SiteInstance should not be live.
1965 RenderFrameHostManager* opener_manager = root->render_manager();
1966 RenderViewHostImpl* opener_rvh =
1967 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get());
1968 EXPECT_TRUE(opener_rvh);
1969 EXPECT_FALSE(opener_rvh->IsRenderViewLive());
1970 RenderFrameProxyHost* opener_rfph =
1971 opener_manager->GetRenderFrameProxyHost(foo_site_instance.get());
1972 EXPECT_TRUE(opener_rfph);
1973 EXPECT_FALSE(opener_rfph->is_render_frame_proxy_live());
1975 // Re-navigate the popup to the same URL and check that this recreates the
1976 // opener's swapped out RVH and proxy in the foo.com SiteInstance.
1977 EXPECT_TRUE(NavigateToURL(new_shell, cross_site_url));
1978 EXPECT_TRUE(opener_rvh->IsRenderViewLive());
1979 EXPECT_TRUE(opener_rfph->is_render_frame_proxy_live());
1982 // Test that when a frame's opener is updated via window.open, the browser
1983 // process and the frame's proxies in other processes find out about the new
1984 // opener. Open two popups in different processes, set one popup's opener to
1985 // the other popup, and ensure that the opener is updated in all processes.
1986 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, UpdateOpener) {
1987 StartEmbeddedServer();
1989 GURL main_url = embedded_test_server()->GetURL("/post_message.html");
1990 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1992 // It is safe to obtain the root frame tree node here, as it doesn't change.
1993 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1994 ->GetFrameTree()
1995 ->root();
1997 scoped_refptr<SiteInstance> orig_site_instance(
1998 shell()->web_contents()->GetSiteInstance());
1999 EXPECT_TRUE(orig_site_instance);
2001 // Open a cross-site popup named "foo" and a same-site popup named "bar".
2002 Shell* foo_shell =
2003 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
2004 EXPECT_TRUE(foo_shell);
2005 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/post_message.html"));
2006 NavigateToURL(foo_shell, foo_url);
2008 GURL bar_url(embedded_test_server()->GetURL(
2009 "/frame_tree/page_with_post_message_frames.html"));
2010 Shell* bar_shell = OpenPopup(shell()->web_contents(), bar_url, "bar");
2011 EXPECT_TRUE(bar_shell);
2013 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2014 foo_shell->web_contents()->GetSiteInstance());
2015 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
2016 bar_shell->web_contents()->GetSiteInstance());
2018 // Initially, both popups' openers should point to main window.
2019 FrameTreeNode* foo_root =
2020 static_cast<WebContentsImpl*>(foo_shell->web_contents())
2021 ->GetFrameTree()
2022 ->root();
2023 FrameTreeNode* bar_root =
2024 static_cast<WebContentsImpl*>(bar_shell->web_contents())
2025 ->GetFrameTree()
2026 ->root();
2027 EXPECT_EQ(root, foo_root->opener());
2028 EXPECT_EQ(root, bar_root->opener());
2030 // From the bar process, use window.open to update foo's opener to point to
2031 // bar. This is allowed since bar is same-origin with foo's opener. Use
2032 // window.open with an empty URL, which should return a reference to the
2033 // target frame without navigating it.
2034 bool success = false;
2035 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2036 bar_shell->web_contents(),
2037 "window.domAutomationController.send(!!window.open('','foo'));",
2038 &success));
2039 EXPECT_TRUE(success);
2040 EXPECT_FALSE(foo_shell->web_contents()->IsLoading());
2041 EXPECT_EQ(foo_url, foo_root->current_url());
2043 // Check that updated opener propagated to the browser process.
2044 EXPECT_EQ(bar_root, foo_root->opener());
2046 // Check that foo's opener was updated in foo's process. Send a postMessage
2047 // to the opener and check that the right window (bar_shell) receives it.
2048 base::string16 expected_title = ASCIIToUTF16("opener-msg");
2049 TitleWatcher title_watcher(bar_shell->web_contents(), expected_title);
2050 success = false;
2051 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2052 foo_shell->web_contents(),
2053 "window.domAutomationController.send(postToOpener('opener-msg', '*'));",
2054 &success));
2055 EXPECT_TRUE(success);
2056 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2058 // Check that a non-null assignment to the opener doesn't change the opener
2059 // in the browser process.
2060 EXPECT_TRUE(
2061 ExecuteScript(foo_shell->web_contents(), "window.opener = window;"));
2062 EXPECT_EQ(bar_root, foo_root->opener());
2065 } // namespace content