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 "base/files/file_path.h"
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "content/browser/frame_host/cross_site_transferring_request.h"
      8 #include "content/browser/frame_host/navigation_controller_impl.h"
      9 #include "content/browser/frame_host/navigation_entry_impl.h"
     10 #include "content/browser/frame_host/navigator.h"
     11 #include "content/browser/frame_host/render_frame_host_manager.h"
     12 #include "content/browser/site_instance_impl.h"
     13 #include "content/browser/webui/web_ui_controller_factory_registry.h"
     14 #include "content/common/frame_messages.h"
     15 #include "content/common/view_messages.h"
     16 #include "content/public/browser/notification_details.h"
     17 #include "content/public/browser/notification_service.h"
     18 #include "content/public/browser/notification_source.h"
     19 #include "content/public/browser/notification_types.h"
     20 #include "content/public/browser/render_process_host.h"
     21 #include "content/public/browser/render_widget_host_iterator.h"
     22 #include "content/public/browser/web_contents_delegate.h"
     23 #include "content/public/browser/web_contents_observer.h"
     24 #include "content/public/browser/web_ui_controller.h"
     25 #include "content/public/common/bindings_policy.h"
     26 #include "content/public/common/javascript_message_type.h"
     27 #include "content/public/common/page_transition_types.h"
     28 #include "content/public/common/url_constants.h"
     29 #include "content/public/common/url_utils.h"
     30 #include "content/public/test/mock_render_process_host.h"
     31 #include "content/public/test/test_notification_tracker.h"
     32 #include "content/test/test_content_browser_client.h"
     33 #include "content/test/test_content_client.h"
     34 #include "content/test/test_render_view_host.h"
     35 #include "content/test/test_web_contents.h"
     36 #include "testing/gtest/include/gtest/gtest.h"
     37 
     38 namespace content {
     39 namespace {
     40 
     41 class RenderFrameHostManagerTestWebUIControllerFactory
     42     : public WebUIControllerFactory {
     43  public:
     44   RenderFrameHostManagerTestWebUIControllerFactory()
     45     : should_create_webui_(false) {
     46   }
     47   virtual ~RenderFrameHostManagerTestWebUIControllerFactory() {}
     48 
     49   void set_should_create_webui(bool should_create_webui) {
     50     should_create_webui_ = should_create_webui;
     51   }
     52 
     53   // WebUIFactory implementation.
     54   virtual WebUIController* CreateWebUIControllerForURL(
     55       WebUI* web_ui, const GURL& url) const OVERRIDE {
     56     if (!(should_create_webui_ && HasWebUIScheme(url)))
     57       return NULL;
     58     return new WebUIController(web_ui);
     59   }
     60 
     61    virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
     62       const GURL& url) const OVERRIDE {
     63     return WebUI::kNoWebUI;
     64   }
     65 
     66   virtual bool UseWebUIForURL(BrowserContext* browser_context,
     67                               const GURL& url) const OVERRIDE {
     68     return HasWebUIScheme(url);
     69   }
     70 
     71   virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
     72                                       const GURL& url) const OVERRIDE {
     73     return HasWebUIScheme(url);
     74   }
     75 
     76  private:
     77   bool should_create_webui_;
     78 
     79   DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManagerTestWebUIControllerFactory);
     80 };
     81 
     82 class BeforeUnloadFiredWebContentsDelegate : public WebContentsDelegate {
     83  public:
     84   BeforeUnloadFiredWebContentsDelegate() {}
     85   virtual ~BeforeUnloadFiredWebContentsDelegate() {}
     86 
     87   virtual void BeforeUnloadFired(WebContents* web_contents,
     88                                  bool proceed,
     89                                  bool* proceed_to_fire_unload) OVERRIDE {
     90     *proceed_to_fire_unload = proceed;
     91   }
     92 
     93  private:
     94   DISALLOW_COPY_AND_ASSIGN(BeforeUnloadFiredWebContentsDelegate);
     95 };
     96 
     97 // This observer keeps track of the last deleted RenderViewHost to avoid
     98 // accessing it and causing use-after-free condition.
     99 class RenderViewHostDeletedObserver : public WebContentsObserver {
    100  public:
    101   RenderViewHostDeletedObserver(RenderViewHost* rvh)
    102       : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
    103         process_id_(rvh->GetProcess()->GetID()),
    104         routing_id_(rvh->GetRoutingID()),
    105         deleted_(false) {
    106   }
    107 
    108   virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
    109     if (render_view_host->GetProcess()->GetID() == process_id_ &&
    110         render_view_host->GetRoutingID() == routing_id_) {
    111       deleted_ = true;
    112     }
    113   }
    114 
    115   bool deleted() {
    116     return deleted_;
    117   }
    118 
    119  private:
    120   int process_id_;
    121   int routing_id_;
    122   bool deleted_;
    123 
    124   DISALLOW_COPY_AND_ASSIGN(RenderViewHostDeletedObserver);
    125 };
    126 
    127 // This observer keeps track of the last deleted RenderFrameHost to avoid
    128 // accessing it and causing use-after-free condition.
    129 class RenderFrameHostDeletedObserver : public WebContentsObserver {
    130  public:
    131   RenderFrameHostDeletedObserver(RenderFrameHost* rfh)
    132       : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
    133         process_id_(rfh->GetProcess()->GetID()),
    134         routing_id_(rfh->GetRoutingID()),
    135         deleted_(false) {
    136   }
    137 
    138   virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
    139     if (render_frame_host->GetProcess()->GetID() == process_id_ &&
    140         render_frame_host->GetRoutingID() == routing_id_) {
    141       deleted_ = true;
    142     }
    143   }
    144 
    145   bool deleted() {
    146     return deleted_;
    147   }
    148 
    149  private:
    150   int process_id_;
    151   int routing_id_;
    152   bool deleted_;
    153 
    154   DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver);
    155 };
    156 
    157 
    158 // This observer is used to check whether IPC messages are being filtered for
    159 // swapped out RenderFrameHost objects. It observes the plugin crash and favicon
    160 // update events, which the FilterMessagesWhileSwappedOut test simulates being
    161 // sent. The test is successful if the event is not observed.
    162 // See http://crbug.com/351815
    163 class PluginFaviconMessageObserver : public WebContentsObserver {
    164  public:
    165   PluginFaviconMessageObserver(WebContents* web_contents)
    166       : WebContentsObserver(web_contents),
    167         plugin_crashed_(false),
    168         favicon_received_(false) { }
    169 
    170   virtual void PluginCrashed(const base::FilePath& plugin_path,
    171                              base::ProcessId plugin_pid) OVERRIDE {
    172     plugin_crashed_ = true;
    173   }
    174 
    175   virtual void DidUpdateFaviconURL(
    176       const std::vector<FaviconURL>& candidates) OVERRIDE {
    177     favicon_received_ = true;
    178   }
    179 
    180   bool plugin_crashed() {
    181     return plugin_crashed_;
    182   }
    183 
    184   bool favicon_received() {
    185     return favicon_received_;
    186   }
    187 
    188  private:
    189   bool plugin_crashed_;
    190   bool favicon_received_;
    191 
    192   DISALLOW_COPY_AND_ASSIGN(PluginFaviconMessageObserver);
    193 };
    194 
    195 // Ensures that RenderFrameDeleted and RenderFrameCreated are called in a
    196 // consistent manner.
    197 class FrameLifetimeConsistencyChecker : public WebContentsObserver {
    198  public:
    199   explicit FrameLifetimeConsistencyChecker(WebContentsImpl* web_contents)
    200       : WebContentsObserver(web_contents) {
    201     RenderViewCreated(web_contents->GetRenderViewHost());
    202     RenderFrameCreated(web_contents->GetMainFrame());
    203   }
    204 
    205   virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
    206     std::pair<int, int> routing_pair =
    207         std::make_pair(render_frame_host->GetProcess()->GetID(),
    208                        render_frame_host->GetRoutingID());
    209     bool was_live_already = !live_routes_.insert(routing_pair).second;
    210     bool was_used_before = deleted_routes_.count(routing_pair) != 0;
    211 
    212     if (was_live_already) {
    213       FAIL() << "RenderFrameCreated called more than once for routing pair: "
    214              << Format(render_frame_host);
    215     } else if (was_used_before) {
    216       FAIL() << "RenderFrameCreated called for routing pair "
    217              << Format(render_frame_host) << " that was previously deleted.";
    218     }
    219   }
    220 
    221   virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
    222     std::pair<int, int> routing_pair =
    223         std::make_pair(render_frame_host->GetProcess()->GetID(),
    224                        render_frame_host->GetRoutingID());
    225     bool was_live = live_routes_.erase(routing_pair);
    226     bool was_dead_already = !deleted_routes_.insert(routing_pair).second;
    227 
    228     if (was_dead_already) {
    229       FAIL() << "RenderFrameDeleted called more than once for routing pair "
    230              << Format(render_frame_host);
    231     } else if (!was_live) {
    232       FAIL() << "RenderFrameDeleted called for routing pair "
    233              << Format(render_frame_host)
    234              << " for which RenderFrameCreated was never called";
    235     }
    236   }
    237 
    238  private:
    239   std::string Format(RenderFrameHost* render_frame_host) {
    240     return base::StringPrintf(
    241         "(%d, %d -> %s )",
    242         render_frame_host->GetProcess()->GetID(),
    243         render_frame_host->GetRoutingID(),
    244         render_frame_host->GetSiteInstance()->GetSiteURL().spec().c_str());
    245   }
    246   std::set<std::pair<int, int> > live_routes_;
    247   std::set<std::pair<int, int> > deleted_routes_;
    248 };
    249 
    250 }  // namespace
    251 
    252 class RenderFrameHostManagerTest
    253     : public RenderViewHostImplTestHarness {
    254  public:
    255   virtual void SetUp() OVERRIDE {
    256     RenderViewHostImplTestHarness::SetUp();
    257     WebUIControllerFactory::RegisterFactory(&factory_);
    258     lifetime_checker_.reset(new FrameLifetimeConsistencyChecker(contents()));
    259   }
    260 
    261   virtual void TearDown() OVERRIDE {
    262     lifetime_checker_.reset();
    263     RenderViewHostImplTestHarness::TearDown();
    264     WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
    265   }
    266 
    267   void set_should_create_webui(bool should_create_webui) {
    268     factory_.set_should_create_webui(should_create_webui);
    269   }
    270 
    271   void StartCrossSiteTransition(TestWebContents* contents) {
    272     std::vector<GURL> url_chain;
    273     contents->GetRenderManagerForTesting()->OnCrossSiteResponse(
    274         contents->GetRenderManagerForTesting()->pending_frame_host(),
    275         GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
    276         url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
    277     EXPECT_TRUE(contents->cross_navigation_pending());
    278     RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    279         contents->GetRenderViewHost());
    280     EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
    281               rvh->rvh_state());
    282   }
    283 
    284   void NavigateActiveAndCommit(const GURL& url) {
    285     // Note: we navigate the active RenderViewHost because previous navigations
    286     // won't have committed yet, so NavigateAndCommit does the wrong thing
    287     // for us.
    288     controller().LoadURL(url, Referrer(), PAGE_TRANSITION_LINK, std::string());
    289     TestRenderViewHost* old_rvh = test_rvh();
    290 
    291     // Simulate the BeforeUnload_ACK that is received from the current renderer
    292     // for a cross-site navigation.
    293     if (old_rvh != active_rvh()) {
    294       old_rvh->SendBeforeUnloadACK(true);
    295       EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, old_rvh->rvh_state());
    296     }
    297 
    298     // Commit the navigation with a new page ID.
    299     int32 max_page_id = contents()->GetMaxPageIDForSiteInstance(
    300         active_rvh()->GetSiteInstance());
    301 
    302     // Simulate the response coming from the pending renderer.
    303     if (old_rvh != active_rvh())
    304       StartCrossSiteTransition(contents());
    305 
    306     // Simulate the SwapOut_ACK that fires if you commit a cross-site
    307     // navigation.
    308     if (old_rvh != active_rvh()) {
    309       old_rvh->OnSwappedOut(false);
    310       EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT,
    311                 old_rvh->rvh_state());
    312     }
    313 
    314     // Use an observer to avoid accessing a deleted renderer later on when the
    315     // state is being checked.
    316     RenderViewHostDeletedObserver rvh_observer(old_rvh);
    317     active_test_rvh()->SendNavigate(max_page_id + 1, url);
    318 
    319     if (old_rvh != active_rvh() && !rvh_observer.deleted())
    320       EXPECT_TRUE(old_rvh->IsSwappedOut());
    321   }
    322 
    323   bool ShouldSwapProcesses(RenderFrameHostManager* manager,
    324                            const NavigationEntryImpl* current_entry,
    325                            const NavigationEntryImpl* new_entry) const {
    326     return manager->ShouldSwapBrowsingInstancesForNavigation(current_entry,
    327                                                              new_entry);
    328   }
    329 
    330   // Creates a test RenderViewHost that's swapped out.
    331   TestRenderViewHost* CreateSwappedOutRenderViewHost() {
    332     const GURL kChromeURL("chrome://foo");
    333     const GURL kDestUrl("http://www.google.com/");
    334 
    335     // Navigate our first tab to a chrome url and then to the destination.
    336     NavigateActiveAndCommit(kChromeURL);
    337     TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
    338         contents()->GetRenderManagerForTesting()->current_host());
    339 
    340     // Navigate to a cross-site URL.
    341     contents()->GetController().LoadURL(
    342         kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
    343     EXPECT_TRUE(contents()->cross_navigation_pending());
    344 
    345     // Manually increase the number of active views in the
    346     // SiteInstance that ntp_rvh belongs to, to prevent it from being
    347     // destroyed when it gets swapped out.
    348     static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
    349         increment_active_view_count();
    350 
    351     TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
    352         contents()->GetRenderManagerForTesting()->pending_render_view_host());
    353     CHECK(dest_rvh);
    354     EXPECT_NE(ntp_rvh, dest_rvh);
    355 
    356     // BeforeUnload finishes.
    357     ntp_rvh->SendBeforeUnloadACK(true);
    358 
    359     dest_rvh->SendNavigate(101, kDestUrl);
    360     ntp_rvh->OnSwappedOut(false);
    361 
    362     EXPECT_TRUE(ntp_rvh->IsSwappedOut());
    363     return ntp_rvh;
    364   }
    365 
    366  private:
    367   RenderFrameHostManagerTestWebUIControllerFactory factory_;
    368   scoped_ptr<FrameLifetimeConsistencyChecker> lifetime_checker_;
    369 };
    370 
    371 // Tests that when you navigate from a chrome:// url to another page, and
    372 // then do that same thing in another tab, that the two resulting pages have
    373 // different SiteInstances, BrowsingInstances, and RenderProcessHosts. This is
    374 // a regression test for bug 9364.
    375 TEST_F(RenderFrameHostManagerTest, NewTabPageProcesses) {
    376   set_should_create_webui(true);
    377   const GURL kChromeUrl("chrome://foo");
    378   const GURL kDestUrl("http://www.google.com/");
    379 
    380   // Navigate our first tab to the chrome url and then to the destination,
    381   // ensuring we grant bindings to the chrome URL.
    382   NavigateActiveAndCommit(kChromeUrl);
    383   EXPECT_TRUE(active_rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
    384   NavigateActiveAndCommit(kDestUrl);
    385 
    386   // Make a second tab.
    387   scoped_ptr<TestWebContents> contents2(
    388       TestWebContents::Create(browser_context(), NULL));
    389 
    390   // Load the two URLs in the second tab. Note that the first navigation creates
    391   // a RVH that's not pending (since there is no cross-site transition), so
    392   // we use the committed one.
    393   contents2->GetController().LoadURL(
    394       kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
    395   TestRenderViewHost* ntp_rvh2 = static_cast<TestRenderViewHost*>(
    396       contents2->GetRenderManagerForTesting()->current_host());
    397   EXPECT_FALSE(contents2->cross_navigation_pending());
    398   ntp_rvh2->SendNavigate(100, kChromeUrl);
    399 
    400   // The second one is the opposite, creating a cross-site transition and
    401   // requiring a beforeunload ack.
    402   contents2->GetController().LoadURL(
    403       kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
    404   EXPECT_TRUE(contents2->cross_navigation_pending());
    405   TestRenderViewHost* dest_rvh2 = static_cast<TestRenderViewHost*>(
    406       contents2->GetRenderManagerForTesting()->pending_render_view_host());
    407   ASSERT_TRUE(dest_rvh2);
    408 
    409   ntp_rvh2->SendBeforeUnloadACK(true);
    410   StartCrossSiteTransition(contents2.get());
    411   dest_rvh2->SendNavigate(101, kDestUrl);
    412 
    413   // The two RVH's should be different in every way.
    414   EXPECT_NE(active_rvh()->GetProcess(), dest_rvh2->GetProcess());
    415   EXPECT_NE(active_rvh()->GetSiteInstance(), dest_rvh2->GetSiteInstance());
    416   EXPECT_FALSE(active_rvh()->GetSiteInstance()->IsRelatedSiteInstance(
    417                    dest_rvh2->GetSiteInstance()));
    418 
    419   // Navigate both to the new tab page, and verify that they share a
    420   // RenderProcessHost (not a SiteInstance).
    421   NavigateActiveAndCommit(kChromeUrl);
    422 
    423   contents2->GetController().LoadURL(
    424       kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
    425   dest_rvh2->SendBeforeUnloadACK(true);
    426   StartCrossSiteTransition(contents2.get());
    427   static_cast<TestRenderViewHost*>(contents2->GetRenderManagerForTesting()->
    428       pending_render_view_host())->SendNavigate(102, kChromeUrl);
    429 
    430   EXPECT_NE(active_rvh()->GetSiteInstance(),
    431             contents2->GetRenderViewHost()->GetSiteInstance());
    432   EXPECT_EQ(active_rvh()->GetSiteInstance()->GetProcess(),
    433             contents2->GetRenderViewHost()->GetSiteInstance()->GetProcess());
    434 }
    435 
    436 // Ensure that the browser ignores most IPC messages that arrive from a
    437 // RenderViewHost that has been swapped out.  We do not want to take
    438 // action on requests from a non-active renderer.  The main exception is
    439 // for synchronous messages, which cannot be ignored without leaving the
    440 // renderer in a stuck state.  See http://crbug.com/93427.
    441 TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
    442   const GURL kChromeURL("chrome://foo");
    443   const GURL kDestUrl("http://www.google.com/");
    444   std::vector<FaviconURL> icons;
    445 
    446   // Navigate our first tab to a chrome url and then to the destination.
    447   NavigateActiveAndCommit(kChromeURL);
    448   TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
    449       contents()->GetRenderManagerForTesting()->current_host());
    450 
    451   // Send an update favicon message and make sure it works.
    452   const base::string16 ntp_title = base::ASCIIToUTF16("NTP Title");
    453   {
    454     PluginFaviconMessageObserver observer(contents());
    455     EXPECT_TRUE(ntp_rvh->OnMessageReceived(
    456                     ViewHostMsg_UpdateFaviconURL(
    457                         rvh()->GetRoutingID(), icons)));
    458     EXPECT_TRUE(observer.favicon_received());
    459   }
    460   // Create one more view in the same SiteInstance where ntp_rvh
    461   // exists so that it doesn't get deleted on navigation to another
    462   // site.
    463   static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
    464       increment_active_view_count();
    465 
    466 
    467   // Navigate to a cross-site URL.
    468   NavigateActiveAndCommit(kDestUrl);
    469   TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
    470       contents()->GetRenderViewHost());
    471   ASSERT_TRUE(dest_rvh);
    472   EXPECT_NE(ntp_rvh, dest_rvh);
    473 
    474   // The new RVH should be able to update its favicon.
    475   const base::string16 dest_title = base::ASCIIToUTF16("Google");
    476   {
    477     PluginFaviconMessageObserver observer(contents());
    478     EXPECT_TRUE(
    479         dest_rvh->OnMessageReceived(
    480             ViewHostMsg_UpdateFaviconURL(rvh()->GetRoutingID(), icons)));
    481     EXPECT_TRUE(observer.favicon_received());
    482   }
    483 
    484   // The old renderer, being slow, now updates the favicon. It should be
    485   // filtered out and not take effect.
    486   EXPECT_TRUE(ntp_rvh->IsSwappedOut());
    487   {
    488     PluginFaviconMessageObserver observer(contents());
    489     EXPECT_TRUE(
    490         ntp_rvh->OnMessageReceived(
    491             ViewHostMsg_UpdateFaviconURL(rvh()->GetRoutingID(), icons)));
    492     EXPECT_FALSE(observer.favicon_received());
    493   }
    494 
    495   // The same logic should apply to RenderFrameHosts as well and routing through
    496   // swapped out RFH shouldn't be allowed. Use a PluginCrashObserver to check
    497   // if the IPC message is allowed through or not.
    498   {
    499     PluginFaviconMessageObserver observer(contents());
    500     // TODO(nasko): Check that the RFH is in swapped out when the state moves
    501     // from RVH to RFH.
    502     EXPECT_TRUE(ntp_rvh->main_render_frame_host()->OnMessageReceived(
    503                     FrameHostMsg_PluginCrashed(
    504                         main_rfh()->GetRoutingID(), base::FilePath(), 0)));
    505     EXPECT_FALSE(observer.plugin_crashed());
    506   }
    507 
    508   // We cannot filter out synchronous IPC messages, because the renderer would
    509   // be left waiting for a reply.  We pick RunBeforeUnloadConfirm as an example
    510   // that can run easily within a unit test, and that needs to receive a reply
    511   // without showing an actual dialog.
    512   MockRenderProcessHost* ntp_process_host =
    513       static_cast<MockRenderProcessHost*>(ntp_rvh->GetProcess());
    514   ntp_process_host->sink().ClearMessages();
    515   RenderFrameHost* ntp_rfh = ntp_rvh->GetMainFrame();
    516   const base::string16 msg = base::ASCIIToUTF16("Message");
    517   bool result = false;
    518   base::string16 unused;
    519   FrameHostMsg_RunBeforeUnloadConfirm before_unload_msg(
    520       ntp_rfh->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
    521   // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
    522   before_unload_msg.EnableMessagePumping();
    523   EXPECT_TRUE(ntp_rfh->OnMessageReceived(before_unload_msg));
    524   EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
    525 
    526   // Also test RunJavaScriptMessage.
    527   ntp_process_host->sink().ClearMessages();
    528   FrameHostMsg_RunJavaScriptMessage js_msg(
    529       ntp_rfh->GetRoutingID(), msg, msg, kChromeURL,
    530       JAVASCRIPT_MESSAGE_TYPE_CONFIRM, &result, &unused);
    531   js_msg.EnableMessagePumping();
    532   EXPECT_TRUE(ntp_rfh->OnMessageReceived(js_msg));
    533   EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
    534 }
    535 
    536 TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) {
    537   TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
    538   TestRenderWidgetHostView* swapped_out_rwhv =
    539       static_cast<TestRenderWidgetHostView*>(swapped_out_rvh->GetView());
    540   EXPECT_FALSE(swapped_out_rwhv->did_swap_compositor_frame());
    541 
    542   MockRenderProcessHost* process_host =
    543       static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
    544   process_host->sink().ClearMessages();
    545 
    546   cc::CompositorFrame frame;
    547   ViewHostMsg_SwapCompositorFrame msg(rvh()->GetRoutingID(), 0, frame);
    548 
    549   EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
    550   EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame());
    551 }
    552 
    553 // Test if RenderViewHost::GetRenderWidgetHosts() only returns active
    554 // widgets.
    555 TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
    556   TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
    557   EXPECT_TRUE(swapped_out_rvh->IsSwappedOut());
    558 
    559   scoped_ptr<RenderWidgetHostIterator> widgets(
    560       RenderWidgetHost::GetRenderWidgetHosts());
    561   // We know that there is the only one active widget. Another view is
    562   // now swapped out, so the swapped out view is not included in the
    563   // list.
    564   RenderWidgetHost* widget = widgets->GetNextHost();
    565   EXPECT_FALSE(widgets->GetNextHost());
    566   RenderViewHost* rvh = RenderViewHost::From(widget);
    567   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
    568             static_cast<RenderViewHostImpl*>(rvh)->rvh_state());
    569 }
    570 
    571 // Test if RenderViewHost::GetRenderWidgetHosts() returns a subset of
    572 // RenderViewHostImpl::GetAllRenderWidgetHosts().
    573 // RenderViewHost::GetRenderWidgetHosts() returns only active widgets, but
    574 // RenderViewHostImpl::GetAllRenderWidgetHosts() returns everything
    575 // including swapped out ones.
    576 TEST_F(RenderFrameHostManagerTest,
    577        GetRenderWidgetHostsWithinGetAllRenderWidgetHosts) {
    578   TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
    579   EXPECT_TRUE(swapped_out_rvh->IsSwappedOut());
    580 
    581   scoped_ptr<RenderWidgetHostIterator> widgets(
    582       RenderWidgetHost::GetRenderWidgetHosts());
    583 
    584   while (RenderWidgetHost* w = widgets->GetNextHost()) {
    585     bool found = false;
    586     scoped_ptr<RenderWidgetHostIterator> all_widgets(
    587         RenderWidgetHostImpl::GetAllRenderWidgetHosts());
    588     while (RenderWidgetHost* widget = all_widgets->GetNextHost()) {
    589       if (w == widget) {
    590         found = true;
    591         break;
    592       }
    593     }
    594     EXPECT_TRUE(found);
    595   }
    596 }
    597 
    598 // Test if SiteInstanceImpl::active_view_count() is correctly updated
    599 // as views in a SiteInstance get swapped out and in.
    600 TEST_F(RenderFrameHostManagerTest, ActiveViewCountWhileSwappingInandOut) {
    601   const GURL kUrl1("http://www.google.com/");
    602   const GURL kUrl2("http://www.chromium.org/");
    603 
    604   // Navigate to an initial URL.
    605   contents()->NavigateAndCommit(kUrl1);
    606   TestRenderViewHost* rvh1 = test_rvh();
    607 
    608   SiteInstanceImpl* instance1 =
    609       static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance());
    610   EXPECT_EQ(instance1->active_view_count(), 1U);
    611 
    612   // Create 2 new tabs and simulate them being the opener chain for the main
    613   // tab.  They should be in the same SiteInstance.
    614   scoped_ptr<TestWebContents> opener1(
    615       TestWebContents::Create(browser_context(), instance1));
    616   contents()->SetOpener(opener1.get());
    617 
    618   scoped_ptr<TestWebContents> opener2(
    619       TestWebContents::Create(browser_context(), instance1));
    620   opener1->SetOpener(opener2.get());
    621 
    622   EXPECT_EQ(instance1->active_view_count(), 3U);
    623 
    624   // Navigate to a cross-site URL (different SiteInstance but same
    625   // BrowsingInstance).
    626   contents()->NavigateAndCommit(kUrl2);
    627   TestRenderViewHost* rvh2 = test_rvh();
    628   SiteInstanceImpl* instance2 =
    629       static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance());
    630 
    631   // rvh2 is on chromium.org which is different from google.com on
    632   // which other tabs are.
    633   EXPECT_EQ(instance2->active_view_count(), 1U);
    634 
    635   // There are two active views on google.com now.
    636   EXPECT_EQ(instance1->active_view_count(), 2U);
    637 
    638   // Navigate to the original origin (google.com).
    639   contents()->NavigateAndCommit(kUrl1);
    640 
    641   EXPECT_EQ(instance1->active_view_count(), 3U);
    642 }
    643 
    644 // This deletes a WebContents when the given RVH is deleted. This is
    645 // only for testing whether deleting an RVH does not cause any UaF in
    646 // other parts of the system. For now, this class is only used for the
    647 // next test cases to detect the bug mentioned at
    648 // http://crbug.com/259859.
    649 class RenderViewHostDestroyer : public WebContentsObserver {
    650  public:
    651   RenderViewHostDestroyer(RenderViewHost* render_view_host,
    652                           WebContents* web_contents)
    653       : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
    654         render_view_host_(render_view_host),
    655         web_contents_(web_contents) {}
    656 
    657   virtual void RenderViewDeleted(
    658       RenderViewHost* render_view_host) OVERRIDE {
    659     if (render_view_host == render_view_host_)
    660       delete web_contents_;
    661   }
    662 
    663  private:
    664   RenderViewHost* render_view_host_;
    665   WebContents* web_contents_;
    666 
    667   DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestroyer);
    668 };
    669 
    670 // Test if ShutdownRenderViewHostsInSiteInstance() does not touch any
    671 // RenderWidget that has been freed while deleting a RenderViewHost in
    672 // a previous iteration. This is a regression test for
    673 // http://crbug.com/259859.
    674 TEST_F(RenderFrameHostManagerTest,
    675        DetectUseAfterFreeInShutdownRenderViewHostsInSiteInstance) {
    676   const GURL kChromeURL("chrome://newtab");
    677   const GURL kUrl1("http://www.google.com");
    678   const GURL kUrl2("http://www.chromium.org");
    679 
    680   // Navigate our first tab to a chrome url and then to the destination.
    681   NavigateActiveAndCommit(kChromeURL);
    682   TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
    683       contents()->GetRenderManagerForTesting()->current_host());
    684 
    685   // Create one more tab and navigate to kUrl1.  web_contents is not
    686   // wrapped as scoped_ptr since it intentionally deleted by destroyer
    687   // below as part of this test.
    688   TestWebContents* web_contents =
    689       TestWebContents::Create(browser_context(), ntp_rvh->GetSiteInstance());
    690   web_contents->NavigateAndCommit(kUrl1);
    691   RenderViewHostDestroyer destroyer(ntp_rvh, web_contents);
    692 
    693   // This causes the first tab to navigate to kUrl2, which destroys
    694   // the ntp_rvh in ShutdownRenderViewHostsInSiteInstance(). When
    695   // ntp_rvh is destroyed, it also destroys the RVHs in web_contents
    696   // too. This can test whether
    697   // SiteInstanceImpl::ShutdownRenderViewHostsInSiteInstance() can
    698   // touch any object freed in this way or not while iterating through
    699   // all widgets.
    700   contents()->NavigateAndCommit(kUrl2);
    701 }
    702 
    703 // When there is an error with the specified page, renderer exits view-source
    704 // mode. See WebFrameImpl::DidFail(). We check by this test that
    705 // EnableViewSourceMode message is sent on every navigation regardless
    706 // RenderView is being newly created or reused.
    707 TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
    708   const GURL kChromeUrl("chrome://foo");
    709   const GURL kUrl("view-source:http://foo");
    710 
    711   // We have to navigate to some page at first since without this, the first
    712   // navigation will reuse the SiteInstance created by Init(), and the second
    713   // one will create a new SiteInstance. Because current_instance and
    714   // new_instance will be different, a new RenderViewHost will be created for
    715   // the second navigation. We have to avoid this in order to exercise the
    716   // target code patch.
    717   NavigateActiveAndCommit(kChromeUrl);
    718 
    719   // Navigate.
    720   controller().LoadURL(
    721       kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    722   // Simulate response from RenderFrame for DispatchBeforeUnload.
    723   base::TimeTicks now = base::TimeTicks::Now();
    724   main_test_rfh()->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(
    725       main_test_rfh()->GetRoutingID(), true, now, now));
    726   ASSERT_TRUE(pending_rvh());  // New pending RenderViewHost will be created.
    727   RenderViewHost* last_rvh = pending_rvh();
    728   int32 new_id = contents()->GetMaxPageIDForSiteInstance(
    729       active_rvh()->GetSiteInstance()) + 1;
    730   pending_test_rvh()->SendNavigate(new_id, kUrl);
    731   EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
    732   ASSERT_TRUE(controller().GetLastCommittedEntry());
    733   EXPECT_TRUE(kUrl == controller().GetLastCommittedEntry()->GetURL());
    734   EXPECT_FALSE(controller().GetPendingEntry());
    735   // Because we're using TestWebContents and TestRenderViewHost in this
    736   // unittest, no one calls WebContentsImpl::RenderViewCreated(). So, we see no
    737   // EnableViewSourceMode message, here.
    738 
    739   // Clear queued messages before load.
    740   process()->sink().ClearMessages();
    741   // Navigate, again.
    742   controller().LoadURL(
    743       kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    744   // The same RenderViewHost should be reused.
    745   EXPECT_FALSE(pending_rvh());
    746   EXPECT_TRUE(last_rvh == rvh());
    747   test_rvh()->SendNavigate(new_id, kUrl);  // The same page_id returned.
    748   EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
    749   EXPECT_FALSE(controller().GetPendingEntry());
    750   // New message should be sent out to make sure to enter view-source mode.
    751   EXPECT_TRUE(process()->sink().GetUniqueMessageMatching(
    752       ViewMsg_EnableViewSourceMode::ID));
    753 }
    754 
    755 // Tests the Init function by checking the initial RenderViewHost.
    756 TEST_F(RenderFrameHostManagerTest, Init) {
    757   // Using TestBrowserContext.
    758   SiteInstanceImpl* instance =
    759       static_cast<SiteInstanceImpl*>(SiteInstance::Create(browser_context()));
    760   EXPECT_FALSE(instance->HasSite());
    761 
    762   scoped_ptr<TestWebContents> web_contents(
    763       TestWebContents::Create(browser_context(), instance));
    764 
    765   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
    766   RenderViewHostImpl* rvh = manager->current_host();
    767   RenderFrameHostImpl* rfh = manager->current_frame_host();
    768   ASSERT_TRUE(rvh);
    769   ASSERT_TRUE(rfh);
    770   EXPECT_EQ(rvh, rfh->render_view_host());
    771   EXPECT_EQ(instance, rvh->GetSiteInstance());
    772   EXPECT_EQ(web_contents.get(), rvh->GetDelegate());
    773   EXPECT_EQ(web_contents.get(), rfh->delegate());
    774   EXPECT_TRUE(manager->GetRenderWidgetHostView());
    775   EXPECT_FALSE(manager->pending_render_view_host());
    776 }
    777 
    778 // Tests the Navigate function. We navigate three sites consecutively and check
    779 // how the pending/committed RenderViewHost are modified.
    780 TEST_F(RenderFrameHostManagerTest, Navigate) {
    781   TestNotificationTracker notifications;
    782 
    783   SiteInstance* instance = SiteInstance::Create(browser_context());
    784 
    785   scoped_ptr<TestWebContents> web_contents(
    786       TestWebContents::Create(browser_context(), instance));
    787   notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
    788                           Source<WebContents>(web_contents.get()));
    789 
    790   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
    791   RenderFrameHostImpl* host;
    792 
    793   // 1) The first navigation. --------------------------
    794   const GURL kUrl1("http://www.google.com/");
    795   NavigationEntryImpl entry1(
    796       NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
    797       base::string16() /* title */, PAGE_TRANSITION_TYPED,
    798       false /* is_renderer_init */);
    799   host = manager->Navigate(entry1);
    800 
    801   // The RenderFrameHost created in Init will be reused.
    802   EXPECT_TRUE(host == manager->current_frame_host());
    803   EXPECT_FALSE(manager->pending_frame_host());
    804 
    805   // Commit.
    806   manager->DidNavigateFrame(host);
    807   // Commit to SiteInstance should be delayed until RenderView commit.
    808   EXPECT_TRUE(host == manager->current_frame_host());
    809   ASSERT_TRUE(host);
    810   EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
    811       HasSite());
    812   static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
    813 
    814   // 2) Navigate to next site. -------------------------
    815   const GURL kUrl2("http://www.google.com/foo");
    816   NavigationEntryImpl entry2(
    817       NULL /* instance */, -1 /* page_id */, kUrl2,
    818       Referrer(kUrl1, blink::WebReferrerPolicyDefault),
    819       base::string16() /* title */, PAGE_TRANSITION_LINK,
    820       true /* is_renderer_init */);
    821   host = manager->Navigate(entry2);
    822 
    823   // The RenderFrameHost created in Init will be reused.
    824   EXPECT_TRUE(host == manager->current_frame_host());
    825   EXPECT_FALSE(manager->pending_frame_host());
    826 
    827   // Commit.
    828   manager->DidNavigateFrame(host);
    829   EXPECT_TRUE(host == manager->current_frame_host());
    830   ASSERT_TRUE(host);
    831   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
    832       HasSite());
    833 
    834   // 3) Cross-site navigate to next site. --------------
    835   const GURL kUrl3("http://webkit.org/");
    836   NavigationEntryImpl entry3(
    837       NULL /* instance */, -1 /* page_id */, kUrl3,
    838       Referrer(kUrl2, blink::WebReferrerPolicyDefault),
    839       base::string16() /* title */, PAGE_TRANSITION_LINK,
    840       false /* is_renderer_init */);
    841   host = manager->Navigate(entry3);
    842 
    843   // A new RenderFrameHost should be created.
    844   EXPECT_TRUE(manager->pending_frame_host());
    845   ASSERT_EQ(host, manager->pending_frame_host());
    846 
    847   notifications.Reset();
    848 
    849   // Commit.
    850   manager->DidNavigateFrame(manager->pending_frame_host());
    851   EXPECT_TRUE(host == manager->current_frame_host());
    852   ASSERT_TRUE(host);
    853   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
    854       HasSite());
    855   // Check the pending RenderFrameHost has been committed.
    856   EXPECT_FALSE(manager->pending_frame_host());
    857 
    858   // We should observe a notification.
    859   EXPECT_TRUE(
    860       notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
    861 }
    862 
    863 // Tests the Navigate function. In this unit test we verify that the Navigate
    864 // function can handle a new navigation event before the previous navigation
    865 // has been committed. This is also a regression test for
    866 // http://crbug.com/104600.
    867 TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
    868   TestNotificationTracker notifications;
    869 
    870   SiteInstance* instance = SiteInstance::Create(browser_context());
    871 
    872   scoped_ptr<TestWebContents> web_contents(
    873       TestWebContents::Create(browser_context(), instance));
    874   notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
    875                           Source<WebContents>(web_contents.get()));
    876 
    877   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
    878 
    879   // 1) The first navigation. --------------------------
    880   const GURL kUrl1("http://www.google.com/");
    881   NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
    882                              Referrer(), base::string16() /* title */,
    883                              PAGE_TRANSITION_TYPED,
    884                              false /* is_renderer_init */);
    885   RenderFrameHostImpl* host = manager->Navigate(entry1);
    886 
    887   // The RenderFrameHost created in Init will be reused.
    888   EXPECT_TRUE(host == manager->current_frame_host());
    889   EXPECT_FALSE(manager->pending_frame_host());
    890 
    891   // We should observe a notification.
    892   EXPECT_TRUE(
    893       notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
    894   notifications.Reset();
    895 
    896   // Commit.
    897   manager->DidNavigateFrame(host);
    898 
    899   // Commit to SiteInstance should be delayed until RenderView commit.
    900   EXPECT_TRUE(host == manager->current_frame_host());
    901   ASSERT_TRUE(host);
    902   EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
    903       HasSite());
    904   static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
    905 
    906   // 2) Cross-site navigate to next site. -------------------------
    907   const GURL kUrl2("http://www.example.com");
    908   NavigationEntryImpl entry2(
    909       NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
    910       base::string16() /* title */, PAGE_TRANSITION_TYPED,
    911       false /* is_renderer_init */);
    912   RenderFrameHostImpl* host2 = manager->Navigate(entry2);
    913   int host2_process_id = host2->GetProcess()->GetID();
    914 
    915   // A new RenderFrameHost should be created.
    916   EXPECT_TRUE(manager->pending_frame_host());
    917   ASSERT_EQ(host2, manager->pending_frame_host());
    918   EXPECT_NE(host2, host);
    919 
    920   // Check that the navigation is still suspended because the old RVH
    921   // is not swapped out, yet.
    922   EXPECT_TRUE(host2->render_view_host()->are_navigations_suspended());
    923   MockRenderProcessHost* test_process_host2 =
    924       static_cast<MockRenderProcessHost*>(host2->GetProcess());
    925   test_process_host2->sink().ClearMessages();
    926   host2->render_view_host()->NavigateToURL(kUrl2);
    927   EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
    928       FrameMsg_Navigate::ID));
    929 
    930   // Allow closing the current Render View (precondition for swapping out
    931   // the RVH): Simulate response from RenderFrame for FrameMsg_BeforeUnload sent
    932   // by DispatchBeforeUnload.
    933   TestRenderViewHost* test_host =
    934       static_cast<TestRenderViewHost*>(host->render_view_host());
    935   MockRenderProcessHost* test_process_host =
    936       static_cast<MockRenderProcessHost*>(test_host->GetProcess());
    937   EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
    938       FrameMsg_BeforeUnload::ID));
    939   test_host->SendBeforeUnloadACK(true);
    940 
    941   // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
    942   // call of RenderFrameHostManager::SwapOutOldPage before
    943   // RenderFrameHostManager::DidNavigateFrame is called.
    944   // The RVH is swapped out after receiving the unload ack.
    945   manager->SwapOutOldPage();
    946   EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
    947       FrameMsg_SwapOut::ID));
    948   test_host->OnSwappedOut(false);
    949 
    950   EXPECT_EQ(host, manager->current_frame_host());
    951   EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
    952   EXPECT_EQ(host2, manager->pending_frame_host());
    953   // There should be still no navigation messages being sent.
    954   EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
    955       FrameMsg_Navigate::ID));
    956 
    957   // 3) Cross-site navigate to next site before 2) has committed. --------------
    958   const GURL kUrl3("http://webkit.org/");
    959   NavigationEntryImpl entry3(NULL /* instance */, -1 /* page_id */, kUrl3,
    960                              Referrer(), base::string16() /* title */,
    961                              PAGE_TRANSITION_TYPED,
    962                              false /* is_renderer_init */);
    963   test_process_host->sink().ClearMessages();
    964   RenderFrameHostImpl* host3 = manager->Navigate(entry3);
    965 
    966   // A new RenderFrameHost should be created. host2 is now deleted.
    967   EXPECT_TRUE(manager->pending_frame_host());
    968   ASSERT_EQ(host3, manager->pending_frame_host());
    969   EXPECT_NE(host3, host);
    970   EXPECT_NE(host3->GetProcess()->GetID(), host2_process_id);
    971 
    972   // Navigations in the new RVH should be suspended.
    973   EXPECT_TRUE(static_cast<RenderViewHostImpl*>(
    974       host3->render_view_host())->are_navigations_suspended());
    975   EXPECT_EQ(host, manager->current_frame_host());
    976   EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
    977 
    978   // Simulate a response to the second beforeunload request.
    979   EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
    980       FrameMsg_BeforeUnload::ID));
    981   test_host->SendBeforeUnloadACK(true);
    982 
    983   // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
    984   // call of RenderFrameHostManager::SwapOutOldPage before
    985   // RenderFrameHostManager::DidNavigateFrame is called. Since the previous
    986   // navigation has already caused the renderer to start swapping out, there
    987   // will be no more SwapOut messages being sent.
    988   manager->SwapOutOldPage();
    989   EXPECT_FALSE(test_process_host->sink().GetUniqueMessageMatching(
    990       FrameMsg_SwapOut::ID));
    991   test_host->OnSwappedOut(false);
    992 
    993   // Commit.
    994   manager->DidNavigateFrame(host3);
    995   EXPECT_TRUE(host3 == manager->current_frame_host());
    996   ASSERT_TRUE(host3);
    997   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host3->GetSiteInstance())->
    998       HasSite());
    999   // Check the pending RenderFrameHost has been committed.
   1000   EXPECT_FALSE(manager->pending_frame_host());
   1001 
   1002   // We should observe a notification.
   1003   EXPECT_TRUE(
   1004       notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
   1005 }
   1006 
   1007 // Test that navigation is not blocked when we make new navigation before
   1008 // previous one has been committed. This is also a regression test for
   1009 // http://crbug.com/104600.
   1010 TEST_F(RenderFrameHostManagerTest, NewCrossNavigationBetweenSwapOutAndCommit) {
   1011   const GURL kUrl1("http://www.google.com/");
   1012   const GURL kUrl2("http://www.chromium.org/");
   1013   const GURL kUrl3("http://www.youtube.com/");
   1014 
   1015   contents()->NavigateAndCommit(kUrl1);
   1016   TestRenderViewHost* rvh1 = test_rvh();
   1017 
   1018   // Keep active_view_count nonzero so that no swapped out views in
   1019   // this SiteInstance get forcefully deleted.
   1020   static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
   1021       increment_active_view_count();
   1022 
   1023   // Navigate but don't commit.
   1024   contents()->GetController().LoadURL(
   1025       kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1026   EXPECT_TRUE(rvh1->is_waiting_for_beforeunload_ack());
   1027   contents()->ProceedWithCrossSiteNavigation();
   1028   EXPECT_FALSE(rvh1->is_waiting_for_beforeunload_ack());
   1029   StartCrossSiteTransition(contents());
   1030   EXPECT_TRUE(rvh1->IsWaitingForUnloadACK());
   1031 
   1032   rvh1->OnSwappedOut(false);
   1033   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
   1034 
   1035   TestRenderViewHost* rvh2 = pending_test_rvh();
   1036   EXPECT_TRUE(rvh2);
   1037   static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
   1038       increment_active_view_count();
   1039 
   1040   contents()->GetController().LoadURL(
   1041       kUrl3, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1042   // Pending rvh2 is already deleted.
   1043   contents()->ProceedWithCrossSiteNavigation();
   1044 
   1045   TestRenderViewHost* rvh3 = pending_test_rvh();
   1046   EXPECT_TRUE(rvh3);
   1047   // Navigation should be already unblocked by rvh1.
   1048   EXPECT_FALSE(rvh3->are_navigations_suspended());
   1049 }
   1050 
   1051 // Tests WebUI creation.
   1052 TEST_F(RenderFrameHostManagerTest, WebUI) {
   1053   set_should_create_webui(true);
   1054   SiteInstance* instance = SiteInstance::Create(browser_context());
   1055 
   1056   scoped_ptr<TestWebContents> web_contents(
   1057       TestWebContents::Create(browser_context(), instance));
   1058   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
   1059 
   1060   EXPECT_FALSE(manager->current_host()->IsRenderViewLive());
   1061 
   1062   const GURL kUrl("chrome://foo");
   1063   NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl,
   1064                             Referrer(), base::string16() /* title */,
   1065                             PAGE_TRANSITION_TYPED,
   1066                             false /* is_renderer_init */);
   1067   RenderFrameHostImpl* host = manager->Navigate(entry);
   1068 
   1069   // We commit the pending RenderFrameHost immediately because the previous
   1070   // RenderFrameHost was not live.  We test a case where it is live in
   1071   // WebUIInNewTab.
   1072   EXPECT_TRUE(host);
   1073   EXPECT_EQ(host, manager->current_frame_host());
   1074   EXPECT_FALSE(manager->pending_frame_host());
   1075 
   1076   // It's important that the site instance get set on the Web UI page as soon
   1077   // as the navigation starts, rather than lazily after it commits, so we don't
   1078   // try to re-use the SiteInstance/process for non Web UI things that may
   1079   // get loaded in between.
   1080   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
   1081       HasSite());
   1082   EXPECT_EQ(kUrl, host->GetSiteInstance()->GetSiteURL());
   1083 
   1084   // The Web UI is committed immediately because the RenderViewHost has not been
   1085   // used yet. UpdateStateForNavigate() took the short cut path.
   1086   EXPECT_FALSE(manager->pending_web_ui());
   1087   EXPECT_TRUE(manager->web_ui());
   1088 
   1089   // Commit.
   1090   manager->DidNavigateFrame(host);
   1091   EXPECT_TRUE(
   1092       host->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   1093 }
   1094 
   1095 // Tests that we can open a WebUI link in a new tab from a WebUI page and still
   1096 // grant the correct bindings.  http://crbug.com/189101.
   1097 TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
   1098   set_should_create_webui(true);
   1099   SiteInstance* blank_instance = SiteInstance::Create(browser_context());
   1100 
   1101   // Create a blank tab.
   1102   scoped_ptr<TestWebContents> web_contents1(
   1103       TestWebContents::Create(browser_context(), blank_instance));
   1104   RenderFrameHostManager* manager1 =
   1105       web_contents1->GetRenderManagerForTesting();
   1106   // Test the case that new RVH is considered live.
   1107   manager1->current_host()->CreateRenderView(
   1108       base::string16(), -1, MSG_ROUTING_NONE, -1, false);
   1109 
   1110   // Navigate to a WebUI page.
   1111   const GURL kUrl1("chrome://foo");
   1112   NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
   1113                              Referrer(), base::string16() /* title */,
   1114                              PAGE_TRANSITION_TYPED,
   1115                              false /* is_renderer_init */);
   1116   RenderFrameHostImpl* host1 = manager1->Navigate(entry1);
   1117 
   1118   // We should have a pending navigation to the WebUI RenderViewHost.
   1119   // It should already have bindings.
   1120   EXPECT_EQ(host1, manager1->pending_frame_host());
   1121   EXPECT_NE(host1, manager1->current_frame_host());
   1122   EXPECT_TRUE(
   1123       host1->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   1124 
   1125   // Commit and ensure we still have bindings.
   1126   manager1->DidNavigateFrame(host1);
   1127   SiteInstance* webui_instance = host1->GetSiteInstance();
   1128   EXPECT_EQ(host1, manager1->current_frame_host());
   1129   EXPECT_TRUE(
   1130       host1->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   1131 
   1132   // Now simulate clicking a link that opens in a new tab.
   1133   scoped_ptr<TestWebContents> web_contents2(
   1134       TestWebContents::Create(browser_context(), webui_instance));
   1135   RenderFrameHostManager* manager2 =
   1136       web_contents2->GetRenderManagerForTesting();
   1137   // Make sure the new RVH is considered live.  This is usually done in
   1138   // RenderWidgetHost::Init when opening a new tab from a link.
   1139   manager2->current_host()->CreateRenderView(
   1140       base::string16(), -1, MSG_ROUTING_NONE, -1, false);
   1141 
   1142   const GURL kUrl2("chrome://foo/bar");
   1143   NavigationEntryImpl entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
   1144                              Referrer(), base::string16() /* title */,
   1145                              PAGE_TRANSITION_LINK,
   1146                              true /* is_renderer_init */);
   1147   RenderFrameHostImpl* host2 = manager2->Navigate(entry2);
   1148 
   1149   // No cross-process transition happens because we are already in the right
   1150   // SiteInstance.  We should grant bindings immediately.
   1151   EXPECT_EQ(host2, manager2->current_frame_host());
   1152   EXPECT_TRUE(
   1153       host2->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   1154 
   1155   manager2->DidNavigateFrame(host2);
   1156 }
   1157 
   1158 // Tests that we don't end up in an inconsistent state if a page does a back and
   1159 // then reload. http://crbug.com/51680
   1160 TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
   1161   const GURL kUrl1("http://www.google.com/");
   1162   const GURL kUrl2("http://www.evil-site.com/");
   1163 
   1164   // Navigate to a safe site, then an evil site.
   1165   // This will switch RenderViewHosts.  We cannot assert that the first and
   1166   // second RVHs are different, though, because the first one may be promptly
   1167   // deleted.
   1168   contents()->NavigateAndCommit(kUrl1);
   1169   contents()->NavigateAndCommit(kUrl2);
   1170   RenderViewHost* evil_rvh = contents()->GetRenderViewHost();
   1171 
   1172   // Now let's simulate the evil page calling history.back().
   1173   contents()->OnGoToEntryAtOffset(-1);
   1174   // We should have a new pending RVH.
   1175   // Note that in this case, the navigation has not committed, so evil_rvh will
   1176   // not be deleted yet.
   1177   EXPECT_NE(evil_rvh, contents()->GetRenderManagerForTesting()->
   1178       pending_render_view_host());
   1179 
   1180   // Before that RVH has committed, the evil page reloads itself.
   1181   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1182   params.page_id = 1;
   1183   params.url = kUrl2;
   1184   params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
   1185   params.should_update_history = false;
   1186   params.gesture = NavigationGestureAuto;
   1187   params.was_within_same_page = false;
   1188   params.is_post = false;
   1189   params.page_state = PageState::CreateFromURL(kUrl2);
   1190 
   1191   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(evil_rvh);
   1192   RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(
   1193       rvh->GetProcess()->GetID(), rvh->main_frame_routing_id());
   1194   contents()->GetFrameTree()->root()->navigator()->DidNavigate(rfh, params);
   1195 
   1196   // That should have cancelled the pending RVH, and the evil RVH should be the
   1197   // current one.
   1198   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
   1199       pending_render_view_host() == NULL);
   1200   EXPECT_EQ(evil_rvh, contents()->GetRenderManagerForTesting()->current_host());
   1201 
   1202   // Also we should not have a pending navigation entry.
   1203   EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL);
   1204   NavigationEntry* entry = contents()->GetController().GetVisibleEntry();
   1205   ASSERT_TRUE(entry != NULL);
   1206   EXPECT_EQ(kUrl2, entry->GetURL());
   1207 }
   1208 
   1209 // Ensure that we can go back and forward even if a SwapOut ACK isn't received.
   1210 // See http://crbug.com/93427.
   1211 TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
   1212   const GURL kUrl1("http://www.google.com/");
   1213   const GURL kUrl2("http://www.chromium.org/");
   1214 
   1215   // Navigate to two pages.
   1216   contents()->NavigateAndCommit(kUrl1);
   1217   TestRenderViewHost* rvh1 = test_rvh();
   1218 
   1219   // Keep active_view_count nonzero so that no swapped out views in
   1220   // this SiteInstance get forcefully deleted.
   1221   static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
   1222       increment_active_view_count();
   1223 
   1224   contents()->NavigateAndCommit(kUrl2);
   1225   TestRenderViewHost* rvh2 = test_rvh();
   1226   static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
   1227       increment_active_view_count();
   1228 
   1229   // Now go back, but suppose the SwapOut_ACK isn't received.  This shouldn't
   1230   // happen, but we have seen it when going back quickly across many entries
   1231   // (http://crbug.com/93427).
   1232   contents()->GetController().GoBack();
   1233   EXPECT_TRUE(rvh2->is_waiting_for_beforeunload_ack());
   1234   contents()->ProceedWithCrossSiteNavigation();
   1235   EXPECT_FALSE(rvh2->is_waiting_for_beforeunload_ack());
   1236   StartCrossSiteTransition(contents());
   1237   EXPECT_TRUE(rvh2->IsWaitingForUnloadACK());
   1238 
   1239   // The back navigation commits.
   1240   const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
   1241   rvh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
   1242   EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh2->rvh_state());
   1243 
   1244   // We should be able to navigate forward.
   1245   contents()->GetController().GoForward();
   1246   contents()->ProceedWithCrossSiteNavigation();
   1247   StartCrossSiteTransition(contents());
   1248   const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
   1249   rvh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
   1250   EXPECT_EQ(rvh2, rvh());
   1251   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
   1252   EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
   1253   rvh1->OnSwappedOut(false);
   1254   EXPECT_TRUE(rvh1->IsSwappedOut());
   1255 }
   1256 
   1257 // Test that we create swapped out RVHs for the opener chain when navigating an
   1258 // opened tab cross-process.  This allows us to support certain cross-process
   1259 // JavaScript calls (http://crbug.com/99202).
   1260 TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRVHs) {
   1261   const GURL kUrl1("http://www.google.com/");
   1262   const GURL kUrl2("http://www.chromium.org/");
   1263   const GURL kChromeUrl("chrome://foo");
   1264 
   1265   // Navigate to an initial URL.
   1266   contents()->NavigateAndCommit(kUrl1);
   1267   RenderFrameHostManager* manager = contents()->GetRenderManagerForTesting();
   1268   TestRenderViewHost* rvh1 = test_rvh();
   1269 
   1270   // Create 2 new tabs and simulate them being the opener chain for the main
   1271   // tab.  They should be in the same SiteInstance.
   1272   scoped_ptr<TestWebContents> opener1(
   1273       TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
   1274   RenderFrameHostManager* opener1_manager =
   1275       opener1->GetRenderManagerForTesting();
   1276   contents()->SetOpener(opener1.get());
   1277 
   1278   scoped_ptr<TestWebContents> opener2(
   1279       TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
   1280   RenderFrameHostManager* opener2_manager =
   1281       opener2->GetRenderManagerForTesting();
   1282   opener1->SetOpener(opener2.get());
   1283 
   1284   // Navigate to a cross-site URL (different SiteInstance but same
   1285   // BrowsingInstance).
   1286   contents()->NavigateAndCommit(kUrl2);
   1287   TestRenderViewHost* rvh2 = test_rvh();
   1288   EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
   1289   EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
   1290                   rvh2->GetSiteInstance()));
   1291 
   1292   // Ensure rvh1 is placed on swapped out list of the current tab.
   1293   EXPECT_TRUE(manager->IsRVHOnSwappedOutList(rvh1));
   1294   EXPECT_EQ(rvh1,
   1295             manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
   1296 
   1297   // Ensure a swapped out RVH is created in the first opener tab.
   1298   TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
   1299       opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
   1300   EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
   1301   EXPECT_TRUE(opener1_rvh->IsSwappedOut());
   1302 
   1303   // Ensure a swapped out RVH is created in the second opener tab.
   1304   TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
   1305       opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
   1306   EXPECT_TRUE(opener2_manager->IsRVHOnSwappedOutList(opener2_rvh));
   1307   EXPECT_TRUE(opener2_rvh->IsSwappedOut());
   1308 
   1309   // Navigate to a cross-BrowsingInstance URL.
   1310   contents()->NavigateAndCommit(kChromeUrl);
   1311   TestRenderViewHost* rvh3 = test_rvh();
   1312   EXPECT_NE(rvh1->GetSiteInstance(), rvh3->GetSiteInstance());
   1313   EXPECT_FALSE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
   1314                    rvh3->GetSiteInstance()));
   1315 
   1316   // No scripting is allowed across BrowsingInstances, so we should not create
   1317   // swapped out RVHs for the opener chain in this case.
   1318   EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
   1319                    rvh3->GetSiteInstance()));
   1320   EXPECT_FALSE(opener2_manager->GetSwappedOutRenderViewHost(
   1321                    rvh3->GetSiteInstance()));
   1322 }
   1323 
   1324 // Test that we clean up swapped out RenderViewHosts when a process hosting
   1325 // those associated RenderViews crashes. http://crbug.com/258993
   1326 TEST_F(RenderFrameHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
   1327   const GURL kUrl1("http://www.google.com/");
   1328   const GURL kUrl2("http://www.chromium.org/");
   1329 
   1330   // Navigate to an initial URL.
   1331   contents()->NavigateAndCommit(kUrl1);
   1332   TestRenderViewHost* rvh1 = test_rvh();
   1333 
   1334   // Create a new tab as an opener for the main tab.
   1335   scoped_ptr<TestWebContents> opener1(
   1336       TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
   1337   RenderFrameHostManager* opener1_manager =
   1338       opener1->GetRenderManagerForTesting();
   1339   contents()->SetOpener(opener1.get());
   1340 
   1341   // Make sure the new opener RVH is considered live.
   1342   opener1_manager->current_host()->CreateRenderView(
   1343       base::string16(), -1, MSG_ROUTING_NONE, -1, false);
   1344 
   1345   // Use a cross-process navigation in the opener to swap out the old RVH.
   1346   EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
   1347       rvh1->GetSiteInstance()));
   1348   opener1->NavigateAndCommit(kUrl2);
   1349   EXPECT_TRUE(opener1_manager->GetSwappedOutRenderViewHost(
   1350       rvh1->GetSiteInstance()));
   1351 
   1352   // Fake a process crash.
   1353   RenderProcessHost::RendererClosedDetails details(
   1354       rvh1->GetProcess()->GetHandle(),
   1355       base::TERMINATION_STATUS_PROCESS_CRASHED,
   1356       0);
   1357   NotificationService::current()->Notify(
   1358       NOTIFICATION_RENDERER_PROCESS_CLOSED,
   1359       Source<RenderProcessHost>(rvh1->GetProcess()),
   1360       Details<RenderProcessHost::RendererClosedDetails>(&details));
   1361   rvh1->set_render_view_created(false);
   1362 
   1363   // Ensure that the swapped out RenderViewHost has been deleted.
   1364   EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
   1365       rvh1->GetSiteInstance()));
   1366 
   1367   // Reload the initial tab. This should recreate the opener's swapped out RVH
   1368   // in the original SiteInstance.
   1369   contents()->GetController().Reload(true);
   1370   EXPECT_EQ(opener1_manager->GetSwappedOutRenderViewHost(
   1371                 rvh1->GetSiteInstance())->GetRoutingID(),
   1372             test_rvh()->opener_route_id());
   1373 }
   1374 
   1375 // Test that RenderViewHosts created for WebUI navigations are properly
   1376 // granted WebUI bindings even if an unprivileged swapped out RenderViewHost
   1377 // is in the same process (http://crbug.com/79918).
   1378 TEST_F(RenderFrameHostManagerTest, EnableWebUIWithSwappedOutOpener) {
   1379   set_should_create_webui(true);
   1380   const GURL kSettingsUrl("chrome://chrome/settings");
   1381   const GURL kPluginUrl("chrome://plugins");
   1382 
   1383   // Navigate to an initial WebUI URL.
   1384   contents()->NavigateAndCommit(kSettingsUrl);
   1385 
   1386   // Ensure the RVH has WebUI bindings.
   1387   TestRenderViewHost* rvh1 = test_rvh();
   1388   EXPECT_TRUE(rvh1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   1389 
   1390   // Create a new tab and simulate it being the opener for the main
   1391   // tab.  It should be in the same SiteInstance.
   1392   scoped_ptr<TestWebContents> opener1(
   1393       TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
   1394   RenderFrameHostManager* opener1_manager =
   1395       opener1->GetRenderManagerForTesting();
   1396   contents()->SetOpener(opener1.get());
   1397 
   1398   // Navigate to a different WebUI URL (different SiteInstance, same
   1399   // BrowsingInstance).
   1400   contents()->NavigateAndCommit(kPluginUrl);
   1401   TestRenderViewHost* rvh2 = test_rvh();
   1402   EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
   1403   EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
   1404                   rvh2->GetSiteInstance()));
   1405 
   1406   // Ensure a swapped out RVH is created in the first opener tab.
   1407   TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
   1408       opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
   1409   EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
   1410   EXPECT_TRUE(opener1_rvh->IsSwappedOut());
   1411 
   1412   // Ensure the new RVH has WebUI bindings.
   1413   EXPECT_TRUE(rvh2->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   1414 }
   1415 
   1416 // Test that we reuse the same guest SiteInstance if we navigate across sites.
   1417 TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
   1418   TestNotificationTracker notifications;
   1419 
   1420   GURL guest_url(std::string(kGuestScheme).append("://abc123"));
   1421   SiteInstance* instance =
   1422       SiteInstance::CreateForURL(browser_context(), guest_url);
   1423   scoped_ptr<TestWebContents> web_contents(
   1424       TestWebContents::Create(browser_context(), instance));
   1425 
   1426   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
   1427 
   1428   RenderFrameHostImpl* host;
   1429 
   1430   // 1) The first navigation. --------------------------
   1431   const GURL kUrl1("http://www.google.com/");
   1432   NavigationEntryImpl entry1(
   1433       NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
   1434       base::string16() /* title */, PAGE_TRANSITION_TYPED,
   1435       false /* is_renderer_init */);
   1436   host = manager->Navigate(entry1);
   1437 
   1438   // The RenderFrameHost created in Init will be reused.
   1439   EXPECT_TRUE(host == manager->current_frame_host());
   1440   EXPECT_FALSE(manager->pending_frame_host());
   1441   EXPECT_EQ(manager->current_frame_host()->GetSiteInstance(), instance);
   1442 
   1443   // Commit.
   1444   manager->DidNavigateFrame(host);
   1445   // Commit to SiteInstance should be delayed until RenderView commit.
   1446   EXPECT_EQ(host, manager->current_frame_host());
   1447   ASSERT_TRUE(host);
   1448   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
   1449       HasSite());
   1450 
   1451   // 2) Navigate to a different domain. -------------------------
   1452   // Guests stay in the same process on navigation.
   1453   const GURL kUrl2("http://www.chromium.org");
   1454   NavigationEntryImpl entry2(
   1455       NULL /* instance */, -1 /* page_id */, kUrl2,
   1456       Referrer(kUrl1, blink::WebReferrerPolicyDefault),
   1457       base::string16() /* title */, PAGE_TRANSITION_LINK,
   1458       true /* is_renderer_init */);
   1459   host = manager->Navigate(entry2);
   1460 
   1461   // The RenderFrameHost created in Init will be reused.
   1462   EXPECT_EQ(host, manager->current_frame_host());
   1463   EXPECT_FALSE(manager->pending_frame_host());
   1464 
   1465   // Commit.
   1466   manager->DidNavigateFrame(host);
   1467   EXPECT_EQ(host, manager->current_frame_host());
   1468   ASSERT_TRUE(host);
   1469   EXPECT_EQ(static_cast<SiteInstanceImpl*>(host->GetSiteInstance()),
   1470       instance);
   1471 }
   1472 
   1473 // Test that we cancel a pending RVH if we close the tab while it's pending.
   1474 // http://crbug.com/294697.
   1475 TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
   1476   TestNotificationTracker notifications;
   1477 
   1478   SiteInstance* instance = SiteInstance::Create(browser_context());
   1479 
   1480   BeforeUnloadFiredWebContentsDelegate delegate;
   1481   scoped_ptr<TestWebContents> web_contents(
   1482       TestWebContents::Create(browser_context(), instance));
   1483   web_contents->SetDelegate(&delegate);
   1484   notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
   1485                           Source<WebContents>(web_contents.get()));
   1486 
   1487   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
   1488 
   1489   // 1) The first navigation. --------------------------
   1490   const GURL kUrl1("http://www.google.com/");
   1491   NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
   1492                              Referrer(), base::string16() /* title */,
   1493                              PAGE_TRANSITION_TYPED,
   1494                              false /* is_renderer_init */);
   1495   RenderFrameHostImpl* host = manager->Navigate(entry1);
   1496 
   1497   // The RenderFrameHost created in Init will be reused.
   1498   EXPECT_EQ(host, manager->current_frame_host());
   1499   EXPECT_FALSE(manager->pending_frame_host());
   1500 
   1501   // We should observe a notification.
   1502   EXPECT_TRUE(
   1503       notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
   1504   notifications.Reset();
   1505 
   1506   // Commit.
   1507   manager->DidNavigateFrame(host);
   1508 
   1509   // Commit to SiteInstance should be delayed until RenderFrame commits.
   1510   EXPECT_EQ(host, manager->current_frame_host());
   1511   EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
   1512       HasSite());
   1513   static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
   1514 
   1515   // 2) Cross-site navigate to next site. -------------------------
   1516   const GURL kUrl2("http://www.example.com");
   1517   NavigationEntryImpl entry2(
   1518       NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
   1519       base::string16() /* title */, PAGE_TRANSITION_TYPED,
   1520       false /* is_renderer_init */);
   1521   RenderFrameHostImpl* host2 = manager->Navigate(entry2);
   1522 
   1523   // A new RenderFrameHost should be created.
   1524   ASSERT_EQ(host2, manager->pending_frame_host());
   1525   EXPECT_NE(host2, host);
   1526 
   1527   EXPECT_EQ(host, manager->current_frame_host());
   1528   EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
   1529   EXPECT_EQ(host2, manager->pending_frame_host());
   1530 
   1531   // 3) Close the tab. -------------------------
   1532   notifications.ListenFor(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
   1533                           Source<RenderWidgetHost>(host2->render_view_host()));
   1534   manager->OnBeforeUnloadACK(false, true, base::TimeTicks());
   1535 
   1536   EXPECT_TRUE(
   1537       notifications.Check1AndReset(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED));
   1538   EXPECT_FALSE(manager->pending_frame_host());
   1539   EXPECT_EQ(host, manager->current_frame_host());
   1540 }
   1541 
   1542 // Tests that the RenderViewHost is properly deleted when the SwapOutACK is
   1543 // received before the new page commits.
   1544 TEST_F(RenderFrameHostManagerTest,
   1545        SwapOutACKBeforeNewPageCommitsLeadsToDeletion) {
   1546   const GURL kUrl1("http://www.google.com/");
   1547   const GURL kUrl2("http://www.chromium.org/");
   1548 
   1549   // Navigate to the first page.
   1550   contents()->NavigateAndCommit(kUrl1);
   1551   TestRenderViewHost* rvh1 = test_rvh();
   1552   RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
   1553   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
   1554 
   1555   // Navigate to new site, simulating onbeforeunload approval.
   1556   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1557   base::TimeTicks now = base::TimeTicks::Now();
   1558   main_test_rfh()->OnMessageReceived(
   1559       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1560   EXPECT_TRUE(contents()->cross_navigation_pending());
   1561   TestRenderViewHost* rvh2 =
   1562       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1563 
   1564   // Simulate rvh2's response, which leads to an unload request being sent to
   1565   // rvh1.
   1566   std::vector<GURL> url_chain;
   1567   url_chain.push_back(GURL());
   1568   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
   1569       contents()->GetRenderManagerForTesting()->pending_frame_host(),
   1570       GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
   1571       url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   1572   EXPECT_TRUE(contents()->cross_navigation_pending());
   1573   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
   1574             rvh1->rvh_state());
   1575 
   1576   // Simulate the swap out ack.
   1577   rvh1->OnSwappedOut(false);
   1578   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
   1579 
   1580   // The new page commits.
   1581   contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   1582   EXPECT_FALSE(contents()->cross_navigation_pending());
   1583   EXPECT_EQ(rvh2, rvh());
   1584   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1585   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
   1586 
   1587   // rvh1 should have been deleted.
   1588   EXPECT_TRUE(rvh_deleted_observer.deleted());
   1589   rvh1 = NULL;
   1590 }
   1591 
   1592 // Tests that the RenderViewHost is properly swapped out when the SwapOutACK is
   1593 // received before the new page commits.
   1594 TEST_F(RenderFrameHostManagerTest,
   1595        SwapOutACKBeforeNewPageCommitsLeadsToSwapOut) {
   1596   const GURL kUrl1("http://www.google.com/");
   1597   const GURL kUrl2("http://www.chromium.org/");
   1598 
   1599   // Navigate to the first page.
   1600   contents()->NavigateAndCommit(kUrl1);
   1601   TestRenderViewHost* rvh1 = test_rvh();
   1602   RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
   1603   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
   1604 
   1605   // Increment the number of active views in SiteInstanceImpl so that rvh2 is
   1606   // not deleted on swap out.
   1607   static_cast<SiteInstanceImpl*>(
   1608       rvh1->GetSiteInstance())->increment_active_view_count();
   1609 
   1610   // Navigate to new site, simulating onbeforeunload approval.
   1611   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1612   base::TimeTicks now = base::TimeTicks::Now();
   1613   main_test_rfh()->OnMessageReceived(
   1614       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1615   EXPECT_TRUE(contents()->cross_navigation_pending());
   1616   TestRenderViewHost* rvh2 =
   1617       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1618 
   1619   // Simulate rvh2's response, which leads to an unload request being sent to
   1620   // rvh1.
   1621   std::vector<GURL> url_chain;
   1622   url_chain.push_back(GURL());
   1623   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
   1624       contents()->GetRenderManagerForTesting()->pending_frame_host(),
   1625       GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
   1626       url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   1627   EXPECT_TRUE(contents()->cross_navigation_pending());
   1628   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
   1629             rvh1->rvh_state());
   1630 
   1631   // Simulate the swap out ack.
   1632   rvh1->OnSwappedOut(false);
   1633   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
   1634 
   1635   // The new page commits.
   1636   contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   1637   EXPECT_FALSE(contents()->cross_navigation_pending());
   1638   EXPECT_EQ(rvh2, rvh());
   1639   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1640   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
   1641 
   1642   // rvh1 should be swapped out.
   1643   EXPECT_FALSE(rvh_deleted_observer.deleted());
   1644   EXPECT_TRUE(rvh1->IsSwappedOut());
   1645 }
   1646 
   1647 // Tests that the RenderViewHost is properly deleted when the new
   1648 // page commits before the swap out ack is received.
   1649 TEST_F(RenderFrameHostManagerTest,
   1650        NewPageCommitsBeforeSwapOutACKLeadsToDeletion) {
   1651   const GURL kUrl1("http://www.google.com/");
   1652   const GURL kUrl2("http://www.chromium.org/");
   1653 
   1654   // Navigate to the first page.
   1655   contents()->NavigateAndCommit(kUrl1);
   1656   TestRenderViewHost* rvh1 = test_rvh();
   1657   RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
   1658   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
   1659 
   1660   // Navigate to new site, simulating onbeforeunload approval.
   1661   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1662   base::TimeTicks now = base::TimeTicks::Now();
   1663   main_test_rfh()->OnMessageReceived(
   1664       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1665   EXPECT_TRUE(contents()->cross_navigation_pending());
   1666   TestRenderViewHost* rvh2 =
   1667       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1668 
   1669   // Simulate rvh2's response, which leads to an unload request being sent to
   1670   // rvh1.
   1671   std::vector<GURL> url_chain;
   1672   url_chain.push_back(GURL());
   1673   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
   1674       contents()->GetRenderManagerForTesting()->pending_frame_host(),
   1675       GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
   1676       url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   1677   EXPECT_TRUE(contents()->cross_navigation_pending());
   1678   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
   1679             rvh1->rvh_state());
   1680 
   1681   // The new page commits.
   1682   contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   1683   EXPECT_FALSE(contents()->cross_navigation_pending());
   1684   EXPECT_EQ(rvh2, rvh());
   1685   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1686   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
   1687   EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN, rvh1->rvh_state());
   1688 
   1689   // Simulate the swap out ack.
   1690   rvh1->OnSwappedOut(false);
   1691 
   1692   // rvh1 should have been deleted.
   1693   EXPECT_TRUE(rvh_deleted_observer.deleted());
   1694   rvh1 = NULL;
   1695 }
   1696 
   1697 // Tests that the RenderViewHost is properly swapped out when the new page
   1698 // commits before the swap out ack is received.
   1699 TEST_F(RenderFrameHostManagerTest,
   1700        NewPageCommitsBeforeSwapOutACKLeadsToSwapOut) {
   1701   const GURL kUrl1("http://www.google.com/");
   1702   const GURL kUrl2("http://www.chromium.org/");
   1703 
   1704   // Navigate to the first page.
   1705   contents()->NavigateAndCommit(kUrl1);
   1706   TestRenderViewHost* rvh1 = test_rvh();
   1707   RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
   1708   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
   1709 
   1710   // Increment the number of active views in SiteInstanceImpl so that rvh1 is
   1711   // not deleted on swap out.
   1712   static_cast<SiteInstanceImpl*>(
   1713       rvh1->GetSiteInstance())->increment_active_view_count();
   1714 
   1715   // Navigate to new site, simulating onbeforeunload approval.
   1716   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1717   base::TimeTicks now = base::TimeTicks::Now();
   1718   main_test_rfh()->OnMessageReceived(
   1719       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1720   EXPECT_TRUE(contents()->cross_navigation_pending());
   1721   TestRenderViewHost* rvh2 =
   1722       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1723 
   1724   // Simulate rvh2's response, which leads to an unload request being sent to
   1725   // rvh1.
   1726   std::vector<GURL> url_chain;
   1727   url_chain.push_back(GURL());
   1728   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
   1729       contents()->GetRenderManagerForTesting()->pending_frame_host(),
   1730       GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
   1731       url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   1732   EXPECT_TRUE(contents()->cross_navigation_pending());
   1733   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
   1734             rvh1->rvh_state());
   1735 
   1736   // The new page commits.
   1737   contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   1738   EXPECT_FALSE(contents()->cross_navigation_pending());
   1739   EXPECT_EQ(rvh2, rvh());
   1740   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1741   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
   1742   EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
   1743 
   1744   // Simulate the swap out ack.
   1745   rvh1->OnSwappedOut(false);
   1746 
   1747   // rvh1 should be swapped out.
   1748   EXPECT_FALSE(rvh_deleted_observer.deleted());
   1749   EXPECT_TRUE(rvh1->IsSwappedOut());
   1750 }
   1751 
   1752 // Test that the RenderViewHost is properly swapped out if a navigation in the
   1753 // new renderer commits before sending the SwapOut message to the old renderer.
   1754 // This simulates a cross-site navigation to a synchronously committing URL
   1755 // (e.g., a data URL) and ensures it works properly.
   1756 TEST_F(RenderFrameHostManagerTest,
   1757        CommitNewNavigationBeforeSendingSwapOut) {
   1758   const GURL kUrl1("http://www.google.com/");
   1759   const GURL kUrl2("http://www.chromium.org/");
   1760 
   1761   // Navigate to the first page.
   1762   contents()->NavigateAndCommit(kUrl1);
   1763   TestRenderViewHost* rvh1 = test_rvh();
   1764   RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
   1765   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
   1766 
   1767   // Increment the number of active views in SiteInstanceImpl so that rvh1 is
   1768   // not deleted on swap out.
   1769   static_cast<SiteInstanceImpl*>(
   1770       rvh1->GetSiteInstance())->increment_active_view_count();
   1771 
   1772   // Navigate to new site, simulating onbeforeunload approval.
   1773   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1774   base::TimeTicks now = base::TimeTicks::Now();
   1775   main_test_rfh()->OnMessageReceived(
   1776       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1777   EXPECT_TRUE(contents()->cross_navigation_pending());
   1778   TestRenderViewHost* rvh2 =
   1779       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1780 
   1781   // The new page commits.
   1782   contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   1783   EXPECT_FALSE(contents()->cross_navigation_pending());
   1784   EXPECT_EQ(rvh2, rvh());
   1785   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1786   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
   1787   EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
   1788 
   1789   // Simulate the swap out ack.
   1790   rvh1->OnSwappedOut(false);
   1791 
   1792   // rvh1 should be swapped out.
   1793   EXPECT_FALSE(rvh_deleted_observer.deleted());
   1794   EXPECT_TRUE(rvh1->IsSwappedOut());
   1795 }
   1796 
   1797 // Test that a RenderFrameHost is properly deleted or swapped out when a
   1798 // cross-site navigation is cancelled.
   1799 TEST_F(RenderFrameHostManagerTest,
   1800        CancelPendingProperlyDeletesOrSwaps) {
   1801   const GURL kUrl1("http://www.google.com/");
   1802   const GURL kUrl2("http://www.chromium.org/");
   1803   RenderFrameHostImpl* pending_rfh = NULL;
   1804   base::TimeTicks now = base::TimeTicks::Now();
   1805 
   1806   // Navigate to the first page.
   1807   contents()->NavigateAndCommit(kUrl1);
   1808   TestRenderViewHost* rvh1 = test_rvh();
   1809   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
   1810 
   1811   // Navigate to a new site, starting a cross-site navigation.
   1812   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1813   {
   1814     pending_rfh = contents()->GetFrameTree()->root()->render_manager()
   1815         ->pending_frame_host();
   1816     RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
   1817 
   1818     // Cancel the navigation by simulating a declined beforeunload dialog.
   1819     main_test_rfh()->OnMessageReceived(
   1820         FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
   1821     EXPECT_FALSE(contents()->cross_navigation_pending());
   1822 
   1823     // Since the pending RFH is the only one for the new SiteInstance, it should
   1824     // be deleted.
   1825     EXPECT_TRUE(rvh_deleted_observer.deleted());
   1826   }
   1827 
   1828   // Start another cross-site navigation.
   1829   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   1830   {
   1831     pending_rfh = contents()->GetFrameTree()->root()->render_manager()
   1832         ->pending_frame_host();
   1833     RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
   1834 
   1835     // Increment the number of active views in the new SiteInstance, which will
   1836     // cause the pending RFH to be swapped out instead of deleted.
   1837     static_cast<SiteInstanceImpl*>(
   1838         pending_rfh->GetSiteInstance())->increment_active_view_count();
   1839 
   1840     main_test_rfh()->OnMessageReceived(
   1841         FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
   1842     EXPECT_FALSE(contents()->cross_navigation_pending());
   1843     EXPECT_FALSE(rvh_deleted_observer.deleted());
   1844   }
   1845 }
   1846 
   1847 }  // namespace content
   1848