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