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