Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blob19e81a0875803714a81796585bd5a769904a8f17
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 "content/test/content_browser_test_utils_internal.h"
41 #include "net/base/net_util.h"
42 #include "net/dns/mock_host_resolver.h"
43 #include "net/test/embedded_test_server/embedded_test_server.h"
44 #include "net/test/spawned_test_server/spawned_test_server.h"
46 using base::ASCIIToUTF16;
48 namespace content {
50 namespace {
52 const char kOpenUrlViaClickTargetFunc[] =
53 "(function(url) {\n"
54 " var lnk = document.createElement(\"a\");\n"
55 " lnk.href = url;\n"
56 " lnk.target = \"_blank\";\n"
57 " document.body.appendChild(lnk);\n"
58 " lnk.click();\n"
59 "})";
61 // Adds a link with given url and target=_blank, and clicks on it.
62 void OpenUrlViaClickTarget(const ToRenderFrameHost& adapter, const GURL& url) {
63 EXPECT_TRUE(ExecuteScript(adapter,
64 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
67 } // anonymous namespace
69 class RenderFrameHostManagerTest : public ContentBrowserTest {
70 public:
71 RenderFrameHostManagerTest() : foo_com_("foo.com") {
72 replace_host_.SetHostStr(foo_com_);
75 static bool GetFilePathWithHostAndPortReplacement(
76 const std::string& original_file_path,
77 const net::HostPortPair& host_port_pair,
78 std::string* replacement_path) {
79 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
80 replacement_text.push_back(
81 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
82 return net::SpawnedTestServer::GetFilePathWithReplacements(
83 original_file_path, replacement_text, replacement_path);
86 void StartServer() {
87 // Support multiple sites on the test server.
88 host_resolver()->AddRule("*", "127.0.0.1");
89 ASSERT_TRUE(test_server()->Start());
91 foo_host_port_ = test_server()->host_port_pair();
92 foo_host_port_.set_host(foo_com_);
95 void StartEmbeddedServer() {
96 // Support multiple sites on the embedded test server.
97 host_resolver()->AddRule("*", "127.0.0.1");
98 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
99 SetupCrossSiteRedirector(embedded_test_server());
102 // Returns a URL on foo.com with the given path.
103 GURL GetCrossSiteURL(const std::string& path) {
104 GURL cross_site_url(test_server()->GetURL(path));
105 return cross_site_url.ReplaceComponents(replace_host_);
108 protected:
109 std::string foo_com_;
110 GURL::Replacements replace_host_;
111 net::HostPortPair foo_host_port_;
114 // Web pages should not have script access to the swapped out page.
115 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
116 StartServer();
118 // Load a page with links that open in a new window.
119 std::string replacement_path;
120 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
121 "files/click-noreferrer-links.html",
122 foo_host_port_,
123 &replacement_path));
124 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
126 // Get the original SiteInstance for later comparison.
127 scoped_refptr<SiteInstance> orig_site_instance(
128 shell()->web_contents()->GetSiteInstance());
129 EXPECT_TRUE(orig_site_instance.get() != NULL);
131 // Open a same-site link in a new window.
132 ShellAddedObserver new_shell_observer;
133 bool success = false;
134 EXPECT_TRUE(ExecuteScriptAndExtractBool(
135 shell()->web_contents(),
136 "window.domAutomationController.send(clickSameSiteTargetedLink());",
137 &success));
138 EXPECT_TRUE(success);
139 Shell* new_shell = new_shell_observer.GetShell();
141 // Wait for the navigation in the new window to finish, if it hasn't.
142 WaitForLoadStop(new_shell->web_contents());
143 EXPECT_EQ("/files/navigate_opener.html",
144 new_shell->web_contents()->GetLastCommittedURL().path());
146 // Should have the same SiteInstance.
147 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
149 // We should have access to the opened window's location.
150 success = false;
151 EXPECT_TRUE(ExecuteScriptAndExtractBool(
152 shell()->web_contents(),
153 "window.domAutomationController.send(testScriptAccessToWindow());",
154 &success));
155 EXPECT_TRUE(success);
157 // Now navigate the new window to a different site.
158 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
159 scoped_refptr<SiteInstance> new_site_instance(
160 new_shell->web_contents()->GetSiteInstance());
161 EXPECT_NE(orig_site_instance, new_site_instance);
163 // We should no longer have script access to the opened window's location.
164 success = false;
165 EXPECT_TRUE(ExecuteScriptAndExtractBool(
166 shell()->web_contents(),
167 "window.domAutomationController.send(testScriptAccessToWindow());",
168 &success));
169 EXPECT_FALSE(success);
171 // We now navigate the window to an about:blank page.
172 success = false;
173 EXPECT_TRUE(ExecuteScriptAndExtractBool(
174 shell()->web_contents(),
175 "window.domAutomationController.send(clickBlankTargetedLink());",
176 &success));
177 EXPECT_TRUE(success);
179 // Wait for the navigation in the new window to finish.
180 WaitForLoadStop(new_shell->web_contents());
181 GURL blank_url(url::kAboutBlankURL);
182 EXPECT_EQ(blank_url,
183 new_shell->web_contents()->GetLastCommittedURL());
184 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
186 // We should have access to the opened window's location.
187 success = false;
188 EXPECT_TRUE(ExecuteScriptAndExtractBool(
189 shell()->web_contents(),
190 "window.domAutomationController.send(testScriptAccessToWindow());",
191 &success));
192 EXPECT_TRUE(success);
195 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
196 // and target=_blank should create a new SiteInstance.
197 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
198 SwapProcessWithRelNoreferrerAndTargetBlank) {
199 StartServer();
201 // Load a page with links that open in a new window.
202 std::string replacement_path;
203 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
204 "files/click-noreferrer-links.html",
205 foo_host_port_,
206 &replacement_path));
207 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
209 // Get the original SiteInstance for later comparison.
210 scoped_refptr<SiteInstance> orig_site_instance(
211 shell()->web_contents()->GetSiteInstance());
212 EXPECT_TRUE(orig_site_instance.get() != NULL);
214 // Test clicking a rel=noreferrer + target=blank link.
215 ShellAddedObserver new_shell_observer;
216 bool success = false;
217 EXPECT_TRUE(ExecuteScriptAndExtractBool(
218 shell()->web_contents(),
219 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
220 &success));
221 EXPECT_TRUE(success);
223 // Wait for the window to open.
224 Shell* new_shell = new_shell_observer.GetShell();
226 EXPECT_EQ("/files/title2.html",
227 new_shell->web_contents()->GetVisibleURL().path());
229 // Wait for the cross-site transition in the new tab to finish.
230 WaitForLoadStop(new_shell->web_contents());
231 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
232 new_shell->web_contents());
233 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
234 pending_render_view_host());
236 // Should have a new SiteInstance.
237 scoped_refptr<SiteInstance> noref_blank_site_instance(
238 new_shell->web_contents()->GetSiteInstance());
239 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
242 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
243 // for rel=noreferrer links in new windows, even to same site pages and named
244 // targets.
245 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
246 SwapProcessWithSameSiteRelNoreferrer) {
247 StartServer();
249 // Load a page with links that open in a new window.
250 std::string replacement_path;
251 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
252 "files/click-noreferrer-links.html",
253 foo_host_port_,
254 &replacement_path));
255 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
257 // Get the original SiteInstance for later comparison.
258 scoped_refptr<SiteInstance> orig_site_instance(
259 shell()->web_contents()->GetSiteInstance());
260 EXPECT_TRUE(orig_site_instance.get() != NULL);
262 // Test clicking a same-site rel=noreferrer + target=foo link.
263 ShellAddedObserver new_shell_observer;
264 bool success = false;
265 EXPECT_TRUE(ExecuteScriptAndExtractBool(
266 shell()->web_contents(),
267 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
268 &success));
269 EXPECT_TRUE(success);
271 // Wait for the window to open.
272 Shell* new_shell = new_shell_observer.GetShell();
274 // Opens in new window.
275 EXPECT_EQ("/files/title2.html",
276 new_shell->web_contents()->GetVisibleURL().path());
278 // Wait for the cross-site transition in the new tab to finish.
279 WaitForLoadStop(new_shell->web_contents());
280 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
281 new_shell->web_contents());
282 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
283 pending_render_view_host());
285 // Should have a new SiteInstance (in a new BrowsingInstance).
286 scoped_refptr<SiteInstance> noref_blank_site_instance(
287 new_shell->web_contents()->GetSiteInstance());
288 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
291 // Test for crbug.com/24447. Following a cross-site link with just
292 // target=_blank should not create a new SiteInstance, unless we
293 // are running in --site-per-process mode.
294 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
295 DontSwapProcessWithOnlyTargetBlank) {
296 StartServer();
298 // Load a page with links that open in a new window.
299 std::string replacement_path;
300 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
301 "files/click-noreferrer-links.html",
302 foo_host_port_,
303 &replacement_path));
304 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path)));
306 // Get the original SiteInstance for later comparison.
307 scoped_refptr<SiteInstance> orig_site_instance(
308 shell()->web_contents()->GetSiteInstance());
309 EXPECT_TRUE(orig_site_instance.get() != NULL);
311 // Test clicking a target=blank link.
312 ShellAddedObserver new_shell_observer;
313 bool success = false;
314 EXPECT_TRUE(ExecuteScriptAndExtractBool(
315 shell()->web_contents(),
316 "window.domAutomationController.send(clickTargetBlankLink());",
317 &success));
318 EXPECT_TRUE(success);
320 // Wait for the window to open.
321 Shell* new_shell = new_shell_observer.GetShell();
323 // Wait for the cross-site transition in the new tab to finish.
324 EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
325 EXPECT_EQ("/files/title2.html",
326 new_shell->web_contents()->GetLastCommittedURL().path());
328 // Should have the same SiteInstance unless we're in site-per-process mode.
329 scoped_refptr<SiteInstance> blank_site_instance(
330 new_shell->web_contents()->GetSiteInstance());
331 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
332 switches::kSitePerProcess))
333 EXPECT_EQ(orig_site_instance, blank_site_instance);
334 else
335 EXPECT_NE(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 (!base::CommandLine::ForCurrentProcess()->HasSwitch(
377 switches::kSitePerProcess))
378 EXPECT_EQ(orig_site_instance, noref_site_instance);
379 else
380 EXPECT_NE(orig_site_instance, noref_site_instance);
383 // Test for crbug.com/116192. Targeted links should still work after the
384 // named target window has swapped processes.
385 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
386 AllowTargetedNavigationsAfterSwap) {
387 StartServer();
389 // Load a page with links that open in a new window.
390 std::string replacement_path;
391 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
392 "files/click-noreferrer-links.html",
393 foo_host_port_,
394 &replacement_path));
395 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
397 // Get the original SiteInstance for later comparison.
398 scoped_refptr<SiteInstance> orig_site_instance(
399 shell()->web_contents()->GetSiteInstance());
400 EXPECT_TRUE(orig_site_instance.get() != NULL);
402 // Test clicking a target=foo link.
403 ShellAddedObserver new_shell_observer;
404 bool success = false;
405 EXPECT_TRUE(ExecuteScriptAndExtractBool(
406 shell()->web_contents(),
407 "window.domAutomationController.send(clickSameSiteTargetedLink());",
408 &success));
409 EXPECT_TRUE(success);
410 Shell* new_shell = new_shell_observer.GetShell();
412 // Wait for the navigation in the new tab to finish, if it hasn't.
413 WaitForLoadStop(new_shell->web_contents());
414 EXPECT_EQ("/files/navigate_opener.html",
415 new_shell->web_contents()->GetLastCommittedURL().path());
417 // Should have the same SiteInstance.
418 scoped_refptr<SiteInstance> blank_site_instance(
419 new_shell->web_contents()->GetSiteInstance());
420 EXPECT_EQ(orig_site_instance, blank_site_instance);
422 // Now navigate the new tab to a different site.
423 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
424 NavigateToURL(new_shell, cross_site_url);
425 scoped_refptr<SiteInstance> new_site_instance(
426 new_shell->web_contents()->GetSiteInstance());
427 EXPECT_NE(orig_site_instance, new_site_instance);
429 // Clicking the original link in the first tab should cause us to swap back.
430 TestNavigationObserver navigation_observer(new_shell->web_contents());
431 EXPECT_TRUE(ExecuteScriptAndExtractBool(
432 shell()->web_contents(),
433 "window.domAutomationController.send(clickSameSiteTargetedLink());",
434 &success));
435 EXPECT_TRUE(success);
436 navigation_observer.Wait();
438 // Should have swapped back and shown the new window again.
439 scoped_refptr<SiteInstance> revisit_site_instance(
440 new_shell->web_contents()->GetSiteInstance());
441 EXPECT_EQ(orig_site_instance, revisit_site_instance);
443 // If it navigates away to another process, the original window should
444 // still be able to close it (using a cross-process close message).
445 NavigateToURL(new_shell, cross_site_url);
446 EXPECT_EQ(new_site_instance.get(),
447 new_shell->web_contents()->GetSiteInstance());
448 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
449 EXPECT_TRUE(ExecuteScriptAndExtractBool(
450 shell()->web_contents(),
451 "window.domAutomationController.send(testCloseWindow());",
452 &success));
453 EXPECT_TRUE(success);
454 close_watcher.Wait();
457 // Test that setting the opener to null in a window affects cross-process
458 // navigations, including those to existing entries. http://crbug.com/156669.
459 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
460 #if defined(THREAD_SANITIZER)
461 #define MAYBE_DisownOpener DISABLED_DisownOpener
462 #else
463 #define MAYBE_DisownOpener DisownOpener
464 #endif
465 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
466 StartServer();
468 // Load a page with links that open in a new window.
469 std::string replacement_path;
470 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
471 "files/click-noreferrer-links.html",
472 foo_host_port_,
473 &replacement_path));
474 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
476 // Get the original SiteInstance for later comparison.
477 scoped_refptr<SiteInstance> orig_site_instance(
478 shell()->web_contents()->GetSiteInstance());
479 EXPECT_TRUE(orig_site_instance.get() != NULL);
481 // Test clicking a target=_blank link.
482 ShellAddedObserver new_shell_observer;
483 bool success = false;
484 EXPECT_TRUE(ExecuteScriptAndExtractBool(
485 shell()->web_contents(),
486 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
487 &success));
488 EXPECT_TRUE(success);
489 Shell* new_shell = new_shell_observer.GetShell();
490 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
492 // Wait for the navigation in the new tab to finish, if it hasn't.
493 WaitForLoadStop(new_shell->web_contents());
494 EXPECT_EQ("/files/title2.html",
495 new_shell->web_contents()->GetLastCommittedURL().path());
497 // Should have the same SiteInstance.
498 scoped_refptr<SiteInstance> blank_site_instance(
499 new_shell->web_contents()->GetSiteInstance());
500 EXPECT_EQ(orig_site_instance, blank_site_instance);
502 // Now navigate the new tab to a different site.
503 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
504 scoped_refptr<SiteInstance> new_site_instance(
505 new_shell->web_contents()->GetSiteInstance());
506 EXPECT_NE(orig_site_instance, new_site_instance);
507 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
509 // Now disown the opener.
510 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
511 "window.opener = null;"));
512 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
514 // Go back and ensure the opener is still null.
516 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
517 new_shell->web_contents()->GetController().GoBack();
518 back_nav_load_observer.Wait();
520 success = false;
521 EXPECT_TRUE(ExecuteScriptAndExtractBool(
522 new_shell->web_contents(),
523 "window.domAutomationController.send(window.opener == null);",
524 &success));
525 EXPECT_TRUE(success);
526 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
528 // Now navigate forward again (creating a new process) and check opener.
529 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
530 success = false;
531 EXPECT_TRUE(ExecuteScriptAndExtractBool(
532 new_shell->web_contents(),
533 "window.domAutomationController.send(window.opener == null);",
534 &success));
535 EXPECT_TRUE(success);
536 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
539 // Test that subframes can disown their openers. http://crbug.com/225528.
540 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
541 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
542 NavigateToURL(shell(), frame_url);
544 // Give the frame an opener using window.open.
545 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
546 "window.open('about:blank','foo');"));
548 // Now disown the frame's opener. Shouldn't crash.
549 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
550 "window.frames[0].opener = null;"));
553 // Check that window.name is preserved for top frames when they navigate
554 // cross-process. See https://crbug.com/504164.
555 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
556 PreserveTopFrameWindowNameOnCrossProcessNavigations) {
557 StartEmbeddedServer();
559 GURL main_url(embedded_test_server()->GetURL("/title1.html"));
560 EXPECT_TRUE(NavigateToURL(shell(), main_url));
562 // Get the original SiteInstance for later comparison.
563 scoped_refptr<SiteInstance> orig_site_instance(
564 shell()->web_contents()->GetSiteInstance());
565 EXPECT_TRUE(orig_site_instance.get() != NULL);
567 // Open a popup using window.open with a 'foo' window.name.
568 Shell* new_shell =
569 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
570 EXPECT_TRUE(new_shell);
572 // The window.name for the new popup should be "foo".
573 std::string name;
574 EXPECT_TRUE(ExecuteScriptAndExtractString(
575 new_shell->web_contents(),
576 "window.domAutomationController.send(window.name);", &name));
577 EXPECT_EQ("foo", name);
579 // Now navigate the new tab to a different site.
580 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
581 EXPECT_TRUE(NavigateToURL(new_shell, foo_url));
582 scoped_refptr<SiteInstance> new_site_instance(
583 new_shell->web_contents()->GetSiteInstance());
584 EXPECT_NE(orig_site_instance, new_site_instance);
586 // window.name should still be "foo".
587 name = "";
588 EXPECT_TRUE(ExecuteScriptAndExtractString(
589 new_shell->web_contents(),
590 "window.domAutomationController.send(window.name);", &name));
591 EXPECT_EQ("foo", name);
593 // Open another popup from the 'foo' popup and navigate it cross-site.
594 Shell* new_shell2 =
595 OpenPopup(new_shell->web_contents(), GURL(url::kAboutBlankURL), "bar");
596 EXPECT_TRUE(new_shell2);
597 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title3.html"));
598 EXPECT_TRUE(NavigateToURL(new_shell2, bar_url));
600 // Check that the new popup's window.opener has name "foo", which verifies
601 // that new swapped-out RenderViews also propagate window.name. This has to
602 // be done via window.open, since window.name isn't readable cross-origin.
603 bool success = false;
604 EXPECT_TRUE(ExecuteScriptAndExtractBool(
605 new_shell2->web_contents(),
606 "window.domAutomationController.send("
607 " window.opener === window.open('','foo'));",
608 &success));
609 EXPECT_TRUE(success);
612 // Test for crbug.com/99202. PostMessage calls should still work after
613 // navigating the source and target windows to different sites.
614 // Specifically:
615 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
616 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
617 // 3) Post a message from "foo" to opener, which replies back to "foo".
618 // 4) Post a message from _blank to "foo".
619 // 5) Post a message from "foo" to a subframe of opener, which replies back.
620 // 6) Post a message from _blank to a subframe of "foo".
621 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
622 SupportCrossProcessPostMessage) {
623 StartServer();
625 // Load a page with links that open in a new window.
626 std::string replacement_path;
627 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
628 "files/click-noreferrer-links.html",
629 foo_host_port_,
630 &replacement_path));
631 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
633 // Get the original SiteInstance and RVHM for later comparison.
634 WebContents* opener_contents = shell()->web_contents();
635 scoped_refptr<SiteInstance> orig_site_instance(
636 opener_contents->GetSiteInstance());
637 EXPECT_TRUE(orig_site_instance.get() != NULL);
638 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
639 opener_contents)->GetRenderManagerForTesting();
641 // 1) Open two more windows, one named. These initially have openers but no
642 // reference to each other. We will later post a message between them.
644 // First, a named target=foo window.
645 ShellAddedObserver new_shell_observer;
646 bool success = false;
647 EXPECT_TRUE(ExecuteScriptAndExtractBool(
648 opener_contents,
649 "window.domAutomationController.send(clickSameSiteTargetedLink());",
650 &success));
651 EXPECT_TRUE(success);
652 Shell* new_shell = new_shell_observer.GetShell();
654 // Wait for the navigation in the new window to finish, if it hasn't, then
655 // send it to post_message.html on a different site.
656 WebContents* foo_contents = new_shell->web_contents();
657 WaitForLoadStop(foo_contents);
658 EXPECT_EQ("/files/navigate_opener.html",
659 foo_contents->GetLastCommittedURL().path());
660 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
661 scoped_refptr<SiteInstance> foo_site_instance(
662 foo_contents->GetSiteInstance());
663 EXPECT_NE(orig_site_instance, foo_site_instance);
665 // Second, a target=_blank window.
666 ShellAddedObserver new_shell_observer2;
667 EXPECT_TRUE(ExecuteScriptAndExtractBool(
668 shell()->web_contents(),
669 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
670 &success));
671 EXPECT_TRUE(success);
673 // Wait for the navigation in the new window to finish, if it hasn't, then
674 // send it to post_message.html on the original site.
675 Shell* new_shell2 = new_shell_observer2.GetShell();
676 WebContents* new_contents = new_shell2->web_contents();
677 WaitForLoadStop(new_contents);
678 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
679 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
680 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
681 RenderFrameHostManager* new_manager =
682 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
684 // We now have three windows. The opener should have a swapped out RVH
685 // for the new SiteInstance, but the _blank window should not.
686 EXPECT_EQ(3u, Shell::windows().size());
687 EXPECT_TRUE(
688 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
689 EXPECT_FALSE(
690 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
692 // 2) Fail to post a message from the foo window to the opener if the target
693 // origin is wrong. We won't see an error, but we can check for the right
694 // number of received messages below.
695 EXPECT_TRUE(ExecuteScriptAndExtractBool(
696 foo_contents,
697 "window.domAutomationController.send(postToOpener('msg',"
698 " 'http://google.com'));",
699 &success));
700 EXPECT_TRUE(success);
701 ASSERT_FALSE(
702 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
704 // 3) Post a message from the foo window to the opener. The opener will
705 // reply, causing the foo window to update its own title.
706 base::string16 expected_title = ASCIIToUTF16("msg");
707 TitleWatcher title_watcher(foo_contents, expected_title);
708 EXPECT_TRUE(ExecuteScriptAndExtractBool(
709 foo_contents,
710 "window.domAutomationController.send(postToOpener('msg','*'));",
711 &success));
712 EXPECT_TRUE(success);
713 ASSERT_FALSE(
714 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
715 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
717 // We should have received only 1 message in the opener and "foo" tabs,
718 // and updated the title.
719 int opener_received_messages = 0;
720 EXPECT_TRUE(ExecuteScriptAndExtractInt(
721 opener_contents,
722 "window.domAutomationController.send(window.receivedMessages);",
723 &opener_received_messages));
724 int foo_received_messages = 0;
725 EXPECT_TRUE(ExecuteScriptAndExtractInt(
726 foo_contents,
727 "window.domAutomationController.send(window.receivedMessages);",
728 &foo_received_messages));
729 EXPECT_EQ(1, foo_received_messages);
730 EXPECT_EQ(1, opener_received_messages);
731 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
733 // 4) Now post a message from the _blank window to the foo window. The
734 // foo window will update its title and will not reply.
735 expected_title = ASCIIToUTF16("msg2");
736 TitleWatcher title_watcher2(foo_contents, expected_title);
737 EXPECT_TRUE(ExecuteScriptAndExtractBool(
738 new_contents,
739 "window.domAutomationController.send(postToFoo('msg2'));",
740 &success));
741 EXPECT_TRUE(success);
742 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
744 // This postMessage should have created a swapped out RVH for the new
745 // SiteInstance in the target=_blank window.
746 EXPECT_TRUE(
747 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
749 // TODO(nasko): Test subframe targeting of postMessage once
750 // http://crbug.com/153701 is fixed.
753 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
754 // messages which contain Transferables and get intercepted by
755 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
756 // swapped out) should work.
757 // Specifically:
758 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
759 // 2) Post a message containing a message port from opener to "foo".
760 // 3) Post a message from "foo" back to opener via the passed message port.
761 // The test will be enabled when the feature implementation lands.
762 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
763 SupportCrossProcessPostMessageWithMessagePort) {
764 StartServer();
766 // Load a page with links that open in a new window.
767 std::string replacement_path;
768 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
769 "files/click-noreferrer-links.html",
770 foo_host_port_,
771 &replacement_path));
772 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
774 // Get the original SiteInstance and RVHM for later comparison.
775 WebContents* opener_contents = shell()->web_contents();
776 scoped_refptr<SiteInstance> orig_site_instance(
777 opener_contents->GetSiteInstance());
778 EXPECT_TRUE(orig_site_instance.get() != NULL);
779 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
780 opener_contents)->GetRenderManagerForTesting();
782 // 1) Open a named target=foo window. We will later post a message between the
783 // opener and the new window.
784 ShellAddedObserver new_shell_observer;
785 bool success = false;
786 EXPECT_TRUE(ExecuteScriptAndExtractBool(
787 opener_contents,
788 "window.domAutomationController.send(clickSameSiteTargetedLink());",
789 &success));
790 EXPECT_TRUE(success);
791 Shell* new_shell = new_shell_observer.GetShell();
793 // Wait for the navigation in the new window to finish, if it hasn't, then
794 // send it to post_message.html on a different site.
795 WebContents* foo_contents = new_shell->web_contents();
796 WaitForLoadStop(foo_contents);
797 EXPECT_EQ("/files/navigate_opener.html",
798 foo_contents->GetLastCommittedURL().path());
799 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
800 scoped_refptr<SiteInstance> foo_site_instance(
801 foo_contents->GetSiteInstance());
802 EXPECT_NE(orig_site_instance, foo_site_instance);
804 // We now have two windows. The opener should have a swapped out RVH
805 // for the new SiteInstance.
806 EXPECT_EQ(2u, Shell::windows().size());
807 EXPECT_TRUE(
808 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
810 // 2) Post a message containing a MessagePort from opener to the the foo
811 // window. The foo window will reply via the passed port, causing the opener
812 // to update its own title.
813 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
814 TitleWatcher title_observer(opener_contents, expected_title);
815 EXPECT_TRUE(ExecuteScriptAndExtractBool(
816 opener_contents,
817 "window.domAutomationController.send(postWithPortToFoo());",
818 &success));
819 EXPECT_TRUE(success);
820 ASSERT_FALSE(
821 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
822 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
824 // Check message counts.
825 int opener_received_messages_via_port = 0;
826 EXPECT_TRUE(ExecuteScriptAndExtractInt(
827 opener_contents,
828 "window.domAutomationController.send(window.receivedMessagesViaPort);",
829 &opener_received_messages_via_port));
830 int foo_received_messages = 0;
831 EXPECT_TRUE(ExecuteScriptAndExtractInt(
832 foo_contents,
833 "window.domAutomationController.send(window.receivedMessages);",
834 &foo_received_messages));
835 int foo_received_messages_with_port = 0;
836 EXPECT_TRUE(ExecuteScriptAndExtractInt(
837 foo_contents,
838 "window.domAutomationController.send(window.receivedMessagesWithPort);",
839 &foo_received_messages_with_port));
840 EXPECT_EQ(1, foo_received_messages);
841 EXPECT_EQ(1, foo_received_messages_with_port);
842 EXPECT_EQ(1, opener_received_messages_via_port);
843 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
844 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
847 // Test for crbug.com/116192. Navigations to a window's opener should
848 // still work after a process swap.
849 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
850 AllowTargetedNavigationsInOpenerAfterSwap) {
851 StartServer();
853 // Load a page with links that open in a new window.
854 std::string replacement_path;
855 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
856 "files/click-noreferrer-links.html",
857 foo_host_port_,
858 &replacement_path));
859 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
861 // Get the original tab and SiteInstance for later comparison.
862 WebContents* orig_contents = shell()->web_contents();
863 scoped_refptr<SiteInstance> orig_site_instance(
864 orig_contents->GetSiteInstance());
865 EXPECT_TRUE(orig_site_instance.get() != NULL);
867 // Test clicking a target=foo link.
868 ShellAddedObserver new_shell_observer;
869 bool success = false;
870 EXPECT_TRUE(ExecuteScriptAndExtractBool(
871 orig_contents,
872 "window.domAutomationController.send(clickSameSiteTargetedLink());",
873 &success));
874 EXPECT_TRUE(success);
875 Shell* new_shell = new_shell_observer.GetShell();
877 // Wait for the navigation in the new window to finish, if it hasn't.
878 WaitForLoadStop(new_shell->web_contents());
879 EXPECT_EQ("/files/navigate_opener.html",
880 new_shell->web_contents()->GetLastCommittedURL().path());
882 // Should have the same SiteInstance.
883 scoped_refptr<SiteInstance> blank_site_instance(
884 new_shell->web_contents()->GetSiteInstance());
885 EXPECT_EQ(orig_site_instance, blank_site_instance);
887 // Now navigate the original (opener) tab to a different site.
888 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
889 scoped_refptr<SiteInstance> new_site_instance(
890 shell()->web_contents()->GetSiteInstance());
891 EXPECT_NE(orig_site_instance, new_site_instance);
893 // The opened tab should be able to navigate the opener back to its process.
894 TestNavigationObserver navigation_observer(orig_contents);
895 EXPECT_TRUE(ExecuteScriptAndExtractBool(
896 new_shell->web_contents(),
897 "window.domAutomationController.send(navigateOpener());",
898 &success));
899 EXPECT_TRUE(success);
900 navigation_observer.Wait();
902 // Should have swapped back into this process.
903 scoped_refptr<SiteInstance> revisit_site_instance(
904 shell()->web_contents()->GetSiteInstance());
905 EXPECT_EQ(orig_site_instance, revisit_site_instance);
908 // Test that subframes do not crash when sending a postMessage to the top frame
909 // from an unload handler while the top frame is being swapped out as part of
910 // navigating cross-process. https://crbug.com/475651.
911 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
912 PostMessageFromSubframeUnloadHandler) {
913 StartServer();
915 GURL frame_url(test_server()->GetURL("files/post_message.html"));
916 GURL main_url("data:text/html,<iframe name='foo' src='" + frame_url.spec() +
917 "'></iframe>");
918 EXPECT_TRUE(NavigateToURL(shell(), main_url));
920 // Get the original SiteInstance for later comparison.
921 scoped_refptr<SiteInstance> orig_site_instance(
922 shell()->web_contents()->GetSiteInstance());
923 EXPECT_NE(nullptr, orig_site_instance.get());
925 // It is safe to obtain the root frame tree node here, as it doesn't change.
926 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
927 ->GetFrameTree()
928 ->root();
929 ASSERT_EQ(1U, root->child_count());
930 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
932 // Register an unload handler that sends a postMessage to the top frame.
933 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
934 "registerUnload();"));
936 // Navigate the top frame cross-site. This will cause the top frame to be
937 // swapped out and run unload handlers, and the original renderer process
938 // should then terminate since it's not rendering any other frames.
939 RenderProcessHostWatcher exit_observer(
940 root->current_frame_host()->GetProcess(),
941 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
942 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
943 scoped_refptr<SiteInstance> new_site_instance(
944 shell()->web_contents()->GetSiteInstance());
945 EXPECT_NE(orig_site_instance, new_site_instance);
947 // Ensure that the original renderer process exited cleanly without crashing.
948 exit_observer.Wait();
949 EXPECT_EQ(true, exit_observer.did_exit_normally());
952 // Test that opening a new window in the same SiteInstance and then navigating
953 // both windows to a different SiteInstance allows the first process to exit.
954 // See http://crbug.com/126333.
955 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
956 ProcessExitWithSwappedOutViews) {
957 StartServer();
959 // Load a page with links that open in a new window.
960 std::string replacement_path;
961 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
962 "files/click-noreferrer-links.html",
963 foo_host_port_,
964 &replacement_path));
965 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
967 // Get the original SiteInstance for later comparison.
968 scoped_refptr<SiteInstance> orig_site_instance(
969 shell()->web_contents()->GetSiteInstance());
970 EXPECT_TRUE(orig_site_instance.get() != NULL);
972 // Test clicking a target=foo link.
973 ShellAddedObserver new_shell_observer;
974 bool success = false;
975 EXPECT_TRUE(ExecuteScriptAndExtractBool(
976 shell()->web_contents(),
977 "window.domAutomationController.send(clickSameSiteTargetedLink());",
978 &success));
979 EXPECT_TRUE(success);
980 Shell* new_shell = new_shell_observer.GetShell();
982 // Wait for the navigation in the new window to finish, if it hasn't.
983 WaitForLoadStop(new_shell->web_contents());
984 EXPECT_EQ("/files/navigate_opener.html",
985 new_shell->web_contents()->GetLastCommittedURL().path());
987 // Should have the same SiteInstance.
988 scoped_refptr<SiteInstance> opened_site_instance(
989 new_shell->web_contents()->GetSiteInstance());
990 EXPECT_EQ(orig_site_instance, opened_site_instance);
992 // Now navigate the opened window to a different site.
993 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
994 scoped_refptr<SiteInstance> new_site_instance(
995 new_shell->web_contents()->GetSiteInstance());
996 EXPECT_NE(orig_site_instance, new_site_instance);
998 // The original process should still be alive, since it is still used in the
999 // first window.
1000 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
1001 EXPECT_TRUE(orig_process->HasConnection());
1003 // Navigate the first window to a different site as well. The original
1004 // process should exit, since all of its views are now swapped out.
1005 RenderProcessHostWatcher exit_observer(
1006 orig_process,
1007 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1008 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1009 exit_observer.Wait();
1010 scoped_refptr<SiteInstance> new_site_instance2(
1011 shell()->web_contents()->GetSiteInstance());
1012 EXPECT_EQ(new_site_instance, new_site_instance2);
1015 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
1016 // error should not make us ignore future renderer-initiated navigations.
1017 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
1018 StartServer();
1020 // Get the original SiteInstance for later comparison.
1021 scoped_refptr<SiteInstance> orig_site_instance(
1022 shell()->web_contents()->GetSiteInstance());
1023 EXPECT_TRUE(orig_site_instance.get() != NULL);
1025 // Load a cross-site page that fails with a 204 error.
1026 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
1027 GetCrossSiteURL("nocontent")));
1029 // We should still be looking at the normal page. Because we started from a
1030 // blank new tab, the typed URL will still be visible until the user clears it
1031 // manually. The last committed URL will be the previous page.
1032 scoped_refptr<SiteInstance> post_nav_site_instance(
1033 shell()->web_contents()->GetSiteInstance());
1034 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
1035 EXPECT_EQ("/nocontent",
1036 shell()->web_contents()->GetVisibleURL().path());
1037 EXPECT_FALSE(
1038 shell()->web_contents()->GetController().GetLastCommittedEntry());
1040 // Renderer-initiated navigations should work.
1041 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
1042 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1043 GURL url = test_server()->GetURL("files/title2.html");
1044 EXPECT_TRUE(ExecuteScript(
1045 shell()->web_contents(),
1046 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
1047 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1049 // Opens in same tab.
1050 EXPECT_EQ(1u, Shell::windows().size());
1051 EXPECT_EQ("/files/title2.html",
1052 shell()->web_contents()->GetLastCommittedURL().path());
1054 // Should have the same SiteInstance.
1055 scoped_refptr<SiteInstance> new_site_instance(
1056 shell()->web_contents()->GetSiteInstance());
1057 EXPECT_EQ(orig_site_instance, new_site_instance);
1060 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1061 // initiated navigation in a new tab, until the content of the initial
1062 // about:blank page is modified by another window. At that point, we should
1063 // revert to showing about:blank to prevent a URL spoof.
1064 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
1065 ASSERT_TRUE(test_server()->Start());
1067 // Load a page that can open a URL that won't commit in a new window.
1068 NavigateToURL(
1069 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1070 WebContents* orig_contents = shell()->web_contents();
1072 // Click a /nocontent link that opens in a new window but never commits.
1073 ShellAddedObserver new_shell_observer;
1074 bool success = false;
1075 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1076 orig_contents,
1077 "window.domAutomationController.send(clickNoContentTargetedLink());",
1078 &success));
1079 EXPECT_TRUE(success);
1081 // Wait for the window to open.
1082 Shell* new_shell = new_shell_observer.GetShell();
1084 // Ensure the destination URL is visible, because it is considered the
1085 // initial navigation.
1086 WebContents* contents = new_shell->web_contents();
1087 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
1088 EXPECT_EQ("/nocontent",
1089 contents->GetController().GetVisibleEntry()->GetURL().path());
1091 // Now modify the contents of the new window from the opener. This will also
1092 // modify the title of the document to give us something to listen for.
1093 base::string16 expected_title = ASCIIToUTF16("Modified Title");
1094 TitleWatcher title_watcher(contents, expected_title);
1095 success = false;
1096 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1097 orig_contents,
1098 "window.domAutomationController.send(modifyNewWindow());",
1099 &success));
1100 EXPECT_TRUE(success);
1101 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1103 // At this point, we should no longer be showing the destination URL.
1104 // The visible entry should be null, resulting in about:blank in the address
1105 // bar.
1106 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1109 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1110 // initiated navigation in a new tab if it is not the initial navigation. In
1111 // this case, the renderer will not notify us of a modification, so we cannot
1112 // show the pending URL without allowing a spoof.
1113 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1114 DontShowLoadingURLIfNotInitialNav) {
1115 ASSERT_TRUE(test_server()->Start());
1117 // Load a page that can open a URL that won't commit in a new window.
1118 NavigateToURL(
1119 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1120 WebContents* orig_contents = shell()->web_contents();
1122 // Click a /nocontent link that opens in a new window but never commits.
1123 // By using an onclick handler that first creates the window, the slow
1124 // navigation is not considered an initial navigation.
1125 ShellAddedObserver new_shell_observer;
1126 bool success = false;
1127 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1128 orig_contents,
1129 "window.domAutomationController.send("
1130 "clickNoContentScriptedTargetedLink());",
1131 &success));
1132 EXPECT_TRUE(success);
1134 // Wait for the window to open.
1135 Shell* new_shell = new_shell_observer.GetShell();
1137 // Ensure the destination URL is not visible, because it is not the initial
1138 // navigation.
1139 WebContents* contents = new_shell->web_contents();
1140 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1141 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1144 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1145 #if defined(THREAD_SANITIZER)
1146 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1147 #else
1148 #define MAYBE_BackForwardNotStale BackForwardNotStale
1149 #endif
1150 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1151 // do not cause back/forward navigations to be considered stale by the
1152 // renderer.
1153 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1154 StartServer();
1155 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1157 // Visit a page on first site.
1158 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1160 // Visit three pages on second site.
1161 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1162 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1163 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1165 // History is now [blank, A1, B1, B2, *B3].
1166 WebContents* contents = shell()->web_contents();
1167 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1169 // Open another window in same process to keep this process alive.
1170 Shell* new_shell = CreateBrowser();
1171 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1173 // Go back three times to first site.
1175 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1176 shell()->web_contents()->GetController().GoBack();
1177 back_nav_load_observer.Wait();
1180 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1181 shell()->web_contents()->GetController().GoBack();
1182 back_nav_load_observer.Wait();
1185 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1186 shell()->web_contents()->GetController().GoBack();
1187 back_nav_load_observer.Wait();
1190 // Now go forward twice to B2. Shouldn't be left spinning.
1192 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1193 shell()->web_contents()->GetController().GoForward();
1194 forward_nav_load_observer.Wait();
1197 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1198 shell()->web_contents()->GetController().GoForward();
1199 forward_nav_load_observer.Wait();
1202 // Go back twice to first site.
1204 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1205 shell()->web_contents()->GetController().GoBack();
1206 back_nav_load_observer.Wait();
1209 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1210 shell()->web_contents()->GetController().GoBack();
1211 back_nav_load_observer.Wait();
1214 // Now go forward directly to B3. Shouldn't be left spinning.
1216 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1217 shell()->web_contents()->GetController().GoToIndex(4);
1218 forward_nav_load_observer.Wait();
1222 // Test for http://crbug.com/130016.
1223 // Swapping out a render view should update its visiblity state.
1224 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1225 SwappedOutViewHasCorrectVisibilityState) {
1226 // This test is invalid in --site-per-process mode, as swapped-out is no
1227 // longer used.
1228 if (RenderFrameHostManager::IsSwappedOutStateForbidden())
1229 return;
1230 StartServer();
1232 // Load a page with links that open in a new window.
1233 std::string replacement_path;
1234 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1235 "files/click-noreferrer-links.html",
1236 foo_host_port_,
1237 &replacement_path));
1238 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1240 // Open a same-site link in a new widnow.
1241 ShellAddedObserver new_shell_observer;
1242 bool success = false;
1243 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1244 shell()->web_contents(),
1245 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1246 &success));
1247 EXPECT_TRUE(success);
1248 Shell* new_shell = new_shell_observer.GetShell();
1250 // Wait for the navigation in the new tab to finish, if it hasn't.
1251 WaitForLoadStop(new_shell->web_contents());
1252 EXPECT_EQ("/files/navigate_opener.html",
1253 new_shell->web_contents()->GetLastCommittedURL().path());
1255 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1257 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1258 rvh,
1259 "window.domAutomationController.send("
1260 " document.visibilityState == 'visible');",
1261 &success));
1262 EXPECT_TRUE(success);
1264 // Now navigate the new window to a different site. This should swap out the
1265 // tab's existing RenderView, causing it become hidden.
1266 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1268 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1269 rvh,
1270 "window.domAutomationController.send("
1271 " document.visibilityState == 'hidden');",
1272 &success));
1273 EXPECT_TRUE(success);
1275 // Going back should make the previously swapped-out view to become visible
1276 // again.
1278 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1279 new_shell->web_contents()->GetController().GoBack();
1280 back_nav_load_observer.Wait();
1283 EXPECT_EQ("/files/navigate_opener.html",
1284 new_shell->web_contents()->GetLastCommittedURL().path());
1286 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1288 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1289 rvh,
1290 "window.domAutomationController.send("
1291 " document.visibilityState == 'visible');",
1292 &success));
1293 EXPECT_TRUE(success);
1296 // This class ensures that all the given RenderViewHosts have properly been
1297 // shutdown.
1298 class RenderViewHostDestructionObserver : public WebContentsObserver {
1299 public:
1300 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1301 : WebContentsObserver(web_contents) {}
1302 ~RenderViewHostDestructionObserver() override {}
1303 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1304 watched_render_view_hosts_.insert(rvh);
1306 size_t GetNumberOfWatchedRenderViewHosts() const {
1307 return watched_render_view_hosts_.size();
1310 private:
1311 // WebContentsObserver implementation:
1312 void RenderViewDeleted(RenderViewHost* rvh) override {
1313 watched_render_view_hosts_.erase(rvh);
1316 std::set<RenderViewHost*> watched_render_view_hosts_;
1319 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1320 #if defined(THREAD_SANITIZER)
1321 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1322 #else
1323 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1324 #endif
1325 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1326 // they may cause crashes or memory corruptions when trying to call dead
1327 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1328 // ensure that a separate SiteInstance is created when navigating to view-source
1329 // URLs, regardless of current URL.
1330 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1331 MAYBE_LeakingRenderViewHosts) {
1332 StartServer();
1334 // Observe the created render_view_host's to make sure they will not leak.
1335 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1337 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1338 GURL view_source_url(kViewSourceScheme + std::string(":") +
1339 navigated_url.spec());
1341 // Let's ensure that when we start with a blank window, navigating away to a
1342 // view-source URL, we create a new SiteInstance.
1343 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1344 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1345 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1346 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1347 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1349 // Now navigate to the view-source URL and ensure we got a different
1350 // SiteInstance and RenderViewHost.
1351 NavigateToURL(shell(), view_source_url);
1352 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1353 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1354 GetRenderViewHost()->GetSiteInstance());
1355 rvh_observers.EnsureRVHGetsDestructed(
1356 shell()->web_contents()->GetRenderViewHost());
1358 // Load a random page and then navigate to view-source: of it.
1359 // This used to cause two RVH instances for the same SiteInstance, which
1360 // was a problem. This is no longer the case.
1361 NavigateToURL(shell(), navigated_url);
1362 SiteInstance* site_instance1 = shell()->web_contents()->
1363 GetRenderViewHost()->GetSiteInstance();
1364 rvh_observers.EnsureRVHGetsDestructed(
1365 shell()->web_contents()->GetRenderViewHost());
1367 NavigateToURL(shell(), view_source_url);
1368 rvh_observers.EnsureRVHGetsDestructed(
1369 shell()->web_contents()->GetRenderViewHost());
1370 SiteInstance* site_instance2 = shell()->web_contents()->
1371 GetRenderViewHost()->GetSiteInstance();
1373 // Ensure that view-source navigations force a new SiteInstance.
1374 EXPECT_NE(site_instance1, site_instance2);
1376 // Now navigate to a different instance so that we swap out again.
1377 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1378 rvh_observers.EnsureRVHGetsDestructed(
1379 shell()->web_contents()->GetRenderViewHost());
1381 // This used to leak a render view host.
1382 shell()->Close();
1384 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1386 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1389 // Test for crbug.com/143155. Frame tree updates during unload should not
1390 // interrupt the intended navigation and show swappedout:// instead.
1391 // Specifically:
1392 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1393 // 2) Send the second tab to a different foo.com SiteInstance.
1394 // This creates a swapped out opener for the first tab in the foo process.
1395 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1396 // tab's unload handler remove its frame.
1397 // This used to cause an update to the frame tree of the swapped out RV,
1398 // just as it was navigating to a real page. That pre-empted the real
1399 // navigation and visibly sent the tab to swappedout://.
1400 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1401 DontPreemptNavigationWithFrameTreeUpdate) {
1402 StartServer();
1404 // 1. Load a page that deletes its iframe during unload.
1405 NavigateToURL(shell(),
1406 test_server()->GetURL("files/remove_frame_on_unload.html"));
1408 // Get the original SiteInstance for later comparison.
1409 scoped_refptr<SiteInstance> orig_site_instance(
1410 shell()->web_contents()->GetSiteInstance());
1412 // Open a same-site page in a new window.
1413 ShellAddedObserver new_shell_observer;
1414 bool success = false;
1415 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1416 shell()->web_contents(),
1417 "window.domAutomationController.send(openWindow());",
1418 &success));
1419 EXPECT_TRUE(success);
1420 Shell* new_shell = new_shell_observer.GetShell();
1422 // Wait for the navigation in the new window to finish, if it hasn't.
1423 WaitForLoadStop(new_shell->web_contents());
1424 EXPECT_EQ("/files/title1.html",
1425 new_shell->web_contents()->GetLastCommittedURL().path());
1427 // Should have the same SiteInstance.
1428 EXPECT_EQ(orig_site_instance.get(),
1429 new_shell->web_contents()->GetSiteInstance());
1431 // 2. Send the second tab to a different process.
1432 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1433 scoped_refptr<SiteInstance> new_site_instance(
1434 new_shell->web_contents()->GetSiteInstance());
1435 EXPECT_NE(orig_site_instance, new_site_instance);
1437 // 3. Send the first tab to the second tab's process.
1438 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1440 // Make sure it ends up at the right page.
1441 WaitForLoadStop(shell()->web_contents());
1442 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1443 shell()->web_contents()->GetLastCommittedURL());
1444 EXPECT_EQ(new_site_instance.get(),
1445 shell()->web_contents()->GetSiteInstance());
1448 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1449 // are meant to run in the current page. We had a bug where we expected a
1450 // BrowsingInstance swap to occur on pages like view-source and extensions,
1451 // which broke chrome://crash and javascript: URLs.
1452 // See http://crbug.com/335503.
1453 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1454 ASSERT_TRUE(test_server()->Start());
1456 GURL original_url(test_server()->GetURL("files/title2.html"));
1457 GURL view_source_url(kViewSourceScheme + std::string(":") +
1458 original_url.spec());
1460 NavigateToURL(shell(), view_source_url);
1462 // Check that javascript: URLs work.
1463 base::string16 expected_title = ASCIIToUTF16("msg");
1464 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1465 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1466 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1468 // Crash the renderer of the view-source page.
1469 RenderProcessHostWatcher crash_observer(
1470 shell()->web_contents(),
1471 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1472 EXPECT_TRUE(
1473 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1474 crash_observer.Wait();
1477 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1478 // Otherwise, we might try to load an unprivileged about:blank page into a
1479 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1480 // See http://crbug.com/334214.
1481 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1482 IgnoreRendererDebugURLsWhenCrashed) {
1483 // Visit a WebUI page with bindings.
1484 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1485 std::string(kChromeUIGpuHost));
1486 NavigateToURL(shell(), webui_url);
1487 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1488 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1490 // Crash the renderer of the WebUI page.
1491 RenderProcessHostWatcher crash_observer(
1492 shell()->web_contents(),
1493 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1494 EXPECT_TRUE(
1495 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1496 crash_observer.Wait();
1498 // Load the crash URL again but don't wait for any action. If it is not
1499 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1500 shell()->LoadURL(GURL(kChromeUICrashURL));
1502 // Ensure that such URLs can still work as the initial navigation of a tab.
1503 // We postpone the initial navigation of the tab using an empty GURL, so that
1504 // we can add a watcher for crashes.
1505 Shell* shell2 = Shell::CreateNewWindow(
1506 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, gfx::Size());
1507 RenderProcessHostWatcher crash_observer2(
1508 shell2->web_contents(),
1509 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1510 EXPECT_TRUE(
1511 NavigateToURLAndExpectNoCommit(shell2, GURL(kChromeUIKillURL)));
1512 crash_observer2.Wait();
1515 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1516 // See http://crbug.com/428329.
1517 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1518 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1519 #else
1520 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1521 #endif
1522 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1523 // Otherwise it might get picked up by InitRenderView when granting bindings
1524 // to other RenderViewHosts. See http://crbug.com/330811.
1525 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1526 MAYBE_ClearPendingWebUIOnCommit) {
1527 // Visit a WebUI page with bindings.
1528 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1529 std::string(kChromeUIGpuHost)));
1530 NavigateToURL(shell(), webui_url);
1531 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1532 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1533 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1534 shell()->web_contents());
1535 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1536 EXPECT_TRUE(webui);
1537 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1539 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1540 // clear pending_web_ui() when it commits.
1541 GURL webui_url2(webui_url.spec() + "#foo");
1542 NavigateToURL(shell(), webui_url2);
1543 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1544 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1547 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1548 public:
1549 RFHMProcessPerTabTest() {}
1551 void SetUpCommandLine(base::CommandLine* command_line) override {
1552 command_line->AppendSwitch(switches::kProcessPerTab);
1556 // Test that we still swap processes for BrowsingInstance changes even in
1557 // --process-per-tab mode. See http://crbug.com/343017.
1558 // Disabled on Android: http://crbug.com/345873.
1559 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1560 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1561 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1562 #else
1563 #define MAYBE_BackFromWebUI BackFromWebUI
1564 #endif
1565 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1566 ASSERT_TRUE(test_server()->Start());
1567 GURL original_url(test_server()->GetURL("files/title2.html"));
1568 NavigateToURL(shell(), original_url);
1570 // Visit a WebUI page with bindings.
1571 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1572 std::string(kChromeUIGpuHost)));
1573 NavigateToURL(shell(), webui_url);
1574 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1575 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1577 // Go back and ensure we have no WebUI bindings.
1578 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1579 shell()->web_contents()->GetController().GoBack();
1580 back_nav_load_observer.Wait();
1581 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1582 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1583 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1586 // crbug.com/372360
1587 // The test loads url1, opens a link pointing to url2 in a new tab, and
1588 // navigates the new tab to url1.
1589 // The following is needed for the bug to happen:
1590 // - url1 must require webui bindings;
1591 // - navigating to url2 in the site instance of url1 should not swap
1592 // browsing instances, but should require a new site instance.
1593 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1594 GURL url1(std::string(kChromeUIScheme) + "://" +
1595 std::string(kChromeUIGpuHost));
1596 GURL url2(std::string(kChromeUIScheme) + "://" +
1597 std::string(kChromeUIAccessibilityHost));
1599 // Visit a WebUI page with bindings.
1600 NavigateToURL(shell(), url1);
1601 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1602 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1603 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1605 // Open a new tab. Initially it gets a render view in the original tab's
1606 // current site instance.
1607 TestNavigationObserver nav_observer(NULL);
1608 nav_observer.StartWatchingNewWebContents();
1609 ShellAddedObserver shao;
1610 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1611 nav_observer.Wait();
1612 Shell* new_shell = shao.GetShell();
1613 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1614 new_shell->web_contents());
1615 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1617 EXPECT_NE(site_instance2, site_instance1);
1618 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1619 RenderViewHost* initial_rvh = new_web_contents->
1620 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1621 ASSERT_TRUE(initial_rvh);
1622 // The following condition is what was causing the bug.
1623 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1625 // Navigate to url1 and check bindings.
1626 NavigateToURL(new_shell, url1);
1627 // The navigation should have used the first SiteInstance, otherwise
1628 // |initial_rvh| did not have a chance to be used.
1629 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1630 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1631 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1634 // crbug.com/424526
1635 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1636 // page and then to a regular page. The bug reproduces if blank page is visited
1637 // in between WebUI and regular page.
1638 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1639 ForceSwapAfterWebUIBindings) {
1640 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1641 switches::kProcessPerTab);
1642 ASSERT_TRUE(test_server()->Start());
1644 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1645 std::string(kChromeUIGpuHost));
1646 NavigateToURL(shell(), web_ui_url);
1647 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1648 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1650 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1652 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1653 NavigateToURL(shell(), regular_page_url);
1654 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1655 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1658 class FileChooserDelegate : public WebContentsDelegate {
1659 public:
1660 FileChooserDelegate(const base::FilePath& file)
1661 : file_(file), file_chosen_(false) {}
1663 void RunFileChooser(WebContents* web_contents,
1664 const FileChooserParams& params) override {
1665 // Send the selected file to the renderer process.
1666 FileChooserFileInfo file_info;
1667 file_info.file_path = file_;
1668 std::vector<FileChooserFileInfo> files;
1669 files.push_back(file_info);
1670 web_contents->GetRenderViewHost()->FilesSelectedInChooser(
1671 files, FileChooserParams::Open);
1673 file_chosen_ = true;
1676 bool file_chosen() { return file_chosen_; }
1678 private:
1679 base::FilePath file_;
1680 bool file_chosen_;
1683 // Test for http://crbug.com/262948.
1684 // Flaky on Mac. http://crbug.com/452018
1685 #if defined(OS_MACOSX)
1686 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1687 DISABLED_RestoreFileAccessForHistoryNavigation
1688 #else
1689 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1690 RestoreFileAccessForHistoryNavigation
1691 #endif
1692 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1693 MAYBE_RestoreFileAccessForHistoryNavigation) {
1694 StartServer();
1695 base::FilePath file;
1696 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1697 file = file.AppendASCII("bar");
1699 // Navigate to url and get it to reference a file in its PageState.
1700 GURL url1(test_server()->GetURL("files/file_input.html"));
1701 NavigateToURL(shell(), url1);
1702 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1703 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1704 shell()->web_contents()->SetDelegate(delegate.get());
1705 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1706 "document.getElementById('fileinput').click();"));
1707 EXPECT_TRUE(delegate->file_chosen());
1708 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1709 process_id, file));
1711 // Navigate to a different process without access to the file, and wait for
1712 // the old process to exit.
1713 RenderProcessHostWatcher exit_observer(
1714 shell()->web_contents()->GetRenderProcessHost(),
1715 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1716 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1717 exit_observer.Wait();
1718 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1719 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1721 // Ensure that the file ended up in the PageState of the previous entry.
1722 NavigationEntry* prev_entry =
1723 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1724 EXPECT_EQ(url1, prev_entry->GetURL());
1725 const std::vector<base::FilePath>& files =
1726 prev_entry->GetPageState().GetReferencedFiles();
1727 ASSERT_EQ(1U, files.size());
1728 EXPECT_EQ(file, files.at(0));
1730 // Go back, ending up in a different RenderProcessHost than before.
1731 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1732 shell()->web_contents()->GetController().GoBack();
1733 back_nav_load_observer.Wait();
1734 EXPECT_NE(process_id,
1735 shell()->web_contents()->GetRenderProcessHost()->GetID());
1737 // Ensure that the file access still exists in the new process ID.
1738 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1739 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1741 // Navigate to a same site page to trigger a PageState update and ensure the
1742 // renderer is not killed.
1743 EXPECT_TRUE(
1744 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1747 // Test for http://crbug.com/441966.
1748 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1749 RestoreSubframeFileAccessForHistoryNavigation) {
1750 StartServer();
1751 base::FilePath file;
1752 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1753 file = file.AppendASCII("bar");
1755 // Navigate to url and get it to reference a file in its PageState.
1756 GURL url1(test_server()->GetURL("files/file_input_subframe.html"));
1757 NavigateToURL(shell(), url1);
1758 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
1759 FrameTreeNode* root = wc->GetFrameTree()->root();
1760 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1761 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1762 shell()->web_contents()->SetDelegate(delegate.get());
1763 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1764 "document.getElementById('fileinput').click();"));
1765 EXPECT_TRUE(delegate->file_chosen());
1766 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1767 process_id, file));
1769 // Navigate to a different process without access to the file, and wait for
1770 // the old process to exit.
1771 RenderProcessHostWatcher exit_observer(
1772 shell()->web_contents()->GetRenderProcessHost(),
1773 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1774 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1775 exit_observer.Wait();
1776 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1777 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1779 // Ensure that the file ended up in the PageState of the previous entry.
1780 NavigationEntry* prev_entry =
1781 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1782 EXPECT_EQ(url1, prev_entry->GetURL());
1783 const std::vector<base::FilePath>& files =
1784 prev_entry->GetPageState().GetReferencedFiles();
1785 ASSERT_EQ(1U, files.size());
1786 EXPECT_EQ(file, files.at(0));
1788 // Go back, ending up in a different RenderProcessHost than before.
1789 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1790 shell()->web_contents()->GetController().GoBack();
1791 back_nav_load_observer.Wait();
1792 EXPECT_NE(process_id,
1793 shell()->web_contents()->GetRenderProcessHost()->GetID());
1795 // Ensure that the file access still exists in the new process ID.
1796 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1797 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1800 // This class implements waiting for RenderFrameHost destruction. It relies on
1801 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1802 // destroyed.
1803 // Note: RenderFrameDeleted is also fired when the process associated with the
1804 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1805 // is expected.
1806 class RenderFrameHostDestructionObserver : public WebContentsObserver {
1807 public:
1808 explicit RenderFrameHostDestructionObserver(RenderFrameHost* rfh)
1809 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
1810 message_loop_runner_(new MessageLoopRunner),
1811 deleted_(false),
1812 render_frame_host_(rfh) {}
1813 ~RenderFrameHostDestructionObserver() override {}
1815 void Wait() {
1816 if (deleted_)
1817 return;
1819 message_loop_runner_->Run();
1822 // WebContentsObserver implementation:
1823 void RenderFrameDeleted(RenderFrameHost* rfh) override {
1824 if (rfh == render_frame_host_) {
1825 CHECK(!deleted_);
1826 deleted_ = true;
1829 if (deleted_ && message_loop_runner_->loop_running()) {
1830 base::ThreadTaskRunnerHandle::Get()->PostTask(
1831 FROM_HERE, message_loop_runner_->QuitClosure());
1835 private:
1836 scoped_refptr<MessageLoopRunner> message_loop_runner_;
1837 bool deleted_;
1838 RenderFrameHost* render_frame_host_;
1841 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1842 // doing a simple cross-process navigation.
1843 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1844 CleanupOnCrossProcessNavigation) {
1845 StartEmbeddedServer();
1847 // Do an initial navigation and capture objects we expect to be cleaned up
1848 // on cross-process navigation.
1849 GURL start_url = embedded_test_server()->GetURL("/title1.html");
1850 NavigateToURL(shell(), start_url);
1852 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1853 ->GetFrameTree()
1854 ->root();
1855 int32 orig_site_instance_id =
1856 root->current_frame_host()->GetSiteInstance()->GetId();
1857 int initial_process_id =
1858 root->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1859 int initial_rfh_id = root->current_frame_host()->GetRoutingID();
1860 int initial_rvh_id =
1861 root->current_frame_host()->render_view_host()->GetRoutingID();
1863 // Navigate cross-process and ensure that cleanup is performed as expected.
1864 GURL cross_site_url =
1865 embedded_test_server()->GetURL("foo.com", "/title2.html");
1866 RenderFrameHostDestructionObserver rfh_observer(root->current_frame_host());
1867 NavigateToURL(shell(), cross_site_url);
1868 rfh_observer.Wait();
1870 EXPECT_NE(orig_site_instance_id,
1871 root->current_frame_host()->GetSiteInstance()->GetId());
1872 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id, initial_rfh_id));
1873 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id, initial_rvh_id));
1876 // Ensure that the opener chain proxies and RVHs are properly reinitialized if
1877 // a tab crashes and reloads. See https://crbug.com/505090.
1878 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1879 ReinitializeOpenerChainAfterCrashAndReload) {
1880 StartEmbeddedServer();
1882 GURL main_url = embedded_test_server()->GetURL("/title1.html");
1883 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1885 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1886 ->GetFrameTree()
1887 ->root();
1889 scoped_refptr<SiteInstance> orig_site_instance(
1890 shell()->web_contents()->GetSiteInstance());
1891 EXPECT_TRUE(orig_site_instance);
1893 // Open a popup and navigate it cross-site.
1894 Shell* new_shell =
1895 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
1896 EXPECT_TRUE(new_shell);
1897 FrameTreeNode* popup_root =
1898 static_cast<WebContentsImpl*>(new_shell->web_contents())
1899 ->GetFrameTree()
1900 ->root();
1902 GURL cross_site_url =
1903 embedded_test_server()->GetURL("foo.com", "/title2.html");
1904 EXPECT_TRUE(NavigateToURL(new_shell, cross_site_url));
1906 scoped_refptr<SiteInstance> foo_site_instance(
1907 new_shell->web_contents()->GetSiteInstance());
1908 EXPECT_NE(foo_site_instance, orig_site_instance);
1910 // Kill the popup's process.
1911 RenderProcessHost* popup_process =
1912 popup_root->current_frame_host()->GetProcess();
1913 RenderProcessHostWatcher crash_observer(
1914 popup_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1915 popup_process->Shutdown(0, false);
1916 crash_observer.Wait();
1917 EXPECT_FALSE(popup_root->current_frame_host()->IsRenderFrameLive());
1918 EXPECT_FALSE(
1919 popup_root->current_frame_host()->render_view_host()->IsRenderViewLive());
1921 // The swapped-out RVH and proxy for the opener page in the foo.com
1922 // SiteInstance should not be live.
1923 RenderFrameHostManager* opener_manager = root->render_manager();
1924 RenderViewHostImpl* opener_rvh =
1925 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get());
1926 EXPECT_TRUE(opener_rvh);
1927 EXPECT_FALSE(opener_rvh->IsRenderViewLive());
1928 RenderFrameProxyHost* opener_rfph =
1929 opener_manager->GetRenderFrameProxyHost(foo_site_instance.get());
1930 EXPECT_TRUE(opener_rfph);
1931 EXPECT_FALSE(opener_rfph->is_render_frame_proxy_live());
1933 // Re-navigate the popup to the same URL and check that this recreates the
1934 // opener's swapped out RVH and proxy in the foo.com SiteInstance.
1935 EXPECT_TRUE(NavigateToURL(new_shell, cross_site_url));
1936 EXPECT_TRUE(opener_rvh->IsRenderViewLive());
1937 EXPECT_TRUE(opener_rfph->is_render_frame_proxy_live());
1940 } // namespace content