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