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