- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_view_host_manager_browsertest.cc
1 // Copyright (c) 2012 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/json/json_reader.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/path_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "content/browser/renderer_host/render_view_host_impl.h"
13 #include "content/browser/site_instance_impl.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/common/content_constants_internal.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_entry.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_observer.h"
20 #include "content/public/browser/notification_registrar.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_observer.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/test/content_browser_test.h"
31 #include "content/test/content_browser_test_utils.h"
32 #include "net/base/net_util.h"
33 #include "net/test/spawned_test_server/spawned_test_server.h"
34
35 namespace content {
36
37 class RenderViewHostManagerTest : public ContentBrowserTest {
38  public:
39   RenderViewHostManagerTest() {}
40
41   static bool GetFilePathWithHostAndPortReplacement(
42       const std::string& original_file_path,
43       const net::HostPortPair& host_port_pair,
44       std::string* replacement_path) {
45     std::vector<net::SpawnedTestServer::StringPair> replacement_text;
46     replacement_text.push_back(
47         make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
48     return net::SpawnedTestServer::GetFilePathWithReplacements(
49         original_file_path, replacement_text, replacement_path);
50   }
51 };
52
53 // Web pages should not have script access to the swapped out page.
54 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
55                        DISABLED_NoScriptAccessAfterSwapOut) {
56   // Start two servers with different sites.
57   ASSERT_TRUE(test_server()->Start());
58   net::SpawnedTestServer https_server(
59       net::SpawnedTestServer::TYPE_HTTPS,
60       net::SpawnedTestServer::kLocalhost,
61       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
62   ASSERT_TRUE(https_server.Start());
63
64   // Load a page with links that open in a new window.
65   std::string replacement_path;
66   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
67       "files/click-noreferrer-links.html",
68       https_server.host_port_pair(),
69       &replacement_path));
70   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
71
72   // Get the original SiteInstance for later comparison.
73   scoped_refptr<SiteInstance> orig_site_instance(
74       shell()->web_contents()->GetSiteInstance());
75   EXPECT_TRUE(orig_site_instance.get() != NULL);
76
77   // Open a same-site link in a new window.
78   ShellAddedObserver new_shell_observer;
79   bool success = false;
80   EXPECT_TRUE(ExecuteScriptAndExtractBool(
81       shell()->web_contents(),
82       "window.domAutomationController.send(clickSameSiteTargetedLink());",
83       &success));
84   EXPECT_TRUE(success);
85   Shell* new_shell = new_shell_observer.GetShell();
86
87   // Wait for the navigation in the new window to finish, if it hasn't.
88   WaitForLoadStop(new_shell->web_contents());
89   EXPECT_EQ("/files/navigate_opener.html",
90             new_shell->web_contents()->GetLastCommittedURL().path());
91
92   // Should have the same SiteInstance.
93   scoped_refptr<SiteInstance> blank_site_instance(
94       new_shell->web_contents()->GetSiteInstance());
95   EXPECT_EQ(orig_site_instance, blank_site_instance);
96
97   // We should have access to the opened window's location.
98   success = false;
99   EXPECT_TRUE(ExecuteScriptAndExtractBool(
100       shell()->web_contents(),
101       "window.domAutomationController.send(testScriptAccessToWindow());",
102       &success));
103   EXPECT_TRUE(success);
104
105   // Now navigate the new window to a different site.
106   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
107   scoped_refptr<SiteInstance> new_site_instance(
108       new_shell->web_contents()->GetSiteInstance());
109   EXPECT_NE(orig_site_instance, new_site_instance);
110
111   // We should no longer have script access to the opened window's location.
112   success = false;
113   EXPECT_TRUE(ExecuteScriptAndExtractBool(
114       shell()->web_contents(),
115       "window.domAutomationController.send(testScriptAccessToWindow());",
116       &success));
117   EXPECT_FALSE(success);
118 }
119
120 // Test for crbug.com/24447.  Following a cross-site link with rel=noreferrer
121 // and target=_blank should create a new SiteInstance.
122 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
123                        SwapProcessWithRelNoreferrerAndTargetBlank) {
124   // Start two servers with different sites.
125   ASSERT_TRUE(test_server()->Start());
126   net::SpawnedTestServer https_server(
127       net::SpawnedTestServer::TYPE_HTTPS,
128       net::SpawnedTestServer::kLocalhost,
129       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
130   ASSERT_TRUE(https_server.Start());
131
132   // Load a page with links that open in a new window.
133   std::string replacement_path;
134   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
135       "files/click-noreferrer-links.html",
136       https_server.host_port_pair(),
137       &replacement_path));
138   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
139
140   // Get the original SiteInstance for later comparison.
141   scoped_refptr<SiteInstance> orig_site_instance(
142       shell()->web_contents()->GetSiteInstance());
143   EXPECT_TRUE(orig_site_instance.get() != NULL);
144
145   // Test clicking a rel=noreferrer + target=blank link.
146   ShellAddedObserver new_shell_observer;
147   bool success = false;
148   EXPECT_TRUE(ExecuteScriptAndExtractBool(
149       shell()->web_contents(),
150       "window.domAutomationController.send(clickNoRefTargetBlankLink());",
151       &success));
152   EXPECT_TRUE(success);
153
154   // Wait for the window to open.
155   Shell* new_shell = new_shell_observer.GetShell();
156
157   EXPECT_EQ("/files/title2.html",
158             new_shell->web_contents()->GetVisibleURL().path());
159
160   // Wait for the cross-site transition in the new tab to finish.
161   WaitForLoadStop(new_shell->web_contents());
162   WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
163       new_shell->web_contents());
164   EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
165       pending_render_view_host());
166
167   // Should have a new SiteInstance.
168   scoped_refptr<SiteInstance> noref_blank_site_instance(
169       new_shell->web_contents()->GetSiteInstance());
170   EXPECT_NE(orig_site_instance, noref_blank_site_instance);
171 }
172
173 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance)
174 // for rel=noreferrer links in new windows, even to same site pages and named
175 // targets.
176 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
177                        SwapProcessWithSameSiteRelNoreferrer) {
178   // Start two servers with different sites.
179   ASSERT_TRUE(test_server()->Start());
180   net::SpawnedTestServer https_server(
181       net::SpawnedTestServer::TYPE_HTTPS,
182       net::SpawnedTestServer::kLocalhost,
183       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
184   ASSERT_TRUE(https_server.Start());
185
186   // Load a page with links that open in a new window.
187   std::string replacement_path;
188   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
189       "files/click-noreferrer-links.html",
190       https_server.host_port_pair(),
191       &replacement_path));
192   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
193
194   // Get the original SiteInstance for later comparison.
195   scoped_refptr<SiteInstance> orig_site_instance(
196       shell()->web_contents()->GetSiteInstance());
197   EXPECT_TRUE(orig_site_instance.get() != NULL);
198
199   // Test clicking a same-site rel=noreferrer + target=foo link.
200   ShellAddedObserver new_shell_observer;
201   bool success = false;
202   EXPECT_TRUE(ExecuteScriptAndExtractBool(
203       shell()->web_contents(),
204       "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());",
205       &success));
206   EXPECT_TRUE(success);
207
208   // Wait for the window to open.
209   Shell* new_shell = new_shell_observer.GetShell();
210
211   // Opens in new window.
212   EXPECT_EQ("/files/title2.html",
213             new_shell->web_contents()->GetVisibleURL().path());
214
215   // Wait for the cross-site transition in the new tab to finish.
216   WaitForLoadStop(new_shell->web_contents());
217   WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
218       new_shell->web_contents());
219   EXPECT_FALSE(web_contents->GetRenderManagerForTesting()->
220       pending_render_view_host());
221
222   // Should have a new SiteInstance (in a new BrowsingInstance).
223   scoped_refptr<SiteInstance> noref_blank_site_instance(
224       new_shell->web_contents()->GetSiteInstance());
225   EXPECT_NE(orig_site_instance, noref_blank_site_instance);
226 }
227
228 // Test for crbug.com/24447.  Following a cross-site link with just
229 // target=_blank should not create a new SiteInstance.
230 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
231                        DontSwapProcessWithOnlyTargetBlank) {
232   // Start two servers with different sites.
233   ASSERT_TRUE(test_server()->Start());
234   net::SpawnedTestServer https_server(
235       net::SpawnedTestServer::TYPE_HTTPS,
236       net::SpawnedTestServer::kLocalhost,
237       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
238   ASSERT_TRUE(https_server.Start());
239
240   // Load a page with links that open in a new window.
241   std::string replacement_path;
242   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
243       "files/click-noreferrer-links.html",
244       https_server.host_port_pair(),
245       &replacement_path));
246   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
247
248   // Get the original SiteInstance for later comparison.
249   scoped_refptr<SiteInstance> orig_site_instance(
250       shell()->web_contents()->GetSiteInstance());
251   EXPECT_TRUE(orig_site_instance.get() != NULL);
252
253   // Test clicking a target=blank link.
254   ShellAddedObserver new_shell_observer;
255   bool success = false;
256   EXPECT_TRUE(ExecuteScriptAndExtractBool(
257       shell()->web_contents(),
258       "window.domAutomationController.send(clickTargetBlankLink());",
259       &success));
260   EXPECT_TRUE(success);
261
262   // Wait for the window to open.
263   Shell* new_shell = new_shell_observer.GetShell();
264
265   // Wait for the cross-site transition in the new tab to finish.
266   WaitForLoadStop(new_shell->web_contents());
267   EXPECT_EQ("/files/title2.html",
268             new_shell->web_contents()->GetLastCommittedURL().path());
269
270   // Should have the same SiteInstance.
271   scoped_refptr<SiteInstance> blank_site_instance(
272       new_shell->web_contents()->GetSiteInstance());
273   EXPECT_EQ(orig_site_instance, blank_site_instance);
274 }
275
276 // Test for crbug.com/24447.  Following a cross-site link with rel=noreferrer
277 // and no target=_blank should not create a new SiteInstance.
278 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
279                        DontSwapProcessWithOnlyRelNoreferrer) {
280   // Start two servers with different sites.
281   ASSERT_TRUE(test_server()->Start());
282   net::SpawnedTestServer https_server(
283       net::SpawnedTestServer::TYPE_HTTPS,
284       net::SpawnedTestServer::kLocalhost,
285       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
286   ASSERT_TRUE(https_server.Start());
287
288   // Load a page with links that open in a new window.
289   std::string replacement_path;
290   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
291       "files/click-noreferrer-links.html",
292       https_server.host_port_pair(),
293       &replacement_path));
294   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
295
296   // Get the original SiteInstance for later comparison.
297   scoped_refptr<SiteInstance> orig_site_instance(
298       shell()->web_contents()->GetSiteInstance());
299   EXPECT_TRUE(orig_site_instance.get() != NULL);
300
301   // Test clicking a rel=noreferrer link.
302   bool success = false;
303   EXPECT_TRUE(ExecuteScriptAndExtractBool(
304       shell()->web_contents(),
305       "window.domAutomationController.send(clickNoRefLink());",
306       &success));
307   EXPECT_TRUE(success);
308
309   // Wait for the cross-site transition in the current tab to finish.
310   WaitForLoadStop(shell()->web_contents());
311
312   // Opens in same window.
313   EXPECT_EQ(1u, Shell::windows().size());
314   EXPECT_EQ("/files/title2.html",
315             shell()->web_contents()->GetLastCommittedURL().path());
316
317   // Should have the same SiteInstance.
318   scoped_refptr<SiteInstance> noref_site_instance(
319       shell()->web_contents()->GetSiteInstance());
320   EXPECT_EQ(orig_site_instance, noref_site_instance);
321 }
322
323 // Test for crbug.com/116192.  Targeted links should still work after the
324 // named target window has swapped processes.
325 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
326                        AllowTargetedNavigationsAfterSwap) {
327   // Start two servers with different sites.
328   ASSERT_TRUE(test_server()->Start());
329   net::SpawnedTestServer https_server(
330       net::SpawnedTestServer::TYPE_HTTPS,
331       net::SpawnedTestServer::kLocalhost,
332       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
333   ASSERT_TRUE(https_server.Start());
334
335   // Load a page with links that open in a new window.
336   std::string replacement_path;
337   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
338       "files/click-noreferrer-links.html",
339       https_server.host_port_pair(),
340       &replacement_path));
341   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
342
343   // Get the original SiteInstance for later comparison.
344   scoped_refptr<SiteInstance> orig_site_instance(
345       shell()->web_contents()->GetSiteInstance());
346   EXPECT_TRUE(orig_site_instance.get() != NULL);
347
348   // Test clicking a target=foo link.
349   ShellAddedObserver new_shell_observer;
350   bool success = false;
351   EXPECT_TRUE(ExecuteScriptAndExtractBool(
352       shell()->web_contents(),
353       "window.domAutomationController.send(clickSameSiteTargetedLink());",
354       &success));
355   EXPECT_TRUE(success);
356   Shell* new_shell = new_shell_observer.GetShell();
357
358   // Wait for the navigation in the new tab to finish, if it hasn't.
359   WaitForLoadStop(new_shell->web_contents());
360   EXPECT_EQ("/files/navigate_opener.html",
361             new_shell->web_contents()->GetLastCommittedURL().path());
362
363   // Should have the same SiteInstance.
364   scoped_refptr<SiteInstance> blank_site_instance(
365       new_shell->web_contents()->GetSiteInstance());
366   EXPECT_EQ(orig_site_instance, blank_site_instance);
367
368   // Now navigate the new tab to a different site.
369   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
370   scoped_refptr<SiteInstance> new_site_instance(
371       new_shell->web_contents()->GetSiteInstance());
372   EXPECT_NE(orig_site_instance, new_site_instance);
373
374   // Clicking the original link in the first tab should cause us to swap back.
375   TestNavigationObserver navigation_observer(new_shell->web_contents());
376   EXPECT_TRUE(ExecuteScriptAndExtractBool(
377       shell()->web_contents(),
378       "window.domAutomationController.send(clickSameSiteTargetedLink());",
379       &success));
380   EXPECT_TRUE(success);
381   navigation_observer.Wait();
382
383   // Should have swapped back and shown the new window again.
384   scoped_refptr<SiteInstance> revisit_site_instance(
385       new_shell->web_contents()->GetSiteInstance());
386   EXPECT_EQ(orig_site_instance, revisit_site_instance);
387
388   // If it navigates away to another process, the original window should
389   // still be able to close it (using a cross-process close message).
390   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
391   EXPECT_EQ(new_site_instance,
392             new_shell->web_contents()->GetSiteInstance());
393   WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
394   EXPECT_TRUE(ExecuteScriptAndExtractBool(
395       shell()->web_contents(),
396       "window.domAutomationController.send(testCloseWindow());",
397       &success));
398   EXPECT_TRUE(success);
399   close_watcher.Wait();
400 }
401
402 // Test that setting the opener to null in a window affects cross-process
403 // navigations, including those to existing entries.  http://crbug.com/156669.
404 // Flaky on windows: http://crbug.com/291249
405 #if defined(OS_WIN)
406 #define MAYBE_DisownOpener DISABLED_DisownOpener
407 #else
408 #define MAYBE_DisownOpener DisownOpener
409 #endif
410 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, MAYBE_DisownOpener) {
411   // Start two servers with different sites.
412   ASSERT_TRUE(test_server()->Start());
413   net::SpawnedTestServer https_server(
414       net::SpawnedTestServer::TYPE_HTTPS,
415       net::SpawnedTestServer::kLocalhost,
416       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
417   ASSERT_TRUE(https_server.Start());
418
419   // Load a page with links that open in a new window.
420   std::string replacement_path;
421   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
422       "files/click-noreferrer-links.html",
423       https_server.host_port_pair(),
424       &replacement_path));
425   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
426
427   // Get the original SiteInstance for later comparison.
428   scoped_refptr<SiteInstance> orig_site_instance(
429       shell()->web_contents()->GetSiteInstance());
430   EXPECT_TRUE(orig_site_instance.get() != NULL);
431
432   // Test clicking a target=_blank link.
433   ShellAddedObserver new_shell_observer;
434   bool success = false;
435   EXPECT_TRUE(ExecuteScriptAndExtractBool(
436       shell()->web_contents(),
437       "window.domAutomationController.send(clickSameSiteTargetBlankLink());",
438       &success));
439   EXPECT_TRUE(success);
440   Shell* new_shell = new_shell_observer.GetShell();
441
442   // Wait for the navigation in the new tab to finish, if it hasn't.
443   WaitForLoadStop(new_shell->web_contents());
444   EXPECT_EQ("/files/title2.html",
445             new_shell->web_contents()->GetLastCommittedURL().path());
446
447   // Should have the same SiteInstance.
448   scoped_refptr<SiteInstance> blank_site_instance(
449       new_shell->web_contents()->GetSiteInstance());
450   EXPECT_EQ(orig_site_instance, blank_site_instance);
451
452   // Now navigate the new tab to a different site.
453   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
454   scoped_refptr<SiteInstance> new_site_instance(
455       new_shell->web_contents()->GetSiteInstance());
456   EXPECT_NE(orig_site_instance, new_site_instance);
457
458   // Now disown the opener.
459   EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
460                             "window.opener = null;"));
461
462   // Go back and ensure the opener is still null.
463   {
464     TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
465     new_shell->web_contents()->GetController().GoBack();
466     back_nav_load_observer.Wait();
467   }
468   success = false;
469   EXPECT_TRUE(ExecuteScriptAndExtractBool(
470       new_shell->web_contents(),
471       "window.domAutomationController.send(window.opener == null);",
472       &success));
473   EXPECT_TRUE(success);
474
475   // Now navigate forward again (creating a new process) and check opener.
476   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
477   success = false;
478   EXPECT_TRUE(ExecuteScriptAndExtractBool(
479       new_shell->web_contents(),
480       "window.domAutomationController.send(window.opener == null);",
481       &success));
482   EXPECT_TRUE(success);
483 }
484
485 // Test that subframes can disown their openers.  http://crbug.com/225528.
486 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, DisownSubframeOpener) {
487   const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>");
488   NavigateToURL(shell(), frame_url);
489
490   // Give the frame an opener using window.open.
491   EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
492                             "window.open('about:blank','foo');"));
493
494   // Now disown the frame's opener.  Shouldn't crash.
495   EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
496                             "window.frames[0].opener = null;"));
497 }
498
499 // Test for crbug.com/99202.  PostMessage calls should still work after
500 // navigating the source and target windows to different sites.
501 // Specifically:
502 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process.
503 // 2) Fail to post a message from "foo" to opener with the wrong target origin.
504 // 3) Post a message from "foo" to opener, which replies back to "foo".
505 // 4) Post a message from _blank to "foo".
506 // 5) Post a message from "foo" to a subframe of opener, which replies back.
507 // 6) Post a message from _blank to a subframe of "foo".
508 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
509                        SupportCrossProcessPostMessage) {
510   // Start two servers with different sites.
511   ASSERT_TRUE(test_server()->Start());
512   net::SpawnedTestServer https_server(
513       net::SpawnedTestServer::TYPE_HTTPS,
514       net::SpawnedTestServer::kLocalhost,
515       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
516   ASSERT_TRUE(https_server.Start());
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       https_server.host_port_pair(),
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   RenderViewHostManager* 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, https_server.GetURL("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   RenderViewHostManager* 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(RenderViewHostManagerTest,
656                        SupportCrossProcessPostMessageWithMessagePort) {
657   // Start two servers with different sites.
658   ASSERT_TRUE(test_server()->Start());
659   net::SpawnedTestServer https_server(
660       net::SpawnedTestServer::TYPE_HTTPS,
661       net::SpawnedTestServer::kLocalhost,
662       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
663   ASSERT_TRUE(https_server.Start());
664
665   // Load a page with links that open in a new window.
666   std::string replacement_path;
667   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
668       "files/click-noreferrer-links.html",
669       https_server.host_port_pair(),
670       &replacement_path));
671   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
672
673   // Get the original SiteInstance and RVHM for later comparison.
674   WebContents* opener_contents = shell()->web_contents();
675   scoped_refptr<SiteInstance> orig_site_instance(
676       opener_contents->GetSiteInstance());
677   EXPECT_TRUE(orig_site_instance.get() != NULL);
678   RenderViewHostManager* opener_manager = static_cast<WebContentsImpl*>(
679       opener_contents)->GetRenderManagerForTesting();
680
681   // 1) Open a named target=foo window. We will later post a message between the
682   // opener and the new window.
683   ShellAddedObserver new_shell_observer;
684   bool success = false;
685   EXPECT_TRUE(ExecuteScriptAndExtractBool(
686       opener_contents,
687       "window.domAutomationController.send(clickSameSiteTargetedLink());",
688       &success));
689   EXPECT_TRUE(success);
690   Shell* new_shell = new_shell_observer.GetShell();
691
692   // Wait for the navigation in the new window to finish, if it hasn't, then
693   // send it to post_message.html on a different site.
694   WebContents* foo_contents = new_shell->web_contents();
695   WaitForLoadStop(foo_contents);
696   EXPECT_EQ("/files/navigate_opener.html",
697             foo_contents->GetLastCommittedURL().path());
698   NavigateToURL(
699       new_shell,
700       https_server.GetURL("files/post_message.html"));
701   scoped_refptr<SiteInstance> foo_site_instance(
702       foo_contents->GetSiteInstance());
703   EXPECT_NE(orig_site_instance, foo_site_instance);
704
705   // We now have two windows. The opener should have a swapped out RVH
706   // for the new SiteInstance.
707   EXPECT_EQ(2u, Shell::windows().size());
708   EXPECT_TRUE(
709       opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get()));
710
711   // 2) Post a message containing a MessagePort from opener to the the foo
712   // window. The foo window will reply via the passed port, causing the opener
713   // to update its own title.
714   WindowedNotificationObserver title_observer(
715       NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
716       Source<WebContents>(opener_contents));
717   EXPECT_TRUE(ExecuteScriptAndExtractBool(
718       opener_contents,
719       "window.domAutomationController.send(postWithPortToFoo());",
720       &success));
721   EXPECT_TRUE(success);
722   ASSERT_FALSE(
723       opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get()));
724   title_observer.Wait();
725
726   // Check message counts.
727   int opener_received_messages_via_port = 0;
728   EXPECT_TRUE(ExecuteScriptAndExtractInt(
729       opener_contents,
730       "window.domAutomationController.send(window.receivedMessagesViaPort);",
731       &opener_received_messages_via_port));
732   int foo_received_messages = 0;
733   EXPECT_TRUE(ExecuteScriptAndExtractInt(
734       foo_contents,
735       "window.domAutomationController.send(window.receivedMessages);",
736       &foo_received_messages));
737   int foo_received_messages_with_port = 0;
738   EXPECT_TRUE(ExecuteScriptAndExtractInt(
739       foo_contents,
740       "window.domAutomationController.send(window.receivedMessagesWithPort);",
741       &foo_received_messages_with_port));
742   EXPECT_EQ(1, foo_received_messages);
743   EXPECT_EQ(1, foo_received_messages_with_port);
744   EXPECT_EQ(1, opener_received_messages_via_port);
745   EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle());
746   EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle());
747 }
748
749 // Test for crbug.com/116192.  Navigations to a window's opener should
750 // still work after a process swap.
751 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
752                        AllowTargetedNavigationsInOpenerAfterSwap) {
753   // Start two servers with different sites.
754   ASSERT_TRUE(test_server()->Start());
755   net::SpawnedTestServer https_server(
756       net::SpawnedTestServer::TYPE_HTTPS,
757       net::SpawnedTestServer::kLocalhost,
758       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
759   ASSERT_TRUE(https_server.Start());
760
761   // Load a page with links that open in a new window.
762   std::string replacement_path;
763   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
764       "files/click-noreferrer-links.html",
765       https_server.host_port_pair(),
766       &replacement_path));
767   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
768
769   // Get the original tab and SiteInstance for later comparison.
770   WebContents* orig_contents = shell()->web_contents();
771   scoped_refptr<SiteInstance> orig_site_instance(
772       orig_contents->GetSiteInstance());
773   EXPECT_TRUE(orig_site_instance.get() != NULL);
774
775   // Test clicking a target=foo link.
776   ShellAddedObserver new_shell_observer;
777   bool success = false;
778   EXPECT_TRUE(ExecuteScriptAndExtractBool(
779       orig_contents,
780       "window.domAutomationController.send(clickSameSiteTargetedLink());",
781       &success));
782   EXPECT_TRUE(success);
783   Shell* new_shell = new_shell_observer.GetShell();
784
785   // Wait for the navigation in the new window to finish, if it hasn't.
786   WaitForLoadStop(new_shell->web_contents());
787   EXPECT_EQ("/files/navigate_opener.html",
788             new_shell->web_contents()->GetLastCommittedURL().path());
789
790   // Should have the same SiteInstance.
791   scoped_refptr<SiteInstance> blank_site_instance(
792       new_shell->web_contents()->GetSiteInstance());
793   EXPECT_EQ(orig_site_instance, blank_site_instance);
794
795   // Now navigate the original (opener) tab to a different site.
796   NavigateToURL(shell(), https_server.GetURL("files/title1.html"));
797   scoped_refptr<SiteInstance> new_site_instance(
798       shell()->web_contents()->GetSiteInstance());
799   EXPECT_NE(orig_site_instance, new_site_instance);
800
801   // The opened tab should be able to navigate the opener back to its process.
802   TestNavigationObserver navigation_observer(orig_contents);
803   EXPECT_TRUE(ExecuteScriptAndExtractBool(
804       new_shell->web_contents(),
805       "window.domAutomationController.send(navigateOpener());",
806       &success));
807   EXPECT_TRUE(success);
808   navigation_observer.Wait();
809
810   // Should have swapped back into this process.
811   scoped_refptr<SiteInstance> revisit_site_instance(
812       shell()->web_contents()->GetSiteInstance());
813   EXPECT_EQ(orig_site_instance, revisit_site_instance);
814 }
815
816 // Test that opening a new window in the same SiteInstance and then navigating
817 // both windows to a different SiteInstance allows the first process to exit.
818 // See http://crbug.com/126333.
819 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
820                        ProcessExitWithSwappedOutViews) {
821   // Start two servers with different sites.
822   ASSERT_TRUE(test_server()->Start());
823   net::SpawnedTestServer https_server(
824       net::SpawnedTestServer::TYPE_HTTPS,
825       net::SpawnedTestServer::kLocalhost,
826       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
827   ASSERT_TRUE(https_server.Start());
828
829   // Load a page with links that open in a new window.
830   std::string replacement_path;
831   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
832       "files/click-noreferrer-links.html",
833       https_server.host_port_pair(),
834       &replacement_path));
835   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
836
837   // Get the original SiteInstance for later comparison.
838   scoped_refptr<SiteInstance> orig_site_instance(
839       shell()->web_contents()->GetSiteInstance());
840   EXPECT_TRUE(orig_site_instance.get() != NULL);
841
842   // Test clicking a target=foo link.
843   ShellAddedObserver new_shell_observer;
844   bool success = false;
845   EXPECT_TRUE(ExecuteScriptAndExtractBool(
846       shell()->web_contents(),
847       "window.domAutomationController.send(clickSameSiteTargetedLink());",
848       &success));
849   EXPECT_TRUE(success);
850   Shell* new_shell = new_shell_observer.GetShell();
851
852   // Wait for the navigation in the new window to finish, if it hasn't.
853   WaitForLoadStop(new_shell->web_contents());
854   EXPECT_EQ("/files/navigate_opener.html",
855             new_shell->web_contents()->GetLastCommittedURL().path());
856
857   // Should have the same SiteInstance.
858   scoped_refptr<SiteInstance> opened_site_instance(
859       new_shell->web_contents()->GetSiteInstance());
860   EXPECT_EQ(orig_site_instance, opened_site_instance);
861
862   // Now navigate the opened window to a different site.
863   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
864   scoped_refptr<SiteInstance> new_site_instance(
865       new_shell->web_contents()->GetSiteInstance());
866   EXPECT_NE(orig_site_instance, new_site_instance);
867
868   // The original process should still be alive, since it is still used in the
869   // first window.
870   RenderProcessHost* orig_process = orig_site_instance->GetProcess();
871   EXPECT_TRUE(orig_process->HasConnection());
872
873   // Navigate the first window to a different site as well.  The original
874   // process should exit, since all of its views are now swapped out.
875   WindowedNotificationObserver exit_observer(
876       NOTIFICATION_RENDERER_PROCESS_TERMINATED,
877       Source<RenderProcessHost>(orig_process));
878   NavigateToURL(shell(), https_server.GetURL("files/title1.html"));
879   exit_observer.Wait();
880   scoped_refptr<SiteInstance> new_site_instance2(
881       shell()->web_contents()->GetSiteInstance());
882   EXPECT_EQ(new_site_instance, new_site_instance2);
883 }
884
885 // Test for crbug.com/76666.  A cross-site navigation that fails with a 204
886 // error should not make us ignore future renderer-initiated navigations.
887 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, ClickLinkAfter204Error) {
888   // Start two servers with different sites.
889   ASSERT_TRUE(test_server()->Start());
890   net::SpawnedTestServer https_server(
891       net::SpawnedTestServer::TYPE_HTTPS,
892       net::SpawnedTestServer::kLocalhost,
893       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
894   ASSERT_TRUE(https_server.Start());
895
896   // Load a page with links that open in a new window.
897   // The links will point to the HTTPS server.
898   std::string replacement_path;
899   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
900       "files/click-noreferrer-links.html",
901       https_server.host_port_pair(),
902       &replacement_path));
903   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
904
905   // Get the original SiteInstance for later comparison.
906   scoped_refptr<SiteInstance> orig_site_instance(
907       shell()->web_contents()->GetSiteInstance());
908   EXPECT_TRUE(orig_site_instance.get() != NULL);
909
910   // Load a cross-site page that fails with a 204 error.
911   NavigateToURL(shell(), https_server.GetURL("nocontent"));
912
913   // We should still be looking at the normal page.  The typed URL will
914   // still be visible until the user clears it manually, but the last
915   // committed URL will be the previous page.
916   scoped_refptr<SiteInstance> post_nav_site_instance(
917       shell()->web_contents()->GetSiteInstance());
918   EXPECT_EQ(orig_site_instance, post_nav_site_instance);
919   EXPECT_EQ("/nocontent",
920             shell()->web_contents()->GetVisibleURL().path());
921   EXPECT_EQ("/files/click-noreferrer-links.html",
922             shell()->web_contents()->GetController().
923                 GetLastCommittedEntry()->GetVirtualURL().path());
924
925   // Renderer-initiated navigations should work.
926   bool success = false;
927   EXPECT_TRUE(ExecuteScriptAndExtractBool(
928       shell()->web_contents(),
929       "window.domAutomationController.send(clickNoRefLink());",
930       &success));
931   EXPECT_TRUE(success);
932
933   // Wait for the cross-site transition in the current tab to finish.
934   WaitForLoadStop(shell()->web_contents());
935
936   // Opens in same tab.
937   EXPECT_EQ(1u, Shell::windows().size());
938   EXPECT_EQ("/files/title2.html",
939             shell()->web_contents()->GetLastCommittedURL().path());
940
941   // Should have the same SiteInstance.
942   scoped_refptr<SiteInstance> noref_site_instance(
943       shell()->web_contents()->GetSiteInstance());
944   EXPECT_EQ(orig_site_instance, noref_site_instance);
945 }
946
947 // Test for crbug.com/9682.  We should show the URL for a pending renderer-
948 // initiated navigation in a new tab, until the content of the initial
949 // about:blank page is modified by another window.  At that point, we should
950 // revert to showing about:blank to prevent a URL spoof.
951 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, ShowLoadingURLUntilSpoof) {
952   ASSERT_TRUE(test_server()->Start());
953
954   // Load a page that can open a URL that won't commit in a new window.
955   NavigateToURL(
956       shell(), test_server()->GetURL("files/click-nocontent-link.html"));
957   WebContents* orig_contents = shell()->web_contents();
958
959   // Click a /nocontent link that opens in a new window but never commits.
960   ShellAddedObserver new_shell_observer;
961   bool success = false;
962   EXPECT_TRUE(ExecuteScriptAndExtractBool(
963       orig_contents,
964       "window.domAutomationController.send(clickNoContentTargetedLink());",
965       &success));
966   EXPECT_TRUE(success);
967
968   // Wait for the window to open.
969   Shell* new_shell = new_shell_observer.GetShell();
970
971   // Ensure the destination URL is visible, because it is considered the
972   // initial navigation.
973   WebContents* contents = new_shell->web_contents();
974   EXPECT_TRUE(contents->GetController().IsInitialNavigation());
975   EXPECT_EQ("/nocontent",
976             contents->GetController().GetVisibleEntry()->GetURL().path());
977
978   // Now modify the contents of the new window from the opener.  This will also
979   // modify the title of the document to give us something to listen for.
980   base::string16 expected_title = ASCIIToUTF16("Modified Title");
981   TitleWatcher title_watcher(contents, expected_title);
982   success = false;
983   EXPECT_TRUE(ExecuteScriptAndExtractBool(
984       orig_contents,
985       "window.domAutomationController.send(modifyNewWindow());",
986       &success));
987   EXPECT_TRUE(success);
988   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
989
990   // At this point, we should no longer be showing the destination URL.
991   // The visible entry should be null, resulting in about:blank in the address
992   // bar.
993   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
994 }
995
996 // Test for crbug.com/9682.  We should not show the URL for a pending renderer-
997 // initiated navigation in a new tab if it is not the initial navigation.  In
998 // this case, the renderer will not notify us of a modification, so we cannot
999 // show the pending URL without allowing a spoof.
1000 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
1001                        DontShowLoadingURLIfNotInitialNav) {
1002   ASSERT_TRUE(test_server()->Start());
1003
1004   // Load a page that can open a URL that won't commit in a new window.
1005   NavigateToURL(
1006       shell(), test_server()->GetURL("files/click-nocontent-link.html"));
1007   WebContents* orig_contents = shell()->web_contents();
1008
1009   // Click a /nocontent link that opens in a new window but never commits.
1010   // By using an onclick handler that first creates the window, the slow
1011   // navigation is not considered an initial navigation.
1012   ShellAddedObserver new_shell_observer;
1013   bool success = false;
1014   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1015       orig_contents,
1016       "window.domAutomationController.send("
1017       "clickNoContentScriptedTargetedLink());",
1018       &success));
1019   EXPECT_TRUE(success);
1020
1021   // Wait for the window to open.
1022   Shell* new_shell = new_shell_observer.GetShell();
1023
1024   // Ensure the destination URL is not visible, because it is not the initial
1025   // navigation.
1026   WebContents* contents = new_shell->web_contents();
1027   EXPECT_FALSE(contents->GetController().IsInitialNavigation());
1028   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
1029 }
1030
1031 // Test for http://crbug.com/93427.  Ensure that cross-site navigations
1032 // do not cause back/forward navigations to be considered stale by the
1033 // renderer.
1034 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, BackForwardNotStale) {
1035   NavigateToURL(shell(), GURL(kAboutBlankURL));
1036
1037   // Start two servers with different sites.
1038   ASSERT_TRUE(test_server()->Start());
1039   net::SpawnedTestServer https_server(
1040       net::SpawnedTestServer::TYPE_HTTPS,
1041       net::SpawnedTestServer::kLocalhost,
1042       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1043   ASSERT_TRUE(https_server.Start());
1044
1045   // Visit a page on first site.
1046   std::string replacement_path_a1;
1047   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1048       "files/title1.html",
1049       test_server()->host_port_pair(),
1050       &replacement_path_a1));
1051   NavigateToURL(shell(), test_server()->GetURL(replacement_path_a1));
1052
1053   // Visit three pages on second site.
1054   std::string replacement_path_b1;
1055   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1056       "files/title1.html",
1057       https_server.host_port_pair(),
1058       &replacement_path_b1));
1059   NavigateToURL(shell(), https_server.GetURL(replacement_path_b1));
1060   std::string replacement_path_b2;
1061   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1062       "files/title2.html",
1063       https_server.host_port_pair(),
1064       &replacement_path_b2));
1065   NavigateToURL(shell(), https_server.GetURL(replacement_path_b2));
1066   std::string replacement_path_b3;
1067   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1068       "files/title3.html",
1069       https_server.host_port_pair(),
1070       &replacement_path_b3));
1071   NavigateToURL(shell(), https_server.GetURL(replacement_path_b3));
1072
1073   // History is now [blank, A1, B1, B2, *B3].
1074   WebContents* contents = shell()->web_contents();
1075   EXPECT_EQ(5, contents->GetController().GetEntryCount());
1076
1077   // Open another window in same process to keep this process alive.
1078   Shell* new_shell = CreateBrowser();
1079   NavigateToURL(new_shell, https_server.GetURL(replacement_path_b1));
1080
1081   // Go back three times to first site.
1082   {
1083     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1084     shell()->web_contents()->GetController().GoBack();
1085     back_nav_load_observer.Wait();
1086   }
1087   {
1088     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1089     shell()->web_contents()->GetController().GoBack();
1090     back_nav_load_observer.Wait();
1091   }
1092   {
1093     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1094     shell()->web_contents()->GetController().GoBack();
1095     back_nav_load_observer.Wait();
1096   }
1097
1098   // Now go forward twice to B2.  Shouldn't be left spinning.
1099   {
1100     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1101     shell()->web_contents()->GetController().GoForward();
1102     forward_nav_load_observer.Wait();
1103   }
1104   {
1105     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1106     shell()->web_contents()->GetController().GoForward();
1107     forward_nav_load_observer.Wait();
1108   }
1109
1110   // Go back twice to first site.
1111   {
1112     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1113     shell()->web_contents()->GetController().GoBack();
1114     back_nav_load_observer.Wait();
1115   }
1116   {
1117     TestNavigationObserver back_nav_load_observer(shell()->web_contents());
1118     shell()->web_contents()->GetController().GoBack();
1119     back_nav_load_observer.Wait();
1120   }
1121
1122   // Now go forward directly to B3.  Shouldn't be left spinning.
1123   {
1124     TestNavigationObserver forward_nav_load_observer(shell()->web_contents());
1125     shell()->web_contents()->GetController().GoToIndex(4);
1126     forward_nav_load_observer.Wait();
1127   }
1128 }
1129
1130 // Test for http://crbug.com/130016.
1131 // Swapping out a render view should update its visiblity state.
1132 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
1133                        SwappedOutViewHasCorrectVisibilityState) {
1134   // Start two servers with different sites.
1135   ASSERT_TRUE(test_server()->Start());
1136   net::SpawnedTestServer https_server(
1137       net::SpawnedTestServer::TYPE_HTTPS,
1138       net::SpawnedTestServer::kLocalhost,
1139       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1140   ASSERT_TRUE(https_server.Start());
1141
1142   // Load a page with links that open in a new window.
1143   std::string replacement_path;
1144   ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
1145       "files/click-noreferrer-links.html",
1146       https_server.host_port_pair(),
1147       &replacement_path));
1148   NavigateToURL(shell(), test_server()->GetURL(replacement_path));
1149
1150   // Open a same-site link in a new widnow.
1151   ShellAddedObserver new_shell_observer;
1152   bool success = false;
1153   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1154       shell()->web_contents(),
1155       "window.domAutomationController.send(clickSameSiteTargetedLink());",
1156       &success));
1157   EXPECT_TRUE(success);
1158   Shell* new_shell = new_shell_observer.GetShell();
1159
1160   // Wait for the navigation in the new tab to finish, if it hasn't.
1161   WaitForLoadStop(new_shell->web_contents());
1162   EXPECT_EQ("/files/navigate_opener.html",
1163             new_shell->web_contents()->GetLastCommittedURL().path());
1164
1165   RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
1166
1167   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1168       rvh,
1169       "window.domAutomationController.send("
1170       "    document.webkitVisibilityState == 'visible');",
1171       &success));
1172   EXPECT_TRUE(success);
1173
1174   // Now navigate the new window to a different site. This should swap out the
1175   // tab's existing RenderView, causing it become hidden.
1176   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
1177
1178   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1179       rvh,
1180       "window.domAutomationController.send("
1181       "    document.webkitVisibilityState == 'hidden');",
1182       &success));
1183   EXPECT_TRUE(success);
1184
1185   // Going back should make the previously swapped-out view to become visible
1186   // again.
1187   {
1188     TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
1189     new_shell->web_contents()->GetController().GoBack();
1190     back_nav_load_observer.Wait();
1191   }
1192
1193   EXPECT_EQ("/files/navigate_opener.html",
1194             new_shell->web_contents()->GetLastCommittedURL().path());
1195
1196   EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
1197
1198   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1199       rvh,
1200       "window.domAutomationController.send("
1201       "    document.webkitVisibilityState == 'visible');",
1202       &success));
1203   EXPECT_TRUE(success);
1204 }
1205
1206 // This class ensures that all the given RenderViewHosts have properly been
1207 // shutdown.
1208 class RenderViewHostDestructionObserver : public WebContentsObserver {
1209  public:
1210   explicit RenderViewHostDestructionObserver(WebContents* web_contents)
1211       : WebContentsObserver(web_contents) {}
1212   virtual ~RenderViewHostDestructionObserver() {}
1213   void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
1214     watched_render_view_hosts_.insert(rvh);
1215   }
1216   size_t GetNumberOfWatchedRenderViewHosts() const {
1217     return watched_render_view_hosts_.size();
1218   }
1219
1220  private:
1221   // WebContentsObserver implementation:
1222   virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
1223     watched_render_view_hosts_.erase(rvh);
1224   }
1225
1226   std::set<RenderViewHost*> watched_render_view_hosts_;
1227 };
1228
1229 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
1230 // they may cause crashes or memory corruptions when trying to call dead
1231 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to
1232 // ensure that a separate SiteInstance is created when navigating to view-source
1233 // URLs, regardless of current URL.
1234 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, LeakingRenderViewHosts) {
1235   // Start two servers with different sites.
1236   ASSERT_TRUE(test_server()->Start());
1237   net::SpawnedTestServer https_server(
1238       net::SpawnedTestServer::TYPE_HTTPS,
1239       net::SpawnedTestServer::kLocalhost,
1240       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1241   ASSERT_TRUE(https_server.Start());
1242
1243   // Observe the created render_view_host's to make sure they will not leak.
1244   RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
1245
1246   GURL navigated_url(test_server()->GetURL("files/title2.html"));
1247   GURL view_source_url(kViewSourceScheme + std::string(":") +
1248                        navigated_url.spec());
1249
1250   // Let's ensure that when we start with a blank window, navigating away to a
1251   // view-source URL, we create a new SiteInstance.
1252   RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
1253   SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
1254   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
1255   EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
1256   rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
1257
1258   // Now navigate to the view-source URL and ensure we got a different
1259   // SiteInstance and RenderViewHost.
1260   NavigateToURL(shell(), view_source_url);
1261   EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
1262   EXPECT_NE(blank_site_instance, shell()->web_contents()->
1263       GetRenderViewHost()->GetSiteInstance());
1264   rvh_observers.EnsureRVHGetsDestructed(
1265       shell()->web_contents()->GetRenderViewHost());
1266
1267   // Load a random page and then navigate to view-source: of it.
1268   // This used to cause two RVH instances for the same SiteInstance, which
1269   // was a problem.  This is no longer the case.
1270   NavigateToURL(shell(), navigated_url);
1271   SiteInstance* site_instance1 = shell()->web_contents()->
1272       GetRenderViewHost()->GetSiteInstance();
1273   rvh_observers.EnsureRVHGetsDestructed(
1274       shell()->web_contents()->GetRenderViewHost());
1275
1276   NavigateToURL(shell(), view_source_url);
1277   rvh_observers.EnsureRVHGetsDestructed(
1278       shell()->web_contents()->GetRenderViewHost());
1279   SiteInstance* site_instance2 = shell()->web_contents()->
1280       GetRenderViewHost()->GetSiteInstance();
1281
1282   // Ensure that view-source navigations force a new SiteInstance.
1283   EXPECT_NE(site_instance1, site_instance2);
1284
1285   // Now navigate to a different instance so that we swap out again.
1286   NavigateToURL(shell(), https_server.GetURL("files/title2.html"));
1287   rvh_observers.EnsureRVHGetsDestructed(
1288       shell()->web_contents()->GetRenderViewHost());
1289
1290   // This used to leak a render view host.
1291   shell()->Close();
1292
1293   RunAllPendingInMessageLoop();  // Needed on ChromeOS.
1294
1295   EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
1296 }
1297
1298 // Test for crbug.com/143155.  Frame tree updates during unload should not
1299 // interrupt the intended navigation and show swappedout:// instead.
1300 // Specifically:
1301 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener.
1302 // 2) Send the second tab to a different HTTPS SiteInstance.
1303 //    This creates a swapped out opener for the first tab in the HTTPS process.
1304 // 3) Navigate the first tab to the HTTPS SiteInstance, and have the first
1305 //    tab's unload handler remove its frame.
1306 // This used to cause an update to the frame tree of the swapped out RV,
1307 // just as it was navigating to a real page.  That pre-empted the real
1308 // navigation and visibly sent the tab to swappedout://.
1309 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
1310                        DontPreemptNavigationWithFrameTreeUpdate) {
1311   // Start two servers with different sites.
1312   ASSERT_TRUE(test_server()->Start());
1313   net::SpawnedTestServer https_server(
1314       net::SpawnedTestServer::TYPE_HTTPS,
1315       net::SpawnedTestServer::kLocalhost,
1316       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1317   ASSERT_TRUE(https_server.Start());
1318
1319   // 1. Load a page that deletes its iframe during unload.
1320   NavigateToURL(shell(),
1321                 test_server()->GetURL("files/remove_frame_on_unload.html"));
1322
1323   // Get the original SiteInstance for later comparison.
1324   scoped_refptr<SiteInstance> orig_site_instance(
1325       shell()->web_contents()->GetSiteInstance());
1326
1327   // Open a same-site page in a new window.
1328   ShellAddedObserver new_shell_observer;
1329   bool success = false;
1330   EXPECT_TRUE(ExecuteScriptAndExtractBool(
1331       shell()->web_contents(),
1332       "window.domAutomationController.send(openWindow());",
1333       &success));
1334   EXPECT_TRUE(success);
1335   Shell* new_shell = new_shell_observer.GetShell();
1336
1337   // Wait for the navigation in the new window to finish, if it hasn't.
1338   WaitForLoadStop(new_shell->web_contents());
1339   EXPECT_EQ("/files/title1.html",
1340             new_shell->web_contents()->GetLastCommittedURL().path());
1341
1342   // Should have the same SiteInstance.
1343   EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
1344
1345   // 2. Send the second tab to a different process.
1346   NavigateToURL(new_shell, https_server.GetURL("files/title1.html"));
1347   scoped_refptr<SiteInstance> new_site_instance(
1348       new_shell->web_contents()->GetSiteInstance());
1349   EXPECT_NE(orig_site_instance, new_site_instance);
1350
1351   // 3. Send the first tab to the second tab's process.
1352   NavigateToURL(shell(), https_server.GetURL("files/title1.html"));
1353
1354   // Make sure it ends up at the right page.
1355   WaitForLoadStop(shell()->web_contents());
1356   EXPECT_EQ(https_server.GetURL("files/title1.html"),
1357             shell()->web_contents()->GetLastCommittedURL());
1358   EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance());
1359 }
1360
1361 }  // namespace content