Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / frame_host / render_frame_host_manager_browsertest.cc
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.
4
5 #include <set>
6
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"
35
36 using base::ASCIIToUTF16;
37
38 namespace content {
39
40 class RenderFrameHostManagerTest : public ContentBrowserTest {
41  public:
42   RenderFrameHostManagerTest() : foo_com_("foo.com") {
43     replace_host_.SetHostStr(foo_com_);
44   }
45
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);
55   }
56
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());
61
62     foo_host_port_ = test_server()->host_port_pair();
63     foo_host_port_.set_host(foo_com_);
64   }
65
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_);
70   }
71
72  protected:
73   std::string foo_com_;
74   GURL::Replacements replace_host_;
75   net::HostPortPair foo_host_port_;
76 };
77
78 // Web pages should not have script access to the swapped out page.
79 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, NoScriptAccessAfterSwapOut) {
80   StartServer();
81
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));
89
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);
94
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();
104
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());
109
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);
114
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);
122
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);
128
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);
136 }
137
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();
143
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));
151
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);
156
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);
165
166   // Wait for the window to open.
167   Shell* new_shell = new_shell_observer.GetShell();
168
169   EXPECT_EQ("/files/title2.html",
170             new_shell->web_contents()->GetVisibleURL().path());
171
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());
178
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);
183 }
184
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();
191
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));
199
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);
204
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);
213
214   // Wait for the window to open.
215   Shell* new_shell = new_shell_observer.GetShell();
216
217   // Opens in new window.
218   EXPECT_EQ("/files/title2.html",
219             new_shell->web_contents()->GetVisibleURL().path());
220
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());
227
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);
232 }
233
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();
239
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));
247
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);
252
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);
261
262   // Wait for the window to open.
263   Shell* new_shell = new_shell_observer.GetShell();
264
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());
269
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);
274 }
275
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();
281
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));
289
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);
294
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);
302
303   // Wait for the cross-site transition in the current tab to finish.
304   WaitForLoadStop(shell()->web_contents());
305
306   // Opens in same window.
307   EXPECT_EQ(1u, Shell::windows().size());
308   EXPECT_EQ("/files/title2.html",
309             shell()->web_contents()->GetLastCommittedURL().path());
310
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);
315 }
316
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();
322
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));
330
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);
335
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();
345
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());
350
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);
355
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);
362
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();
371
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);
376
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();
389 }
390
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();
402
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));
410
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);
415
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();
425
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());
430
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);
435
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);
441
442   // Now disown the opener.
443   EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
444                             "window.opener = null;"));
445
446   // Go back and ensure the opener is still null.
447   {
448     TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
449     new_shell->web_contents()->GetController().GoBack();
450     back_nav_load_observer.Wait();
451   }
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);
458
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);
467 }
468
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);
473
474   // Give the frame an opener using window.open.
475   EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
476                             "window.open('about:blank','foo');"));
477
478   // Now disown the frame's opener.  Shouldn't crash.
479   EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
480                             "window.frames[0].opener = null;"));
481 }
482
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();
495
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));
503
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();
511
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.
514
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();
524
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);
535
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);
543
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();
554
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()));
562
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()));
574
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());
587
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());
603
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());
614
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()));
619
620   // TODO(nasko): Test subframe targeting of postMessage once
621   // http://crbug.com/153701 is fixed.
622 }
623
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();
636
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));
644
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();
652
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();
663
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);
674
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()));
680
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());
694
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());
716 }
717
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();
723
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));
731
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);
737
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();
747
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());
752
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);
757
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);
763
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();
772
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);
777 }
778
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();
785
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));
793
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);
798
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();
808
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());
813
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);
818
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);
824
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());
829
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);
840 }
841
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();
846
847   // Get the original SiteInstance for later comparison.
848   scoped_refptr<SiteInstance> orig_site_instance(
849       shell()->web_contents()->GetSiteInstance());
850   EXPECT_TRUE(orig_site_instance.get() != NULL);
851
852   // Load a cross-site page that fails with a 204 error.
853   NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
854
855   // We should still be looking at the normal page.  Because we started from a
856   // blank new tab, the typed URL will still be visible until the user clears it
857   // manually.  The last committed URL will be the previous page.
858   scoped_refptr<SiteInstance> post_nav_site_instance(
859       shell()->web_contents()->GetSiteInstance());
860   EXPECT_EQ(orig_site_instance, post_nav_site_instance);
861   EXPECT_EQ("/nocontent",
862             shell()->web_contents()->GetVisibleURL().path());
863   EXPECT_FALSE(
864       shell()->web_contents()->GetController().GetLastCommittedEntry());
865
866   // Renderer-initiated navigations should work.
867   base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
868   TitleWatcher title_watcher(shell()->web_contents(), expected_title);
869   GURL url = test_server()->GetURL("files/title2.html");
870   EXPECT_TRUE(ExecuteScript(
871       shell()->web_contents(),
872       base::StringPrintf("location.href = '%s'", url.spec().c_str())));
873   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
874
875   // Opens in same tab.
876   EXPECT_EQ(1u, Shell::windows().size());
877   EXPECT_EQ("/files/title2.html",
878             shell()->web_contents()->GetLastCommittedURL().path());
879
880   // Should have the same SiteInstance.
881   scoped_refptr<SiteInstance> new_site_instance(
882       shell()->web_contents()->GetSiteInstance());
883   EXPECT_EQ(orig_site_instance, new_site_instance);
884 }
885
886 // Test for crbug.com/9682.  We should show the URL for a pending renderer-
887 // initiated navigation in a new tab, until the content of the initial
888 // about:blank page is modified by another window.  At that point, we should
889 // revert to showing about:blank to prevent a URL spoof.
890 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
891   ASSERT_TRUE(test_server()->Start());
892
893   // Load a page that can open a URL that won't commit in a new window.
894   NavigateToURL(
895       shell(), test_server()->GetURL("files/click-nocontent-link.html"));
896   WebContents* orig_contents = shell()->web_contents();
897
898   // Click a /nocontent link that opens in a new window but never commits.
899   ShellAddedObserver new_shell_observer;
900   bool success = false;
901   EXPECT_TRUE(ExecuteScriptAndExtractBool(
902       orig_contents,
903       "window.domAutomationController.send(clickNoContentTargetedLink());",
904       &success));
905   EXPECT_TRUE(success);
906
907   // Wait for the window to open.
908   Shell* new_shell = new_shell_observer.GetShell();
909
910   // Ensure the destination URL is visible, because it is considered the
911   // initial navigation.
912   WebContents* contents = new_shell->web_contents();
913   EXPECT_TRUE(contents->GetController().IsInitialNavigation());
914   EXPECT_EQ("/nocontent",
915             contents->GetController().GetVisibleEntry()->GetURL().path());
916
917   // Now modify the contents of the new window from the opener.  This will also
918   // modify the title of the document to give us something to listen for.
919   base::string16 expected_title = ASCIIToUTF16("Modified Title");
920   TitleWatcher title_watcher(contents, expected_title);
921   success = false;
922   EXPECT_TRUE(ExecuteScriptAndExtractBool(
923       orig_contents,
924       "window.domAutomationController.send(modifyNewWindow());",
925       &success));
926   EXPECT_TRUE(success);
927   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
928
929   // At this point, we should no longer be showing the destination URL.
930   // The visible entry should be null, resulting in about:blank in the address
931   // bar.
932   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
933 }
934
935 // Test for crbug.com/9682.  We should not show the URL for a pending renderer-
936 // initiated navigation in a new tab if it is not the initial navigation.  In
937 // this case, the renderer will not notify us of a modification, so we cannot
938 // show the pending URL without allowing a spoof.
939 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
940                        DontShowLoadingURLIfNotInitialNav) {
941   ASSERT_TRUE(test_server()->Start());
942
943   // Load a page that can open a URL that won't commit in a new window.
944   NavigateToURL(
945       shell(), test_server()->GetURL("files/click-nocontent-link.html"));
946   WebContents* orig_contents = shell()->web_contents();
947
948   // Click a /nocontent link that opens in a new window but never commits.
949   // By using an onclick handler that first creates the window, the slow
950   // navigation is not considered an initial navigation.
951   ShellAddedObserver new_shell_observer;
952   bool success = false;
953   EXPECT_TRUE(ExecuteScriptAndExtractBool(
954       orig_contents,
955       "window.domAutomationController.send("
956       "clickNoContentScriptedTargetedLink());",
957       &success));
958   EXPECT_TRUE(success);
959
960   // Wait for the window to open.
961   Shell* new_shell = new_shell_observer.GetShell();
962
963   // Ensure the destination URL is not visible, because it is not the initial
964   // navigation.
965   WebContents* contents = new_shell->web_contents();
966   EXPECT_FALSE(contents->GetController().IsInitialNavigation());
967   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
968 }
969
970 // Crashes under ThreadSanitizer, http://crbug.com/356758.
971 #if defined(THREAD_SANITIZER)
972 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
973 #else
974 #define MAYBE_BackForwardNotStale BackForwardNotStale
975 #endif
976 // Test for http://crbug.com/93427.  Ensure that cross-site navigations
977 // do not cause back/forward navigations to be considered stale by the
978 // renderer.
979 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
980   StartServer();
981   NavigateToURL(shell(), GURL(kAboutBlankURL));
982
983   // Visit a page on first site.
984   NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
985
986   // Visit three pages on second site.
987   NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
988   NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
989   NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
990
991   // History is now [blank, A1, B1, B2, *B3].
992   WebContents* contents = shell()->web_contents();
993   EXPECT_EQ(5, contents->GetController().GetEntryCount());
994
995   // Open another window in same process to keep this process alive.
996   Shell* new_shell = CreateBrowser();
997   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
998
999   // Go back three times to first site.
1000   {
1001     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1002     shell()->web_contents()->GetController().GoBack();
1003     back_nav_load_observer.Wait();
1004   }
1005   {
1006     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1007     shell()->web_contents()->GetController().GoBack();
1008     back_nav_load_observer.Wait();
1009   }
1010   {
1011     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1012     shell()->web_contents()->GetController().GoBack();
1013     back_nav_load_observer.Wait();
1014   }
1015
1016   // Now go forward twice to B2.  Shouldn't be left spinning.
1017   {
1018     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1019     shell()->web_contents()->GetController().GoForward();
1020     forward_nav_load_observer.Wait();
1021   }
1022   {
1023     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1024     shell()->web_contents()->GetController().GoForward();
1025     forward_nav_load_observer.Wait();
1026   }
1027
1028   // Go back twice to first site.
1029   {
1030     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1031     shell()->web_contents()->GetController().GoBack();
1032     back_nav_load_observer.Wait();
1033   }
1034   {
1035     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1036     shell()->web_contents()->GetController().GoBack();
1037     back_nav_load_observer.Wait();
1038   }
1039
1040   // Now go forward directly to B3.  Shouldn't be left spinning.
1041   {
1042     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1043     shell()->web_contents()->GetController().GoToIndex(4);
1044     forward_nav_load_observer.Wait();
1045   }
1046 }
1047
1048 // Test for http://crbug.com/130016.
1049 // Swapping out a render view should update its visiblity state.
1050 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1051                        SwappedOutViewHasCorrectVisibilityState) {
1052   StartServer();
1053
1054   // Load a page with links that open in a new window.
1055   std::string replacement_path;
1056   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1057       "files/click-noreferrer-links.html",
1058       foo_host_port_,
1059       &replacement_path));
1060   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1061
1062   // Open a same-site link in a new widnow.
1063   ShellAddedObserver new_shell_observer;
1064   bool success = false;
1065   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1066       shell()->web_contents(),
1067       "window.domAutomationController.send(clickSameSiteTargetedLink());",
1068       &success));
1069   EXPECT_TRUE(success);
1070   Shell* new_shell = new_shell_observer.GetShell();
1071
1072   // Wait for the navigation in the new tab to finish, if it hasn't.
1073   WaitForLoadStop(new_shell->web_contents());
1074   EXPECT_EQ("/files/navigate_opener.html",
1075             new_shell->web_contents()->GetLastCommittedURL().path());
1076
1077   RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1078
1079   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1080       rvh,
1081       "window.domAutomationController.send("
1082       "    document.visibilityState == 'visible');",
1083       &success));
1084   EXPECT_TRUE(success);
1085
1086   // Now navigate the new window to a different site. This should swap out the
1087   // tab's existing RenderView, causing it become hidden.
1088   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1089
1090   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1091       rvh,
1092       "window.domAutomationController.send("
1093       "    document.visibilityState == 'hidden');",
1094       &success));
1095   EXPECT_TRUE(success);
1096
1097   // Going back should make the previously swapped-out view to become visible
1098   // again.
1099   {
1100     TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1101     new_shell->web_contents()->GetController().GoBack();
1102     back_nav_load_observer.Wait();
1103   }
1104
1105   EXPECT_EQ("/files/navigate_opener.html",
1106             new_shell->web_contents()->GetLastCommittedURL().path());
1107
1108   EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1109
1110   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1111       rvh,
1112       "window.domAutomationController.send("
1113       "    document.visibilityState == 'visible');",
1114       &success));
1115   EXPECT_TRUE(success);
1116 }
1117
1118 // This class ensures that all the given RenderViewHosts have properly been
1119 // shutdown.
1120 class RenderViewHostDestructionObserver : public WebContentsObserver {
1121  public:
1122   explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1123       : WebContentsObserver(web_contents) {}
1124   virtual ~RenderViewHostDestructionObserver() {}
1125   void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1126     watched_render_view_hosts_.insert(rvh);
1127   }
1128   size_t GetNumberOfWatchedRenderViewHosts() const {
1129     return watched_render_view_hosts_.size();
1130   }
1131
1132  private:
1133   // WebContentsObserver implementation:
1134   virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
1135     watched_render_view_hosts_.erase(rvh);
1136   }
1137
1138   std::set<RenderViewHost*> watched_render_view_hosts_;
1139 };
1140
1141 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1142 #if defined(THREAD_SANITIZER)
1143 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1144 #else
1145 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1146 #endif
1147 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1148 // they may cause crashes or memory corruptions when trying to call dead
1149 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1150 // ensure that a separate SiteInstance is created when navigating to view-source
1151 // URLs, regardless of current URL.
1152 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1153                        MAYBE_LeakingRenderViewHosts) {
1154   StartServer();
1155
1156   // Observe the created render_view_host's to make sure they will not leak.
1157   RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1158
1159   GURL navigated_url(test_server()->GetURL("files/title2.html"));
1160   GURL view_source_url(kViewSourceScheme + std::string(":") +
1161                        navigated_url.spec());
1162
1163   // Let's ensure that when we start with a blank window, navigating away to a
1164   // view-source URL, we create a new SiteInstance.
1165   RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1166   SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1167   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1168   EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1169   rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1170
1171   // Now navigate to the view-source URL and ensure we got a different
1172   // SiteInstance and RenderViewHost.
1173   NavigateToURL(shell(), view_source_url);
1174   EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1175   EXPECT_NE(blank_site_instance, shell()->web_contents()->
1176       GetRenderViewHost()->GetSiteInstance());
1177   rvh_observers.EnsureRVHGetsDestructed(
1178       shell()->web_contents()->GetRenderViewHost());
1179
1180   // Load a random page and then navigate to view-source: of it.
1181   // This used to cause two RVH instances for the same SiteInstance, which
1182   // was a problem.  This is no longer the case.
1183   NavigateToURL(shell(), navigated_url);
1184   SiteInstance* site_instance1 = shell()->web_contents()->
1185       GetRenderViewHost()->GetSiteInstance();
1186   rvh_observers.EnsureRVHGetsDestructed(
1187       shell()->web_contents()->GetRenderViewHost());
1188
1189   NavigateToURL(shell(), view_source_url);
1190   rvh_observers.EnsureRVHGetsDestructed(
1191       shell()->web_contents()->GetRenderViewHost());
1192   SiteInstance* site_instance2 = shell()->web_contents()->
1193       GetRenderViewHost()->GetSiteInstance();
1194
1195   // Ensure that view-source navigations force a new SiteInstance.
1196   EXPECT_NE(site_instance1, site_instance2);
1197
1198   // Now navigate to a different instance so that we swap out again.
1199   NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1200   rvh_observers.EnsureRVHGetsDestructed(
1201       shell()->web_contents()->GetRenderViewHost());
1202
1203   // This used to leak a render view host.
1204   shell()->Close();
1205
1206   RunAllPendingInMessageLoop();  // Needed on ChromeOS.
1207
1208   EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1209 }
1210
1211 // Test for crbug.com/143155.  Frame tree updates during unload should not
1212 // interrupt the intended navigation and show swappedout:// instead.
1213 // Specifically:
1214 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1215 // 2) Send the second tab to a different foo.com SiteInstance.
1216 //    This creates a swapped out opener for the first tab in the foo process.
1217 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1218 //    tab's unload handler remove its frame.
1219 // This used to cause an update to the frame tree of the swapped out RV,
1220 // just as it was navigating to a real page.  That pre-empted the real
1221 // navigation and visibly sent the tab to swappedout://.
1222 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1223                        DontPreemptNavigationWithFrameTreeUpdate) {
1224   StartServer();
1225
1226   // 1. Load a page that deletes its iframe during unload.
1227   NavigateToURL(shell(),
1228                 test_server()->GetURL("files/remove_frame_on_unload.html"));
1229
1230   // Get the original SiteInstance for later comparison.
1231   scoped_refptr<SiteInstance> orig_site_instance(
1232       shell()->web_contents()->GetSiteInstance());
1233
1234   // Open a same-site page in a new window.
1235   ShellAddedObserver new_shell_observer;
1236   bool success = false;
1237   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1238       shell()->web_contents(),
1239       "window.domAutomationController.send(openWindow());",
1240       &success));
1241   EXPECT_TRUE(success);
1242   Shell* new_shell = new_shell_observer.GetShell();
1243
1244   // Wait for the navigation in the new window to finish, if it hasn't.
1245   WaitForLoadStop(new_shell->web_contents());
1246   EXPECT_EQ("/files/title1.html",
1247             new_shell->web_contents()->GetLastCommittedURL().path());
1248
1249   // Should have the same SiteInstance.
1250   EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
1251
1252   // 2. Send the second tab to a different process.
1253   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1254   scoped_refptr<SiteInstance> new_site_instance(
1255       new_shell->web_contents()->GetSiteInstance());
1256   EXPECT_NE(orig_site_instance, new_site_instance);
1257
1258   // 3. Send the first tab to the second tab's process.
1259   NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1260
1261   // Make sure it ends up at the right page.
1262   WaitForLoadStop(shell()->web_contents());
1263   EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1264             shell()->web_contents()->GetLastCommittedURL());
1265   EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance());
1266 }
1267
1268 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1269 // are meant to run in the current page.  We had a bug where we expected a
1270 // BrowsingInstance swap to occur on pages like view-source and extensions,
1271 // which broke chrome://crash and javascript: URLs.
1272 // See http://crbug.com/335503.
1273 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1274   ASSERT_TRUE(test_server()->Start());
1275
1276   GURL original_url(test_server()->GetURL("files/title2.html"));
1277   GURL view_source_url(kViewSourceScheme + std::string(":") +
1278                        original_url.spec());
1279
1280   NavigateToURL(shell(), view_source_url);
1281
1282   // Check that javascript: URLs work.
1283   base::string16 expected_title = ASCIIToUTF16("msg");
1284   TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1285   shell()->LoadURL(GURL("javascript:document.title='msg'"));
1286   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1287
1288   // Crash the renderer of the view-source page.
1289   RenderProcessHostWatcher crash_observer(
1290       shell()->web_contents(),
1291       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1292   NavigateToURL(shell(), GURL(kChromeUICrashURL));
1293   crash_observer.Wait();
1294 }
1295
1296 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1297 // Otherwise, we might try to load an unprivileged about:blank page into a
1298 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1299 // See http://crbug.com/334214.
1300 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1301                        IgnoreRendererDebugURLsWhenCrashed) {
1302   // Visit a WebUI page with bindings.
1303   GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1304                         std::string(kChromeUIGpuHost));
1305   NavigateToURL(shell(), webui_url);
1306   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1307                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1308
1309   // Crash the renderer of the WebUI page.
1310   RenderProcessHostWatcher crash_observer(
1311       shell()->web_contents(),
1312       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1313   NavigateToURL(shell(), GURL(kChromeUICrashURL));
1314   crash_observer.Wait();
1315
1316   // Load the crash URL again but don't wait for any action.  If it is not
1317   // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1318   shell()->LoadURL(GURL(kChromeUICrashURL));
1319
1320   // Ensure that such URLs can still work as the initial navigation of a tab.
1321   // We postpone the initial navigation of the tab using an empty GURL, so that
1322   // we can add a watcher for crashes.
1323   Shell* shell2 = Shell::CreateNewWindow(
1324       shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1325       MSG_ROUTING_NONE, gfx::Size());
1326   RenderProcessHostWatcher crash_observer2(
1327       shell2->web_contents(),
1328       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1329   NavigateToURL(shell2, GURL(kChromeUIKillURL));
1330   crash_observer2.Wait();
1331 }
1332
1333 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1334 // Otherwise it might get picked up by InitRenderView when granting bindings
1335 // to other RenderViewHosts.  See http://crbug.com/330811.
1336 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) {
1337   // Visit a WebUI page with bindings.
1338   GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1339                       std::string(kChromeUIGpuHost)));
1340   NavigateToURL(shell(), webui_url);
1341   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1342                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1343   WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1344       shell()->web_contents());
1345   WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1346   EXPECT_TRUE(webui);
1347   EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1348
1349   // Navigate to another WebUI URL that reuses the WebUI object.  Make sure we
1350   // clear pending_web_ui() when it commits.
1351   GURL webui_url2(webui_url.spec() + "#foo");
1352   NavigateToURL(shell(), webui_url2);
1353   EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1354   EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1355 }
1356
1357 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1358  public:
1359   RFHMProcessPerTabTest() {}
1360
1361   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1362     command_line->AppendSwitch(switches::kProcessPerTab);
1363   }
1364 };
1365
1366 // Test that we still swap processes for BrowsingInstance changes even in
1367 // --process-per-tab mode.  See http://crbug.com/343017.
1368 // Disabled on Android: http://crbug.com/345873.
1369 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1370 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1371 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1372 #else
1373 #define MAYBE_BackFromWebUI BackFromWebUI
1374 #endif
1375 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1376   ASSERT_TRUE(test_server()->Start());
1377   GURL original_url(test_server()->GetURL("files/title2.html"));
1378   NavigateToURL(shell(), original_url);
1379
1380   // Visit a WebUI page with bindings.
1381   GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1382                       std::string(kChromeUIGpuHost)));
1383   NavigateToURL(shell(), webui_url);
1384   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1385                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1386
1387   // Go back and ensure we have no WebUI bindings.
1388   TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1389   shell()->web_contents()->GetController().GoBack();
1390   back_nav_load_observer.Wait();
1391   EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1392   EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1393                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1394 }
1395
1396 }  // namespace content