Upstream version 9.38.198.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,
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 // Flaky on android: http://crbug.com/397185
415 // Flaky on windows: http://crbug.com/291249
416 // This test also crashes under ThreadSanitizer, http://crbug.com/356758.
417 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(THREAD_SANITIZER)
418 #define MAYBE_DisownOpener DISABLED_DisownOpener
419 #else
420 #define MAYBE_DisownOpener DisownOpener
421 #endif
422 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
423   StartServer();
424
425   // Load a page with links that open in a new window.
426   std::string replacement_path;
427   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
428       "files/click-noreferrer-links.html",
429       foo_host_port_,
430       &replacement_path));
431   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
432
433   // Get the original SiteInstance for later comparison.
434   scoped_refptr<SiteInstance> orig_site_instance(
435       shell()->web_contents()->GetSiteInstance());
436   EXPECT_TRUE(orig_site_instance.get() != NULL);
437
438   // Test clicking a target=_blank link.
439   ShellAddedObserver new_shell_observer;
440   bool success = false;
441   EXPECT_TRUE(ExecuteScriptAndExtractBool(
442       shell()->web_contents(),
443       "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
444       &success));
445   EXPECT_TRUE(success);
446   Shell* new_shell = new_shell_observer.GetShell();
447
448   // Wait for the navigation in the new tab to finish, if it hasn't.
449   WaitForLoadStop(new_shell->web_contents());
450   EXPECT_EQ("/files/title2.html",
451             new_shell->web_contents()->GetLastCommittedURL().path());
452
453   // Should have the same SiteInstance.
454   scoped_refptr<SiteInstance> blank_site_instance(
455       new_shell->web_contents()->GetSiteInstance());
456   EXPECT_EQ(orig_site_instance, blank_site_instance);
457
458   // Now navigate the new tab to a different site.
459   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
460   scoped_refptr<SiteInstance> new_site_instance(
461       new_shell->web_contents()->GetSiteInstance());
462   EXPECT_NE(orig_site_instance, new_site_instance);
463
464   // Now disown the opener.
465   EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
466                             "window.opener = null;"));
467
468   // Go back and ensure the opener is still null.
469   {
470     TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
471     new_shell->web_contents()->GetController().GoBack();
472     back_nav_load_observer.Wait();
473   }
474   success = false;
475   EXPECT_TRUE(ExecuteScriptAndExtractBool(
476       new_shell->web_contents(),
477       "window.domAutomationController.send(window.opener == null);",
478       &success));
479   EXPECT_TRUE(success);
480
481   // Now navigate forward again (creating a new process) and check opener.
482   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
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 }
490
491 // Test that subframes can disown their openers.  http://crbug.com/225528.
492 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, DisownSubframeOpener) {
493   const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
494   NavigateToURL(shell(), frame_url);
495
496   // Give the frame an opener using window.open.
497   EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
498                             "window.open('about:blank','foo');"));
499
500   // Now disown the frame's opener.  Shouldn't crash.
501   EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
502                             "window.frames[0].opener = null;"));
503 }
504
505 // Test for crbug.com/99202.  PostMessage calls should still work after
506 // navigating the source and target windows to different sites.
507 // Specifically:
508 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
509 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
510 // 3) Post a message from "foo" to opener, which replies back to "foo".
511 // 4) Post a message from _blank to "foo".
512 // 5) Post a message from "foo" to a subframe of opener, which replies back.
513 // 6) Post a message from _blank to a subframe of "foo".
514 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
515                        SupportCrossProcessPostMessage) {
516   StartServer();
517
518   // Load a page with links that open in a new window.
519   std::string replacement_path;
520   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
521       "files/click-noreferrer-links.html",
522       foo_host_port_,
523       &replacement_path));
524   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
525
526   // Get the original SiteInstance and RVHM for later comparison.
527   WebContents* opener_contents = shell()->web_contents();
528   scoped_refptr<SiteInstance> orig_site_instance(
529       opener_contents->GetSiteInstance());
530   EXPECT_TRUE(orig_site_instance.get() != NULL);
531   RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
532       opener_contents)->GetRenderManagerForTesting();
533
534   // 1) Open two more windows, one named.  These initially have openers but no
535   // reference to each other.  We will later post a message between them.
536
537   // First, a named target=foo window.
538   ShellAddedObserver new_shell_observer;
539   bool success = false;
540   EXPECT_TRUE(ExecuteScriptAndExtractBool(
541       opener_contents,
542       "window.domAutomationController.send(clickSameSiteTargetedLink());",
543       &success));
544   EXPECT_TRUE(success);
545   Shell* new_shell = new_shell_observer.GetShell();
546
547   // Wait for the navigation in the new window to finish, if it hasn't, then
548   // send it to post_message.html on a different site.
549   WebContents* foo_contents = new_shell->web_contents();
550   WaitForLoadStop(foo_contents);
551   EXPECT_EQ("/files/navigate_opener.html",
552             foo_contents->GetLastCommittedURL().path());
553   NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
554   scoped_refptr<SiteInstance> foo_site_instance(
555       foo_contents->GetSiteInstance());
556   EXPECT_NE(orig_site_instance, foo_site_instance);
557
558   // Second, a target=_blank window.
559   ShellAddedObserver new_shell_observer2;
560   EXPECT_TRUE(ExecuteScriptAndExtractBool(
561       shell()->web_contents(),
562       "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
563       &success));
564   EXPECT_TRUE(success);
565
566   // Wait for the navigation in the new window to finish, if it hasn't, then
567   // send it to post_message.html on the original site.
568   Shell* new_shell2 = new_shell_observer2.GetShell();
569   WebContents* new_contents = new_shell2->web_contents();
570   WaitForLoadStop(new_contents);
571   EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
572   NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
573   EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance());
574   RenderFrameHostManager* new_manager =
575       static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
576
577   // We now have three windows.  The opener should have a swapped out RVH
578   // for the new SiteInstance, but the _blank window should not.
579   EXPECT_EQ(3u, Shell::windows().size());
580   EXPECT_TRUE(
581       opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
582   EXPECT_FALSE(
583       new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
584
585   // 2) Fail to post a message from the foo window to the opener if the target
586   // origin is wrong.  We won't see an error, but we can check for the right
587   // number of received messages below.
588   EXPECT_TRUE(ExecuteScriptAndExtractBool(
589       foo_contents,
590       "window.domAutomationController.send(postToOpener('msg',"
591       "    'http://google.com'));",
592       &success));
593   EXPECT_TRUE(success);
594   ASSERT_FALSE(
595       opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
596
597   // 3) Post a message from the foo window to the opener.  The opener will
598   // reply, causing the foo window to update its own title.
599   base::string16 expected_title = ASCIIToUTF16("msg");
600   TitleWatcher title_watcher(foo_contents, expected_title);
601   EXPECT_TRUE(ExecuteScriptAndExtractBool(
602       foo_contents,
603       "window.domAutomationController.send(postToOpener('msg','*'));",
604       &success));
605   EXPECT_TRUE(success);
606   ASSERT_FALSE(
607       opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
608   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
609
610   // We should have received only 1 message in the opener and "foo" tabs,
611   // and updated the title.
612   int opener_received_messages = 0;
613   EXPECT_TRUE(ExecuteScriptAndExtractInt(
614       opener_contents,
615       "window.domAutomationController.send(window.receivedMessages);",
616       &opener_received_messages));
617   int foo_received_messages = 0;
618   EXPECT_TRUE(ExecuteScriptAndExtractInt(
619       foo_contents,
620       "window.domAutomationController.send(window.receivedMessages);",
621       &foo_received_messages));
622   EXPECT_EQ(1, foo_received_messages);
623   EXPECT_EQ(1, opener_received_messages);
624   EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle());
625
626   // 4) Now post a message from the _blank window to the foo window.  The
627   // foo window will update its title and will not reply.
628   expected_title = ASCIIToUTF16("msg2");
629   TitleWatcher title_watcher2(foo_contents, expected_title);
630   EXPECT_TRUE(ExecuteScriptAndExtractBool(
631       new_contents,
632       "window.domAutomationController.send(postToFoo('msg2'));",
633       &success));
634   EXPECT_TRUE(success);
635   ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle());
636
637   // This postMessage should have created a swapped out RVH for the new
638   // SiteInstance in the target=_blank window.
639   EXPECT_TRUE(
640       new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
641
642   // TODO(nasko): Test subframe targeting of postMessage once
643   // http://crbug.com/153701 is fixed.
644 }
645
646 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e.,
647 // messages which contain Transferables and get intercepted by
648 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is
649 // swapped out) should work.
650 // Specifically:
651 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process.
652 // 2) Post a message containing a message port from opener to "foo".
653 // 3) Post a message from "foo" back to opener via the passed message port.
654 // The test will be enabled when the feature implementation lands.
655 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
656                        SupportCrossProcessPostMessageWithMessagePort) {
657   StartServer();
658
659   // Load a page with links that open in a new window.
660   std::string replacement_path;
661   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
662       "files/click-noreferrer-links.html",
663       foo_host_port_,
664       &replacement_path));
665   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
666
667   // Get the original SiteInstance and RVHM for later comparison.
668   WebContents* opener_contents = shell()->web_contents();
669   scoped_refptr<SiteInstance> orig_site_instance(
670       opener_contents->GetSiteInstance());
671   EXPECT_TRUE(orig_site_instance.get() != NULL);
672   RenderFrameHostManager* opener_manager = static_cast<WebContentsImpl*>(
673       opener_contents)->GetRenderManagerForTesting();
674
675   // 1) Open a named target=foo window. We will later post a message between the
676   // opener and the new window.
677   ShellAddedObserver new_shell_observer;
678   bool success = false;
679   EXPECT_TRUE(ExecuteScriptAndExtractBool(
680       opener_contents,
681       "window.domAutomationController.send(clickSameSiteTargetedLink());",
682       &success));
683   EXPECT_TRUE(success);
684   Shell* new_shell = new_shell_observer.GetShell();
685
686   // Wait for the navigation in the new window to finish, if it hasn't, then
687   // send it to post_message.html on a different site.
688   WebContents* foo_contents = new_shell->web_contents();
689   WaitForLoadStop(foo_contents);
690   EXPECT_EQ("/files/navigate_opener.html",
691             foo_contents->GetLastCommittedURL().path());
692   NavigateToURL(new_shell, GetCrossSiteURL("files/post_message.html"));
693   scoped_refptr<SiteInstance> foo_site_instance(
694       foo_contents->GetSiteInstance());
695   EXPECT_NE(orig_site_instance, foo_site_instance);
696
697   // We now have two windows. The opener should have a swapped out RVH
698   // for the new SiteInstance.
699   EXPECT_EQ(2u, Shell::windows().size());
700   EXPECT_TRUE(
701       opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
702
703   // 2) Post a message containing a MessagePort from opener to the the foo
704   // window. The foo window will reply via the passed port, causing the opener
705   // to update its own title.
706   base::string16 expected_title = ASCIIToUTF16("msg-back-via-port");
707   TitleWatcher title_observer(opener_contents, expected_title);
708   EXPECT_TRUE(ExecuteScriptAndExtractBool(
709       opener_contents,
710       "window.domAutomationController.send(postWithPortToFoo());",
711       &success));
712   EXPECT_TRUE(success);
713   ASSERT_FALSE(
714       opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
715   ASSERT_EQ(expected_title, title_observer.WaitAndGetTitle());
716
717   // Check message counts.
718   int opener_received_messages_via_port = 0;
719   EXPECT_TRUE(ExecuteScriptAndExtractInt(
720       opener_contents,
721       "window.domAutomationController.send(window.receivedMessagesViaPort);",
722       &opener_received_messages_via_port));
723   int foo_received_messages = 0;
724   EXPECT_TRUE(ExecuteScriptAndExtractInt(
725       foo_contents,
726       "window.domAutomationController.send(window.receivedMessages);",
727       &foo_received_messages));
728   int foo_received_messages_with_port = 0;
729   EXPECT_TRUE(ExecuteScriptAndExtractInt(
730       foo_contents,
731       "window.domAutomationController.send(window.receivedMessagesWithPort);",
732       &foo_received_messages_with_port));
733   EXPECT_EQ(1, foo_received_messages);
734   EXPECT_EQ(1, foo_received_messages_with_port);
735   EXPECT_EQ(1, opener_received_messages_via_port);
736   EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
737   EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
738 }
739
740 // Test for crbug.com/116192.  Navigations to a window's opener should
741 // still work after a process swap.
742 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
743                        AllowTargetedNavigationsInOpenerAfterSwap) {
744   StartServer();
745
746   // Load a page with links that open in a new window.
747   std::string replacement_path;
748   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
749       "files/click-noreferrer-links.html",
750       foo_host_port_,
751       &replacement_path));
752   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
753
754   // Get the original tab and SiteInstance for later comparison.
755   WebContents* orig_contents = shell()->web_contents();
756   scoped_refptr<SiteInstance> orig_site_instance(
757       orig_contents->GetSiteInstance());
758   EXPECT_TRUE(orig_site_instance.get() != NULL);
759
760   // Test clicking a target=foo link.
761   ShellAddedObserver new_shell_observer;
762   bool success = false;
763   EXPECT_TRUE(ExecuteScriptAndExtractBool(
764       orig_contents,
765       "window.domAutomationController.send(clickSameSiteTargetedLink());",
766       &success));
767   EXPECT_TRUE(success);
768   Shell* new_shell = new_shell_observer.GetShell();
769
770   // Wait for the navigation in the new window to finish, if it hasn't.
771   WaitForLoadStop(new_shell->web_contents());
772   EXPECT_EQ("/files/navigate_opener.html",
773             new_shell->web_contents()->GetLastCommittedURL().path());
774
775   // Should have the same SiteInstance.
776   scoped_refptr<SiteInstance> blank_site_instance(
777       new_shell->web_contents()->GetSiteInstance());
778   EXPECT_EQ(orig_site_instance, blank_site_instance);
779
780   // Now navigate the original (opener) tab to a different site.
781   NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
782   scoped_refptr<SiteInstance> new_site_instance(
783       shell()->web_contents()->GetSiteInstance());
784   EXPECT_NE(orig_site_instance, new_site_instance);
785
786   // The opened tab should be able to navigate the opener back to its process.
787   TestNavigationObserver navigation_observer(orig_contents);
788   EXPECT_TRUE(ExecuteScriptAndExtractBool(
789       new_shell->web_contents(),
790       "window.domAutomationController.send(navigateOpener());",
791       &success));
792   EXPECT_TRUE(success);
793   navigation_observer.Wait();
794
795   // Should have swapped back into this process.
796   scoped_refptr<SiteInstance> revisit_site_instance(
797       shell()->web_contents()->GetSiteInstance());
798   EXPECT_EQ(orig_site_instance, revisit_site_instance);
799 }
800
801 // Test that opening a new window in the same SiteInstance and then navigating
802 // both windows to a different SiteInstance allows the first process to exit.
803 // See http://crbug.com/126333.
804 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
805                        ProcessExitWithSwappedOutViews) {
806   StartServer();
807
808   // Load a page with links that open in a new window.
809   std::string replacement_path;
810   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
811       "files/click-noreferrer-links.html",
812       foo_host_port_,
813       &replacement_path));
814   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
815
816   // Get the original SiteInstance for later comparison.
817   scoped_refptr<SiteInstance> orig_site_instance(
818       shell()->web_contents()->GetSiteInstance());
819   EXPECT_TRUE(orig_site_instance.get() != NULL);
820
821   // Test clicking a target=foo link.
822   ShellAddedObserver new_shell_observer;
823   bool success = false;
824   EXPECT_TRUE(ExecuteScriptAndExtractBool(
825       shell()->web_contents(),
826       "window.domAutomationController.send(clickSameSiteTargetedLink());",
827       &success));
828   EXPECT_TRUE(success);
829   Shell* new_shell = new_shell_observer.GetShell();
830
831   // Wait for the navigation in the new window to finish, if it hasn't.
832   WaitForLoadStop(new_shell->web_contents());
833   EXPECT_EQ("/files/navigate_opener.html",
834             new_shell->web_contents()->GetLastCommittedURL().path());
835
836   // Should have the same SiteInstance.
837   scoped_refptr<SiteInstance> opened_site_instance(
838       new_shell->web_contents()->GetSiteInstance());
839   EXPECT_EQ(orig_site_instance, opened_site_instance);
840
841   // Now navigate the opened window to a different site.
842   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
843   scoped_refptr<SiteInstance> new_site_instance(
844       new_shell->web_contents()->GetSiteInstance());
845   EXPECT_NE(orig_site_instance, new_site_instance);
846
847   // The original process should still be alive, since it is still used in the
848   // first window.
849   RenderProcessHost* orig_process = orig_site_instance->GetProcess();
850   EXPECT_TRUE(orig_process->HasConnection());
851
852   // Navigate the first window to a different site as well.  The original
853   // process should exit, since all of its views are now swapped out.
854   RenderProcessHostWatcher exit_observer(
855       orig_process,
856       RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
857   NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
858   exit_observer.Wait();
859   scoped_refptr<SiteInstance> new_site_instance2(
860       shell()->web_contents()->GetSiteInstance());
861   EXPECT_EQ(new_site_instance, new_site_instance2);
862 }
863
864 // Test for crbug.com/76666.  A cross-site navigation that fails with a 204
865 // error should not make us ignore future renderer-initiated navigations.
866 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClickLinkAfter204Error) {
867   StartServer();
868
869   // Get the original SiteInstance for later comparison.
870   scoped_refptr<SiteInstance> orig_site_instance(
871       shell()->web_contents()->GetSiteInstance());
872   EXPECT_TRUE(orig_site_instance.get() != NULL);
873
874   // Load a cross-site page that fails with a 204 error.
875   NavigateToURL(shell(), GetCrossSiteURL("nocontent"));
876
877   // We should still be looking at the normal page.  Because we started from a
878   // blank new tab, the typed URL will still be visible until the user clears it
879   // manually.  The last committed URL will be the previous page.
880   scoped_refptr<SiteInstance> post_nav_site_instance(
881       shell()->web_contents()->GetSiteInstance());
882   EXPECT_EQ(orig_site_instance, post_nav_site_instance);
883   EXPECT_EQ("/nocontent",
884             shell()->web_contents()->GetVisibleURL().path());
885   EXPECT_FALSE(
886       shell()->web_contents()->GetController().GetLastCommittedEntry());
887
888   // Renderer-initiated navigations should work.
889   base::string16 expected_title = ASCIIToUTF16("Title Of Awesomeness");
890   TitleWatcher title_watcher(shell()->web_contents(), expected_title);
891   GURL url = test_server()->GetURL("files/title2.html");
892   EXPECT_TRUE(ExecuteScript(
893       shell()->web_contents(),
894       base::StringPrintf("location.href = '%s'", url.spec().c_str())));
895   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
896
897   // Opens in same tab.
898   EXPECT_EQ(1u, Shell::windows().size());
899   EXPECT_EQ("/files/title2.html",
900             shell()->web_contents()->GetLastCommittedURL().path());
901
902   // Should have the same SiteInstance.
903   scoped_refptr<SiteInstance> new_site_instance(
904       shell()->web_contents()->GetSiteInstance());
905   EXPECT_EQ(orig_site_instance, new_site_instance);
906 }
907
908 // Test for crbug.com/9682.  We should show the URL for a pending renderer-
909 // initiated navigation in a new tab, until the content of the initial
910 // about:blank page is modified by another window.  At that point, we should
911 // revert to showing about:blank to prevent a URL spoof.
912 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ShowLoadingURLUntilSpoof) {
913   ASSERT_TRUE(test_server()->Start());
914
915   // Load a page that can open a URL that won't commit in a new window.
916   NavigateToURL(
917       shell(), test_server()->GetURL("files/click-nocontent-link.html"));
918   WebContents* orig_contents = shell()->web_contents();
919
920   // Click a /nocontent link that opens in a new window but never commits.
921   ShellAddedObserver new_shell_observer;
922   bool success = false;
923   EXPECT_TRUE(ExecuteScriptAndExtractBool(
924       orig_contents,
925       "window.domAutomationController.send(clickNoContentTargetedLink());",
926       &success));
927   EXPECT_TRUE(success);
928
929   // Wait for the window to open.
930   Shell* new_shell = new_shell_observer.GetShell();
931
932   // Ensure the destination URL is visible, because it is considered the
933   // initial navigation.
934   WebContents* contents = new_shell->web_contents();
935   EXPECT_TRUE(contents->GetController().IsInitialNavigation());
936   EXPECT_EQ("/nocontent",
937             contents->GetController().GetVisibleEntry()->GetURL().path());
938
939   // Now modify the contents of the new window from the opener.  This will also
940   // modify the title of the document to give us something to listen for.
941   base::string16 expected_title = ASCIIToUTF16("Modified Title");
942   TitleWatcher title_watcher(contents, expected_title);
943   success = false;
944   EXPECT_TRUE(ExecuteScriptAndExtractBool(
945       orig_contents,
946       "window.domAutomationController.send(modifyNewWindow());",
947       &success));
948   EXPECT_TRUE(success);
949   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
950
951   // At this point, we should no longer be showing the destination URL.
952   // The visible entry should be null, resulting in about:blank in the address
953   // bar.
954   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
955 }
956
957 // Test for crbug.com/9682.  We should not show the URL for a pending renderer-
958 // initiated navigation in a new tab if it is not the initial navigation.  In
959 // this case, the renderer will not notify us of a modification, so we cannot
960 // show the pending URL without allowing a spoof.
961 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
962                        DontShowLoadingURLIfNotInitialNav) {
963   ASSERT_TRUE(test_server()->Start());
964
965   // Load a page that can open a URL that won't commit in a new window.
966   NavigateToURL(
967       shell(), test_server()->GetURL("files/click-nocontent-link.html"));
968   WebContents* orig_contents = shell()->web_contents();
969
970   // Click a /nocontent link that opens in a new window but never commits.
971   // By using an onclick handler that first creates the window, the slow
972   // navigation is not considered an initial navigation.
973   ShellAddedObserver new_shell_observer;
974   bool success = false;
975   EXPECT_TRUE(ExecuteScriptAndExtractBool(
976       orig_contents,
977       "window.domAutomationController.send("
978       "clickNoContentScriptedTargetedLink());",
979       &success));
980   EXPECT_TRUE(success);
981
982   // Wait for the window to open.
983   Shell* new_shell = new_shell_observer.GetShell();
984
985   // Ensure the destination URL is not visible, because it is not the initial
986   // navigation.
987   WebContents* contents = new_shell->web_contents();
988   EXPECT_FALSE(contents->GetController().IsInitialNavigation());
989   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
990 }
991
992 // Crashes under ThreadSanitizer, http://crbug.com/356758.
993 #if defined(THREAD_SANITIZER)
994 #define MAYBE_BackForwardNotStale DISABLED_BackForwardNotStale
995 #else
996 #define MAYBE_BackForwardNotStale BackForwardNotStale
997 #endif
998 // Test for http://crbug.com/93427.  Ensure that cross-site navigations
999 // do not cause back/forward navigations to be considered stale by the
1000 // renderer.
1001 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
1002   StartServer();
1003   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
1004
1005   // Visit a page on first site.
1006   NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
1007
1008   // Visit three pages on second site.
1009   NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1010   NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1011   NavigateToURL(shell(), GetCrossSiteURL("files/title3.html"));
1012
1013   // History is now [blank, A1, B1, B2, *B3].
1014   WebContents* contents = shell()->web_contents();
1015   EXPECT_EQ(5, contents->GetController().GetEntryCount());
1016
1017   // Open another window in same process to keep this process alive.
1018   Shell* new_shell = CreateBrowser();
1019   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1020
1021   // Go back three times to first site.
1022   {
1023     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1024     shell()->web_contents()->GetController().GoBack();
1025     back_nav_load_observer.Wait();
1026   }
1027   {
1028     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1029     shell()->web_contents()->GetController().GoBack();
1030     back_nav_load_observer.Wait();
1031   }
1032   {
1033     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1034     shell()->web_contents()->GetController().GoBack();
1035     back_nav_load_observer.Wait();
1036   }
1037
1038   // Now go forward twice to B2.  Shouldn't be left spinning.
1039   {
1040     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1041     shell()->web_contents()->GetController().GoForward();
1042     forward_nav_load_observer.Wait();
1043   }
1044   {
1045     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1046     shell()->web_contents()->GetController().GoForward();
1047     forward_nav_load_observer.Wait();
1048   }
1049
1050   // Go back twice to first site.
1051   {
1052     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1053     shell()->web_contents()->GetController().GoBack();
1054     back_nav_load_observer.Wait();
1055   }
1056   {
1057     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1058     shell()->web_contents()->GetController().GoBack();
1059     back_nav_load_observer.Wait();
1060   }
1061
1062   // Now go forward directly to B3.  Shouldn't be left spinning.
1063   {
1064     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1065     shell()->web_contents()->GetController().GoToIndex(4);
1066     forward_nav_load_observer.Wait();
1067   }
1068 }
1069
1070 // Test for http://crbug.com/130016.
1071 // Swapping out a render view should update its visiblity state.
1072 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1073                        SwappedOutViewHasCorrectVisibilityState) {
1074   StartServer();
1075
1076   // Load a page with links that open in a new window.
1077   std::string replacement_path;
1078   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1079       "files/click-noreferrer-links.html",
1080       foo_host_port_,
1081       &replacement_path));
1082   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1083
1084   // Open a same-site link in a new widnow.
1085   ShellAddedObserver new_shell_observer;
1086   bool success = false;
1087   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1088       shell()->web_contents(),
1089       "window.domAutomationController.send(clickSameSiteTargetedLink());",
1090       &success));
1091   EXPECT_TRUE(success);
1092   Shell* new_shell = new_shell_observer.GetShell();
1093
1094   // Wait for the navigation in the new tab to finish, if it hasn't.
1095   WaitForLoadStop(new_shell->web_contents());
1096   EXPECT_EQ("/files/navigate_opener.html",
1097             new_shell->web_contents()->GetLastCommittedURL().path());
1098
1099   RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1100
1101   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1102       rvh,
1103       "window.domAutomationController.send("
1104       "    document.visibilityState == 'visible');",
1105       &success));
1106   EXPECT_TRUE(success);
1107
1108   // Now navigate the new window to a different site. This should swap out the
1109   // tab's existing RenderView, causing it become hidden.
1110   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1111
1112   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1113       rvh,
1114       "window.domAutomationController.send("
1115       "    document.visibilityState == 'hidden');",
1116       &success));
1117   EXPECT_TRUE(success);
1118
1119   // Going back should make the previously swapped-out view to become visible
1120   // again.
1121   {
1122     TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1123     new_shell->web_contents()->GetController().GoBack();
1124     back_nav_load_observer.Wait();
1125   }
1126
1127   EXPECT_EQ("/files/navigate_opener.html",
1128             new_shell->web_contents()->GetLastCommittedURL().path());
1129
1130   EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1131
1132   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1133       rvh,
1134       "window.domAutomationController.send("
1135       "    document.visibilityState == 'visible');",
1136       &success));
1137   EXPECT_TRUE(success);
1138 }
1139
1140 // This class ensures that all the given RenderViewHosts have properly been
1141 // shutdown.
1142 class RenderViewHostDestructionObserver : public WebContentsObserver {
1143  public:
1144   explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1145       : WebContentsObserver(web_contents) {}
1146   virtual ~RenderViewHostDestructionObserver() {}
1147   void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1148     watched_render_view_hosts_.insert(rvh);
1149   }
1150   size_t GetNumberOfWatchedRenderViewHosts() const {
1151     return watched_render_view_hosts_.size();
1152   }
1153
1154  private:
1155   // WebContentsObserver implementation:
1156   virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
1157     watched_render_view_hosts_.erase(rvh);
1158   }
1159
1160   std::set<RenderViewHost*> watched_render_view_hosts_;
1161 };
1162
1163 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1164 #if defined(THREAD_SANITIZER)
1165 #define MAYBE_LeakingRenderViewHosts DISABLED_LeakingRenderViewHosts
1166 #else
1167 #define MAYBE_LeakingRenderViewHosts LeakingRenderViewHosts
1168 #endif
1169 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1170 // they may cause crashes or memory corruptions when trying to call dead
1171 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1172 // ensure that a separate SiteInstance is created when navigating to view-source
1173 // URLs, regardless of current URL.
1174 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1175                        MAYBE_LeakingRenderViewHosts) {
1176   StartServer();
1177
1178   // Observe the created render_view_host's to make sure they will not leak.
1179   RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1180
1181   GURL navigated_url(test_server()->GetURL("files/title2.html"));
1182   GURL view_source_url(kViewSourceScheme + std::string(":") +
1183                        navigated_url.spec());
1184
1185   // Let's ensure that when we start with a blank window, navigating away to a
1186   // view-source URL, we create a new SiteInstance.
1187   RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1188   SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1189   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1190   EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1191   rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1192
1193   // Now navigate to the view-source URL and ensure we got a different
1194   // SiteInstance and RenderViewHost.
1195   NavigateToURL(shell(), view_source_url);
1196   EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1197   EXPECT_NE(blank_site_instance, shell()->web_contents()->
1198       GetRenderViewHost()->GetSiteInstance());
1199   rvh_observers.EnsureRVHGetsDestructed(
1200       shell()->web_contents()->GetRenderViewHost());
1201
1202   // Load a random page and then navigate to view-source: of it.
1203   // This used to cause two RVH instances for the same SiteInstance, which
1204   // was a problem.  This is no longer the case.
1205   NavigateToURL(shell(), navigated_url);
1206   SiteInstance* site_instance1 = shell()->web_contents()->
1207       GetRenderViewHost()->GetSiteInstance();
1208   rvh_observers.EnsureRVHGetsDestructed(
1209       shell()->web_contents()->GetRenderViewHost());
1210
1211   NavigateToURL(shell(), view_source_url);
1212   rvh_observers.EnsureRVHGetsDestructed(
1213       shell()->web_contents()->GetRenderViewHost());
1214   SiteInstance* site_instance2 = shell()->web_contents()->
1215       GetRenderViewHost()->GetSiteInstance();
1216
1217   // Ensure that view-source navigations force a new SiteInstance.
1218   EXPECT_NE(site_instance1, site_instance2);
1219
1220   // Now navigate to a different instance so that we swap out again.
1221   NavigateToURL(shell(), GetCrossSiteURL("files/title2.html"));
1222   rvh_observers.EnsureRVHGetsDestructed(
1223       shell()->web_contents()->GetRenderViewHost());
1224
1225   // This used to leak a render view host.
1226   shell()->Close();
1227
1228   RunAllPendingInMessageLoop();  // Needed on ChromeOS.
1229
1230   EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1231 }
1232
1233 // Test for crbug.com/143155.  Frame tree updates during unload should not
1234 // interrupt the intended navigation and show swappedout:// instead.
1235 // Specifically:
1236 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1237 // 2) Send the second tab to a different foo.com SiteInstance.
1238 //    This creates a swapped out opener for the first tab in the foo process.
1239 // 3) Navigate the first tab to the foo.com SiteInstance, and have the first
1240 //    tab's unload handler remove its frame.
1241 // This used to cause an update to the frame tree of the swapped out RV,
1242 // just as it was navigating to a real page.  That pre-empted the real
1243 // navigation and visibly sent the tab to swappedout://.
1244 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1245                        DontPreemptNavigationWithFrameTreeUpdate) {
1246   StartServer();
1247
1248   // 1. Load a page that deletes its iframe during unload.
1249   NavigateToURL(shell(),
1250                 test_server()->GetURL("files/remove_frame_on_unload.html"));
1251
1252   // Get the original SiteInstance for later comparison.
1253   scoped_refptr<SiteInstance> orig_site_instance(
1254       shell()->web_contents()->GetSiteInstance());
1255
1256   // Open a same-site page in a new window.
1257   ShellAddedObserver new_shell_observer;
1258   bool success = false;
1259   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1260       shell()->web_contents(),
1261       "window.domAutomationController.send(openWindow());",
1262       &success));
1263   EXPECT_TRUE(success);
1264   Shell* new_shell = new_shell_observer.GetShell();
1265
1266   // Wait for the navigation in the new window to finish, if it hasn't.
1267   WaitForLoadStop(new_shell->web_contents());
1268   EXPECT_EQ("/files/title1.html",
1269             new_shell->web_contents()->GetLastCommittedURL().path());
1270
1271   // Should have the same SiteInstance.
1272   EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
1273
1274   // 2. Send the second tab to a different process.
1275   NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
1276   scoped_refptr<SiteInstance> new_site_instance(
1277       new_shell->web_contents()->GetSiteInstance());
1278   EXPECT_NE(orig_site_instance, new_site_instance);
1279
1280   // 3. Send the first tab to the second tab's process.
1281   NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
1282
1283   // Make sure it ends up at the right page.
1284   WaitForLoadStop(shell()->web_contents());
1285   EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
1286             shell()->web_contents()->GetLastCommittedURL());
1287   EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance());
1288 }
1289
1290 // Ensure that renderer-side debug URLs do not cause a process swap, since they
1291 // are meant to run in the current page.  We had a bug where we expected a
1292 // BrowsingInstance swap to occur on pages like view-source and extensions,
1293 // which broke chrome://crash and javascript: URLs.
1294 // See http://crbug.com/335503.
1295 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, RendererDebugURLsDontSwap) {
1296   ASSERT_TRUE(test_server()->Start());
1297
1298   GURL original_url(test_server()->GetURL("files/title2.html"));
1299   GURL view_source_url(kViewSourceScheme + std::string(":") +
1300                        original_url.spec());
1301
1302   NavigateToURL(shell(), view_source_url);
1303
1304   // Check that javascript: URLs work.
1305   base::string16 expected_title = ASCIIToUTF16("msg");
1306   TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1307   shell()->LoadURL(GURL("javascript:document.title='msg'"));
1308   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1309
1310   // Crash the renderer of the view-source page.
1311   RenderProcessHostWatcher crash_observer(
1312       shell()->web_contents(),
1313       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1314   NavigateToURL(shell(), GURL(kChromeUICrashURL));
1315   crash_observer.Wait();
1316 }
1317
1318 // Ensure that renderer-side debug URLs don't take effect on crashed renderers.
1319 // Otherwise, we might try to load an unprivileged about:blank page into a
1320 // WebUI-enabled RenderProcessHost, failing a safety check in InitRenderView.
1321 // See http://crbug.com/334214.
1322 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
1323                        IgnoreRendererDebugURLsWhenCrashed) {
1324   // Visit a WebUI page with bindings.
1325   GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
1326                         std::string(kChromeUIGpuHost));
1327   NavigateToURL(shell(), webui_url);
1328   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1329                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1330
1331   // Crash the renderer of the WebUI page.
1332   RenderProcessHostWatcher crash_observer(
1333       shell()->web_contents(),
1334       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1335   NavigateToURL(shell(), GURL(kChromeUICrashURL));
1336   crash_observer.Wait();
1337
1338   // Load the crash URL again but don't wait for any action.  If it is not
1339   // ignored this time, we will fail the WebUI CHECK in InitRenderView.
1340   shell()->LoadURL(GURL(kChromeUICrashURL));
1341
1342   // Ensure that such URLs can still work as the initial navigation of a tab.
1343   // We postpone the initial navigation of the tab using an empty GURL, so that
1344   // we can add a watcher for crashes.
1345   Shell* shell2 = Shell::CreateNewWindow(
1346       shell()->web_contents()->GetBrowserContext(), GURL(), NULL,
1347       MSG_ROUTING_NONE, gfx::Size());
1348   RenderProcessHostWatcher crash_observer2(
1349       shell2->web_contents(),
1350       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1351   NavigateToURL(shell2, GURL(kChromeUIKillURL));
1352   crash_observer2.Wait();
1353 }
1354
1355 // Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
1356 // Otherwise it might get picked up by InitRenderView when granting bindings
1357 // to other RenderViewHosts.  See http://crbug.com/330811.
1358 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) {
1359   // Visit a WebUI page with bindings.
1360   GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1361                       std::string(kChromeUIGpuHost)));
1362   NavigateToURL(shell(), webui_url);
1363   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1364                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1365   WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1366       shell()->web_contents());
1367   WebUIImpl* webui = web_contents->GetRenderManagerForTesting()->web_ui();
1368   EXPECT_TRUE(webui);
1369   EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1370
1371   // Navigate to another WebUI URL that reuses the WebUI object.  Make sure we
1372   // clear pending_web_ui() when it commits.
1373   GURL webui_url2(webui_url.spec() + "#foo");
1374   NavigateToURL(shell(), webui_url2);
1375   EXPECT_EQ(webui, web_contents->GetRenderManagerForTesting()->web_ui());
1376   EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->pending_web_ui());
1377 }
1378
1379 class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
1380  public:
1381   RFHMProcessPerTabTest() {}
1382
1383   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1384     command_line->AppendSwitch(switches::kProcessPerTab);
1385   }
1386 };
1387
1388 // Test that we still swap processes for BrowsingInstance changes even in
1389 // --process-per-tab mode.  See http://crbug.com/343017.
1390 // Disabled on Android: http://crbug.com/345873.
1391 // Crashes under ThreadSanitizer, http://crbug.com/356758.
1392 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
1393 #define MAYBE_BackFromWebUI DISABLED_BackFromWebUI
1394 #else
1395 #define MAYBE_BackFromWebUI BackFromWebUI
1396 #endif
1397 IN_PROC_BROWSER_TEST_F(RFHMProcessPerTabTest, MAYBE_BackFromWebUI) {
1398   ASSERT_TRUE(test_server()->Start());
1399   GURL original_url(test_server()->GetURL("files/title2.html"));
1400   NavigateToURL(shell(), original_url);
1401
1402   // Visit a WebUI page with bindings.
1403   GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
1404                       std::string(kChromeUIGpuHost)));
1405   NavigateToURL(shell(), webui_url);
1406   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1407                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1408
1409   // Go back and ensure we have no WebUI bindings.
1410   TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1411   shell()->web_contents()->GetController().GoBack();
1412   back_nav_load_observer.Wait();
1413   EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
1414   EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1415                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1416 }
1417
1418 // crbug.com/372360
1419 // The test loads url1, opens a link pointing to url2 in a new tab, and
1420 // navigates the new tab to url1.
1421 // The following is needed for the bug to happen:
1422 //  - url1 must require webui bindings;
1423 //  - navigating to url2 in the site instance of url1 should not swap
1424 //   browsing instances, but should require a new site instance.
1425 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
1426   GURL url1(std::string(kChromeUIScheme) + "://" +
1427             std::string(kChromeUIGpuHost));
1428   GURL url2(std::string(kChromeUIScheme) + "://" +
1429             std::string(kChromeUIAccessibilityHost));
1430
1431   // Visit a WebUI page with bindings.
1432   NavigateToURL(shell(), url1);
1433   EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1434                   shell()->web_contents()->GetRenderProcessHost()->GetID()));
1435   SiteInstance* site_instance1 = shell()->web_contents()->GetSiteInstance();
1436
1437   // Open a new tab. Initially it gets a render view in the original tab's
1438   // current site instance.
1439   TestNavigationObserver nav_observer(NULL);
1440   nav_observer.StartWatchingNewWebContents();
1441   ShellAddedObserver shao;
1442   OpenUrlViaClickTarget(shell()->web_contents(), url2);
1443   nav_observer.Wait();
1444   Shell* new_shell = shao.GetShell();
1445   WebContentsImpl* new_web_contents = static_cast<WebContentsImpl*>(
1446       new_shell->web_contents());
1447   SiteInstance* site_instance2 = new_web_contents->GetSiteInstance();
1448
1449   EXPECT_NE(site_instance2, site_instance1);
1450   EXPECT_TRUE(site_instance2->IsRelatedSiteInstance(site_instance1));
1451   RenderViewHost* initial_rvh = new_web_contents->
1452       GetRenderManagerForTesting()->GetSwappedOutRenderViewHost(site_instance1);
1453   ASSERT_TRUE(initial_rvh);
1454   // The following condition is what was causing the bug.
1455   EXPECT_EQ(0, initial_rvh->GetEnabledBindings());
1456
1457   // Navigate to url1 and check bindings.
1458   NavigateToURL(new_shell, url1);
1459   // The navigation should have used the first SiteInstance, otherwise
1460   // |initial_rvh| did not have a chance to be used.
1461   EXPECT_EQ(new_web_contents->GetSiteInstance(), site_instance1);
1462   EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
1463       new_web_contents->GetRenderViewHost()->GetEnabledBindings());
1464 }
1465
1466 }  // namespace content