render_frame_host_manager_browsertest.cc revision f2477e01787aa58f445919b809d89e252beef54f
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/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
35namespace content {
36
37class RenderFrameHostManagerTest : public ContentBrowserTest {
38 public:
39  RenderFrameHostManagerTest() {}
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.
54IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
122IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
176IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
230IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
278IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
325IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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
410IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 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.
486IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 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".
508IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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  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, 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  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.
655IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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  RenderFrameHostManager* 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.
751IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
819IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
887IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 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.
951IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 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.
1000IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.
1034IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 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.
1132IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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.visibilityState == '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.visibilityState == '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.visibilityState == 'visible');",
1202      &success));
1203  EXPECT_TRUE(success);
1204}
1205
1206// This class ensures that all the given RenderViewHosts have properly been
1207// shutdown.
1208class 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.
1234IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, 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://.
1309IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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
1362