Roll ANGLE e754fb8..6ffeb74
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blob60723022831d7dba7b5c9710c36ab19cf13da934
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/renderer_host/render_view_host_impl.h"
18 #include "content/browser/site_instance_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/browser/webui/web_ui_impl.h"
21 #include "content/common/content_constants_internal.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "content/public/common/bindings_policy.h"
28 #include "content/public/common/content_switches.h"
29 #include "content/public/common/file_chooser_file_info.h"
30 #include "content/public/common/file_chooser_params.h"
31 #include "content/public/common/page_state.h"
32 #include "content/public/common/url_constants.h"
33 #include "content/public/test/browser_test_utils.h"
34 #include "content/public/test/content_browser_test.h"
35 #include "content/public/test/content_browser_test_utils.h"
36 #include "content/public/test/test_navigation_observer.h"
37 #include "content/public/test/test_utils.h"
38 #include "content/shell/browser/shell.h"
39 #include "net/base/net_util.h"
40 #include "net/dns/mock_host_resolver.h"
41 #include "net/test/embedded_test_server/embedded_test_server.h"
42 #include "net/test/spawned_test_server/spawned_test_server.h"
44 using base::ASCIIToUTF16;
46 namespace content {
48 namespace {
50 const char kOpenUrlViaClickTargetFunc[] =
51 "(function(url) {\n"
52 " var lnk = document.createElement(\"a\");\n"
53 " lnk.href = url;\n"
54 " lnk.target = \"_blank\";\n"
55 " document.body.appendChild(lnk);\n"
56 " lnk.click();\n"
57 "})";
59 // Adds a link with given url and target=_blank, and clicks on it.
60 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter,
61 const GURL& url) {
62 EXPECT_TRUE(ExecuteScript(adapter,
63 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
66 } // anonymous namespace
68 class RenderFrameHostManagerTest : public ContentBrowserTest {
69 public:
70 RenderFrameHostManagerTest() : foo_com_("foo.com") {
71 replace_host_.SetHostStr(foo_com_);
74 static bool GetFilePathWithHostAndPortReplacement(
75 const std::string& original_file_path,
76 const net::HostPortPair& host_port_pair,
77 std::string* replacement_path) {
78 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
79 replacement_text.push_back(
80 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
81 return net::SpawnedTestServer::GetFilePathWithReplacements(
82 original_file_path, replacement_text, replacement_path);
85 void StartServer() {
86 // Support multiple sites on the test server.
87 host_resolver()->AddRule("*", "127.0.0.1");
88 ASSERT_TRUE(test_server()->Start());
90 foo_host_port_ = test_server()->host_port_pair();
91 foo_host_port_.set_host(foo_com_);
94 void StartEmbeddedServer() {
95 // Support multiple sites on the embedded test server.
96 host_resolver()->AddRule("*", "127.0.0.1");
97 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
98 SetupCrossSiteRedirector(embedded_test_server());
101 // Returns a URL on foo.com with the given path.
102 GURL GetCrossSiteURL(const std::string& path) {
103 GURL cross_site_url(test_server()->GetURL(path));
104 return cross_site_url.ReplaceComponents(replace_host_);
107 protected:
108 std::string foo_com_;
109 GURL::Replacements replace_host_;
110 net::HostPortPair foo_host_port_;
113 // Web pages should not have script access to the swapped out page.
114 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
115 StartServer();
117 // Load a page with links that open in a new window.
118 std::string replacement_path;
119 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
120 "files/click-noreferrer-links.html",
121 foo_host_port_,
122 &replacement_path));
123 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
125 // Get the original SiteInstance for later comparison.
126 scoped_refptr<SiteInstance> orig_site_instance(
127 shell()->web_contents()->GetSiteInstance());
128 EXPECT_TRUE(orig_site_instance.get() != NULL);
130 // Open a same-site link in a new window.
131 ShellAddedObserver new_shell_observer;
132 bool success = false;
133 EXPECT_TRUE(ExecuteScriptAndExtractBool(
134 shell()->web_contents(),
135 "window.domAutomationController.send(clickSameSiteTargetedLink());",
136 &success));
137 EXPECT_TRUE(success);
138 Shell* new_shell = new_shell_observer.GetShell();
140 // Wait for the navigation in the new window to finish, if it hasn't.
141 WaitForLoadStop(new_shell->web_contents());
142 EXPECT_EQ("/files/navigate_opener.html",
143 new_shell->web_contents()->GetLastCommittedURL().path());
145 // Should have the same SiteInstance.
146 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
148 // We should have access to the opened window's location.
149 success = false;
150 EXPECT_TRUE(ExecuteScriptAndExtractBool(
151 shell()->web_contents(),
152 "window.domAutomationController.send(testScriptAccessToWindow());",
153 &success));
154 EXPECT_TRUE(success);
156 // Now navigate the new window to a different site.
157 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
158 scoped_refptr<SiteInstance> new_site_instance(
159 new_shell->web_contents()->GetSiteInstance());
160 EXPECT_NE(orig_site_instance, new_site_instance);
162 // We should no longer have script access to the opened window's location.
163 success = false;
164 EXPECT_TRUE(ExecuteScriptAndExtractBool(
165 shell()->web_contents(),
166 "window.domAutomationController.send(testScriptAccessToWindow());",
167 &success));
168 EXPECT_FALSE(success);
170 // We now navigate the window to an about:blank page.
171 success = false;
172 EXPECT_TRUE(ExecuteScriptAndExtractBool(
173 shell()->web_contents(),
174 "window.domAutomationController.send(clickBlankTargetedLink());",
175 &success));
176 EXPECT_TRUE(success);
178 // Wait for the navigation in the new window to finish.
179 WaitForLoadStop(new_shell->web_contents());
180 GURL blank_url(url::kAboutBlankURL);
181 EXPECT_EQ(blank_url,
182 new_shell->web_contents()->GetLastCommittedURL());
183 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
185 // We should have access to the opened window's location.
186 success = false;
187 EXPECT_TRUE(ExecuteScriptAndExtractBool(
188 shell()->web_contents(),
189 "window.domAutomationController.send(testScriptAccessToWindow());",
190 &success));
191 EXPECT_TRUE(success);
194 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
195 // and target=_blank should create a new SiteInstance.
196 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
197 SwapProcessWithRelNoreferrerAndTargetBlank) {
198 StartServer();
200 // Load a page with links that open in a new window.
201 std::string replacement_path;
202 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
203 "files/click-noreferrer-links.html",
204 foo_host_port_,
205 &replacement_path));
206 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
208 // Get the original SiteInstance for later comparison.
209 scoped_refptr<SiteInstance> orig_site_instance(
210 shell()->web_contents()->GetSiteInstance());
211 EXPECT_TRUE(orig_site_instance.get() != NULL);
213 // Test clicking a rel=noreferrer + target=blank link.
214 ShellAddedObserver new_shell_observer;
215 bool success = false;
216 EXPECT_TRUE(ExecuteScriptAndExtractBool(
217 shell()->web_contents(),
218 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
219 &success));
220 EXPECT_TRUE(success);
222 // Wait for the window to open.
223 Shell* new_shell = new_shell_observer.GetShell();
225 EXPECT_EQ("/files/title2.html",
226 new_shell->web_contents()->GetVisibleURL().path());
228 // Wait for the cross-site transition in the new tab to finish.
229 WaitForLoadStop(new_shell->web_contents());
230 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
231 new_shell->web_contents());
232 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
233 pending_render_view_host());
235 // Should have a new SiteInstance.
236 scoped_refptr<SiteInstance> noref_blank_site_instance(
237 new_shell->web_contents()->GetSiteInstance());
238 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
241 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
242 // for rel=noreferrer links in new windows, even to same site pages and named
243 // targets.
244 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
245 SwapProcessWithSameSiteRelNoreferrer) {
246 StartServer();
248 // Load a page with links that open in a new window.
249 std::string replacement_path;
250 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
251 "files/click-noreferrer-links.html",
252 foo_host_port_,
253 &replacement_path));
254 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
256 // Get the original SiteInstance for later comparison.
257 scoped_refptr<SiteInstance> orig_site_instance(
258 shell()->web_contents()->GetSiteInstance());
259 EXPECT_TRUE(orig_site_instance.get() != NULL);
261 // Test clicking a same-site rel=noreferrer + target=foo link.
262 ShellAddedObserver new_shell_observer;
263 bool success = false;
264 EXPECT_TRUE(ExecuteScriptAndExtractBool(
265 shell()->web_contents(),
266 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
267 &success));
268 EXPECT_TRUE(success);
270 // Wait for the window to open.
271 Shell* new_shell = new_shell_observer.GetShell();
273 // Opens in new window.
274 EXPECT_EQ("/files/title2.html",
275 new_shell->web_contents()->GetVisibleURL().path());
277 // Wait for the cross-site transition in the new tab to finish.
278 WaitForLoadStop(new_shell->web_contents());
279 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
280 new_shell->web_contents());
281 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
282 pending_render_view_host());
284 // Should have a new SiteInstance (in a new BrowsingInstance).
285 scoped_refptr<SiteInstance> noref_blank_site_instance(
286 new_shell->web_contents()->GetSiteInstance());
287 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
290 // Test for crbug.com/24447. Following a cross-site link with just
291 // target=_blank should not create a new SiteInstance, unless we
292 // are running in --site-per-process mode.
293 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
294 DontSwapProcessWithOnlyTargetBlank) {
295 StartServer();
297 // Load a page with links that open in a new window.
298 std::string replacement_path;
299 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
300 "files/click-noreferrer-links.html",
301 foo_host_port_,
302 &replacement_path));
303 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path)));
305 // Get the original SiteInstance for later comparison.
306 scoped_refptr<SiteInstance> orig_site_instance(
307 shell()->web_contents()->GetSiteInstance());
308 EXPECT_TRUE(orig_site_instance.get() != NULL);
310 // Test clicking a target=blank link.
311 ShellAddedObserver new_shell_observer;
312 bool success = false;
313 EXPECT_TRUE(ExecuteScriptAndExtractBool(
314 shell()->web_contents(),
315 "window.domAutomationController.send(clickTargetBlankLink());",
316 &success));
317 EXPECT_TRUE(success);
319 // Wait for the window to open.
320 Shell* new_shell = new_shell_observer.GetShell();
322 // Wait for the cross-site transition in the new tab to finish.
323 EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
324 EXPECT_EQ("/files/title2.html",
325 new_shell->web_contents()->GetLastCommittedURL().path());
327 // Should have the same SiteInstance unless we're in site-per-process mode.
328 scoped_refptr<SiteInstance> blank_site_instance(
329 new_shell->web_contents()->GetSiteInstance());
330 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
331 switches::kSitePerProcess))
332 EXPECT_EQ(orig_site_instance, blank_site_instance);
333 else
334 EXPECT_NE(orig_site_instance, blank_site_instance);
337 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
338 // and no target=_blank should not create a new SiteInstance.
339 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
340 DontSwapProcessWithOnlyRelNoreferrer) {
341 StartServer();
343 // Load a page with links that open in a new window.
344 std::string replacement_path;
345 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
346 "files/click-noreferrer-links.html",
347 foo_host_port_,
348 &replacement_path));
349 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
351 // Get the original SiteInstance for later comparison.
352 scoped_refptr<SiteInstance> orig_site_instance(
353 shell()->web_contents()->GetSiteInstance());
354 EXPECT_TRUE(orig_site_instance.get() != NULL);
356 // Test clicking a rel=noreferrer link.
357 bool success = false;
358 EXPECT_TRUE(ExecuteScriptAndExtractBool(
359 shell()->web_contents(),
360 "window.domAutomationController.send(clickNoRefLink());",
361 &success));
362 EXPECT_TRUE(success);
364 // Wait for the cross-site transition in the current tab to finish.
365 WaitForLoadStop(shell()->web_contents());
367 // Opens in same window.
368 EXPECT_EQ(1u, Shell::windows().size());
369 EXPECT_EQ("/files/title2.html",
370 shell()->web_contents()->GetLastCommittedURL().path());
372 // Should have the same SiteInstance unless we're in site-per-process mode.
373 scoped_refptr<SiteInstance> noref_site_instance(
374 shell()->web_contents()->GetSiteInstance());
375 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
376 switches::kSitePerProcess))
377 EXPECT_EQ(orig_site_instance, noref_site_instance);
378 else
379 EXPECT_NE(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 // Now disown the frame's opener. Shouldn't crash.
548 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
549 "window.frames[0].opener = null;"));
552 // Test for crbug.com/99202. PostMessage calls should still work after
553 // navigating the source and target windows to different sites.
554 // Specifically:
555 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
556 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
557 // 3) Post a message from "foo" to opener, which replies back to "foo".
558 // 4) Post a message from _blank to "foo".
559 // 5) Post a message from "foo" to a subframe of opener, which replies back.
560 // 6) Post a message from _blank to a subframe of "foo".
561 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
562 SupportCrossProcessPostMessage) {
563 StartServer();
565 // Load a page with links that open in a new window.
566 std::string replacement_path;
567 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
568 "files/click-noreferrer-links.html",
569 foo_host_port_,
570 &replacement_path));
571 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
573 // Get the original SiteInstance and RVHM for later comparison.
574 WebContents* opener_contents = shell()->web_contents();
575 scoped_refptr<SiteInstance> orig_site_instance(
576 opener_contents->GetSiteInstance());
577 EXPECT_TRUE(orig_site_instance.get() != NULL);
578 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
579 opener_contents)->GetRenderManagerForTesting();
581 // 1) Open two more windows, one named. These initially have openers but no
582 // reference to each other. We will later post a message between them.
584 // First, a named target=foo window.
585 ShellAddedObserver new_shell_observer;
586 bool success = false;
587 EXPECT_TRUE(ExecuteScriptAndExtractBool(
588 opener_contents,
589 "window.domAutomationController.send(clickSameSiteTargetedLink());",
590 &success));
591 EXPECT_TRUE(success);
592 Shell* new_shell = new_shell_observer.GetShell();
594 // Wait for the navigation in the new window to finish, if it hasn't, then
595 // send it to post_message.html on a different site.
596 WebContents* foo_contents = new_shell->web_contents();
597 WaitForLoadStop(foo_contents);
598 EXPECT_EQ("/files/navigate_opener.html",
599 foo_contents->GetLastCommittedURL().path());
600 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
601 scoped_refptr<SiteInstance> foo_site_instance(
602 foo_contents->GetSiteInstance());
603 EXPECT_NE(orig_site_instance, foo_site_instance);
605 // Second, a target=_blank window.
606 ShellAddedObserver new_shell_observer2;
607 EXPECT_TRUE(ExecuteScriptAndExtractBool(
608 shell()->web_contents(),
609 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
610 &success));
611 EXPECT_TRUE(success);
613 // Wait for the navigation in the new window to finish, if it hasn't, then
614 // send it to post_message.html on the original site.
615 Shell* new_shell2 = new_shell_observer2.GetShell();
616 WebContents* new_contents = new_shell2->web_contents();
617 WaitForLoadStop(new_contents);
618 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
619 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
620 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
621 RenderFrameHostManager* new_manager =
622 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
624 // We now have three windows. The opener should have a swapped out RVH
625 // for the new SiteInstance, but the _blank window should not.
626 EXPECT_EQ(3u, Shell::windows().size());
627 EXPECT_TRUE(
628 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
629 EXPECT_FALSE(
630 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
632 // 2) Fail to post a message from the foo window to the opener if the target
633 // origin is wrong. We won't see an error, but we can check for the right
634 // number of received messages below.
635 EXPECT_TRUE(ExecuteScriptAndExtractBool(
636 foo_contents,
637 "window.domAutomationController.send(postToOpener('msg',"
638 " 'http://google.com'));",
639 &success));
640 EXPECT_TRUE(success);
641 ASSERT_FALSE(
642 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
644 // 3) Post a message from the foo window to the opener. The opener will
645 // reply, causing the foo window to update its own title.
646 base::string16 expected_title = ASCIIToUTF16("msg");
647 TitleWatcher title_watcher(foo_contents, expected_title);
648 EXPECT_TRUE(ExecuteScriptAndExtractBool(
649 foo_contents,
650 "window.domAutomationController.send(postToOpener('msg','*'));",
651 &success));
652 EXPECT_TRUE(success);
653 ASSERT_FALSE(
654 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
655 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
657 // We should have received only 1 message in the opener and "foo" tabs,
658 // and updated the title.
659 int opener_received_messages = 0;
660 EXPECT_TRUE(ExecuteScriptAndExtractInt(
661 opener_contents,
662 "window.domAutomationController.send(window.receivedMessages);",
663 &opener_received_messages));
664 int foo_received_messages = 0;
665 EXPECT_TRUE(ExecuteScriptAndExtractInt(
666 foo_contents,
667 "window.domAutomationController.send(window.receivedMessages);",
668 &foo_received_messages));
669 EXPECT_EQ(1, foo_received_messages);
670 EXPECT_EQ(1, opener_received_messages);
671 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
673 // 4) Now post a message from the _blank window to the foo window. The
674 // foo window will update its title and will not reply.
675 expected_title = ASCIIToUTF16("msg2");
676 TitleWatcher title_watcher2(foo_contents, expected_title);
677 EXPECT_TRUE(ExecuteScriptAndExtractBool(
678 new_contents,
679 "window.domAutomationController.send(postToFoo('msg2'));",
680 &success));
681 EXPECT_TRUE(success);
682 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
684 // This postMessage should have created a swapped out RVH for the new
685 // SiteInstance in the target=_blank window.
686 EXPECT_TRUE(
687 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
689 // TODO(nasko): Test subframe targeting of postMessage once
690 // http://crbug.com/153701 is fixed.
693 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
694 // messages which contain Transferables and get intercepted by
695 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
696 // swapped out) should work.
697 // Specifically:
698 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
699 // 2) Post a message containing a message port from opener to "foo".
700 // 3) Post a message from "foo" back to opener via the passed message port.
701 // The test will be enabled when the feature implementation lands.
702 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
703 SupportCrossProcessPostMessageWithMessagePort) {
704 StartServer();
706 // Load a page with links that open in a new window.
707 std::string replacement_path;
708 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
709 "files/click-noreferrer-links.html",
710 foo_host_port_,
711 &replacement_path));
712 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
714 // Get the original SiteInstance and RVHM for later comparison.
715 WebContents* opener_contents = shell()->web_contents();
716 scoped_refptr<SiteInstance> orig_site_instance(
717 opener_contents->GetSiteInstance());
718 EXPECT_TRUE(orig_site_instance.get() != NULL);
719 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
720 opener_contents)->GetRenderManagerForTesting();
722 // 1) Open a named target=foo window. We will later post a message between the
723 // opener and the new window.
724 ShellAddedObserver new_shell_observer;
725 bool success = false;
726 EXPECT_TRUE(ExecuteScriptAndExtractBool(
727 opener_contents,
728 "window.domAutomationController.send(clickSameSiteTargetedLink());",
729 &success));
730 EXPECT_TRUE(success);
731 Shell* new_shell = new_shell_observer.GetShell();
733 // Wait for the navigation in the new window to finish, if it hasn't, then
734 // send it to post_message.html on a different site.
735 WebContents* foo_contents = new_shell->web_contents();
736 WaitForLoadStop(foo_contents);
737 EXPECT_EQ("/files/navigate_opener.html",
738 foo_contents->GetLastCommittedURL().path());
739 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
740 scoped_refptr<SiteInstance> foo_site_instance(
741 foo_contents->GetSiteInstance());
742 EXPECT_NE(orig_site_instance, foo_site_instance);
744 // We now have two windows. The opener should have a swapped out RVH
745 // for the new SiteInstance.
746 EXPECT_EQ(2u, Shell::windows().size());
747 EXPECT_TRUE(
748 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
750 // 2) Post a message containing a MessagePort from opener to the the foo
751 // window. The foo window will reply via the passed port, causing the opener
752 // to update its own title.
753 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
754 TitleWatcher title_observer(opener_contents, expected_title);
755 EXPECT_TRUE(ExecuteScriptAndExtractBool(
756 opener_contents,
757 "window.domAutomationController.send(postWithPortToFoo());",
758 &success));
759 EXPECT_TRUE(success);
760 ASSERT_FALSE(
761 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
762 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
764 // Check message counts.
765 int opener_received_messages_via_port = 0;
766 EXPECT_TRUE(ExecuteScriptAndExtractInt(
767 opener_contents,
768 "window.domAutomationController.send(window.receivedMessagesViaPort);",
769 &opener_received_messages_via_port));
770 int foo_received_messages = 0;
771 EXPECT_TRUE(ExecuteScriptAndExtractInt(
772 foo_contents,
773 "window.domAutomationController.send(window.receivedMessages);",
774 &foo_received_messages));
775 int foo_received_messages_with_port = 0;
776 EXPECT_TRUE(ExecuteScriptAndExtractInt(
777 foo_contents,
778 "window.domAutomationController.send(window.receivedMessagesWithPort);",
779 &foo_received_messages_with_port));
780 EXPECT_EQ(1, foo_received_messages);
781 EXPECT_EQ(1, foo_received_messages_with_port);
782 EXPECT_EQ(1, opener_received_messages_via_port);
783 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
784 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
787 // Test for crbug.com/116192. Navigations to a window's opener should
788 // still work after a process swap.
789 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
790 AllowTargetedNavigationsInOpenerAfterSwap) {
791 StartServer();
793 // Load a page with links that open in a new window.
794 std::string replacement_path;
795 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
796 "files/click-noreferrer-links.html",
797 foo_host_port_,
798 &replacement_path));
799 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
801 // Get the original tab and SiteInstance for later comparison.
802 WebContents* orig_contents = shell()->web_contents();
803 scoped_refptr<SiteInstance> orig_site_instance(
804 orig_contents->GetSiteInstance());
805 EXPECT_TRUE(orig_site_instance.get() != NULL);
807 // Test clicking a target=foo link.
808 ShellAddedObserver new_shell_observer;
809 bool success = false;
810 EXPECT_TRUE(ExecuteScriptAndExtractBool(
811 orig_contents,
812 "window.domAutomationController.send(clickSameSiteTargetedLink());",
813 &success));
814 EXPECT_TRUE(success);
815 Shell* new_shell = new_shell_observer.GetShell();
817 // Wait for the navigation in the new window to finish, if it hasn't.
818 WaitForLoadStop(new_shell->web_contents());
819 EXPECT_EQ("/files/navigate_opener.html",
820 new_shell->web_contents()->GetLastCommittedURL().path());
822 // Should have the same SiteInstance.
823 scoped_refptr<SiteInstance> blank_site_instance(
824 new_shell->web_contents()->GetSiteInstance());
825 EXPECT_EQ(orig_site_instance, blank_site_instance);
827 // Now navigate the original (opener) tab to a different site.
828 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
829 scoped_refptr<SiteInstance> new_site_instance(
830 shell()->web_contents()->GetSiteInstance());
831 EXPECT_NE(orig_site_instance, new_site_instance);
833 // The opened tab should be able to navigate the opener back to its process.
834 TestNavigationObserver navigation_observer(orig_contents);
835 EXPECT_TRUE(ExecuteScriptAndExtractBool(
836 new_shell->web_contents(),
837 "window.domAutomationController.send(navigateOpener());",
838 &success));
839 EXPECT_TRUE(success);
840 navigation_observer.Wait();
842 // Should have swapped back into this process.
843 scoped_refptr<SiteInstance> revisit_site_instance(
844 shell()->web_contents()->GetSiteInstance());
845 EXPECT_EQ(orig_site_instance, revisit_site_instance);
848 // Test that subframes do not crash when sending a postMessage to the top frame
849 // from an unload handler while the top frame is being swapped out as part of
850 // navigating cross-process. https://crbug.com/475651.
851 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
852 PostMessageFromSubframeUnloadHandler) {
853 StartServer();
855 GURL frame_url(test_server()->GetURL("files/post_message.html"));
856 GURL main_url("data:text/html,<iframe name='foo' src='" + frame_url.spec() +
857 "'></iframe>");
858 EXPECT_TRUE(NavigateToURL(shell(), main_url));
860 // Get the original SiteInstance for later comparison.
861 scoped_refptr<SiteInstance> orig_site_instance(
862 shell()->web_contents()->GetSiteInstance());
863 EXPECT_NE(nullptr, orig_site_instance.get());
865 // It is safe to obtain the root frame tree node here, as it doesn't change.
866 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
867 ->GetFrameTree()
868 ->root();
869 ASSERT_EQ(1U, root->child_count());
870 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
872 // Register an unload handler that sends a postMessage to the top frame.
873 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
874 "registerUnload();"));
876 // Navigate the top frame cross-site. This will cause the top frame to be
877 // swapped out and run unload handlers, and the original renderer process
878 // should then terminate since it's not rendering any other frames.
879 RenderProcessHostWatcher exit_observer(
880 root->current_frame_host()->GetProcess(),
881 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
882 EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")));
883 scoped_refptr<SiteInstance> new_site_instance(
884 shell()->web_contents()->GetSiteInstance());
885 EXPECT_NE(orig_site_instance, new_site_instance);
887 // Ensure that the original renderer process exited cleanly without crashing.
888 exit_observer.Wait();
889 EXPECT_EQ(true, exit_observer.did_exit_normally());
892 // Test that opening a new window in the same SiteInstance and then navigating
893 // both windows to a different SiteInstance allows the first process to exit.
894 // See http://crbug.com/126333.
895 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
896 ProcessExitWithSwappedOutViews) {
897 StartServer();
899 // Load a page with links that open in a new window.
900 std::string replacement_path;
901 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
902 "files/click-noreferrer-links.html",
903 foo_host_port_,
904 &replacement_path));
905 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
907 // Get the original SiteInstance for later comparison.
908 scoped_refptr<SiteInstance> orig_site_instance(
909 shell()->web_contents()->GetSiteInstance());
910 EXPECT_TRUE(orig_site_instance.get() != NULL);
912 // Test clicking a target=foo link.
913 ShellAddedObserver new_shell_observer;
914 bool success = false;
915 EXPECT_TRUE(ExecuteScriptAndExtractBool(
916 shell()->web_contents(),
917 "window.domAutomationController.send(clickSameSiteTargetedLink());",
918 &success));
919 EXPECT_TRUE(success);
920 Shell* new_shell = new_shell_observer.GetShell();
922 // Wait for the navigation in the new window to finish, if it hasn't.
923 WaitForLoadStop(new_shell->web_contents());
924 EXPECT_EQ("/files/navigate_opener.html",
925 new_shell->web_contents()->GetLastCommittedURL().path());
927 // Should have the same SiteInstance.
928 scoped_refptr<SiteInstance> opened_site_instance(
929 new_shell->web_contents()->GetSiteInstance());
930 EXPECT_EQ(orig_site_instance, opened_site_instance);
932 // Now navigate the opened window to a different site.
933 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
934 scoped_refptr<SiteInstance> new_site_instance(
935 new_shell->web_contents()->GetSiteInstance());
936 EXPECT_NE(orig_site_instance, new_site_instance);
938 // The original process should still be alive, since it is still used in the
939 // first window.
940 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
941 EXPECT_TRUE(orig_process->HasConnection());
943 // Navigate the first window to a different site as well. The original
944 // process should exit, since all of its views are now swapped out.
945 RenderProcessHostWatcher exit_observer(
946 orig_process,
947 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
948 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
949 exit_observer.Wait();
950 scoped_refptr<SiteInstance> new_site_instance2(
951 shell()->web_contents()->GetSiteInstance());
952 EXPECT_EQ(new_site_instance, new_site_instance2);
955 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
956 // error should not make us ignore future renderer-initiated navigations.
957 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
958 StartServer();
960 // Get the original SiteInstance for later comparison.
961 scoped_refptr<SiteInstance> orig_site_instance(
962 shell()->web_contents()->GetSiteInstance());
963 EXPECT_TRUE(orig_site_instance.get() != NULL);
965 // Load a cross-site page that fails with a 204 error.
966 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
967 GetCrossSiteURL("nocontent")));
969 // We should still be looking at the normal page. Because we started from a
970 // blank new tab, the typed URL will still be visible until the user clears it
971 // manually. The last committed URL will be the previous page.
972 scoped_refptr<SiteInstance> post_nav_site_instance(
973 shell()->web_contents()->GetSiteInstance());
974 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
975 EXPECT_EQ("/nocontent",
976 shell()->web_contents()->GetVisibleURL().path());
977 EXPECT_FALSE(
978 shell()->web_contents()->GetController().GetLastCommittedEntry());
980 // Renderer-initiated navigations should work.
981 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
982 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
983 GURL url = test_server()->GetURL("files/title2.html");
984 EXPECT_TRUE(ExecuteScript(
985 shell()->web_contents(),
986 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
987 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
989 // Opens in same tab.
990 EXPECT_EQ(1u, Shell::windows().size());
991 EXPECT_EQ("/files/title2.html",
992 shell()->web_contents()->GetLastCommittedURL().path());
994 // Should have the same SiteInstance.
995 scoped_refptr<SiteInstance> new_site_instance(
996 shell()->web_contents()->GetSiteInstance());
997 EXPECT_EQ(orig_site_instance, new_site_instance);
1000 // Test for crbug.com/9682. We should show the URL for a pending renderer-
1001 // initiated navigation in a new tab, until the content of the initial
1002 // about:blank page is modified by another window. At that point, we should
1003 // revert to showing about:blank to prevent a URL spoof.
1004 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
1005 ASSERT_TRUE(test_server()->Start());
1007 // Load a page that can open a URL that won't commit in a new window.
1008 NavigateToURL(
1009 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1010 WebContents* orig_contents = shell()->web_contents();
1012 // Click a /nocontent link that opens in a new window but never commits.
1013 ShellAddedObserver new_shell_observer;
1014 bool success = false;
1015 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1016 orig_contents,
1017 "window.domAutomationController.send(clickNoContentTargetedLink());",
1018 &success));
1019 EXPECT_TRUE(success);
1021 // Wait for the window to open.
1022 Shell* new_shell = new_shell_observer.GetShell();
1024 // Ensure the destination URL is visible, because it is considered the
1025 // initial navigation.
1026 WebContents* contents = new_shell->web_contents();
1027 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
1028 EXPECT_EQ("/nocontent",
1029 contents->GetController().GetVisibleEntry()->GetURL().path());
1031 // Now modify the contents of the new window from the opener. This will also
1032 // modify the title of the document to give us something to listen for.
1033 base::string16 expected_title = ASCIIToUTF16("Modified Title");
1034 TitleWatcher title_watcher(contents, expected_title);
1035 success = false;
1036 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1037 orig_contents,
1038 "window.domAutomationController.send(modifyNewWindow());",
1039 &success));
1040 EXPECT_TRUE(success);
1041 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1043 // At this point, we should no longer be showing the destination URL.
1044 // The visible entry should be null, resulting in about:blank in the address
1045 // bar.
1046 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1049 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
1050 // initiated navigation in a new tab if it is not the initial navigation. In
1051 // this case, the renderer will not notify us of a modification, so we cannot
1052 // show the pending URL without allowing a spoof.
1053 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1054 DontShowLoadingURLIfNotInitialNav) {
1055 ASSERT_TRUE(test_server()->Start());
1057 // Load a page that can open a URL that won't commit in a new window.
1058 NavigateToURL(
1059 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1060 WebContents* orig_contents = shell()->web_contents();
1062 // Click a /nocontent link that opens in a new window but never commits.
1063 // By using an onclick handler that first creates the window, the slow
1064 // navigation is not considered an initial navigation.
1065 ShellAddedObserver new_shell_observer;
1066 bool success = false;
1067 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1068 orig_contents,
1069 "window.domAutomationController.send("
1070 "clickNoContentScriptedTargetedLink());",
1071 &success));
1072 EXPECT_TRUE(success);
1074 // Wait for the window to open.
1075 Shell* new_shell = new_shell_observer.GetShell();
1077 // Ensure the destination URL is not visible, because it is not the initial
1078 // navigation.
1079 WebContents* contents = new_shell->web_contents();
1080 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1081 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1084 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1085 #if defined(THREAD_SANITIZER)
1086 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1087 #else
1088 #define MAYBE_BackForwardNotStale BackForwardNotStale
1089 #endif
1090 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1091 // do not cause back/forward navigations to be considered stale by the
1092 // renderer.
1093 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1094 StartServer();
1095 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1097 // Visit a page on first site.
1098 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1100 // Visit three pages on second site.
1101 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1102 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1103 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1105 // History is now [blank, A1, B1, B2, *B3].
1106 WebContents* contents = shell()->web_contents();
1107 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1109 // Open another window in same process to keep this process alive.
1110 Shell* new_shell = CreateBrowser();
1111 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1113 // Go back three times to first site.
1115 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1116 shell()->web_contents()->GetController().GoBack();
1117 back_nav_load_observer.Wait();
1120 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1121 shell()->web_contents()->GetController().GoBack();
1122 back_nav_load_observer.Wait();
1125 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1126 shell()->web_contents()->GetController().GoBack();
1127 back_nav_load_observer.Wait();
1130 // Now go forward twice to B2. Shouldn't be left spinning.
1132 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1133 shell()->web_contents()->GetController().GoForward();
1134 forward_nav_load_observer.Wait();
1137 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1138 shell()->web_contents()->GetController().GoForward();
1139 forward_nav_load_observer.Wait();
1142 // Go back twice to first site.
1144 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1145 shell()->web_contents()->GetController().GoBack();
1146 back_nav_load_observer.Wait();
1149 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1150 shell()->web_contents()->GetController().GoBack();
1151 back_nav_load_observer.Wait();
1154 // Now go forward directly to B3. Shouldn't be left spinning.
1156 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1157 shell()->web_contents()->GetController().GoToIndex(4);
1158 forward_nav_load_observer.Wait();
1162 // Test for http://crbug.com/130016.
1163 // Swapping out a render view should update its visiblity state.
1164 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1165 SwappedOutViewHasCorrectVisibilityState) {
1166 // This test is invalid in --site-per-process mode, as swapped-out is no
1167 // longer used.
1168 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1169 switches::kSitePerProcess)) {
1170 return;
1172 StartServer();
1174 // Load a page with links that open in a new window.
1175 std::string replacement_path;
1176 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1177 "files/click-noreferrer-links.html",
1178 foo_host_port_,
1179 &replacement_path));
1180 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1182 // Open a same-site link in a new widnow.
1183 ShellAddedObserver new_shell_observer;
1184 bool success = false;
1185 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1186 shell()->web_contents(),
1187 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1188 &success));
1189 EXPECT_TRUE(success);
1190 Shell* new_shell = new_shell_observer.GetShell();
1192 // Wait for the navigation in the new tab to finish, if it hasn't.
1193 WaitForLoadStop(new_shell->web_contents());
1194 EXPECT_EQ("/files/navigate_opener.html",
1195 new_shell->web_contents()->GetLastCommittedURL().path());
1197 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1199 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1200 rvh,
1201 "window.domAutomationController.send("
1202 " document.visibilityState == 'visible');",
1203 &success));
1204 EXPECT_TRUE(success);
1206 // Now navigate the new window to a different site. This should swap out the
1207 // tab's existing RenderView, causing it become hidden.
1208 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1210 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1211 rvh,
1212 "window.domAutomationController.send("
1213 " document.visibilityState == 'hidden');",
1214 &success));
1215 EXPECT_TRUE(success);
1217 // Going back should make the previously swapped-out view to become visible
1218 // again.
1220 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1221 new_shell->web_contents()->GetController().GoBack();
1222 back_nav_load_observer.Wait();
1225 EXPECT_EQ("/files/navigate_opener.html",
1226 new_shell->web_contents()->GetLastCommittedURL().path());
1228 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1230 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1231 rvh,
1232 "window.domAutomationController.send("
1233 " document.visibilityState == 'visible');",
1234 &success));
1235 EXPECT_TRUE(success);
1238 // This class ensures that all the given RenderViewHosts have properly been
1239 // shutdown.
1240 class RenderViewHostDestructionObserver : public WebContentsObserver {
1241 public:
1242 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1243 : WebContentsObserver(web_contents) {}
1244 ~RenderViewHostDestructionObserver() override {}
1245 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1246 watched_render_view_hosts_.insert(rvh);
1248 size_t GetNumberOfWatchedRenderViewHosts() const {
1249 return watched_render_view_hosts_.size();
1252 private:
1253 // WebContentsObserver implementation:
1254 void RenderViewDeleted(RenderViewHost* rvh) override {
1255 watched_render_view_hosts_.erase(rvh);
1258 std::set<RenderViewHost*> watched_render_view_hosts_;
1261 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1262 #if defined(THREAD_SANITIZER)
1263 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1264 #else
1265 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1266 #endif
1267 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1268 // they may cause crashes or memory corruptions when trying to call dead
1269 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1270 // ensure that a separate SiteInstance is created when navigating to view-source
1271 // URLs, regardless of current URL.
1272 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1273 MAYBE_LeakingRenderViewHosts) {
1274 StartServer();
1276 // Observe the created render_view_host's to make sure they will not leak.
1277 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1279 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1280 GURL view_source_url(kViewSourceScheme + std::string(":") +
1281 navigated_url.spec());
1283 // Let's ensure that when we start with a blank window, navigating away to a
1284 // view-source URL, we create a new SiteInstance.
1285 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1286 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1287 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1288 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1289 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1291 // Now navigate to the view-source URL and ensure we got a different
1292 // SiteInstance and RenderViewHost.
1293 NavigateToURL(shell(), view_source_url);
1294 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1295 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1296 GetRenderViewHost()->GetSiteInstance());
1297 rvh_observers.EnsureRVHGetsDestructed(
1298 shell()->web_contents()->GetRenderViewHost());
1300 // Load a random page and then navigate to view-source: of it.
1301 // This used to cause two RVH instances for the same SiteInstance, which
1302 // was a problem. This is no longer the case.
1303 NavigateToURL(shell(), navigated_url);
1304 SiteInstance* site_instance1 = shell()->web_contents()->
1305 GetRenderViewHost()->GetSiteInstance();
1306 rvh_observers.EnsureRVHGetsDestructed(
1307 shell()->web_contents()->GetRenderViewHost());
1309 NavigateToURL(shell(), view_source_url);
1310 rvh_observers.EnsureRVHGetsDestructed(
1311 shell()->web_contents()->GetRenderViewHost());
1312 SiteInstance* site_instance2 = shell()->web_contents()->
1313 GetRenderViewHost()->GetSiteInstance();
1315 // Ensure that view-source navigations force a new SiteInstance.
1316 EXPECT_NE(site_instance1, site_instance2);
1318 // Now navigate to a different instance so that we swap out again.
1319 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1320 rvh_observers.EnsureRVHGetsDestructed(
1321 shell()->web_contents()->GetRenderViewHost());
1323 // This used to leak a render view host.
1324 shell()->Close();
1326 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1328 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1331 // Test for crbug.com/143155. Frame tree updates during unload should not
1332 // interrupt the intended navigation and show swappedout:// instead.
1333 // Specifically:
1334 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1335 // 2) Send the second tab to a different foo.com SiteInstance.
1336 // This creates a swapped out opener for the first tab in the foo process.
1337 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1338 // tab's unload handler remove its frame.
1339 // This used to cause an update to the frame tree of the swapped out RV,
1340 // just as it was navigating to a real page. That pre-empted the real
1341 // navigation and visibly sent the tab to swappedout://.
1342 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1343 DontPreemptNavigationWithFrameTreeUpdate) {
1344 StartServer();
1346 // 1. Load a page that deletes its iframe during unload.
1347 NavigateToURL(shell(),
1348 test_server()->GetURL("files/remove_frame_on_unload.html"));
1350 // Get the original SiteInstance for later comparison.
1351 scoped_refptr<SiteInstance> orig_site_instance(
1352 shell()->web_contents()->GetSiteInstance());
1354 // Open a same-site page in a new window.
1355 ShellAddedObserver new_shell_observer;
1356 bool success = false;
1357 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1358 shell()->web_contents(),
1359 "window.domAutomationController.send(openWindow());",
1360 &success));
1361 EXPECT_TRUE(success);
1362 Shell* new_shell = new_shell_observer.GetShell();
1364 // Wait for the navigation in the new window to finish, if it hasn't.
1365 WaitForLoadStop(new_shell->web_contents());
1366 EXPECT_EQ("/files/title1.html",
1367 new_shell->web_contents()->GetLastCommittedURL().path());
1369 // Should have the same SiteInstance.
1370 EXPECT_EQ(orig_site_instance.get(),
1371 new_shell->web_contents()->GetSiteInstance());
1373 // 2. Send the second tab to a different process.
1374 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1375 scoped_refptr<SiteInstance> new_site_instance(
1376 new_shell->web_contents()->GetSiteInstance());
1377 EXPECT_NE(orig_site_instance, new_site_instance);
1379 // 3. Send the first tab to the second tab's process.
1380 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1382 // Make sure it ends up at the right page.
1383 WaitForLoadStop(shell()->web_contents());
1384 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1385 shell()->web_contents()->GetLastCommittedURL());
1386 EXPECT_EQ(new_site_instance.get(),
1387 shell()->web_contents()->GetSiteInstance());
1390 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1391 // are meant to run in the current page. We had a bug where we expected a
1392 // BrowsingInstance swap to occur on pages like view-source and extensions,
1393 // which broke chrome://crash and javascript: URLs.
1394 // See http://crbug.com/335503.
1395 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1396 ASSERT_TRUE(test_server()->Start());
1398 GURL original_url(test_server()->GetURL("files/title2.html"));
1399 GURL view_source_url(kViewSourceScheme + std::string(":") +
1400 original_url.spec());
1402 NavigateToURL(shell(), view_source_url);
1404 // Check that javascript: URLs work.
1405 base::string16 expected_title = ASCIIToUTF16("msg");
1406 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1407 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1408 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1410 // Crash the renderer of the view-source page.
1411 RenderProcessHostWatcher crash_observer(
1412 shell()->web_contents(),
1413 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1414 EXPECT_TRUE(
1415 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1416 crash_observer.Wait();
1419 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1420 // Otherwise, we might try to load an unprivileged about:blank page into a
1421 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1422 // See http://crbug.com/334214.
1423 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1424 IgnoreRendererDebugURLsWhenCrashed) {
1425 // Visit a WebUI page with bindings.
1426 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1427 std::string(kChromeUIGpuHost));
1428 NavigateToURL(shell(), webui_url);
1429 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1430 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1432 // Crash the renderer of the WebUI page.
1433 RenderProcessHostWatcher crash_observer(
1434 shell()->web_contents(),
1435 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1436 EXPECT_TRUE(
1437 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1438 crash_observer.Wait();
1440 // Load the crash URL again but don't wait for any action. If it is not
1441 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1442 shell()->LoadURL(GURL(kChromeUICrashURL));
1444 // Ensure that such URLs can still work as the initial navigation of a tab.
1445 // We postpone the initial navigation of the tab using an empty GURL, so that
1446 // we can add a watcher for crashes.
1447 Shell* shell2 = Shell::CreateNewWindow(
1448 shell()->web_contents()->GetBrowserContext(), GURL(), NULL, gfx::Size());
1449 RenderProcessHostWatcher crash_observer2(
1450 shell2->web_contents(),
1451 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1452 EXPECT_TRUE(
1453 NavigateToURLAndExpectNoCommit(shell2, GURL(kChromeUIKillURL)));
1454 crash_observer2.Wait();
1457 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1458 // See http://crbug.com/428329.
1459 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1460 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1461 #else
1462 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1463 #endif
1464 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1465 // Otherwise it might get picked up by InitRenderView when granting bindings
1466 // to other RenderViewHosts. See http://crbug.com/330811.
1467 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1468 MAYBE_ClearPendingWebUIOnCommit) {
1469 // Visit a WebUI page with bindings.
1470 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1471 std::string(kChromeUIGpuHost)));
1472 NavigateToURL(shell(), webui_url);
1473 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1474 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1475 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1476 shell()->web_contents());
1477 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1478 EXPECT_TRUE(webui);
1479 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1481 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1482 // clear pending_web_ui() when it commits.
1483 GURL webui_url2(webui_url.spec() + "#foo");
1484 NavigateToURL(shell(), webui_url2);
1485 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1486 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1489 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1490 public:
1491 RFHMProcessPerTabTest() {}
1493 void SetUpCommandLine(base::CommandLine* command_line) override {
1494 command_line->AppendSwitch(switches::kProcessPerTab);
1498 // Test that we still swap processes for BrowsingInstance changes even in
1499 // --process-per-tab mode. See http://crbug.com/343017.
1500 // Disabled on Android: http://crbug.com/345873.
1501 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1502 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1503 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1504 #else
1505 #define MAYBE_BackFromWebUI BackFromWebUI
1506 #endif
1507 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1508 ASSERT_TRUE(test_server()->Start());
1509 GURL original_url(test_server()->GetURL("files/title2.html"));
1510 NavigateToURL(shell(), original_url);
1512 // Visit a WebUI page with bindings.
1513 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1514 std::string(kChromeUIGpuHost)));
1515 NavigateToURL(shell(), webui_url);
1516 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1517 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1519 // Go back and ensure we have no WebUI bindings.
1520 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1521 shell()->web_contents()->GetController().GoBack();
1522 back_nav_load_observer.Wait();
1523 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1524 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1525 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1528 // crbug.com/372360
1529 // The test loads url1, opens a link pointing to url2 in a new tab, and
1530 // navigates the new tab to url1.
1531 // The following is needed for the bug to happen:
1532 // - url1 must require webui bindings;
1533 // - navigating to url2 in the site instance of url1 should not swap
1534 // browsing instances, but should require a new site instance.
1535 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1536 GURL url1(std::string(kChromeUIScheme) + "://" +
1537 std::string(kChromeUIGpuHost));
1538 GURL url2(std::string(kChromeUIScheme) + "://" +
1539 std::string(kChromeUIAccessibilityHost));
1541 // Visit a WebUI page with bindings.
1542 NavigateToURL(shell(), url1);
1543 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1544 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1545 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1547 // Open a new tab. Initially it gets a render view in the original tab's
1548 // current site instance.
1549 TestNavigationObserver nav_observer(NULL);
1550 nav_observer.StartWatchingNewWebContents();
1551 ShellAddedObserver shao;
1552 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1553 nav_observer.Wait();
1554 Shell* new_shell = shao.GetShell();
1555 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1556 new_shell->web_contents());
1557 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1559 EXPECT_NE(site_instance2, site_instance1);
1560 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1561 RenderViewHost* initial_rvh = new_web_contents->
1562 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1563 ASSERT_TRUE(initial_rvh);
1564 // The following condition is what was causing the bug.
1565 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1567 // Navigate to url1 and check bindings.
1568 NavigateToURL(new_shell, url1);
1569 // The navigation should have used the first SiteInstance, otherwise
1570 // |initial_rvh| did not have a chance to be used.
1571 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1572 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1573 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1576 // crbug.com/424526
1577 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1578 // page and then to a regular page. The bug reproduces if blank page is visited
1579 // in between WebUI and regular page.
1580 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1581 ForceSwapAfterWebUIBindings) {
1582 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1583 switches::kProcessPerTab);
1584 ASSERT_TRUE(test_server()->Start());
1586 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1587 std::string(kChromeUIGpuHost));
1588 NavigateToURL(shell(), web_ui_url);
1589 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1590 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1592 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1594 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1595 NavigateToURL(shell(), regular_page_url);
1596 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1597 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1600 class FileChooserDelegate : public WebContentsDelegate {
1601 public:
1602 FileChooserDelegate(const base::FilePath& file)
1603 : file_(file), file_chosen_(false) {}
1605 void RunFileChooser(WebContents* web_contents,
1606 const FileChooserParams& params) override {
1607 // Send the selected file to the renderer process.
1608 FileChooserFileInfo file_info;
1609 file_info.file_path = file_;
1610 std::vector<FileChooserFileInfo> files;
1611 files.push_back(file_info);
1612 web_contents->GetRenderViewHost()->FilesSelectedInChooser(
1613 files, FileChooserParams::Open);
1615 file_chosen_ = true;
1618 bool file_chosen() { return file_chosen_; }
1620 private:
1621 base::FilePath file_;
1622 bool file_chosen_;
1625 // Test for http://crbug.com/262948.
1626 // Flaky on Mac. http://crbug.com/452018
1627 #if defined(OS_MACOSX)
1628 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1629 DISABLED_RestoreFileAccessForHistoryNavigation
1630 #else
1631 #define MAYBE_RestoreFileAccessForHistoryNavigation \
1632 RestoreFileAccessForHistoryNavigation
1633 #endif
1634 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1635 MAYBE_RestoreFileAccessForHistoryNavigation) {
1636 StartServer();
1637 base::FilePath file;
1638 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1639 file = file.AppendASCII("bar");
1641 // Navigate to url and get it to reference a file in its PageState.
1642 GURL url1(test_server()->GetURL("files/file_input.html"));
1643 NavigateToURL(shell(), url1);
1644 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1645 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
1646 shell()->web_contents()->SetDelegate(delegate.get());
1647 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1648 "document.getElementById('fileinput').click();"));
1649 EXPECT_TRUE(delegate->file_chosen());
1650 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1651 process_id, file));
1653 // Navigate to a different process without access to the file, and wait for
1654 // the old process to exit.
1655 RenderProcessHostWatcher exit_observer(
1656 shell()->web_contents()->GetRenderProcessHost(),
1657 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1658 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1659 exit_observer.Wait();
1660 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1661 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1663 // Ensure that the file ended up in the PageState of the previous entry.
1664 NavigationEntry* prev_entry =
1665 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1666 EXPECT_EQ(url1, prev_entry->GetURL());
1667 const std::vector<base::FilePath>& files =
1668 prev_entry->GetPageState().GetReferencedFiles();
1669 ASSERT_EQ(1U, files.size());
1670 EXPECT_EQ(file, files.at(0));
1672 // Go back, ending up in a different RenderProcessHost than before.
1673 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1674 shell()->web_contents()->GetController().GoBack();
1675 back_nav_load_observer.Wait();
1676 EXPECT_NE(process_id,
1677 shell()->web_contents()->GetRenderProcessHost()->GetID());
1679 // Ensure that the file access still exists in the new process ID.
1680 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1681 shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
1683 // Navigate to a same site page to trigger a PageState update and ensure the
1684 // renderer is not killed.
1685 EXPECT_TRUE(
1686 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1689 // Test for http://crbug.com/441966.
1690 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1691 RestoreSubframeFileAccessForHistoryNavigation) {
1692 StartServer();
1693 base::FilePath file;
1694 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
1695 file = file.AppendASCII("bar");
1697 // Navigate to url and get it to reference a file in its PageState.
1698 GURL url1(test_server()->GetURL("files/file_input_subframe.html"));
1699 NavigateToURL(shell(), url1);
1700 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
1701 FrameTreeNode* root = wc->GetFrameTree()->root();
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(root->child_at(0)->current_frame_host(),
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));
1742 // This class implements waiting for RenderFrameHost destruction. It relies on
1743 // the fact that RenderFrameDeleted event is fired when RenderFrameHost is
1744 // destroyed.
1745 // Note: RenderFrameDeleted is also fired when the process associated with the
1746 // RenderFrameHost crashes, so this cannot be used in cases where process dying
1747 // is expected.
1748 class RenderFrameHostDestructionObserver : public WebContentsObserver {
1749 public:
1750 explicit RenderFrameHostDestructionObserver(RenderFrameHost* rfh)
1751 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
1752 message_loop_runner_(new MessageLoopRunner),
1753 deleted_(false),
1754 render_frame_host_(rfh) {}
1755 ~RenderFrameHostDestructionObserver() override {}
1757 void Wait() {
1758 if (deleted_)
1759 return;
1761 message_loop_runner_->Run();
1764 // WebContentsObserver implementation:
1765 void RenderFrameDeleted(RenderFrameHost* rfh) override {
1766 if (rfh == render_frame_host_) {
1767 CHECK(!deleted_);
1768 deleted_ = true;
1771 if (deleted_ && message_loop_runner_->loop_running()) {
1772 base::ThreadTaskRunnerHandle::Get()->PostTask(
1773 FROM_HERE, message_loop_runner_->QuitClosure());
1777 private:
1778 scoped_refptr<MessageLoopRunner> message_loop_runner_;
1779 bool deleted_;
1780 RenderFrameHost* render_frame_host_;
1783 // Ensures that no RenderFrameHost/RenderViewHost objects are leaked when
1784 // doing a simple cross-process navigation.
1785 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1786 CleanupOnCrossProcessNavigation) {
1787 StartEmbeddedServer();
1789 // Do an initial navigation and capture objects we expect to be cleaned up
1790 // on cross-process navigation.
1791 GURL start_url = embedded_test_server()->GetURL("/title1.html");
1792 NavigateToURL(shell(), start_url);
1794 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1795 ->GetFrameTree()
1796 ->root();
1797 int32 orig_site_instance_id =
1798 root->current_frame_host()->GetSiteInstance()->GetId();
1799 int initial_process_id =
1800 root->current_frame_host()->GetSiteInstance()->GetProcess()->GetID();
1801 int initial_rfh_id = root->current_frame_host()->GetRoutingID();
1802 int initial_rvh_id =
1803 root->current_frame_host()->render_view_host()->GetRoutingID();
1805 // Navigate cross-process and ensure that cleanup is performed as expected.
1806 GURL cross_site_url =
1807 embedded_test_server()->GetURL("foo.com", "/title2.html");
1808 RenderFrameHostDestructionObserver rfh_observer(root->current_frame_host());
1809 NavigateToURL(shell(), cross_site_url);
1810 rfh_observer.Wait();
1812 EXPECT_NE(orig_site_instance_id,
1813 root->current_frame_host()->GetSiteInstance()->GetId());
1814 EXPECT_FALSE(RenderFrameHost::FromID(initial_process_id, initial_rfh_id));
1815 EXPECT_FALSE(RenderViewHost::FromID(initial_process_id, initial_rvh_id));
1818 } // namespace content