Rename isSystemLocationEnabled to isLocationEnabled, as per internal review (185995).
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
bloba19420269a66201abecc1d1e0ca5ab088cf45833
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <set>
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/path_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "content/browser/child_process_security_policy_impl.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/browser/webui/web_ui_impl.h"
18 #include "content/common/content_constants_internal.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/common/bindings_policy.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/file_chooser_file_info.h"
27 #include "content/public/common/file_chooser_params.h"
28 #include "content/public/common/page_state.h"
29 #include "content/public/common/url_constants.h"
30 #include "content/public/test/browser_test_utils.h"
31 #include "content/public/test/content_browser_test.h"
32 #include "content/public/test/content_browser_test_utils.h"
33 #include "content/public/test/test_navigation_observer.h"
34 #include "content/public/test/test_utils.h"
35 #include "content/shell/browser/shell.h"
36 #include "net/base/net_util.h"
37 #include "net/dns/mock_host_resolver.h"
38 #include "net/test/spawned_test_server/spawned_test_server.h"
40 using base::ASCIIToUTF16;
42 namespace content {
44 namespace {
46 const char kOpenUrlViaClickTargetFunc[] =
47 "(function(url) {\n"
48 " var lnk = document.createElement(\"a\");\n"
49 " lnk.href = url;\n"
50 " lnk.target = \"_blank\";\n"
51 " document.body.appendChild(lnk);\n"
52 " lnk.click();\n"
53 "})";
55 // Adds a link with given url and target=_blank, and clicks on it.
56 void OpenUrlViaClickTarget(const internal::ToRenderFrameHost& adapter,
57 const GURL& url) {
58 EXPECT_TRUE(ExecuteScript(adapter,
59 std::string(kOpenUrlViaClickTargetFunc) + "(\"" + url.spec() + "\");"));
62 } // anonymous namespace
64 class RenderFrameHostManagerTest : public ContentBrowserTest {
65 public:
66 RenderFrameHostManagerTest() : foo_com_("foo.com") {
67 replace_host_.SetHostStr(foo_com_);
70 static bool GetFilePathWithHostAndPortReplacement(
71 const std::string& original_file_path,
72 const net::HostPortPair& host_port_pair,
73 std::string* replacement_path) {
74 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
75 replacement_text.push_back(
76 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
77 return net::SpawnedTestServer::GetFilePathWithReplacements(
78 original_file_path, replacement_text, replacement_path);
81 void StartServer() {
82 // Support multiple sites on the test server.
83 host_resolver()->AddRule("*", "127.0.0.1");
84 ASSERT_TRUE(test_server()->Start());
86 foo_host_port_ = test_server()->host_port_pair();
87 foo_host_port_.set_host(foo_com_);
90 // Returns a URL on foo.com with the given path.
91 GURL GetCrossSiteURL(const std::string& path) {
92 GURL cross_site_url(test_server()->GetURL(path));
93 return cross_site_url.ReplaceComponents(replace_host_);
96 protected:
97 std::string foo_com_;
98 GURL::Replacements replace_host_;
99 net::HostPortPair foo_host_port_;
102 // Web pages should not have script access to the swapped out page.
103 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
104 StartServer();
106 // Load a page with links that open in a new window.
107 std::string replacement_path;
108 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
109 "files/click-noreferrer-links.html",
110 foo_host_port_,
111 &replacement_path));
112 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
114 // Get the original SiteInstance for later comparison.
115 scoped_refptr<SiteInstance> orig_site_instance(
116 shell()->web_contents()->GetSiteInstance());
117 EXPECT_TRUE(orig_site_instance.get() != NULL);
119 // Open a same-site link in a new window.
120 ShellAddedObserver new_shell_observer;
121 bool success = false;
122 EXPECT_TRUE(ExecuteScriptAndExtractBool(
123 shell()->web_contents(),
124 "window.domAutomationController.send(clickSameSiteTargetedLink());",
125 &success));
126 EXPECT_TRUE(success);
127 Shell* new_shell = new_shell_observer.GetShell();
129 // Wait for the navigation in the new window to finish, if it hasn't.
130 WaitForLoadStop(new_shell->web_contents());
131 EXPECT_EQ("/files/navigate_opener.html",
132 new_shell->web_contents()->GetLastCommittedURL().path());
134 // Should have the same SiteInstance.
135 scoped_refptr<SiteInstance> blank_site_instance(
136 new_shell->web_contents()->GetSiteInstance());
137 EXPECT_EQ(orig_site_instance, blank_site_instance);
139 // We should have access to the opened window's location.
140 success = false;
141 EXPECT_TRUE(ExecuteScriptAndExtractBool(
142 shell()->web_contents(),
143 "window.domAutomationController.send(testScriptAccessToWindow());",
144 &success));
145 EXPECT_TRUE(success);
147 // Now navigate the new window to a different site.
148 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
149 scoped_refptr<SiteInstance> new_site_instance(
150 new_shell->web_contents()->GetSiteInstance());
151 EXPECT_NE(orig_site_instance, new_site_instance);
153 // We should no longer have script access to the opened window's location.
154 success = false;
155 EXPECT_TRUE(ExecuteScriptAndExtractBool(
156 shell()->web_contents(),
157 "window.domAutomationController.send(testScriptAccessToWindow());",
158 &success));
159 EXPECT_FALSE(success);
162 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
163 // and target=_blank should create a new SiteInstance.
164 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
165 SwapProcessWithRelNoreferrerAndTargetBlank) {
166 StartServer();
168 // Load a page with links that open in a new window.
169 std::string replacement_path;
170 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
171 "files/click-noreferrer-links.html",
172 foo_host_port_,
173 &replacement_path));
174 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
176 // Get the original SiteInstance for later comparison.
177 scoped_refptr<SiteInstance> orig_site_instance(
178 shell()->web_contents()->GetSiteInstance());
179 EXPECT_TRUE(orig_site_instance.get() != NULL);
181 // Test clicking a rel=noreferrer + target=blank link.
182 ShellAddedObserver new_shell_observer;
183 bool success = false;
184 EXPECT_TRUE(ExecuteScriptAndExtractBool(
185 shell()->web_contents(),
186 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
187 &success));
188 EXPECT_TRUE(success);
190 // Wait for the window to open.
191 Shell* new_shell = new_shell_observer.GetShell();
193 EXPECT_EQ("/files/title2.html",
194 new_shell->web_contents()->GetVisibleURL().path());
196 // Wait for the cross-site transition in the new tab to finish.
197 WaitForLoadStop(new_shell->web_contents());
198 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
199 new_shell->web_contents());
200 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
201 pending_render_view_host());
203 // Should have a new SiteInstance.
204 scoped_refptr<SiteInstance> noref_blank_site_instance(
205 new_shell->web_contents()->GetSiteInstance());
206 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
209 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
210 // for rel=noreferrer links in new windows, even to same site pages and named
211 // targets.
212 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
213 SwapProcessWithSameSiteRelNoreferrer) {
214 StartServer();
216 // Load a page with links that open in a new window.
217 std::string replacement_path;
218 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
219 "files/click-noreferrer-links.html",
220 foo_host_port_,
221 &replacement_path));
222 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
224 // Get the original SiteInstance for later comparison.
225 scoped_refptr<SiteInstance> orig_site_instance(
226 shell()->web_contents()->GetSiteInstance());
227 EXPECT_TRUE(orig_site_instance.get() != NULL);
229 // Test clicking a same-site rel=noreferrer + target=foo link.
230 ShellAddedObserver new_shell_observer;
231 bool success = false;
232 EXPECT_TRUE(ExecuteScriptAndExtractBool(
233 shell()->web_contents(),
234 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
235 &success));
236 EXPECT_TRUE(success);
238 // Wait for the window to open.
239 Shell* new_shell = new_shell_observer.GetShell();
241 // Opens in new window.
242 EXPECT_EQ("/files/title2.html",
243 new_shell->web_contents()->GetVisibleURL().path());
245 // Wait for the cross-site transition in the new tab to finish.
246 WaitForLoadStop(new_shell->web_contents());
247 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
248 new_shell->web_contents());
249 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
250 pending_render_view_host());
252 // Should have a new SiteInstance (in a new BrowsingInstance).
253 scoped_refptr<SiteInstance> noref_blank_site_instance(
254 new_shell->web_contents()->GetSiteInstance());
255 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
258 // Test for crbug.com/24447. Following a cross-site link with just
259 // target=_blank should not create a new SiteInstance, unless we
260 // are running in --site-per-process mode.
261 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
262 DontSwapProcessWithOnlyTargetBlank) {
263 StartServer();
265 // Load a page with links that open in a new window.
266 std::string replacement_path;
267 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
268 "files/click-noreferrer-links.html",
269 foo_host_port_,
270 &replacement_path));
271 EXPECT_TRUE(NavigateToURL(shell(), test_server()->GetURL(replacement_path)));
273 // Get the original SiteInstance for later comparison.
274 scoped_refptr<SiteInstance> orig_site_instance(
275 shell()->web_contents()->GetSiteInstance());
276 EXPECT_TRUE(orig_site_instance.get() != NULL);
278 // Test clicking a target=blank link.
279 ShellAddedObserver new_shell_observer;
280 bool success = false;
281 EXPECT_TRUE(ExecuteScriptAndExtractBool(
282 shell()->web_contents(),
283 "window.domAutomationController.send(clickTargetBlankLink());",
284 &success));
285 EXPECT_TRUE(success);
287 // Wait for the window to open.
288 Shell* new_shell = new_shell_observer.GetShell();
290 // Wait for the cross-site transition in the new tab to finish.
291 EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
292 EXPECT_EQ("/files/title2.html",
293 new_shell->web_contents()->GetLastCommittedURL().path());
295 // Should have the same SiteInstance unless we're in site-per-process mode.
296 scoped_refptr<SiteInstance> blank_site_instance(
297 new_shell->web_contents()->GetSiteInstance());
298 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
299 switches::kSitePerProcess))
300 EXPECT_EQ(orig_site_instance, blank_site_instance);
301 else
302 EXPECT_NE(orig_site_instance, blank_site_instance);
305 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
306 // and no target=_blank should not create a new SiteInstance.
307 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
308 DontSwapProcessWithOnlyRelNoreferrer) {
309 StartServer();
311 // Load a page with links that open in a new window.
312 std::string replacement_path;
313 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
314 "files/click-noreferrer-links.html",
315 foo_host_port_,
316 &replacement_path));
317 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
319 // Get the original SiteInstance for later comparison.
320 scoped_refptr<SiteInstance> orig_site_instance(
321 shell()->web_contents()->GetSiteInstance());
322 EXPECT_TRUE(orig_site_instance.get() != NULL);
324 // Test clicking a rel=noreferrer link.
325 bool success = false;
326 EXPECT_TRUE(ExecuteScriptAndExtractBool(
327 shell()->web_contents(),
328 "window.domAutomationController.send(clickNoRefLink());",
329 &success));
330 EXPECT_TRUE(success);
332 // Wait for the cross-site transition in the current tab to finish.
333 WaitForLoadStop(shell()->web_contents());
335 // Opens in same window.
336 EXPECT_EQ(1u, Shell::windows().size());
337 EXPECT_EQ("/files/title2.html",
338 shell()->web_contents()->GetLastCommittedURL().path());
340 // Should have the same SiteInstance unless we're in site-per-process mode.
341 scoped_refptr<SiteInstance> noref_site_instance(
342 shell()->web_contents()->GetSiteInstance());
343 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
344 switches::kSitePerProcess))
345 EXPECT_EQ(orig_site_instance, noref_site_instance);
346 else
347 EXPECT_NE(orig_site_instance, noref_site_instance);
350 // Test for crbug.com/116192. Targeted links should still work after the
351 // named target window has swapped processes.
352 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
353 AllowTargetedNavigationsAfterSwap) {
354 StartServer();
356 // Load a page with links that open in a new window.
357 std::string replacement_path;
358 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
359 "files/click-noreferrer-links.html",
360 foo_host_port_,
361 &replacement_path));
362 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
364 // Get the original SiteInstance for later comparison.
365 scoped_refptr<SiteInstance> orig_site_instance(
366 shell()->web_contents()->GetSiteInstance());
367 EXPECT_TRUE(orig_site_instance.get() != NULL);
369 // Test clicking a target=foo link.
370 ShellAddedObserver new_shell_observer;
371 bool success = false;
372 EXPECT_TRUE(ExecuteScriptAndExtractBool(
373 shell()->web_contents(),
374 "window.domAutomationController.send(clickSameSiteTargetedLink());",
375 &success));
376 EXPECT_TRUE(success);
377 Shell* new_shell = new_shell_observer.GetShell();
379 // Wait for the navigation in the new tab to finish, if it hasn't.
380 WaitForLoadStop(new_shell->web_contents());
381 EXPECT_EQ("/files/navigate_opener.html",
382 new_shell->web_contents()->GetLastCommittedURL().path());
384 // Should have the same SiteInstance.
385 scoped_refptr<SiteInstance> blank_site_instance(
386 new_shell->web_contents()->GetSiteInstance());
387 EXPECT_EQ(orig_site_instance, blank_site_instance);
389 // Now navigate the new tab to a different site.
390 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
391 NavigateToURL(new_shell, cross_site_url);
392 scoped_refptr<SiteInstance> new_site_instance(
393 new_shell->web_contents()->GetSiteInstance());
394 EXPECT_NE(orig_site_instance, new_site_instance);
396 // Clicking the original link in the first tab should cause us to swap back.
397 TestNavigationObserver navigation_observer(new_shell->web_contents());
398 EXPECT_TRUE(ExecuteScriptAndExtractBool(
399 shell()->web_contents(),
400 "window.domAutomationController.send(clickSameSiteTargetedLink());",
401 &success));
402 EXPECT_TRUE(success);
403 navigation_observer.Wait();
405 // Should have swapped back and shown the new window again.
406 scoped_refptr<SiteInstance> revisit_site_instance(
407 new_shell->web_contents()->GetSiteInstance());
408 EXPECT_EQ(orig_site_instance, revisit_site_instance);
410 // If it navigates away to another process, the original window should
411 // still be able to close it (using a cross-process close message).
412 NavigateToURL(new_shell, cross_site_url);
413 EXPECT_EQ(new_site_instance.get(),
414 new_shell->web_contents()->GetSiteInstance());
415 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
416 EXPECT_TRUE(ExecuteScriptAndExtractBool(
417 shell()->web_contents(),
418 "window.domAutomationController.send(testCloseWindow());",
419 &success));
420 EXPECT_TRUE(success);
421 close_watcher.Wait();
424 // Test that setting the opener to null in a window affects cross-process
425 // navigations, including those to existing entries. http://crbug.com/156669.
426 // This test crashes under ThreadSanitizer, http://crbug.com/356758.
427 #if defined(THREAD_SANITIZER)
428 #define MAYBE_DisownOpener DISABLED_DisownOpener
429 #else
430 #define MAYBE_DisownOpener DisownOpener
431 #endif
432 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
433 StartServer();
435 // Load a page with links that open in a new window.
436 std::string replacement_path;
437 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
438 "files/click-noreferrer-links.html",
439 foo_host_port_,
440 &replacement_path));
441 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
443 // Get the original SiteInstance for later comparison.
444 scoped_refptr<SiteInstance> orig_site_instance(
445 shell()->web_contents()->GetSiteInstance());
446 EXPECT_TRUE(orig_site_instance.get() != NULL);
448 // Test clicking a target=_blank link.
449 ShellAddedObserver new_shell_observer;
450 bool success = false;
451 EXPECT_TRUE(ExecuteScriptAndExtractBool(
452 shell()->web_contents(),
453 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
454 &success));
455 EXPECT_TRUE(success);
456 Shell* new_shell = new_shell_observer.GetShell();
457 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
459 // Wait for the navigation in the new tab to finish, if it hasn't.
460 WaitForLoadStop(new_shell->web_contents());
461 EXPECT_EQ("/files/title2.html",
462 new_shell->web_contents()->GetLastCommittedURL().path());
464 // Should have the same SiteInstance.
465 scoped_refptr<SiteInstance> blank_site_instance(
466 new_shell->web_contents()->GetSiteInstance());
467 EXPECT_EQ(orig_site_instance, blank_site_instance);
469 // Now navigate the new tab to a different site.
470 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
471 scoped_refptr<SiteInstance> new_site_instance(
472 new_shell->web_contents()->GetSiteInstance());
473 EXPECT_NE(orig_site_instance, new_site_instance);
474 EXPECT_TRUE(new_shell->web_contents()->HasOpener());
476 // Now disown the opener.
477 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
478 "window.opener = null;"));
479 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
481 // Go back and ensure the opener is still null.
483 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
484 new_shell->web_contents()->GetController().GoBack();
485 back_nav_load_observer.Wait();
487 success = false;
488 EXPECT_TRUE(ExecuteScriptAndExtractBool(
489 new_shell->web_contents(),
490 "window.domAutomationController.send(window.opener == null);",
491 &success));
492 EXPECT_TRUE(success);
493 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
495 // Now navigate forward again (creating a new process) and check opener.
496 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
497 success = false;
498 EXPECT_TRUE(ExecuteScriptAndExtractBool(
499 new_shell->web_contents(),
500 "window.domAutomationController.send(window.opener == null);",
501 &success));
502 EXPECT_TRUE(success);
503 EXPECT_FALSE(new_shell->web_contents()->HasOpener());
506 // Test that subframes can disown their openers. http://crbug.com/225528.
507 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
508 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
509 NavigateToURL(shell(), frame_url);
511 // Give the frame an opener using window.open.
512 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
513 "window.open('about:blank','foo');"));
515 // Now disown the frame's opener. Shouldn't crash.
516 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
517 "window.frames[0].opener = null;"));
520 // Test for crbug.com/99202. PostMessage calls should still work after
521 // navigating the source and target windows to different sites.
522 // Specifically:
523 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
524 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
525 // 3) Post a message from "foo" to opener, which replies back to "foo".
526 // 4) Post a message from _blank to "foo".
527 // 5) Post a message from "foo" to a subframe of opener, which replies back.
528 // 6) Post a message from _blank to a subframe of "foo".
529 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
530 SupportCrossProcessPostMessage) {
531 StartServer();
533 // Load a page with links that open in a new window.
534 std::string replacement_path;
535 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
536 "files/click-noreferrer-links.html",
537 foo_host_port_,
538 &replacement_path));
539 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
541 // Get the original SiteInstance and RVHM for later comparison.
542 WebContents* opener_contents = shell()->web_contents();
543 scoped_refptr<SiteInstance> orig_site_instance(
544 opener_contents->GetSiteInstance());
545 EXPECT_TRUE(orig_site_instance.get() != NULL);
546 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
547 opener_contents)->GetRenderManagerForTesting();
549 // 1) Open two more windows, one named. These initially have openers but no
550 // reference to each other. We will later post a message between them.
552 // First, a named target=foo window.
553 ShellAddedObserver new_shell_observer;
554 bool success = false;
555 EXPECT_TRUE(ExecuteScriptAndExtractBool(
556 opener_contents,
557 "window.domAutomationController.send(clickSameSiteTargetedLink());",
558 &success));
559 EXPECT_TRUE(success);
560 Shell* new_shell = new_shell_observer.GetShell();
562 // Wait for the navigation in the new window to finish, if it hasn't, then
563 // send it to post_message.html on a different site.
564 WebContents* foo_contents = new_shell->web_contents();
565 WaitForLoadStop(foo_contents);
566 EXPECT_EQ("/files/navigate_opener.html",
567 foo_contents->GetLastCommittedURL().path());
568 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
569 scoped_refptr<SiteInstance> foo_site_instance(
570 foo_contents->GetSiteInstance());
571 EXPECT_NE(orig_site_instance, foo_site_instance);
573 // Second, a target=_blank window.
574 ShellAddedObserver new_shell_observer2;
575 EXPECT_TRUE(ExecuteScriptAndExtractBool(
576 shell()->web_contents(),
577 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
578 &success));
579 EXPECT_TRUE(success);
581 // Wait for the navigation in the new window to finish, if it hasn't, then
582 // send it to post_message.html on the original site.
583 Shell* new_shell2 = new_shell_observer2.GetShell();
584 WebContents* new_contents = new_shell2->web_contents();
585 WaitForLoadStop(new_contents);
586 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
587 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
588 EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
589 RenderFrameHostManager* new_manager =
590 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
592 // We now have three windows. The opener should have a swapped out RVH
593 // for the new SiteInstance, but the _blank window should not.
594 EXPECT_EQ(3u, Shell::windows().size());
595 EXPECT_TRUE(
596 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
597 EXPECT_FALSE(
598 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
600 // 2) Fail to post a message from the foo window to the opener if the target
601 // origin is wrong. We won't see an error, but we can check for the right
602 // number of received messages below.
603 EXPECT_TRUE(ExecuteScriptAndExtractBool(
604 foo_contents,
605 "window.domAutomationController.send(postToOpener('msg',"
606 " 'http://google.com'));",
607 &success));
608 EXPECT_TRUE(success);
609 ASSERT_FALSE(
610 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
612 // 3) Post a message from the foo window to the opener. The opener will
613 // reply, causing the foo window to update its own title.
614 base::string16 expected_title = ASCIIToUTF16("msg");
615 TitleWatcher title_watcher(foo_contents, expected_title);
616 EXPECT_TRUE(ExecuteScriptAndExtractBool(
617 foo_contents,
618 "window.domAutomationController.send(postToOpener('msg','*'));",
619 &success));
620 EXPECT_TRUE(success);
621 ASSERT_FALSE(
622 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
623 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
625 // We should have received only 1 message in the opener and "foo" tabs,
626 // and updated the title.
627 int opener_received_messages = 0;
628 EXPECT_TRUE(ExecuteScriptAndExtractInt(
629 opener_contents,
630 "window.domAutomationController.send(window.receivedMessages);",
631 &opener_received_messages));
632 int foo_received_messages = 0;
633 EXPECT_TRUE(ExecuteScriptAndExtractInt(
634 foo_contents,
635 "window.domAutomationController.send(window.receivedMessages);",
636 &foo_received_messages));
637 EXPECT_EQ(1, foo_received_messages);
638 EXPECT_EQ(1, opener_received_messages);
639 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
641 // 4) Now post a message from the _blank window to the foo window. The
642 // foo window will update its title and will not reply.
643 expected_title = ASCIIToUTF16("msg2");
644 TitleWatcher title_watcher2(foo_contents, expected_title);
645 EXPECT_TRUE(ExecuteScriptAndExtractBool(
646 new_contents,
647 "window.domAutomationController.send(postToFoo('msg2'));",
648 &success));
649 EXPECT_TRUE(success);
650 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
652 // This postMessage should have created a swapped out RVH for the new
653 // SiteInstance in the target=_blank window.
654 EXPECT_TRUE(
655 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
657 // TODO(nasko): Test subframe targeting of postMessage once
658 // http://crbug.com/153701 is fixed.
661 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
662 // messages which contain Transferables and get intercepted by
663 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
664 // swapped out) should work.
665 // Specifically:
666 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
667 // 2) Post a message containing a message port from opener to "foo".
668 // 3) Post a message from "foo" back to opener via the passed message port.
669 // The test will be enabled when the feature implementation lands.
670 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
671 SupportCrossProcessPostMessageWithMessagePort) {
672 StartServer();
674 // Load a page with links that open in a new window.
675 std::string replacement_path;
676 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
677 "files/click-noreferrer-links.html",
678 foo_host_port_,
679 &replacement_path));
680 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
682 // Get the original SiteInstance and RVHM for later comparison.
683 WebContents* opener_contents = shell()->web_contents();
684 scoped_refptr<SiteInstance> orig_site_instance(
685 opener_contents->GetSiteInstance());
686 EXPECT_TRUE(orig_site_instance.get() != NULL);
687 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
688 opener_contents)->GetRenderManagerForTesting();
690 // 1) Open a named target=foo window. We will later post a message between the
691 // opener and the new window.
692 ShellAddedObserver new_shell_observer;
693 bool success = false;
694 EXPECT_TRUE(ExecuteScriptAndExtractBool(
695 opener_contents,
696 "window.domAutomationController.send(clickSameSiteTargetedLink());",
697 &success));
698 EXPECT_TRUE(success);
699 Shell* new_shell = new_shell_observer.GetShell();
701 // Wait for the navigation in the new window to finish, if it hasn't, then
702 // send it to post_message.html on a different site.
703 WebContents* foo_contents = new_shell->web_contents();
704 WaitForLoadStop(foo_contents);
705 EXPECT_EQ("/files/navigate_opener.html",
706 foo_contents->GetLastCommittedURL().path());
707 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
708 scoped_refptr<SiteInstance> foo_site_instance(
709 foo_contents->GetSiteInstance());
710 EXPECT_NE(orig_site_instance, foo_site_instance);
712 // We now have two windows. The opener should have a swapped out RVH
713 // for the new SiteInstance.
714 EXPECT_EQ(2u, Shell::windows().size());
715 EXPECT_TRUE(
716 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
718 // 2) Post a message containing a MessagePort from opener to the the foo
719 // window. The foo window will reply via the passed port, causing the opener
720 // to update its own title.
721 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
722 TitleWatcher title_observer(opener_contents, expected_title);
723 EXPECT_TRUE(ExecuteScriptAndExtractBool(
724 opener_contents,
725 "window.domAutomationController.send(postWithPortToFoo());",
726 &success));
727 EXPECT_TRUE(success);
728 ASSERT_FALSE(
729 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
730 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
732 // Check message counts.
733 int opener_received_messages_via_port = 0;
734 EXPECT_TRUE(ExecuteScriptAndExtractInt(
735 opener_contents,
736 "window.domAutomationController.send(window.receivedMessagesViaPort);",
737 &opener_received_messages_via_port));
738 int foo_received_messages = 0;
739 EXPECT_TRUE(ExecuteScriptAndExtractInt(
740 foo_contents,
741 "window.domAutomationController.send(window.receivedMessages);",
742 &foo_received_messages));
743 int foo_received_messages_with_port = 0;
744 EXPECT_TRUE(ExecuteScriptAndExtractInt(
745 foo_contents,
746 "window.domAutomationController.send(window.receivedMessagesWithPort);",
747 &foo_received_messages_with_port));
748 EXPECT_EQ(1, foo_received_messages);
749 EXPECT_EQ(1, foo_received_messages_with_port);
750 EXPECT_EQ(1, opener_received_messages_via_port);
751 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
752 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
755 // Test for crbug.com/116192. Navigations to a window's opener should
756 // still work after a process swap.
757 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
758 AllowTargetedNavigationsInOpenerAfterSwap) {
759 StartServer();
761 // Load a page with links that open in a new window.
762 std::string replacement_path;
763 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
764 "files/click-noreferrer-links.html",
765 foo_host_port_,
766 &replacement_path));
767 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
769 // Get the original tab and SiteInstance for later comparison.
770 WebContents* orig_contents = shell()->web_contents();
771 scoped_refptr<SiteInstance> orig_site_instance(
772 orig_contents->GetSiteInstance());
773 EXPECT_TRUE(orig_site_instance.get() != NULL);
775 // Test clicking a target=foo link.
776 ShellAddedObserver new_shell_observer;
777 bool success = false;
778 EXPECT_TRUE(ExecuteScriptAndExtractBool(
779 orig_contents,
780 "window.domAutomationController.send(clickSameSiteTargetedLink());",
781 &success));
782 EXPECT_TRUE(success);
783 Shell* new_shell = new_shell_observer.GetShell();
785 // Wait for the navigation in the new window to finish, if it hasn't.
786 WaitForLoadStop(new_shell->web_contents());
787 EXPECT_EQ("/files/navigate_opener.html",
788 new_shell->web_contents()->GetLastCommittedURL().path());
790 // Should have the same SiteInstance.
791 scoped_refptr<SiteInstance> blank_site_instance(
792 new_shell->web_contents()->GetSiteInstance());
793 EXPECT_EQ(orig_site_instance, blank_site_instance);
795 // Now navigate the original (opener) tab to a different site.
796 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
797 scoped_refptr<SiteInstance> new_site_instance(
798 shell()->web_contents()->GetSiteInstance());
799 EXPECT_NE(orig_site_instance, new_site_instance);
801 // The opened tab should be able to navigate the opener back to its process.
802 TestNavigationObserver navigation_observer(orig_contents);
803 EXPECT_TRUE(ExecuteScriptAndExtractBool(
804 new_shell->web_contents(),
805 "window.domAutomationController.send(navigateOpener());",
806 &success));
807 EXPECT_TRUE(success);
808 navigation_observer.Wait();
810 // Should have swapped back into this process.
811 scoped_refptr<SiteInstance> revisit_site_instance(
812 shell()->web_contents()->GetSiteInstance());
813 EXPECT_EQ(orig_site_instance, revisit_site_instance);
816 // Test that opening a new window in the same SiteInstance and then navigating
817 // both windows to a different SiteInstance allows the first process to exit.
818 // See http://crbug.com/126333.
819 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
820 ProcessExitWithSwappedOutViews) {
821 StartServer();
823 // Load a page with links that open in a new window.
824 std::string replacement_path;
825 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
826 "files/click-noreferrer-links.html",
827 foo_host_port_,
828 &replacement_path));
829 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
831 // Get the original SiteInstance for later comparison.
832 scoped_refptr<SiteInstance> orig_site_instance(
833 shell()->web_contents()->GetSiteInstance());
834 EXPECT_TRUE(orig_site_instance.get() != NULL);
836 // Test clicking a target=foo link.
837 ShellAddedObserver new_shell_observer;
838 bool success = false;
839 EXPECT_TRUE(ExecuteScriptAndExtractBool(
840 shell()->web_contents(),
841 "window.domAutomationController.send(clickSameSiteTargetedLink());",
842 &success));
843 EXPECT_TRUE(success);
844 Shell* new_shell = new_shell_observer.GetShell();
846 // Wait for the navigation in the new window to finish, if it hasn't.
847 WaitForLoadStop(new_shell->web_contents());
848 EXPECT_EQ("/files/navigate_opener.html",
849 new_shell->web_contents()->GetLastCommittedURL().path());
851 // Should have the same SiteInstance.
852 scoped_refptr<SiteInstance> opened_site_instance(
853 new_shell->web_contents()->GetSiteInstance());
854 EXPECT_EQ(orig_site_instance, opened_site_instance);
856 // Now navigate the opened window to a different site.
857 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
858 scoped_refptr<SiteInstance> new_site_instance(
859 new_shell->web_contents()->GetSiteInstance());
860 EXPECT_NE(orig_site_instance, new_site_instance);
862 // The original process should still be alive, since it is still used in the
863 // first window.
864 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
865 EXPECT_TRUE(orig_process->HasConnection());
867 // Navigate the first window to a different site as well. The original
868 // process should exit, since all of its views are now swapped out.
869 RenderProcessHostWatcher exit_observer(
870 orig_process,
871 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
872 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
873 exit_observer.Wait();
874 scoped_refptr<SiteInstance> new_site_instance2(
875 shell()->web_contents()->GetSiteInstance());
876 EXPECT_EQ(new_site_instance, new_site_instance2);
879 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
880 // error should not make us ignore future renderer-initiated navigations.
881 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
882 StartServer();
884 // Get the original SiteInstance for later comparison.
885 scoped_refptr<SiteInstance> orig_site_instance(
886 shell()->web_contents()->GetSiteInstance());
887 EXPECT_TRUE(orig_site_instance.get() != NULL);
889 // Load a cross-site page that fails with a 204 error.
890 EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(),
891 GetCrossSiteURL("nocontent")));
893 // We should still be looking at the normal page. Because we started from a
894 // blank new tab, the typed URL will still be visible until the user clears it
895 // manually. The last committed URL will be the previous page.
896 scoped_refptr<SiteInstance> post_nav_site_instance(
897 shell()->web_contents()->GetSiteInstance());
898 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
899 EXPECT_EQ("/nocontent",
900 shell()->web_contents()->GetVisibleURL().path());
901 EXPECT_FALSE(
902 shell()->web_contents()->GetController().GetLastCommittedEntry());
904 // Renderer-initiated navigations should work.
905 base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
906 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
907 GURL url = test_server()->GetURL("files/title2.html");
908 EXPECT_TRUE(ExecuteScript(
909 shell()->web_contents(),
910 base::StringPrintf("location.href = '%s'", url.spec().c_str())));
911 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
913 // Opens in same tab.
914 EXPECT_EQ(1u, Shell::windows().size());
915 EXPECT_EQ("/files/title2.html",
916 shell()->web_contents()->GetLastCommittedURL().path());
918 // Should have the same SiteInstance.
919 scoped_refptr<SiteInstance> new_site_instance(
920 shell()->web_contents()->GetSiteInstance());
921 EXPECT_EQ(orig_site_instance, new_site_instance);
924 // Test for crbug.com/9682. We should show the URL for a pending renderer-
925 // initiated navigation in a new tab, until the content of the initial
926 // about:blank page is modified by another window. At that point, we should
927 // revert to showing about:blank to prevent a URL spoof.
928 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
929 ASSERT_TRUE(test_server()->Start());
931 // Load a page that can open a URL that won't commit in a new window.
932 NavigateToURL(
933 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
934 WebContents* orig_contents = shell()->web_contents();
936 // Click a /nocontent link that opens in a new window but never commits.
937 ShellAddedObserver new_shell_observer;
938 bool success = false;
939 EXPECT_TRUE(ExecuteScriptAndExtractBool(
940 orig_contents,
941 "window.domAutomationController.send(clickNoContentTargetedLink());",
942 &success));
943 EXPECT_TRUE(success);
945 // Wait for the window to open.
946 Shell* new_shell = new_shell_observer.GetShell();
948 // Ensure the destination URL is visible, because it is considered the
949 // initial navigation.
950 WebContents* contents = new_shell->web_contents();
951 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
952 EXPECT_EQ("/nocontent",
953 contents->GetController().GetVisibleEntry()->GetURL().path());
955 // Now modify the contents of the new window from the opener. This will also
956 // modify the title of the document to give us something to listen for.
957 base::string16 expected_title = ASCIIToUTF16("Modified Title");
958 TitleWatcher title_watcher(contents, expected_title);
959 success = false;
960 EXPECT_TRUE(ExecuteScriptAndExtractBool(
961 orig_contents,
962 "window.domAutomationController.send(modifyNewWindow());",
963 &success));
964 EXPECT_TRUE(success);
965 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
967 // At this point, we should no longer be showing the destination URL.
968 // The visible entry should be null, resulting in about:blank in the address
969 // bar.
970 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
973 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
974 // initiated navigation in a new tab if it is not the initial navigation. In
975 // this case, the renderer will not notify us of a modification, so we cannot
976 // show the pending URL without allowing a spoof.
977 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
978 DontShowLoadingURLIfNotInitialNav) {
979 ASSERT_TRUE(test_server()->Start());
981 // Load a page that can open a URL that won't commit in a new window.
982 NavigateToURL(
983 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
984 WebContents* orig_contents = shell()->web_contents();
986 // Click a /nocontent link that opens in a new window but never commits.
987 // By using an onclick handler that first creates the window, the slow
988 // navigation is not considered an initial navigation.
989 ShellAddedObserver new_shell_observer;
990 bool success = false;
991 EXPECT_TRUE(ExecuteScriptAndExtractBool(
992 orig_contents,
993 "window.domAutomationController.send("
994 "clickNoContentScriptedTargetedLink());",
995 &success));
996 EXPECT_TRUE(success);
998 // Wait for the window to open.
999 Shell* new_shell = new_shell_observer.GetShell();
1001 // Ensure the destination URL is not visible, because it is not the initial
1002 // navigation.
1003 WebContents* contents = new_shell->web_contents();
1004 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1005 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1008 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1009 #if defined(THREAD_SANITIZER)
1010 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
1011 #else
1012 #define MAYBE_BackForwardNotStale BackForwardNotStale
1013 #endif
1014 // Test for http://crbug.com/93427. Ensure that cross-site navigations
1015 // do not cause back/forward navigations to be considered stale by the
1016 // renderer.
1017 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1018 StartServer();
1019 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1021 // Visit a page on first site.
1022 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1024 // Visit three pages on second site.
1025 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1026 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1027 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1029 // History is now [blank, A1, B1, B2, *B3].
1030 WebContents* contents = shell()->web_contents();
1031 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1033 // Open another window in same process to keep this process alive.
1034 Shell* new_shell = CreateBrowser();
1035 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1037 // Go back three times to first site.
1039 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1040 shell()->web_contents()->GetController().GoBack();
1041 back_nav_load_observer.Wait();
1044 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1045 shell()->web_contents()->GetController().GoBack();
1046 back_nav_load_observer.Wait();
1049 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1050 shell()->web_contents()->GetController().GoBack();
1051 back_nav_load_observer.Wait();
1054 // Now go forward twice to B2. Shouldn't be left spinning.
1056 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1057 shell()->web_contents()->GetController().GoForward();
1058 forward_nav_load_observer.Wait();
1061 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1062 shell()->web_contents()->GetController().GoForward();
1063 forward_nav_load_observer.Wait();
1066 // Go back twice to first site.
1068 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1069 shell()->web_contents()->GetController().GoBack();
1070 back_nav_load_observer.Wait();
1073 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1074 shell()->web_contents()->GetController().GoBack();
1075 back_nav_load_observer.Wait();
1078 // Now go forward directly to B3. Shouldn't be left spinning.
1080 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1081 shell()->web_contents()->GetController().GoToIndex(4);
1082 forward_nav_load_observer.Wait();
1086 // Test for http://crbug.com/130016.
1087 // Swapping out a render view should update its visiblity state.
1088 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1089 SwappedOutViewHasCorrectVisibilityState) {
1090 StartServer();
1092 // Load a page with links that open in a new window.
1093 std::string replacement_path;
1094 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1095 "files/click-noreferrer-links.html",
1096 foo_host_port_,
1097 &replacement_path));
1098 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1100 // Open a same-site link in a new widnow.
1101 ShellAddedObserver new_shell_observer;
1102 bool success = false;
1103 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1104 shell()->web_contents(),
1105 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1106 &success));
1107 EXPECT_TRUE(success);
1108 Shell* new_shell = new_shell_observer.GetShell();
1110 // Wait for the navigation in the new tab to finish, if it hasn't.
1111 WaitForLoadStop(new_shell->web_contents());
1112 EXPECT_EQ("/files/navigate_opener.html",
1113 new_shell->web_contents()->GetLastCommittedURL().path());
1115 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1117 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1118 rvh,
1119 "window.domAutomationController.send("
1120 " document.visibilityState == 'visible');",
1121 &success));
1122 EXPECT_TRUE(success);
1124 // Now navigate the new window to a different site. This should swap out the
1125 // tab's existing RenderView, causing it become hidden.
1126 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1128 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1129 rvh,
1130 "window.domAutomationController.send("
1131 " document.visibilityState == 'hidden');",
1132 &success));
1133 EXPECT_TRUE(success);
1135 // Going back should make the previously swapped-out view to become visible
1136 // again.
1138 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1139 new_shell->web_contents()->GetController().GoBack();
1140 back_nav_load_observer.Wait();
1143 EXPECT_EQ("/files/navigate_opener.html",
1144 new_shell->web_contents()->GetLastCommittedURL().path());
1146 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1148 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1149 rvh,
1150 "window.domAutomationController.send("
1151 " document.visibilityState == 'visible');",
1152 &success));
1153 EXPECT_TRUE(success);
1156 // This class ensures that all the given RenderViewHosts have properly been
1157 // shutdown.
1158 class RenderViewHostDestructionObserver : public WebContentsObserver {
1159 public:
1160 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1161 : WebContentsObserver(web_contents) {}
1162 ~RenderViewHostDestructionObserver() override {}
1163 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1164 watched_render_view_hosts_.insert(rvh);
1166 size_t GetNumberOfWatchedRenderViewHosts() const {
1167 return watched_render_view_hosts_.size();
1170 private:
1171 // WebContentsObserver implementation:
1172 void RenderViewDeleted(RenderViewHost* rvh) override {
1173 watched_render_view_hosts_.erase(rvh);
1176 std::set<RenderViewHost*> watched_render_view_hosts_;
1179 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1180 #if defined(THREAD_SANITIZER)
1181 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1182 #else
1183 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1184 #endif
1185 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1186 // they may cause crashes or memory corruptions when trying to call dead
1187 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1188 // ensure that a separate SiteInstance is created when navigating to view-source
1189 // URLs, regardless of current URL.
1190 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1191 MAYBE_LeakingRenderViewHosts) {
1192 StartServer();
1194 // Observe the created render_view_host's to make sure they will not leak.
1195 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1197 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1198 GURL view_source_url(kViewSourceScheme + std::string(":") +
1199 navigated_url.spec());
1201 // Let's ensure that when we start with a blank window, navigating away to a
1202 // view-source URL, we create a new SiteInstance.
1203 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1204 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1205 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1206 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1207 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1209 // Now navigate to the view-source URL and ensure we got a different
1210 // SiteInstance and RenderViewHost.
1211 NavigateToURL(shell(), view_source_url);
1212 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1213 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1214 GetRenderViewHost()->GetSiteInstance());
1215 rvh_observers.EnsureRVHGetsDestructed(
1216 shell()->web_contents()->GetRenderViewHost());
1218 // Load a random page and then navigate to view-source: of it.
1219 // This used to cause two RVH instances for the same SiteInstance, which
1220 // was a problem. This is no longer the case.
1221 NavigateToURL(shell(), navigated_url);
1222 SiteInstance* site_instance1 = shell()->web_contents()->
1223 GetRenderViewHost()->GetSiteInstance();
1224 rvh_observers.EnsureRVHGetsDestructed(
1225 shell()->web_contents()->GetRenderViewHost());
1227 NavigateToURL(shell(), view_source_url);
1228 rvh_observers.EnsureRVHGetsDestructed(
1229 shell()->web_contents()->GetRenderViewHost());
1230 SiteInstance* site_instance2 = shell()->web_contents()->
1231 GetRenderViewHost()->GetSiteInstance();
1233 // Ensure that view-source navigations force a new SiteInstance.
1234 EXPECT_NE(site_instance1, site_instance2);
1236 // Now navigate to a different instance so that we swap out again.
1237 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1238 rvh_observers.EnsureRVHGetsDestructed(
1239 shell()->web_contents()->GetRenderViewHost());
1241 // This used to leak a render view host.
1242 shell()->Close();
1244 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1246 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1249 // Test for crbug.com/143155. Frame tree updates during unload should not
1250 // interrupt the intended navigation and show swappedout:// instead.
1251 // Specifically:
1252 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1253 // 2) Send the second tab to a different foo.com SiteInstance.
1254 // This creates a swapped out opener for the first tab in the foo process.
1255 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1256 // tab's unload handler remove its frame.
1257 // This used to cause an update to the frame tree of the swapped out RV,
1258 // just as it was navigating to a real page. That pre-empted the real
1259 // navigation and visibly sent the tab to swappedout://.
1260 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1261 DontPreemptNavigationWithFrameTreeUpdate) {
1262 StartServer();
1264 // 1. Load a page that deletes its iframe during unload.
1265 NavigateToURL(shell(),
1266 test_server()->GetURL("files/remove_frame_on_unload.html"));
1268 // Get the original SiteInstance for later comparison.
1269 scoped_refptr<SiteInstance> orig_site_instance(
1270 shell()->web_contents()->GetSiteInstance());
1272 // Open a same-site page in a new window.
1273 ShellAddedObserver new_shell_observer;
1274 bool success = false;
1275 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1276 shell()->web_contents(),
1277 "window.domAutomationController.send(openWindow());",
1278 &success));
1279 EXPECT_TRUE(success);
1280 Shell* new_shell = new_shell_observer.GetShell();
1282 // Wait for the navigation in the new window to finish, if it hasn't.
1283 WaitForLoadStop(new_shell->web_contents());
1284 EXPECT_EQ("/files/title1.html",
1285 new_shell->web_contents()->GetLastCommittedURL().path());
1287 // Should have the same SiteInstance.
1288 EXPECT_EQ(orig_site_instance.get(),
1289 new_shell->web_contents()->GetSiteInstance());
1291 // 2. Send the second tab to a different process.
1292 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1293 scoped_refptr<SiteInstance> new_site_instance(
1294 new_shell->web_contents()->GetSiteInstance());
1295 EXPECT_NE(orig_site_instance, new_site_instance);
1297 // 3. Send the first tab to the second tab's process.
1298 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1300 // Make sure it ends up at the right page.
1301 WaitForLoadStop(shell()->web_contents());
1302 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1303 shell()->web_contents()->GetLastCommittedURL());
1304 EXPECT_EQ(new_site_instance.get(),
1305 shell()->web_contents()->GetSiteInstance());
1308 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1309 // are meant to run in the current page. We had a bug where we expected a
1310 // BrowsingInstance swap to occur on pages like view-source and extensions,
1311 // which broke chrome://crash and javascript: URLs.
1312 // See http://crbug.com/335503.
1313 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1314 ASSERT_TRUE(test_server()->Start());
1316 GURL original_url(test_server()->GetURL("files/title2.html"));
1317 GURL view_source_url(kViewSourceScheme + std::string(":") +
1318 original_url.spec());
1320 NavigateToURL(shell(), view_source_url);
1322 // Check that javascript: URLs work.
1323 base::string16 expected_title = ASCIIToUTF16("msg");
1324 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1325 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1326 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1328 // Crash the renderer of the view-source page.
1329 RenderProcessHostWatcher crash_observer(
1330 shell()->web_contents(),
1331 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1332 EXPECT_TRUE(
1333 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1334 crash_observer.Wait();
1337 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1338 // Otherwise, we might try to load an unprivileged about:blank page into a
1339 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1340 // See http://crbug.com/334214.
1341 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1342 IgnoreRendererDebugURLsWhenCrashed) {
1343 // Visit a WebUI page with bindings.
1344 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1345 std::string(kChromeUIGpuHost));
1346 NavigateToURL(shell(), webui_url);
1347 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1348 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1350 // Crash the renderer of the WebUI page.
1351 RenderProcessHostWatcher crash_observer(
1352 shell()->web_contents(),
1353 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1354 EXPECT_TRUE(
1355 NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
1356 crash_observer.Wait();
1358 // Load the crash URL again but don't wait for any action. If it is not
1359 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1360 shell()->LoadURL(GURL(kChromeUICrashURL));
1362 // Ensure that such URLs can still work as the initial navigation of a tab.
1363 // We postpone the initial navigation of the tab using an empty GURL, so that
1364 // we can add a watcher for crashes.
1365 Shell* shell2 = Shell::CreateNewWindow(
1366 shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1367 MSG_ROUTING_NONE, gfx::Size());
1368 RenderProcessHostWatcher crash_observer2(
1369 shell2->web_contents(),
1370 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1371 EXPECT_TRUE(
1372 NavigateToURLAndExpectNoCommit(shell2, GURL(kChromeUIKillURL)));
1373 crash_observer2.Wait();
1376 // The test fails with Android ASAN with changes in v8 that seem unrelated.
1377 // See http://crbug.com/428329.
1378 #if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
1379 #define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
1380 #else
1381 #define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
1382 #endif
1383 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1384 // Otherwise it might get picked up by InitRenderView when granting bindings
1385 // to other RenderViewHosts. See http://crbug.com/330811.
1386 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1387 MAYBE_ClearPendingWebUIOnCommit) {
1388 // Visit a WebUI page with bindings.
1389 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1390 std::string(kChromeUIGpuHost)));
1391 NavigateToURL(shell(), webui_url);
1392 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1393 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1394 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1395 shell()->web_contents());
1396 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1397 EXPECT_TRUE(webui);
1398 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1400 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1401 // clear pending_web_ui() when it commits.
1402 GURL webui_url2(webui_url.spec() + "#foo");
1403 NavigateToURL(shell(), webui_url2);
1404 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1405 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1408 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1409 public:
1410 RFHMProcessPerTabTest() {}
1412 void SetUpCommandLine(CommandLine* command_line) override {
1413 command_line->AppendSwitch(switches::kProcessPerTab);
1417 // Test that we still swap processes for BrowsingInstance changes even in
1418 // --process-per-tab mode. See http://crbug.com/343017.
1419 // Disabled on Android: http://crbug.com/345873.
1420 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1421 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1422 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1423 #else
1424 #define MAYBE_BackFromWebUI BackFromWebUI
1425 #endif
1426 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1427 ASSERT_TRUE(test_server()->Start());
1428 GURL original_url(test_server()->GetURL("files/title2.html"));
1429 NavigateToURL(shell(), original_url);
1431 // Visit a WebUI page with bindings.
1432 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1433 std::string(kChromeUIGpuHost)));
1434 NavigateToURL(shell(), webui_url);
1435 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1436 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1438 // Go back and ensure we have no WebUI bindings.
1439 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1440 shell()->web_contents()->GetController().GoBack();
1441 back_nav_load_observer.Wait();
1442 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1443 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1444 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1447 // crbug.com/372360
1448 // The test loads url1, opens a link pointing to url2 in a new tab, and
1449 // navigates the new tab to url1.
1450 // The following is needed for the bug to happen:
1451 // - url1 must require webui bindings;
1452 // - navigating to url2 in the site instance of url1 should not swap
1453 // browsing instances, but should require a new site instance.
1454 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1455 GURL url1(std::string(kChromeUIScheme) + "://" +
1456 std::string(kChromeUIGpuHost));
1457 GURL url2(std::string(kChromeUIScheme) + "://" +
1458 std::string(kChromeUIAccessibilityHost));
1460 // Visit a WebUI page with bindings.
1461 NavigateToURL(shell(), url1);
1462 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1463 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1464 SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1466 // Open a new tab. Initially it gets a render view in the original tab's
1467 // current site instance.
1468 TestNavigationObserver nav_observer(NULL);
1469 nav_observer.StartWatchingNewWebContents();
1470 ShellAddedObserver shao;
1471 OpenUrlViaClickTarget(shell()->web_contents(), url2);
1472 nav_observer.Wait();
1473 Shell* new_shell = shao.GetShell();
1474 WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1475 new_shell->web_contents());
1476 SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1478 EXPECT_NE(site_instance2, site_instance1);
1479 EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1480 RenderViewHost* initial_rvh = new_web_contents->
1481 GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1482 ASSERT_TRUE(initial_rvh);
1483 // The following condition is what was causing the bug.
1484 EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1486 // Navigate to url1 and check bindings.
1487 NavigateToURL(new_shell, url1);
1488 // The navigation should have used the first SiteInstance, otherwise
1489 // |initial_rvh| did not have a chance to be used.
1490 EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1491 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1492 new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1495 // crbug.com/424526
1496 // The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
1497 // page and then to a regular page. The bug reproduces if blank page is visited
1498 // in between WebUI and regular page.
1499 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1500 ForceSwapAfterWebUIBindings) {
1501 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kProcessPerTab);
1502 ASSERT_TRUE(test_server()->Start());
1504 const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
1505 std::string(kChromeUIGpuHost));
1506 NavigateToURL(shell(), web_ui_url);
1507 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1508 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1510 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1512 GURL regular_page_url(test_server()->GetURL("files/title2.html"));
1513 NavigateToURL(shell(), regular_page_url);
1514 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1515 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1518 class FileChooserDelegate : public WebContentsDelegate {
1519 public:
1520 FileChooserDelegate(const base::FilePath& file)
1521 : file_(file), file_chosen_(false) {}
1523 void RunFileChooser(WebContents* web_contents,
1524 const FileChooserParams& params) override {
1525 // Send the selected file to the renderer process.
1526 FileChooserFileInfo file_info;
1527 file_info.file_path = file_;
1528 std::vector<FileChooserFileInfo> files;
1529 files.push_back(file_info);
1530 web_contents->GetRenderViewHost()->FilesSelectedInChooser(
1531 files, FileChooserParams::Open);
1533 file_chosen_ = true;
1536 bool file_chosen() { return file_chosen_; }
1538 private:
1539 base::FilePath file_;
1540 bool file_chosen_;
1543 // Test for http://crbug.com/262948.
1544 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1545 RestoreFileAccessForHistoryNavigation) {
1546 StartServer();
1547 base::FilePath file_path;
1548 EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path));
1549 file_path = file_path.AppendASCII("bar");
1551 // Navigate to url and get it to reference a file in its PageState.
1552 GURL url1(test_server()->GetURL("files/file_input.html"));
1553 NavigateToURL(shell(), url1);
1554 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
1555 scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file_path));
1556 shell()->web_contents()->SetDelegate(delegate.get());
1557 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1558 "document.getElementById('fileinput').click();"));
1559 EXPECT_TRUE(delegate->file_chosen());
1560 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1561 process_id, file_path));
1563 // Navigate to a different process without access to the file, and wait for
1564 // the old process to exit.
1565 RenderProcessHostWatcher exit_observer(
1566 shell()->web_contents()->GetRenderProcessHost(),
1567 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
1568 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1569 exit_observer.Wait();
1570 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1571 shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path));
1573 // Ensure that the file ended up in the PageState of the previous entry.
1574 NavigationEntry* prev_entry =
1575 shell()->web_contents()->GetController().GetEntryAtIndex(0);
1576 EXPECT_EQ(url1, prev_entry->GetURL());
1577 const std::vector<base::FilePath>& file_paths =
1578 prev_entry->GetPageState().GetReferencedFiles();
1579 ASSERT_EQ(1U, file_paths.size());
1580 EXPECT_EQ(file_path, file_paths.at(0));
1582 // Go back, ending up in a different RenderProcessHost than before.
1583 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1584 shell()->web_contents()->GetController().GoBack();
1585 back_nav_load_observer.Wait();
1586 EXPECT_NE(process_id,
1587 shell()->web_contents()->GetRenderProcessHost()->GetID());
1589 // Ensure that the file access still exists in the new process ID.
1590 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
1591 shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path));
1593 // Navigate to a same site page to trigger a PageState update and ensure the
1594 // renderer is not killed.
1595 EXPECT_TRUE(
1596 NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
1599 } // namespace content