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