Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / frame_host / render_frame_host_manager_browsertest.cc
blobcb1901fc87a78a3a24f6cfcbbaba005df3f31170
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/content_switches.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/content_browser_test.h"
28 #include "content/public/test/content_browser_test_utils.h"
29 #include "content/public/test/test_navigation_observer.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "net/base/net_util.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "net/test/spawned_test_server/spawned_test_server.h"
36 using base::ASCIIToUTF16;
38 namespace content {
40 class RenderFrameHostManagerTest : public ContentBrowserTest {
41 public:
42 RenderFrameHostManagerTest() : foo_com_("foo.com") {
43 replace_host_.SetHostStr(foo_com_);
46 static bool GetFilePathWithHostAndPortReplacement(
47 const std::string& original_file_path,
48 const net::HostPortPair& host_port_pair,
49 std::string* replacement_path) {
50 std::vector<net::SpawnedTestServer::StringPair> replacement_text;
51 replacement_text.push_back(
52 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
53 return net::SpawnedTestServer::GetFilePathWithReplacements(
54 original_file_path, replacement_text, replacement_path);
57 void StartServer() {
58 // Support multiple sites on the test server.
59 host_resolver()->AddRule("*", "127.0.0.1");
60 ASSERT_TRUE(test_server()->Start());
62 foo_host_port_ = test_server()->host_port_pair();
63 foo_host_port_.set_host(foo_com_);
66 // Returns a URL on foo.com with the given path.
67 GURL GetCrossSiteURL(const std::string& path) {
68 GURL cross_site_url(test_server()->GetURL(path));
69 return cross_site_url.ReplaceComponents(replace_host_);
72 protected:
73 std::string foo_com_;
74 GURL::Replacements replace_host_;
75 net::HostPortPair foo_host_port_;
78 // Web pages should not have script access to the swapped out page.
79 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
80 StartServer();
82 // Load a page with links that open in a new window.
83 std::string replacement_path;
84 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
85 "files/click-noreferrer-links.html",
86 foo_host_port_,
87 &replacement_path));
88 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
90 // Get the original SiteInstance for later comparison.
91 scoped_refptr<SiteInstance> orig_site_instance(
92 shell()->web_contents()->GetSiteInstance());
93 EXPECT_TRUE(orig_site_instance.get() != NULL);
95 // Open a same-site link in a new window.
96 ShellAddedObserver new_shell_observer;
97 bool success = false;
98 EXPECT_TRUE(ExecuteScriptAndExtractBool(
99 shell()->web_contents(),
100 "window.domAutomationController.send(clickSameSiteTargetedLink());",
101 &success));
102 EXPECT_TRUE(success);
103 Shell* new_shell = new_shell_observer.GetShell();
105 // Wait for the navigation in the new window to finish, if it hasn't.
106 WaitForLoadStop(new_shell->web_contents());
107 EXPECT_EQ("/files/navigate_opener.html",
108 new_shell->web_contents()->GetLastCommittedURL().path());
110 // Should have the same SiteInstance.
111 scoped_refptr<SiteInstance> blank_site_instance(
112 new_shell->web_contents()->GetSiteInstance());
113 EXPECT_EQ(orig_site_instance, blank_site_instance);
115 // We should have access to the opened window's location.
116 success = false;
117 EXPECT_TRUE(ExecuteScriptAndExtractBool(
118 shell()->web_contents(),
119 "window.domAutomationController.send(testScriptAccessToWindow());",
120 &success));
121 EXPECT_TRUE(success);
123 // Now navigate the new window to a different site.
124 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
125 scoped_refptr<SiteInstance> new_site_instance(
126 new_shell->web_contents()->GetSiteInstance());
127 EXPECT_NE(orig_site_instance, new_site_instance);
129 // We should no longer have script access to the opened window's location.
130 success = false;
131 EXPECT_TRUE(ExecuteScriptAndExtractBool(
132 shell()->web_contents(),
133 "window.domAutomationController.send(testScriptAccessToWindow());",
134 &success));
135 EXPECT_FALSE(success);
138 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
139 // and target=_blank should create a new SiteInstance.
140 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
141 SwapProcessWithRelNoreferrerAndTargetBlank) {
142 StartServer();
144 // Load a page with links that open in a new window.
145 std::string replacement_path;
146 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
147 "files/click-noreferrer-links.html",
148 foo_host_port_,
149 &replacement_path));
150 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
152 // Get the original SiteInstance for later comparison.
153 scoped_refptr<SiteInstance> orig_site_instance(
154 shell()->web_contents()->GetSiteInstance());
155 EXPECT_TRUE(orig_site_instance.get() != NULL);
157 // Test clicking a rel=noreferrer + target=blank link.
158 ShellAddedObserver new_shell_observer;
159 bool success = false;
160 EXPECT_TRUE(ExecuteScriptAndExtractBool(
161 shell()->web_contents(),
162 "window.domAutomationController.send(clickNoRefTargetBlankLink());",
163 &success));
164 EXPECT_TRUE(success);
166 // Wait for the window to open.
167 Shell* new_shell = new_shell_observer.GetShell();
169 EXPECT_EQ("/files/title2.html",
170 new_shell->web_contents()->GetVisibleURL().path());
172 // Wait for the cross-site transition in the new tab to finish.
173 WaitForLoadStop(new_shell->web_contents());
174 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
175 new_shell->web_contents());
176 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
177 pending_render_view_host());
179 // Should have a new SiteInstance.
180 scoped_refptr<SiteInstance> noref_blank_site_instance(
181 new_shell->web_contents()->GetSiteInstance());
182 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
185 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
186 // for rel=noreferrer links in new windows, even to same site pages and named
187 // targets.
188 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
189 SwapProcessWithSameSiteRelNoreferrer) {
190 StartServer();
192 // Load a page with links that open in a new window.
193 std::string replacement_path;
194 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
195 "files/click-noreferrer-links.html",
196 foo_host_port_,
197 &replacement_path));
198 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
200 // Get the original SiteInstance for later comparison.
201 scoped_refptr<SiteInstance> orig_site_instance(
202 shell()->web_contents()->GetSiteInstance());
203 EXPECT_TRUE(orig_site_instance.get() != NULL);
205 // Test clicking a same-site rel=noreferrer + target=foo link.
206 ShellAddedObserver new_shell_observer;
207 bool success = false;
208 EXPECT_TRUE(ExecuteScriptAndExtractBool(
209 shell()->web_contents(),
210 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
211 &success));
212 EXPECT_TRUE(success);
214 // Wait for the window to open.
215 Shell* new_shell = new_shell_observer.GetShell();
217 // Opens in new window.
218 EXPECT_EQ("/files/title2.html",
219 new_shell->web_contents()->GetVisibleURL().path());
221 // Wait for the cross-site transition in the new tab to finish.
222 WaitForLoadStop(new_shell->web_contents());
223 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
224 new_shell->web_contents());
225 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
226 pending_render_view_host());
228 // Should have a new SiteInstance (in a new BrowsingInstance).
229 scoped_refptr<SiteInstance> noref_blank_site_instance(
230 new_shell->web_contents()->GetSiteInstance());
231 EXPECT_NE(orig_site_instance, noref_blank_site_instance);
234 // Test for crbug.com/24447. Following a cross-site link with just
235 // target=_blank should not create a new SiteInstance.
236 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
237 DontSwapProcessWithOnlyTargetBlank) {
238 StartServer();
240 // Load a page with links that open in a new window.
241 std::string replacement_path;
242 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
243 "files/click-noreferrer-links.html",
244 foo_host_port_,
245 &replacement_path));
246 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
248 // Get the original SiteInstance for later comparison.
249 scoped_refptr<SiteInstance> orig_site_instance(
250 shell()->web_contents()->GetSiteInstance());
251 EXPECT_TRUE(orig_site_instance.get() != NULL);
253 // Test clicking a target=blank link.
254 ShellAddedObserver new_shell_observer;
255 bool success = false;
256 EXPECT_TRUE(ExecuteScriptAndExtractBool(
257 shell()->web_contents(),
258 "window.domAutomationController.send(clickTargetBlankLink());",
259 &success));
260 EXPECT_TRUE(success);
262 // Wait for the window to open.
263 Shell* new_shell = new_shell_observer.GetShell();
265 // Wait for the cross-site transition in the new tab to finish.
266 WaitForLoadStop(new_shell->web_contents());
267 EXPECT_EQ("/files/title2.html",
268 new_shell->web_contents()->GetLastCommittedURL().path());
270 // Should have the same SiteInstance.
271 scoped_refptr<SiteInstance> blank_site_instance(
272 new_shell->web_contents()->GetSiteInstance());
273 EXPECT_EQ(orig_site_instance, blank_site_instance);
276 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
277 // and no target=_blank should not create a new SiteInstance.
278 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
279 DontSwapProcessWithOnlyRelNoreferrer) {
280 StartServer();
282 // Load a page with links that open in a new window.
283 std::string replacement_path;
284 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
285 "files/click-noreferrer-links.html",
286 foo_host_port_,
287 &replacement_path));
288 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
290 // Get the original SiteInstance for later comparison.
291 scoped_refptr<SiteInstance> orig_site_instance(
292 shell()->web_contents()->GetSiteInstance());
293 EXPECT_TRUE(orig_site_instance.get() != NULL);
295 // Test clicking a rel=noreferrer link.
296 bool success = false;
297 EXPECT_TRUE(ExecuteScriptAndExtractBool(
298 shell()->web_contents(),
299 "window.domAutomationController.send(clickNoRefLink());",
300 &success));
301 EXPECT_TRUE(success);
303 // Wait for the cross-site transition in the current tab to finish.
304 WaitForLoadStop(shell()->web_contents());
306 // Opens in same window.
307 EXPECT_EQ(1u, Shell::windows().size());
308 EXPECT_EQ("/files/title2.html",
309 shell()->web_contents()->GetLastCommittedURL().path());
311 // Should have the same SiteInstance.
312 scoped_refptr<SiteInstance> noref_site_instance(
313 shell()->web_contents()->GetSiteInstance());
314 EXPECT_EQ(orig_site_instance, noref_site_instance);
317 // Test for crbug.com/116192. Targeted links should still work after the
318 // named target window has swapped processes.
319 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
320 AllowTargetedNavigationsAfterSwap) {
321 StartServer();
323 // Load a page with links that open in a new window.
324 std::string replacement_path;
325 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
326 "files/click-noreferrer-links.html",
327 foo_host_port_,
328 &replacement_path));
329 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
331 // Get the original SiteInstance for later comparison.
332 scoped_refptr<SiteInstance> orig_site_instance(
333 shell()->web_contents()->GetSiteInstance());
334 EXPECT_TRUE(orig_site_instance.get() != NULL);
336 // Test clicking a target=foo link.
337 ShellAddedObserver new_shell_observer;
338 bool success = false;
339 EXPECT_TRUE(ExecuteScriptAndExtractBool(
340 shell()->web_contents(),
341 "window.domAutomationController.send(clickSameSiteTargetedLink());",
342 &success));
343 EXPECT_TRUE(success);
344 Shell* new_shell = new_shell_observer.GetShell();
346 // Wait for the navigation in the new tab to finish, if it hasn't.
347 WaitForLoadStop(new_shell->web_contents());
348 EXPECT_EQ("/files/navigate_opener.html",
349 new_shell->web_contents()->GetLastCommittedURL().path());
351 // Should have the same SiteInstance.
352 scoped_refptr<SiteInstance> blank_site_instance(
353 new_shell->web_contents()->GetSiteInstance());
354 EXPECT_EQ(orig_site_instance, blank_site_instance);
356 // Now navigate the new tab to a different site.
357 GURL cross_site_url(GetCrossSiteURL("files/title1.html"));
358 NavigateToURL(new_shell, cross_site_url);
359 scoped_refptr<SiteInstance> new_site_instance(
360 new_shell->web_contents()->GetSiteInstance());
361 EXPECT_NE(orig_site_instance, new_site_instance);
363 // Clicking the original link in the first tab should cause us to swap back.
364 TestNavigationObserver navigation_observer(new_shell->web_contents());
365 EXPECT_TRUE(ExecuteScriptAndExtractBool(
366 shell()->web_contents(),
367 "window.domAutomationController.send(clickSameSiteTargetedLink());",
368 &success));
369 EXPECT_TRUE(success);
370 navigation_observer.Wait();
372 // Should have swapped back and shown the new window again.
373 scoped_refptr<SiteInstance> revisit_site_instance(
374 new_shell->web_contents()->GetSiteInstance());
375 EXPECT_EQ(orig_site_instance, revisit_site_instance);
377 // If it navigates away to another process, the original window should
378 // still be able to close it (using a cross-process close message).
379 NavigateToURL(new_shell, cross_site_url);
380 EXPECT_EQ(new_site_instance,
381 new_shell->web_contents()->GetSiteInstance());
382 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
383 EXPECT_TRUE(ExecuteScriptAndExtractBool(
384 shell()->web_contents(),
385 "window.domAutomationController.send(testCloseWindow());",
386 &success));
387 EXPECT_TRUE(success);
388 close_watcher.Wait();
391 // Test that setting the opener to null in a window affects cross-process
392 // navigations, including those to existing entries. http://crbug.com/156669.
393 // Flaky on windows: http://crbug.com/291249
394 // This test also crashes under ThreadSanitizer, http://crbug.com/356758.
395 #if defined(OS_WIN) || defined(THREAD_SANITIZER)
396 #define MAYBE_DisownOpener DISABLED_DisownOpener
397 #else
398 #define MAYBE_DisownOpener DisownOpener
399 #endif
400 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
401 StartServer();
403 // Load a page with links that open in a new window.
404 std::string replacement_path;
405 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
406 "files/click-noreferrer-links.html",
407 foo_host_port_,
408 &replacement_path));
409 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
411 // Get the original SiteInstance for later comparison.
412 scoped_refptr<SiteInstance> orig_site_instance(
413 shell()->web_contents()->GetSiteInstance());
414 EXPECT_TRUE(orig_site_instance.get() != NULL);
416 // Test clicking a target=_blank link.
417 ShellAddedObserver new_shell_observer;
418 bool success = false;
419 EXPECT_TRUE(ExecuteScriptAndExtractBool(
420 shell()->web_contents(),
421 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
422 &success));
423 EXPECT_TRUE(success);
424 Shell* new_shell = new_shell_observer.GetShell();
426 // Wait for the navigation in the new tab to finish, if it hasn't.
427 WaitForLoadStop(new_shell->web_contents());
428 EXPECT_EQ("/files/title2.html",
429 new_shell->web_contents()->GetLastCommittedURL().path());
431 // Should have the same SiteInstance.
432 scoped_refptr<SiteInstance> blank_site_instance(
433 new_shell->web_contents()->GetSiteInstance());
434 EXPECT_EQ(orig_site_instance, blank_site_instance);
436 // Now navigate the new tab to a different site.
437 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
438 scoped_refptr<SiteInstance> new_site_instance(
439 new_shell->web_contents()->GetSiteInstance());
440 EXPECT_NE(orig_site_instance, new_site_instance);
442 // Now disown the opener.
443 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
444 "window.opener = null;"));
446 // Go back and ensure the opener is still null.
448 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
449 new_shell->web_contents()->GetController().GoBack();
450 back_nav_load_observer.Wait();
452 success = false;
453 EXPECT_TRUE(ExecuteScriptAndExtractBool(
454 new_shell->web_contents(),
455 "window.domAutomationController.send(window.opener == null);",
456 &success));
457 EXPECT_TRUE(success);
459 // Now navigate forward again (creating a new process) and check opener.
460 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
461 success = false;
462 EXPECT_TRUE(ExecuteScriptAndExtractBool(
463 new_shell->web_contents(),
464 "window.domAutomationController.send(window.opener == null);",
465 &success));
466 EXPECT_TRUE(success);
469 // Test that subframes can disown their openers. http://crbug.com/225528.
470 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
471 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
472 NavigateToURL(shell(), frame_url);
474 // Give the frame an opener using window.open.
475 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
476 "window.open('about:blank','foo');"));
478 // Now disown the frame's opener. Shouldn't crash.
479 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
480 "window.frames[0].opener = null;"));
483 // Test for crbug.com/99202. PostMessage calls should still work after
484 // navigating the source and target windows to different sites.
485 // Specifically:
486 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
487 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
488 // 3) Post a message from "foo" to opener, which replies back to "foo".
489 // 4) Post a message from _blank to "foo".
490 // 5) Post a message from "foo" to a subframe of opener, which replies back.
491 // 6) Post a message from _blank to a subframe of "foo".
492 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
493 SupportCrossProcessPostMessage) {
494 StartServer();
496 // Load a page with links that open in a new window.
497 std::string replacement_path;
498 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
499 "files/click-noreferrer-links.html",
500 foo_host_port_,
501 &replacement_path));
502 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
504 // Get the original SiteInstance and RVHM for later comparison.
505 WebContents* opener_contents = shell()->web_contents();
506 scoped_refptr<SiteInstance> orig_site_instance(
507 opener_contents->GetSiteInstance());
508 EXPECT_TRUE(orig_site_instance.get() != NULL);
509 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
510 opener_contents)->GetRenderManagerForTesting();
512 // 1) Open two more windows, one named. These initially have openers but no
513 // reference to each other. We will later post a message between them.
515 // First, a named target=foo window.
516 ShellAddedObserver new_shell_observer;
517 bool success = false;
518 EXPECT_TRUE(ExecuteScriptAndExtractBool(
519 opener_contents,
520 "window.domAutomationController.send(clickSameSiteTargetedLink());",
521 &success));
522 EXPECT_TRUE(success);
523 Shell* new_shell = new_shell_observer.GetShell();
525 // Wait for the navigation in the new window to finish, if it hasn't, then
526 // send it to post_message.html on a different site.
527 WebContents* foo_contents = new_shell->web_contents();
528 WaitForLoadStop(foo_contents);
529 EXPECT_EQ("/files/navigate_opener.html",
530 foo_contents->GetLastCommittedURL().path());
531 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
532 scoped_refptr<SiteInstance> foo_site_instance(
533 foo_contents->GetSiteInstance());
534 EXPECT_NE(orig_site_instance, foo_site_instance);
536 // Second, a target=_blank window.
537 ShellAddedObserver new_shell_observer2;
538 EXPECT_TRUE(ExecuteScriptAndExtractBool(
539 shell()->web_contents(),
540 "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
541 &success));
542 EXPECT_TRUE(success);
544 // Wait for the navigation in the new window to finish, if it hasn't, then
545 // send it to post_message.html on the original site.
546 Shell* new_shell2 = new_shell_observer2.GetShell();
547 WebContents* new_contents = new_shell2->web_contents();
548 WaitForLoadStop(new_contents);
549 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
550 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
551 EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance());
552 RenderFrameHostManager* new_manager =
553 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
555 // We now have three windows. The opener should have a swapped out RVH
556 // for the new SiteInstance, but the _blank window should not.
557 EXPECT_EQ(3u, Shell::windows().size());
558 EXPECT_TRUE(
559 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
560 EXPECT_FALSE(
561 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
563 // 2) Fail to post a message from the foo window to the opener if the target
564 // origin is wrong. We won't see an error, but we can check for the right
565 // number of received messages below.
566 EXPECT_TRUE(ExecuteScriptAndExtractBool(
567 foo_contents,
568 "window.domAutomationController.send(postToOpener('msg',"
569 " 'http://google.com'));",
570 &success));
571 EXPECT_TRUE(success);
572 ASSERT_FALSE(
573 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
575 // 3) Post a message from the foo window to the opener. The opener will
576 // reply, causing the foo window to update its own title.
577 base::string16 expected_title = ASCIIToUTF16("msg");
578 TitleWatcher title_watcher(foo_contents, expected_title);
579 EXPECT_TRUE(ExecuteScriptAndExtractBool(
580 foo_contents,
581 "window.domAutomationController.send(postToOpener('msg','*'));",
582 &success));
583 EXPECT_TRUE(success);
584 ASSERT_FALSE(
585 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
586 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
588 // We should have received only 1 message in the opener and "foo" tabs,
589 // and updated the title.
590 int opener_received_messages = 0;
591 EXPECT_TRUE(ExecuteScriptAndExtractInt(
592 opener_contents,
593 "window.domAutomationController.send(window.receivedMessages);",
594 &opener_received_messages));
595 int foo_received_messages = 0;
596 EXPECT_TRUE(ExecuteScriptAndExtractInt(
597 foo_contents,
598 "window.domAutomationController.send(window.receivedMessages);",
599 &foo_received_messages));
600 EXPECT_EQ(1, foo_received_messages);
601 EXPECT_EQ(1, opener_received_messages);
602 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
604 // 4) Now post a message from the _blank window to the foo window. The
605 // foo window will update its title and will not reply.
606 expected_title = ASCIIToUTF16("msg2");
607 TitleWatcher title_watcher2(foo_contents, expected_title);
608 EXPECT_TRUE(ExecuteScriptAndExtractBool(
609 new_contents,
610 "window.domAutomationController.send(postToFoo('msg2'));",
611 &success));
612 EXPECT_TRUE(success);
613 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
615 // This postMessage should have created a swapped out RVH for the new
616 // SiteInstance in the target=_blank window.
617 EXPECT_TRUE(
618 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
620 // TODO(nasko): Test subframe targeting of postMessage once
621 // http://crbug.com/153701 is fixed.
624 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
625 // messages which contain Transferables and get intercepted by
626 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
627 // swapped out) should work.
628 // Specifically:
629 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
630 // 2) Post a message containing a message port from opener to "foo".
631 // 3) Post a message from "foo" back to opener via the passed message port.
632 // The test will be enabled when the feature implementation lands.
633 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
634 SupportCrossProcessPostMessageWithMessagePort) {
635 StartServer();
637 // Load a page with links that open in a new window.
638 std::string replacement_path;
639 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
640 "files/click-noreferrer-links.html",
641 foo_host_port_,
642 &replacement_path));
643 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
645 // Get the original SiteInstance and RVHM for later comparison.
646 WebContents* opener_contents = shell()->web_contents();
647 scoped_refptr<SiteInstance> orig_site_instance(
648 opener_contents->GetSiteInstance());
649 EXPECT_TRUE(orig_site_instance.get() != NULL);
650 RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
651 opener_contents)->GetRenderManagerForTesting();
653 // 1) Open a named target=foo window. We will later post a message between the
654 // opener and the new window.
655 ShellAddedObserver new_shell_observer;
656 bool success = false;
657 EXPECT_TRUE(ExecuteScriptAndExtractBool(
658 opener_contents,
659 "window.domAutomationController.send(clickSameSiteTargetedLink());",
660 &success));
661 EXPECT_TRUE(success);
662 Shell* new_shell = new_shell_observer.GetShell();
664 // Wait for the navigation in the new window to finish, if it hasn't, then
665 // send it to post_message.html on a different site.
666 WebContents* foo_contents = new_shell->web_contents();
667 WaitForLoadStop(foo_contents);
668 EXPECT_EQ("/files/navigate_opener.html",
669 foo_contents->GetLastCommittedURL().path());
670 NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
671 scoped_refptr<SiteInstance> foo_site_instance(
672 foo_contents->GetSiteInstance());
673 EXPECT_NE(orig_site_instance, foo_site_instance);
675 // We now have two windows. The opener should have a swapped out RVH
676 // for the new SiteInstance.
677 EXPECT_EQ(2u, Shell::windows().size());
678 EXPECT_TRUE(
679 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
681 // 2) Post a message containing a MessagePort from opener to the the foo
682 // window. The foo window will reply via the passed port, causing the opener
683 // to update its own title.
684 base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
685 TitleWatcher title_observer(opener_contents, expected_title);
686 EXPECT_TRUE(ExecuteScriptAndExtractBool(
687 opener_contents,
688 "window.domAutomationController.send(postWithPortToFoo());",
689 &success));
690 EXPECT_TRUE(success);
691 ASSERT_FALSE(
692 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
693 ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
695 // Check message counts.
696 int opener_received_messages_via_port = 0;
697 EXPECT_TRUE(ExecuteScriptAndExtractInt(
698 opener_contents,
699 "window.domAutomationController.send(window.receivedMessagesViaPort);",
700 &opener_received_messages_via_port));
701 int foo_received_messages = 0;
702 EXPECT_TRUE(ExecuteScriptAndExtractInt(
703 foo_contents,
704 "window.domAutomationController.send(window.receivedMessages);",
705 &foo_received_messages));
706 int foo_received_messages_with_port = 0;
707 EXPECT_TRUE(ExecuteScriptAndExtractInt(
708 foo_contents,
709 "window.domAutomationController.send(window.receivedMessagesWithPort);",
710 &foo_received_messages_with_port));
711 EXPECT_EQ(1, foo_received_messages);
712 EXPECT_EQ(1, foo_received_messages_with_port);
713 EXPECT_EQ(1, opener_received_messages_via_port);
714 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
715 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
718 // Test for crbug.com/116192. Navigations to a window's opener should
719 // still work after a process swap.
720 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
721 AllowTargetedNavigationsInOpenerAfterSwap) {
722 StartServer();
724 // Load a page with links that open in a new window.
725 std::string replacement_path;
726 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
727 "files/click-noreferrer-links.html",
728 foo_host_port_,
729 &replacement_path));
730 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
732 // Get the original tab and SiteInstance for later comparison.
733 WebContents* orig_contents = shell()->web_contents();
734 scoped_refptr<SiteInstance> orig_site_instance(
735 orig_contents->GetSiteInstance());
736 EXPECT_TRUE(orig_site_instance.get() != NULL);
738 // Test clicking a target=foo link.
739 ShellAddedObserver new_shell_observer;
740 bool success = false;
741 EXPECT_TRUE(ExecuteScriptAndExtractBool(
742 orig_contents,
743 "window.domAutomationController.send(clickSameSiteTargetedLink());",
744 &success));
745 EXPECT_TRUE(success);
746 Shell* new_shell = new_shell_observer.GetShell();
748 // Wait for the navigation in the new window to finish, if it hasn't.
749 WaitForLoadStop(new_shell->web_contents());
750 EXPECT_EQ("/files/navigate_opener.html",
751 new_shell->web_contents()->GetLastCommittedURL().path());
753 // Should have the same SiteInstance.
754 scoped_refptr<SiteInstance> blank_site_instance(
755 new_shell->web_contents()->GetSiteInstance());
756 EXPECT_EQ(orig_site_instance, blank_site_instance);
758 // Now navigate the original (opener) tab to a different site.
759 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
760 scoped_refptr<SiteInstance> new_site_instance(
761 shell()->web_contents()->GetSiteInstance());
762 EXPECT_NE(orig_site_instance, new_site_instance);
764 // The opened tab should be able to navigate the opener back to its process.
765 TestNavigationObserver navigation_observer(orig_contents);
766 EXPECT_TRUE(ExecuteScriptAndExtractBool(
767 new_shell->web_contents(),
768 "window.domAutomationController.send(navigateOpener());",
769 &success));
770 EXPECT_TRUE(success);
771 navigation_observer.Wait();
773 // Should have swapped back into this process.
774 scoped_refptr<SiteInstance> revisit_site_instance(
775 shell()->web_contents()->GetSiteInstance());
776 EXPECT_EQ(orig_site_instance, revisit_site_instance);
779 // Test that opening a new window in the same SiteInstance and then navigating
780 // both windows to a different SiteInstance allows the first process to exit.
781 // See http://crbug.com/126333.
782 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
783 ProcessExitWithSwappedOutViews) {
784 StartServer();
786 // Load a page with links that open in a new window.
787 std::string replacement_path;
788 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
789 "files/click-noreferrer-links.html",
790 foo_host_port_,
791 &replacement_path));
792 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
794 // Get the original SiteInstance for later comparison.
795 scoped_refptr<SiteInstance> orig_site_instance(
796 shell()->web_contents()->GetSiteInstance());
797 EXPECT_TRUE(orig_site_instance.get() != NULL);
799 // Test clicking a target=foo link.
800 ShellAddedObserver new_shell_observer;
801 bool success = false;
802 EXPECT_TRUE(ExecuteScriptAndExtractBool(
803 shell()->web_contents(),
804 "window.domAutomationController.send(clickSameSiteTargetedLink());",
805 &success));
806 EXPECT_TRUE(success);
807 Shell* new_shell = new_shell_observer.GetShell();
809 // Wait for the navigation in the new window to finish, if it hasn't.
810 WaitForLoadStop(new_shell->web_contents());
811 EXPECT_EQ("/files/navigate_opener.html",
812 new_shell->web_contents()->GetLastCommittedURL().path());
814 // Should have the same SiteInstance.
815 scoped_refptr<SiteInstance> opened_site_instance(
816 new_shell->web_contents()->GetSiteInstance());
817 EXPECT_EQ(orig_site_instance, opened_site_instance);
819 // Now navigate the opened window to a different site.
820 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
821 scoped_refptr<SiteInstance> new_site_instance(
822 new_shell->web_contents()->GetSiteInstance());
823 EXPECT_NE(orig_site_instance, new_site_instance);
825 // The original process should still be alive, since it is still used in the
826 // first window.
827 RenderProcessHost* orig_process = orig_site_instance->GetProcess();
828 EXPECT_TRUE(orig_process->HasConnection());
830 // Navigate the first window to a different site as well. The original
831 // process should exit, since all of its views are now swapped out.
832 RenderProcessHostWatcher exit_observer(
833 orig_process,
834 RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
835 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
836 exit_observer.Wait();
837 scoped_refptr<SiteInstance> new_site_instance2(
838 shell()->web_contents()->GetSiteInstance());
839 EXPECT_EQ(new_site_instance, new_site_instance2);
842 // Test for crbug.com/76666. A cross-site navigation that fails with a 204
843 // error should not make us ignore future renderer-initiated navigations.
844 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
845 StartServer();
847 // Load a page with links that open in a new window.
848 // The links will point to foo.com.
849 std::string replacement_path;
850 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
851 "files/click-noreferrer-links.html",
852 foo_host_port_,
853 &replacement_path));
854 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
856 // Get the original SiteInstance for later comparison.
857 scoped_refptr<SiteInstance> orig_site_instance(
858 shell()->web_contents()->GetSiteInstance());
859 EXPECT_TRUE(orig_site_instance.get() != NULL);
861 // Load a cross-site page that fails with a 204 error.
862 NavigateToURL(shell(),GetCrossSiteURL("nocontent"));
864 // We should still be looking at the normal page. The typed URL will
865 // still be visible until the user clears it manually, but the last
866 // committed URL will be the previous page.
867 scoped_refptr<SiteInstance> post_nav_site_instance(
868 shell()->web_contents()->GetSiteInstance());
869 EXPECT_EQ(orig_site_instance, post_nav_site_instance);
870 EXPECT_EQ("/nocontent",
871 shell()->web_contents()->GetVisibleURL().path());
872 EXPECT_EQ("/files/click-noreferrer-links.html",
873 shell()->web_contents()->GetController().
874 GetLastCommittedEntry()->GetVirtualURL().path());
876 // Renderer-initiated navigations should work.
877 bool success = false;
878 EXPECT_TRUE(ExecuteScriptAndExtractBool(
879 shell()->web_contents(),
880 "window.domAutomationController.send(clickNoRefLink());",
881 &success));
882 EXPECT_TRUE(success);
884 // Wait for the cross-site transition in the current tab to finish.
885 WaitForLoadStop(shell()->web_contents());
887 // Opens in same tab.
888 EXPECT_EQ(1u, Shell::windows().size());
889 EXPECT_EQ("/files/title2.html",
890 shell()->web_contents()->GetLastCommittedURL().path());
892 // Should have the same SiteInstance.
893 scoped_refptr<SiteInstance> noref_site_instance(
894 shell()->web_contents()->GetSiteInstance());
895 EXPECT_EQ(orig_site_instance, noref_site_instance);
898 // Test for crbug.com/9682. We should show the URL for a pending renderer-
899 // initiated navigation in a new tab, until the content of the initial
900 // about:blank page is modified by another window. At that point, we should
901 // revert to showing about:blank to prevent a URL spoof.
902 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
903 ASSERT_TRUE(test_server()->Start());
905 // Load a page that can open a URL that won't commit in a new window.
906 NavigateToURL(
907 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
908 WebContents* orig_contents = shell()->web_contents();
910 // Click a /nocontent link that opens in a new window but never commits.
911 ShellAddedObserver new_shell_observer;
912 bool success = false;
913 EXPECT_TRUE(ExecuteScriptAndExtractBool(
914 orig_contents,
915 "window.domAutomationController.send(clickNoContentTargetedLink());",
916 &success));
917 EXPECT_TRUE(success);
919 // Wait for the window to open.
920 Shell* new_shell = new_shell_observer.GetShell();
922 // Ensure the destination URL is visible, because it is considered the
923 // initial navigation.
924 WebContents* contents = new_shell->web_contents();
925 EXPECT_TRUE(contents->GetController().IsInitialNavigation());
926 EXPECT_EQ("/nocontent",
927 contents->GetController().GetVisibleEntry()->GetURL().path());
929 // Now modify the contents of the new window from the opener. This will also
930 // modify the title of the document to give us something to listen for.
931 base::string16 expected_title = ASCIIToUTF16("Modified Title");
932 TitleWatcher title_watcher(contents, expected_title);
933 success = false;
934 EXPECT_TRUE(ExecuteScriptAndExtractBool(
935 orig_contents,
936 "window.domAutomationController.send(modifyNewWindow());",
937 &success));
938 EXPECT_TRUE(success);
939 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
941 // At this point, we should no longer be showing the destination URL.
942 // The visible entry should be null, resulting in about:blank in the address
943 // bar.
944 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
947 // Test for crbug.com/9682. We should not show the URL for a pending renderer-
948 // initiated navigation in a new tab if it is not the initial navigation. In
949 // this case, the renderer will not notify us of a modification, so we cannot
950 // show the pending URL without allowing a spoof.
951 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
952 DontShowLoadingURLIfNotInitialNav) {
953 ASSERT_TRUE(test_server()->Start());
955 // Load a page that can open a URL that won't commit in a new window.
956 NavigateToURL(
957 shell(), test_server()->GetURL("files/click-nocontent-link.html"));
958 WebContents* orig_contents = shell()->web_contents();
960 // Click a /nocontent link that opens in a new window but never commits.
961 // By using an onclick handler that first creates the window, the slow
962 // navigation is not considered an initial navigation.
963 ShellAddedObserver new_shell_observer;
964 bool success = false;
965 EXPECT_TRUE(ExecuteScriptAndExtractBool(
966 orig_contents,
967 "window.domAutomationController.send("
968 "clickNoContentScriptedTargetedLink());",
969 &success));
970 EXPECT_TRUE(success);
972 // Wait for the window to open.
973 Shell* new_shell = new_shell_observer.GetShell();
975 // Ensure the destination URL is not visible, because it is not the initial
976 // navigation.
977 WebContents* contents = new_shell->web_contents();
978 EXPECT_FALSE(contents->GetController().IsInitialNavigation());
979 EXPECT_FALSE(contents->GetController().GetVisibleEntry());
982 // Crashes under ThreadSanitizer, http://crbug.com/356758.
983 #if defined(THREAD_SANITIZER)
984 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
985 #else
986 #define MAYBE_BackForwardNotStale BackForwardNotStale
987 #endif
988 // Test for http://crbug.com/93427. Ensure that cross-site navigations
989 // do not cause back/forward navigations to be considered stale by the
990 // renderer.
991 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
992 StartServer();
993 NavigateToURL(shell(), GURL(kAboutBlankURL));
995 // Visit a page on first site.
996 NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
998 // Visit three pages on second site.
999 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1000 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1001 NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1003 // History is now [blank, A1, B1, B2, *B3].
1004 WebContents* contents = shell()->web_contents();
1005 EXPECT_EQ(5, contents->GetController().GetEntryCount());
1007 // Open another window in same process to keep this process alive.
1008 Shell* new_shell = CreateBrowser();
1009 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1011 // Go back three times to first site.
1013 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1014 shell()->web_contents()->GetController().GoBack();
1015 back_nav_load_observer.Wait();
1018 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1019 shell()->web_contents()->GetController().GoBack();
1020 back_nav_load_observer.Wait();
1023 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1024 shell()->web_contents()->GetController().GoBack();
1025 back_nav_load_observer.Wait();
1028 // Now go forward twice to B2. Shouldn't be left spinning.
1030 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1031 shell()->web_contents()->GetController().GoForward();
1032 forward_nav_load_observer.Wait();
1035 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1036 shell()->web_contents()->GetController().GoForward();
1037 forward_nav_load_observer.Wait();
1040 // Go back twice to first site.
1042 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1043 shell()->web_contents()->GetController().GoBack();
1044 back_nav_load_observer.Wait();
1047 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1048 shell()->web_contents()->GetController().GoBack();
1049 back_nav_load_observer.Wait();
1052 // Now go forward directly to B3. Shouldn't be left spinning.
1054 TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1055 shell()->web_contents()->GetController().GoToIndex(4);
1056 forward_nav_load_observer.Wait();
1060 // Test for http://crbug.com/130016.
1061 // Swapping out a render view should update its visiblity state.
1062 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1063 SwappedOutViewHasCorrectVisibilityState) {
1064 StartServer();
1066 // Load a page with links that open in a new window.
1067 std::string replacement_path;
1068 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1069 "files/click-noreferrer-links.html",
1070 foo_host_port_,
1071 &replacement_path));
1072 NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1074 // Open a same-site link in a new widnow.
1075 ShellAddedObserver new_shell_observer;
1076 bool success = false;
1077 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1078 shell()->web_contents(),
1079 "window.domAutomationController.send(clickSameSiteTargetedLink());",
1080 &success));
1081 EXPECT_TRUE(success);
1082 Shell* new_shell = new_shell_observer.GetShell();
1084 // Wait for the navigation in the new tab to finish, if it hasn't.
1085 WaitForLoadStop(new_shell->web_contents());
1086 EXPECT_EQ("/files/navigate_opener.html",
1087 new_shell->web_contents()->GetLastCommittedURL().path());
1089 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1091 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1092 rvh,
1093 "window.domAutomationController.send("
1094 " document.visibilityState == 'visible');",
1095 &success));
1096 EXPECT_TRUE(success);
1098 // Now navigate the new window to a different site. This should swap out the
1099 // tab's existing RenderView, causing it become hidden.
1100 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1102 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1103 rvh,
1104 "window.domAutomationController.send("
1105 " document.visibilityState == 'hidden');",
1106 &success));
1107 EXPECT_TRUE(success);
1109 // Going back should make the previously swapped-out view to become visible
1110 // again.
1112 TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1113 new_shell->web_contents()->GetController().GoBack();
1114 back_nav_load_observer.Wait();
1117 EXPECT_EQ("/files/navigate_opener.html",
1118 new_shell->web_contents()->GetLastCommittedURL().path());
1120 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1122 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1123 rvh,
1124 "window.domAutomationController.send("
1125 " document.visibilityState == 'visible');",
1126 &success));
1127 EXPECT_TRUE(success);
1130 // This class ensures that all the given RenderViewHosts have properly been
1131 // shutdown.
1132 class RenderViewHostDestructionObserver : public WebContentsObserver {
1133 public:
1134 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1135 : WebContentsObserver(web_contents) {}
1136 virtual ~RenderViewHostDestructionObserver() {}
1137 void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1138 watched_render_view_hosts_.insert(rvh);
1140 size_t GetNumberOfWatchedRenderViewHosts() const {
1141 return watched_render_view_hosts_.size();
1144 private:
1145 // WebContentsObserver implementation:
1146 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
1147 watched_render_view_hosts_.erase(rvh);
1150 std::set<RenderViewHost*> watched_render_view_hosts_;
1153 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1154 #if defined(THREAD_SANITIZER)
1155 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1156 #else
1157 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1158 #endif
1159 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1160 // they may cause crashes or memory corruptions when trying to call dead
1161 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1162 // ensure that a separate SiteInstance is created when navigating to view-source
1163 // URLs, regardless of current URL.
1164 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1165 MAYBE_LeakingRenderViewHosts) {
1166 StartServer();
1168 // Observe the created render_view_host's to make sure they will not leak.
1169 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1171 GURL navigated_url(test_server()->GetURL("files/title2.html"));
1172 GURL view_source_url(kViewSourceScheme + std::string(":") +
1173 navigated_url.spec());
1175 // Let's ensure that when we start with a blank window, navigating away to a
1176 // view-source URL, we create a new SiteInstance.
1177 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1178 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1179 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1180 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1181 rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1183 // Now navigate to the view-source URL and ensure we got a different
1184 // SiteInstance and RenderViewHost.
1185 NavigateToURL(shell(), view_source_url);
1186 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1187 EXPECT_NE(blank_site_instance, shell()->web_contents()->
1188 GetRenderViewHost()->GetSiteInstance());
1189 rvh_observers.EnsureRVHGetsDestructed(
1190 shell()->web_contents()->GetRenderViewHost());
1192 // Load a random page and then navigate to view-source: of it.
1193 // This used to cause two RVH instances for the same SiteInstance, which
1194 // was a problem. This is no longer the case.
1195 NavigateToURL(shell(), navigated_url);
1196 SiteInstance* site_instance1 = shell()->web_contents()->
1197 GetRenderViewHost()->GetSiteInstance();
1198 rvh_observers.EnsureRVHGetsDestructed(
1199 shell()->web_contents()->GetRenderViewHost());
1201 NavigateToURL(shell(), view_source_url);
1202 rvh_observers.EnsureRVHGetsDestructed(
1203 shell()->web_contents()->GetRenderViewHost());
1204 SiteInstance* site_instance2 = shell()->web_contents()->
1205 GetRenderViewHost()->GetSiteInstance();
1207 // Ensure that view-source navigations force a new SiteInstance.
1208 EXPECT_NE(site_instance1, site_instance2);
1210 // Now navigate to a different instance so that we swap out again.
1211 NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1212 rvh_observers.EnsureRVHGetsDestructed(
1213 shell()->web_contents()->GetRenderViewHost());
1215 // This used to leak a render view host.
1216 shell()->Close();
1218 RunAllPendingInMessageLoop(); // Needed on ChromeOS.
1220 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1223 // Test for crbug.com/143155. Frame tree updates during unload should not
1224 // interrupt the intended navigation and show swappedout:// instead.
1225 // Specifically:
1226 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1227 // 2) Send the second tab to a different foo.com SiteInstance.
1228 // This creates a swapped out opener for the first tab in the foo process.
1229 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1230 // tab's unload handler remove its frame.
1231 // This used to cause an update to the frame tree of the swapped out RV,
1232 // just as it was navigating to a real page. That pre-empted the real
1233 // navigation and visibly sent the tab to swappedout://.
1234 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1235 DontPreemptNavigationWithFrameTreeUpdate) {
1236 StartServer();
1238 // 1. Load a page that deletes its iframe during unload.
1239 NavigateToURL(shell(),
1240 test_server()->GetURL("files/remove_frame_on_unload.html"));
1242 // Get the original SiteInstance for later comparison.
1243 scoped_refptr<SiteInstance> orig_site_instance(
1244 shell()->web_contents()->GetSiteInstance());
1246 // Open a same-site page in a new window.
1247 ShellAddedObserver new_shell_observer;
1248 bool success = false;
1249 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1250 shell()->web_contents(),
1251 "window.domAutomationController.send(openWindow());",
1252 &success));
1253 EXPECT_TRUE(success);
1254 Shell* new_shell = new_shell_observer.GetShell();
1256 // Wait for the navigation in the new window to finish, if it hasn't.
1257 WaitForLoadStop(new_shell->web_contents());
1258 EXPECT_EQ("/files/title1.html",
1259 new_shell->web_contents()->GetLastCommittedURL().path());
1261 // Should have the same SiteInstance.
1262 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
1264 // 2. Send the second tab to a different process.
1265 NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1266 scoped_refptr<SiteInstance> new_site_instance(
1267 new_shell->web_contents()->GetSiteInstance());
1268 EXPECT_NE(orig_site_instance, new_site_instance);
1270 // 3. Send the first tab to the second tab's process.
1271 NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1273 // Make sure it ends up at the right page.
1274 WaitForLoadStop(shell()->web_contents());
1275 EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1276 shell()->web_contents()->GetLastCommittedURL());
1277 EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance());
1280 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1281 // are meant to run in the current page. We had a bug where we expected a
1282 // BrowsingInstance swap to occur on pages like view-source and extensions,
1283 // which broke chrome://crash and javascript: URLs.
1284 // See http://crbug.com/335503.
1285 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1286 ASSERT_TRUE(test_server()->Start());
1288 GURL original_url(test_server()->GetURL("files/title2.html"));
1289 GURL view_source_url(kViewSourceScheme + std::string(":") +
1290 original_url.spec());
1292 NavigateToURL(shell(), view_source_url);
1294 // Check that javascript: URLs work.
1295 base::string16 expected_title = ASCIIToUTF16("msg");
1296 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1297 shell()->LoadURL(GURL("javascript:document.title='msg'"));
1298 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1300 // Crash the renderer of the view-source page.
1301 RenderProcessHostWatcher crash_observer(
1302 shell()->web_contents(),
1303 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1304 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1305 crash_observer.Wait();
1308 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1309 // Otherwise, we might try to load an unprivileged about:blank page into a
1310 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1311 // See http://crbug.com/334214.
1312 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1313 IgnoreRendererDebugURLsWhenCrashed) {
1314 // Visit a WebUI page with bindings.
1315 GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1316 std::string(kChromeUIGpuHost));
1317 NavigateToURL(shell(), webui_url);
1318 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1319 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1321 // Crash the renderer of the WebUI page.
1322 RenderProcessHostWatcher crash_observer(
1323 shell()->web_contents(),
1324 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1325 NavigateToURL(shell(), GURL(kChromeUICrashURL));
1326 crash_observer.Wait();
1328 // Load the crash URL again but don't wait for any action. If it is not
1329 // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1330 shell()->LoadURL(GURL(kChromeUICrashURL));
1332 // Ensure that such URLs can still work as the initial navigation of a tab.
1333 // We postpone the initial navigation of the tab using an empty GURL, so that
1334 // we can add a watcher for crashes.
1335 Shell* shell2 = Shell::CreateNewWindow(
1336 shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1337 MSG_ROUTING_NONE, gfx::Size());
1338 RenderProcessHostWatcher crash_observer2(
1339 shell2->web_contents(),
1340 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1341 NavigateToURL(shell2, GURL(kChromeUIKillURL));
1342 crash_observer2.Wait();
1345 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1346 // Otherwise it might get picked up by InitRenderView when granting bindings
1347 // to other RenderViewHosts. See http://crbug.com/330811.
1348 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) {
1349 // Visit a WebUI page with bindings.
1350 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1351 std::string(kChromeUIGpuHost)));
1352 NavigateToURL(shell(), webui_url);
1353 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1354 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1355 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1356 shell()->web_contents());
1357 WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1358 EXPECT_TRUE(webui);
1359 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1361 // Navigate to another WebUI URL that reuses the WebUI object. Make sure we
1362 // clear pending_web_ui() when it commits.
1363 GURL webui_url2(webui_url.spec() + "#foo");
1364 NavigateToURL(shell(), webui_url2);
1365 EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1366 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1369 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1370 public:
1371 RFHMProcessPerTabTest() {}
1373 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1374 command_line->AppendSwitch(switches::kProcessPerTab);
1378 // Test that we still swap processes for BrowsingInstance changes even in
1379 // --process-per-tab mode. See http://crbug.com/343017.
1380 // Disabled on Android: http://crbug.com/345873.
1381 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1382 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1383 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1384 #else
1385 #define MAYBE_BackFromWebUI BackFromWebUI
1386 #endif
1387 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1388 ASSERT_TRUE(test_server()->Start());
1389 GURL original_url(test_server()->GetURL("files/title2.html"));
1390 NavigateToURL(shell(), original_url);
1392 // Visit a WebUI page with bindings.
1393 GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1394 std::string(kChromeUIGpuHost)));
1395 NavigateToURL(shell(), webui_url);
1396 EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1397 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1399 // Go back and ensure we have no WebUI bindings.
1400 TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1401 shell()->web_contents()->GetController().GoBack();
1402 back_nav_load_observer.Wait();
1403 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1404 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1405 shell()->web_contents()->GetRenderProcessHost()->GetID()));
1408 } // namespace content