Home | History | Annotate | Download | only in web_contents
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/logging.h"
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "content/browser/frame_host/interstitial_page_impl.h"
      8 #include "content/browser/frame_host/navigation_entry_impl.h"
      9 #include "content/browser/renderer_host/render_view_host_impl.h"
     10 #include "content/browser/site_instance_impl.h"
     11 #include "content/browser/webui/web_ui_controller_factory_registry.h"
     12 #include "content/common/view_messages.h"
     13 #include "content/public/browser/global_request_id.h"
     14 #include "content/public/browser/interstitial_page_delegate.h"
     15 #include "content/public/browser/navigation_details.h"
     16 #include "content/public/browser/notification_details.h"
     17 #include "content/public/browser/notification_source.h"
     18 #include "content/public/browser/render_widget_host_view.h"
     19 #include "content/public/browser/web_contents_observer.h"
     20 #include "content/public/browser/web_ui_controller.h"
     21 #include "content/public/common/bindings_policy.h"
     22 #include "content/public/common/content_constants.h"
     23 #include "content/public/common/url_constants.h"
     24 #include "content/public/common/url_utils.h"
     25 #include "content/public/test/mock_render_process_host.h"
     26 #include "content/public/test/test_browser_thread.h"
     27 #include "content/public/test/test_utils.h"
     28 #include "content/test/test_content_browser_client.h"
     29 #include "content/test/test_content_client.h"
     30 #include "content/test/test_render_view_host.h"
     31 #include "content/test/test_web_contents.h"
     32 #include "testing/gtest/include/gtest/gtest.h"
     33 
     34 namespace content {
     35 namespace {
     36 
     37 const char kTestWebUIUrl[] = "chrome://blah";
     38 
     39 class WebContentsImplTestWebUIControllerFactory
     40     : public WebUIControllerFactory {
     41  public:
     42   virtual WebUIController* CreateWebUIControllerForURL(
     43       WebUI* web_ui, const GURL& url) const OVERRIDE {
     44     if (!UseWebUI(url))
     45       return NULL;
     46     return new WebUIController(web_ui);
     47   }
     48 
     49   virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
     50       const GURL& url) const OVERRIDE {
     51     return WebUI::kNoWebUI;
     52   }
     53 
     54   virtual bool UseWebUIForURL(BrowserContext* browser_context,
     55                               const GURL& url) const OVERRIDE {
     56     return UseWebUI(url);
     57   }
     58 
     59   virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
     60                                       const GURL& url) const OVERRIDE {
     61     return UseWebUI(url);
     62   }
     63 
     64  private:
     65   bool UseWebUI(const GURL& url) const {
     66     return url == GURL(kTestWebUIUrl);
     67   }
     68 };
     69 
     70 class TestInterstitialPage;
     71 
     72 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
     73  public:
     74   explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
     75       : interstitial_page_(interstitial_page) {}
     76   virtual void CommandReceived(const std::string& command) OVERRIDE;
     77   virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
     78   virtual void OnDontProceed() OVERRIDE;
     79   virtual void OnProceed() OVERRIDE;
     80  private:
     81   TestInterstitialPage* interstitial_page_;
     82 };
     83 
     84 class TestInterstitialPage : public InterstitialPageImpl {
     85  public:
     86   enum InterstitialState {
     87     INVALID = 0,    // Hasn't yet been initialized.
     88     UNDECIDED,      // Initialized, but no decision taken yet.
     89     OKED,           // Proceed was called.
     90     CANCELED        // DontProceed was called.
     91   };
     92 
     93   class Delegate {
     94    public:
     95     virtual void TestInterstitialPageDeleted(
     96         TestInterstitialPage* interstitial) = 0;
     97 
     98    protected:
     99     virtual ~Delegate() {}
    100   };
    101 
    102   // IMPORTANT NOTE: if you pass stack allocated values for |state| and
    103   // |deleted| (like all interstitial related tests do at this point), make sure
    104   // to create an instance of the TestInterstitialPageStateGuard class on the
    105   // stack in your test.  This will ensure that the TestInterstitialPage states
    106   // are cleared when the test finishes.
    107   // Not doing so will cause stack trashing if your test does not hide the
    108   // interstitial, as in such a case it will be destroyed in the test TearDown
    109   // method and will dereference the |deleted| local variable which by then is
    110   // out of scope.
    111   TestInterstitialPage(WebContentsImpl* contents,
    112                        bool new_navigation,
    113                        const GURL& url,
    114                        InterstitialState* state,
    115                        bool* deleted)
    116       : InterstitialPageImpl(
    117             contents,
    118             static_cast<RenderWidgetHostDelegate*>(contents),
    119             new_navigation, url, new TestInterstitialPageDelegate(this)),
    120         state_(state),
    121         deleted_(deleted),
    122         command_received_count_(0),
    123         delegate_(NULL) {
    124     *state_ = UNDECIDED;
    125     *deleted_ = false;
    126   }
    127 
    128   virtual ~TestInterstitialPage() {
    129     if (deleted_)
    130       *deleted_ = true;
    131     if (delegate_)
    132       delegate_->TestInterstitialPageDeleted(this);
    133   }
    134 
    135   void OnDontProceed() {
    136     if (state_)
    137       *state_ = CANCELED;
    138   }
    139   void OnProceed() {
    140     if (state_)
    141       *state_ = OKED;
    142   }
    143 
    144   int command_received_count() const {
    145     return command_received_count_;
    146   }
    147 
    148   void TestDomOperationResponse(const std::string& json_string) {
    149     if (enabled())
    150       CommandReceived();
    151   }
    152 
    153   void TestDidNavigate(int page_id, const GURL& url) {
    154     ViewHostMsg_FrameNavigate_Params params;
    155     InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
    156     DidNavigate(GetRenderViewHostForTesting(), params);
    157   }
    158 
    159   void TestRenderViewTerminated(base::TerminationStatus status,
    160                                 int error_code) {
    161     RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
    162   }
    163 
    164   bool is_showing() const {
    165     return static_cast<TestRenderWidgetHostView*>(
    166         GetRenderViewHostForTesting()->GetView())->is_showing();
    167   }
    168 
    169   void ClearStates() {
    170     state_ = NULL;
    171     deleted_ = NULL;
    172     delegate_ = NULL;
    173   }
    174 
    175   void CommandReceived() {
    176     command_received_count_++;
    177   }
    178 
    179   void set_delegate(Delegate* delegate) {
    180     delegate_ = delegate;
    181   }
    182 
    183  protected:
    184   virtual RenderViewHost* CreateRenderViewHost() OVERRIDE {
    185     return new TestRenderViewHost(
    186         SiteInstance::Create(web_contents()->GetBrowserContext()),
    187         this, this, this, MSG_ROUTING_NONE, MSG_ROUTING_NONE, false);
    188   }
    189 
    190   virtual WebContentsView* CreateWebContentsView() OVERRIDE {
    191     return NULL;
    192   }
    193 
    194  private:
    195   InterstitialState* state_;
    196   bool* deleted_;
    197   int command_received_count_;
    198   Delegate* delegate_;
    199 };
    200 
    201 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
    202   interstitial_page_->CommandReceived();
    203 }
    204 
    205 void TestInterstitialPageDelegate::OnDontProceed() {
    206   interstitial_page_->OnDontProceed();
    207 }
    208 
    209 void TestInterstitialPageDelegate::OnProceed() {
    210   interstitial_page_->OnProceed();
    211 }
    212 
    213 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
    214  public:
    215   explicit TestInterstitialPageStateGuard(
    216       TestInterstitialPage* interstitial_page)
    217       : interstitial_page_(interstitial_page) {
    218     DCHECK(interstitial_page_);
    219     interstitial_page_->set_delegate(this);
    220   }
    221   virtual ~TestInterstitialPageStateGuard() {
    222     if (interstitial_page_)
    223       interstitial_page_->ClearStates();
    224   }
    225 
    226   virtual void TestInterstitialPageDeleted(
    227       TestInterstitialPage* interstitial) OVERRIDE {
    228     DCHECK(interstitial_page_ == interstitial);
    229     interstitial_page_ = NULL;
    230   }
    231 
    232  private:
    233   TestInterstitialPage* interstitial_page_;
    234 };
    235 
    236 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
    237  public:
    238   WebContentsImplTestBrowserClient()
    239       : assign_site_for_url_(false) {}
    240 
    241   virtual ~WebContentsImplTestBrowserClient() {}
    242 
    243   virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
    244     return assign_site_for_url_;
    245   }
    246 
    247   void set_assign_site_for_url(bool assign) {
    248     assign_site_for_url_ = assign;
    249   }
    250 
    251  private:
    252   bool assign_site_for_url_;
    253 };
    254 
    255 class WebContentsImplTest : public RenderViewHostImplTestHarness {
    256  public:
    257   virtual void SetUp() {
    258     RenderViewHostImplTestHarness::SetUp();
    259     WebUIControllerFactory::RegisterFactory(&factory_);
    260   }
    261 
    262   virtual void TearDown() {
    263     WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
    264     RenderViewHostImplTestHarness::TearDown();
    265   }
    266 
    267  private:
    268   WebContentsImplTestWebUIControllerFactory factory_;
    269 };
    270 
    271 class TestWebContentsObserver : public WebContentsObserver {
    272  public:
    273   explicit TestWebContentsObserver(WebContents* contents)
    274       : WebContentsObserver(contents) {
    275   }
    276   virtual ~TestWebContentsObserver() {}
    277 
    278   virtual void DidFinishLoad(int64 frame_id,
    279                              const GURL& validated_url,
    280                              bool is_main_frame,
    281                              RenderViewHost* render_view_host) OVERRIDE {
    282     last_url_ = validated_url;
    283   }
    284   virtual void DidFailLoad(int64 frame_id,
    285                            const GURL& validated_url,
    286                            bool is_main_frame,
    287                            int error_code,
    288                            const base::string16& error_description,
    289                            RenderViewHost* render_view_host) OVERRIDE {
    290     last_url_ = validated_url;
    291   }
    292 
    293   const GURL& last_url() const { return last_url_; }
    294 
    295  private:
    296   GURL last_url_;
    297 
    298   DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
    299 };
    300 
    301 }  // namespace
    302 
    303 // Test to make sure that title updates get stripped of whitespace.
    304 TEST_F(WebContentsImplTest, UpdateTitle) {
    305   NavigationControllerImpl& cont =
    306       static_cast<NavigationControllerImpl&>(controller());
    307   ViewHostMsg_FrameNavigate_Params params;
    308   InitNavigateParams(&params, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
    309 
    310   LoadCommittedDetails details;
    311   cont.RendererDidNavigate(params, &details);
    312 
    313   contents()->UpdateTitle(rvh(), 0, ASCIIToUTF16("    Lots O' Whitespace\n"),
    314                           base::i18n::LEFT_TO_RIGHT);
    315   EXPECT_EQ(ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
    316 }
    317 
    318 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
    319   const GURL kGURL("chrome://blah");
    320   controller().LoadURL(
    321       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    322   EXPECT_EQ(base::string16(), contents()->GetTitle());
    323 }
    324 
    325 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
    326   const GURL kGURL("chrome://blah");
    327   const base::string16 title = ASCIIToUTF16("My Title");
    328   controller().LoadURL(
    329       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    330 
    331   NavigationEntry* entry = controller().GetVisibleEntry();
    332   ASSERT_EQ(kGURL, entry->GetURL());
    333   entry->SetTitle(title);
    334 
    335   EXPECT_EQ(title, contents()->GetTitle());
    336 }
    337 
    338 // Test view source mode for a webui page.
    339 TEST_F(WebContentsImplTest, NTPViewSource) {
    340   NavigationControllerImpl& cont =
    341       static_cast<NavigationControllerImpl&>(controller());
    342   const char kUrl[] = "view-source:chrome://blah";
    343   const GURL kGURL(kUrl);
    344 
    345   process()->sink().ClearMessages();
    346 
    347   cont.LoadURL(
    348       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    349   rvh()->GetDelegate()->RenderViewCreated(rvh());
    350   // Did we get the expected message?
    351   EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
    352       ViewMsg_EnableViewSourceMode::ID));
    353 
    354   ViewHostMsg_FrameNavigate_Params params;
    355   InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
    356   LoadCommittedDetails details;
    357   cont.RendererDidNavigate(params, &details);
    358   // Also check title and url.
    359   EXPECT_EQ(ASCIIToUTF16(kUrl), contents()->GetTitle());
    360 }
    361 
    362 // Test to ensure UpdateMaxPageID is working properly.
    363 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
    364   SiteInstance* instance1 = contents()->GetSiteInstance();
    365   scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
    366 
    367   // Starts at -1.
    368   EXPECT_EQ(-1, contents()->GetMaxPageID());
    369   EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
    370   EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
    371 
    372   // Make sure max_page_id_ is monotonically increasing per SiteInstance.
    373   contents()->UpdateMaxPageID(3);
    374   contents()->UpdateMaxPageID(1);
    375   EXPECT_EQ(3, contents()->GetMaxPageID());
    376   EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
    377   EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
    378 
    379   contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
    380   EXPECT_EQ(3, contents()->GetMaxPageID());
    381   EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
    382   EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
    383 }
    384 
    385 // Test simple same-SiteInstance navigation.
    386 TEST_F(WebContentsImplTest, SimpleNavigation) {
    387   TestRenderViewHost* orig_rvh = test_rvh();
    388   SiteInstance* instance1 = contents()->GetSiteInstance();
    389   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    390 
    391   // Navigate to URL
    392   const GURL url("http://www.google.com");
    393   controller().LoadURL(
    394       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    395   EXPECT_FALSE(contents()->cross_navigation_pending());
    396   EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
    397   // Controller's pending entry will have a NULL site instance until we assign
    398   // it in DidNavigate.
    399   EXPECT_TRUE(
    400       NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
    401           site_instance() == NULL);
    402 
    403   // DidNavigate from the page
    404   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    405   EXPECT_FALSE(contents()->cross_navigation_pending());
    406   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    407   EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
    408   // Controller's entry should now have the SiteInstance, or else we won't be
    409   // able to find it later.
    410   EXPECT_EQ(
    411       instance1,
    412       NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
    413           site_instance());
    414 }
    415 
    416 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
    417 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
    418   // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
    419   const GURL url(std::string("http://example.org/").append(
    420       GetMaxURLChars() + 1, 'a'));
    421 
    422   controller().LoadURL(
    423       url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
    424   EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
    425 }
    426 
    427 // Test that navigating across a site boundary creates a new RenderViewHost
    428 // with a new SiteInstance.  Going back should do the same.
    429 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
    430   contents()->transition_cross_site = true;
    431   TestRenderViewHost* orig_rvh = test_rvh();
    432   int orig_rvh_delete_count = 0;
    433   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    434   SiteInstance* instance1 = contents()->GetSiteInstance();
    435 
    436   // Navigate to URL.  First URL should use first RenderViewHost.
    437   const GURL url("http://www.google.com");
    438   controller().LoadURL(
    439       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    440   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    441 
    442   // Keep the number of active views in orig_rvh's SiteInstance
    443   // non-zero so that orig_rvh doesn't get deleted when it gets
    444   // swapped out.
    445   static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
    446       increment_active_view_count();
    447 
    448   EXPECT_FALSE(contents()->cross_navigation_pending());
    449   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    450   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    451   EXPECT_EQ(url, contents()->GetVisibleURL());
    452 
    453   // Navigate to new site
    454   const GURL url2("http://www.yahoo.com");
    455   controller().LoadURL(
    456       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    457   EXPECT_TRUE(contents()->cross_navigation_pending());
    458   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    459   EXPECT_EQ(url2, contents()->GetVisibleURL());
    460   TestRenderViewHost* pending_rvh =
    461       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    462   int pending_rvh_delete_count = 0;
    463   pending_rvh->set_delete_counter(&pending_rvh_delete_count);
    464 
    465   // Navigations should be suspended in pending_rvh until ShouldCloseACK.
    466   EXPECT_TRUE(pending_rvh->are_navigations_suspended());
    467   orig_rvh->SendShouldCloseACK(true);
    468   EXPECT_FALSE(pending_rvh->are_navigations_suspended());
    469 
    470   // DidNavigate from the pending page
    471   contents()->TestDidNavigate(
    472       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    473   SiteInstance* instance2 = contents()->GetSiteInstance();
    474 
    475   // Keep the number of active views in pending_rvh's SiteInstance
    476   // non-zero so that orig_rvh doesn't get deleted when it gets
    477   // swapped out.
    478   static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
    479       increment_active_view_count();
    480 
    481   EXPECT_FALSE(contents()->cross_navigation_pending());
    482   EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
    483   EXPECT_EQ(url2, contents()->GetLastCommittedURL());
    484   EXPECT_EQ(url2, contents()->GetVisibleURL());
    485   EXPECT_NE(instance1, instance2);
    486   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    487   // We keep the original RVH around, swapped out.
    488   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
    489       orig_rvh));
    490   EXPECT_EQ(orig_rvh_delete_count, 0);
    491 
    492   // Going back should switch SiteInstances again.  The first SiteInstance is
    493   // stored in the NavigationEntry, so it should be the same as at the start.
    494   // We should use the same RVH as before, swapping it back in.
    495   controller().GoBack();
    496   TestRenderViewHost* goback_rvh =
    497       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    498   EXPECT_EQ(orig_rvh, goback_rvh);
    499   EXPECT_TRUE(contents()->cross_navigation_pending());
    500 
    501   // Navigations should be suspended in goback_rvh until ShouldCloseACK.
    502   EXPECT_TRUE(goback_rvh->are_navigations_suspended());
    503   pending_rvh->SendShouldCloseACK(true);
    504   EXPECT_FALSE(goback_rvh->are_navigations_suspended());
    505 
    506   // DidNavigate from the back action
    507   contents()->TestDidNavigate(
    508       goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    509   EXPECT_FALSE(contents()->cross_navigation_pending());
    510   EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
    511   EXPECT_EQ(instance1, contents()->GetSiteInstance());
    512   // The pending RVH should now be swapped out, not deleted.
    513   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
    514       IsOnSwappedOutList(pending_rvh));
    515   EXPECT_EQ(pending_rvh_delete_count, 0);
    516 
    517   // Close contents and ensure RVHs are deleted.
    518   DeleteContents();
    519   EXPECT_EQ(orig_rvh_delete_count, 1);
    520   EXPECT_EQ(pending_rvh_delete_count, 1);
    521 }
    522 
    523 // Test that navigating across a site boundary after a crash creates a new
    524 // RVH without requiring a cross-site transition (i.e., PENDING state).
    525 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
    526   contents()->transition_cross_site = true;
    527   TestRenderViewHost* orig_rvh = test_rvh();
    528   int orig_rvh_delete_count = 0;
    529   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    530   SiteInstance* instance1 = contents()->GetSiteInstance();
    531 
    532   // Navigate to URL.  First URL should use first RenderViewHost.
    533   const GURL url("http://www.google.com");
    534   controller().LoadURL(
    535       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    536   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    537 
    538   EXPECT_FALSE(contents()->cross_navigation_pending());
    539   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    540 
    541   // Crash the renderer.
    542   orig_rvh->set_render_view_created(false);
    543 
    544   // Navigate to new site.  We should not go into PENDING.
    545   const GURL url2("http://www.yahoo.com");
    546   controller().LoadURL(
    547       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    548   RenderViewHost* new_rvh = rvh();
    549   EXPECT_FALSE(contents()->cross_navigation_pending());
    550   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    551   EXPECT_NE(orig_rvh, new_rvh);
    552   EXPECT_EQ(orig_rvh_delete_count, 1);
    553 
    554   // DidNavigate from the new page
    555   contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    556   SiteInstance* instance2 = contents()->GetSiteInstance();
    557 
    558   EXPECT_FALSE(contents()->cross_navigation_pending());
    559   EXPECT_EQ(new_rvh, rvh());
    560   EXPECT_NE(instance1, instance2);
    561   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    562 
    563   // Close contents and ensure RVHs are deleted.
    564   DeleteContents();
    565   EXPECT_EQ(orig_rvh_delete_count, 1);
    566 }
    567 
    568 // Test that opening a new contents in the same SiteInstance and then navigating
    569 // both contentses to a new site will place both contentses in a single
    570 // SiteInstance.
    571 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
    572   contents()->transition_cross_site = true;
    573   TestRenderViewHost* orig_rvh = test_rvh();
    574   SiteInstance* instance1 = contents()->GetSiteInstance();
    575 
    576   // Navigate to URL.  First URL should use first RenderViewHost.
    577   const GURL url("http://www.google.com");
    578   controller().LoadURL(
    579       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    580   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    581 
    582   // Open a new contents with the same SiteInstance, navigated to the same site.
    583   scoped_ptr<TestWebContents> contents2(
    584       TestWebContents::Create(browser_context(), instance1));
    585   contents2->transition_cross_site = true;
    586   contents2->GetController().LoadURL(url, Referrer(),
    587                                     PAGE_TRANSITION_TYPED,
    588                                     std::string());
    589   // Need this page id to be 2 since the site instance is the same (which is the
    590   // scope of page IDs) and we want to consider this a new page.
    591   contents2->TestDidNavigate(
    592       contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
    593 
    594   // Navigate first contents to a new site.
    595   const GURL url2a("http://www.yahoo.com");
    596   controller().LoadURL(
    597       url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    598   orig_rvh->SendShouldCloseACK(true);
    599   TestRenderViewHost* pending_rvh_a =
    600       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    601   contents()->TestDidNavigate(
    602       pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
    603   SiteInstance* instance2a = contents()->GetSiteInstance();
    604   EXPECT_NE(instance1, instance2a);
    605 
    606   // Navigate second contents to the same site as the first tab.
    607   const GURL url2b("http://mail.yahoo.com");
    608   contents2->GetController().LoadURL(url2b, Referrer(),
    609                                     PAGE_TRANSITION_TYPED,
    610                                     std::string());
    611   TestRenderViewHost* rvh2 =
    612       static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
    613   rvh2->SendShouldCloseACK(true);
    614   TestRenderViewHost* pending_rvh_b =
    615       static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
    616   EXPECT_TRUE(pending_rvh_b != NULL);
    617   EXPECT_TRUE(contents2->cross_navigation_pending());
    618 
    619   // NOTE(creis): We used to be in danger of showing a crash page here if the
    620   // second contents hadn't navigated somewhere first (bug 1145430).  That case
    621   // is now covered by the CrossSiteBoundariesAfterCrash test.
    622   contents2->TestDidNavigate(
    623       pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
    624   SiteInstance* instance2b = contents2->GetSiteInstance();
    625   EXPECT_NE(instance1, instance2b);
    626 
    627   // Both contentses should now be in the same SiteInstance.
    628   EXPECT_EQ(instance2a, instance2b);
    629 }
    630 
    631 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
    632   WebContentsImplTestBrowserClient browser_client;
    633   SetBrowserClientForTesting(&browser_client);
    634 
    635   contents()->transition_cross_site = true;
    636   TestRenderViewHost* orig_rvh = test_rvh();
    637   int orig_rvh_delete_count = 0;
    638   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    639   SiteInstanceImpl* orig_instance =
    640       static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
    641 
    642   browser_client.set_assign_site_for_url(false);
    643   // Navigate to an URL that will not assign a new SiteInstance.
    644   const GURL native_url("non-site-url://stuffandthings");
    645   controller().LoadURL(
    646       native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    647   contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
    648 
    649   EXPECT_FALSE(contents()->cross_navigation_pending());
    650   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    651   EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
    652   EXPECT_EQ(native_url, contents()->GetVisibleURL());
    653   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
    654   EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
    655   EXPECT_FALSE(orig_instance->HasSite());
    656 
    657   browser_client.set_assign_site_for_url(true);
    658   // Navigate to new site (should keep same site instance).
    659   const GURL url("http://www.google.com");
    660   controller().LoadURL(
    661       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    662   EXPECT_FALSE(contents()->cross_navigation_pending());
    663   EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
    664   EXPECT_EQ(url, contents()->GetVisibleURL());
    665   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    666   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    667 
    668   // Keep the number of active views in orig_rvh's SiteInstance
    669   // non-zero so that orig_rvh doesn't get deleted when it gets
    670   // swapped out.
    671   static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
    672       increment_active_view_count();
    673 
    674   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
    675   EXPECT_TRUE(
    676       contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
    677   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    678 
    679   // Navigate to another new site (should create a new site instance).
    680   const GURL url2("http://www.yahoo.com");
    681   controller().LoadURL(
    682       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    683   EXPECT_TRUE(contents()->cross_navigation_pending());
    684   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    685   EXPECT_EQ(url2, contents()->GetVisibleURL());
    686   TestRenderViewHost* pending_rvh =
    687       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    688   int pending_rvh_delete_count = 0;
    689   pending_rvh->set_delete_counter(&pending_rvh_delete_count);
    690 
    691   // Navigations should be suspended in pending_rvh until ShouldCloseACK.
    692   EXPECT_TRUE(pending_rvh->are_navigations_suspended());
    693   orig_rvh->SendShouldCloseACK(true);
    694   EXPECT_FALSE(pending_rvh->are_navigations_suspended());
    695 
    696   // DidNavigate from the pending page.
    697   contents()->TestDidNavigate(
    698       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    699   SiteInstance* new_instance = contents()->GetSiteInstance();
    700 
    701   EXPECT_FALSE(contents()->cross_navigation_pending());
    702   EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
    703   EXPECT_EQ(url2, contents()->GetLastCommittedURL());
    704   EXPECT_EQ(url2, contents()->GetVisibleURL());
    705   EXPECT_NE(new_instance, orig_instance);
    706   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    707   // We keep the original RVH around, swapped out.
    708   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
    709       orig_rvh));
    710   EXPECT_EQ(orig_rvh_delete_count, 0);
    711 
    712   // Close contents and ensure RVHs are deleted.
    713   DeleteContents();
    714   EXPECT_EQ(orig_rvh_delete_count, 1);
    715   EXPECT_EQ(pending_rvh_delete_count, 1);
    716 }
    717 
    718 // Test that we can find an opener RVH even if it's pending.
    719 // http://crbug.com/176252.
    720 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
    721   contents()->transition_cross_site = true;
    722   TestRenderViewHost* orig_rvh = test_rvh();
    723 
    724   // Navigate to a URL.
    725   const GURL url("http://www.google.com");
    726   controller().LoadURL(
    727       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    728   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    729 
    730   // Start to navigate first tab to a new site, so that it has a pending RVH.
    731   const GURL url2("http://www.yahoo.com");
    732   controller().LoadURL(
    733       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    734   orig_rvh->SendShouldCloseACK(true);
    735   TestRenderViewHost* pending_rvh =
    736       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    737 
    738   // While it is still pending, simulate opening a new tab with the first tab
    739   // as its opener.  This will call WebContentsImpl::CreateOpenerRenderViews
    740   // on the opener to ensure that an RVH exists.
    741   int opener_routing_id = contents()->CreateOpenerRenderViews(
    742       pending_rvh->GetSiteInstance());
    743 
    744   // We should find the pending RVH and not create a new one.
    745   EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
    746 }
    747 
    748 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
    749 // to determine whether a navigation is cross-site.
    750 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
    751   contents()->transition_cross_site = true;
    752   RenderViewHost* orig_rvh = rvh();
    753   SiteInstance* instance1 = contents()->GetSiteInstance();
    754 
    755   // Navigate to URL.
    756   const GURL url("http://www.google.com");
    757   controller().LoadURL(
    758       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    759   contents()->TestDidNavigate(
    760       orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    761 
    762   // Open a related contents to a second site.
    763   scoped_ptr<TestWebContents> contents2(
    764       TestWebContents::Create(browser_context(), instance1));
    765   contents2->transition_cross_site = true;
    766   const GURL url2("http://www.yahoo.com");
    767   contents2->GetController().LoadURL(url2, Referrer(),
    768                                     PAGE_TRANSITION_TYPED,
    769                                     std::string());
    770   // The first RVH in contents2 isn't live yet, so we shortcut the cross site
    771   // pending.
    772   TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
    773       contents2->GetRenderViewHost());
    774   EXPECT_FALSE(contents2->cross_navigation_pending());
    775   contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
    776   SiteInstance* instance2 = contents2->GetSiteInstance();
    777   EXPECT_NE(instance1, instance2);
    778   EXPECT_FALSE(contents2->cross_navigation_pending());
    779 
    780   // Simulate a link click in first contents to second site.  Doesn't switch
    781   // SiteInstances, because we don't intercept WebKit navigations.
    782   contents()->TestDidNavigate(
    783       orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
    784   SiteInstance* instance3 = contents()->GetSiteInstance();
    785   EXPECT_EQ(instance1, instance3);
    786   EXPECT_FALSE(contents()->cross_navigation_pending());
    787 
    788   // Navigate to the new site.  Doesn't switch SiteInstancees, because we
    789   // compare against the current URL, not the SiteInstance's site.
    790   const GURL url3("http://mail.yahoo.com");
    791   controller().LoadURL(
    792       url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    793   EXPECT_FALSE(contents()->cross_navigation_pending());
    794   contents()->TestDidNavigate(
    795       orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
    796   SiteInstance* instance4 = contents()->GetSiteInstance();
    797   EXPECT_EQ(instance1, instance4);
    798 }
    799 
    800 // Test that the onbeforeunload and onunload handlers run when navigating
    801 // across site boundaries.
    802 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
    803   contents()->transition_cross_site = true;
    804   TestRenderViewHost* orig_rvh = test_rvh();
    805   SiteInstance* instance1 = contents()->GetSiteInstance();
    806 
    807   // Navigate to URL.  First URL should use first RenderViewHost.
    808   const GURL url("http://www.google.com");
    809   controller().LoadURL(
    810       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    811   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    812   EXPECT_FALSE(contents()->cross_navigation_pending());
    813   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    814 
    815   // Navigate to new site, but simulate an onbeforeunload denial.
    816   const GURL url2("http://www.yahoo.com");
    817   controller().LoadURL(
    818       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    819   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    820   base::TimeTicks now = base::TimeTicks::Now();
    821   orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false, now, now));
    822   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    823   EXPECT_FALSE(contents()->cross_navigation_pending());
    824   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    825 
    826   // Navigate again, but simulate an onbeforeunload approval.
    827   controller().LoadURL(
    828       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    829   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    830   now = base::TimeTicks::Now();
    831   orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
    832   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    833   EXPECT_TRUE(contents()->cross_navigation_pending());
    834   TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
    835       contents()->GetPendingRenderViewHost());
    836 
    837   // We won't hear DidNavigate until the onunload handler has finished running.
    838 
    839   // DidNavigate from the pending page.
    840   contents()->TestDidNavigate(
    841       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    842   SiteInstance* instance2 = contents()->GetSiteInstance();
    843   EXPECT_FALSE(contents()->cross_navigation_pending());
    844   EXPECT_EQ(pending_rvh, rvh());
    845   EXPECT_NE(instance1, instance2);
    846   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    847 }
    848 
    849 // Test that during a slow cross-site navigation, the original renderer can
    850 // navigate to a different URL and have it displayed, canceling the slow
    851 // navigation.
    852 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
    853   contents()->transition_cross_site = true;
    854   TestRenderViewHost* orig_rvh = test_rvh();
    855   SiteInstance* instance1 = contents()->GetSiteInstance();
    856 
    857   // Navigate to URL.  First URL should use first RenderViewHost.
    858   const GURL url("http://www.google.com");
    859   controller().LoadURL(
    860       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    861   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    862   EXPECT_FALSE(contents()->cross_navigation_pending());
    863   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    864 
    865   // Navigate to new site, simulating an onbeforeunload approval.
    866   const GURL url2("http://www.yahoo.com");
    867   controller().LoadURL(
    868       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    869   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    870   base::TimeTicks now = base::TimeTicks::Now();
    871   orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
    872   EXPECT_TRUE(contents()->cross_navigation_pending());
    873 
    874   // Suppose the original renderer navigates before the new one is ready.
    875   orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
    876 
    877   // Verify that the pending navigation is cancelled.
    878   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    879   SiteInstance* instance2 = contents()->GetSiteInstance();
    880   EXPECT_FALSE(contents()->cross_navigation_pending());
    881   EXPECT_EQ(orig_rvh, rvh());
    882   EXPECT_EQ(instance1, instance2);
    883   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    884 }
    885 
    886 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
    887   contents()->transition_cross_site = true;
    888 
    889   // Start with a web ui page, which gets a new RVH with WebUI bindings.
    890   const GURL url1("chrome://blah");
    891   controller().LoadURL(
    892       url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    893   TestRenderViewHost* ntp_rvh = test_rvh();
    894   contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
    895   NavigationEntry* entry1 = controller().GetLastCommittedEntry();
    896   SiteInstance* instance1 = contents()->GetSiteInstance();
    897 
    898   EXPECT_FALSE(contents()->cross_navigation_pending());
    899   EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
    900   EXPECT_EQ(url1, entry1->GetURL());
    901   EXPECT_EQ(instance1,
    902             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
    903   EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
    904 
    905   // Navigate to new site.
    906   const GURL url2("http://www.google.com");
    907   controller().LoadURL(
    908       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    909   EXPECT_TRUE(contents()->cross_navigation_pending());
    910   TestRenderViewHost* google_rvh =
    911       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    912 
    913   // Simulate beforeunload approval.
    914   EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
    915   base::TimeTicks now = base::TimeTicks::Now();
    916   ntp_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
    917 
    918   // DidNavigate from the pending page.
    919   contents()->TestDidNavigate(
    920       google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    921   NavigationEntry* entry2 = controller().GetLastCommittedEntry();
    922   SiteInstance* instance2 = contents()->GetSiteInstance();
    923 
    924   EXPECT_FALSE(contents()->cross_navigation_pending());
    925   EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
    926   EXPECT_NE(instance1, instance2);
    927   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    928   EXPECT_EQ(url2, entry2->GetURL());
    929   EXPECT_EQ(instance2,
    930             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
    931   EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
    932 
    933   // Navigate to third page on same site.
    934   const GURL url3("http://news.google.com");
    935   controller().LoadURL(
    936       url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    937   EXPECT_FALSE(contents()->cross_navigation_pending());
    938   contents()->TestDidNavigate(
    939       google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
    940   NavigationEntry* entry3 = controller().GetLastCommittedEntry();
    941   SiteInstance* instance3 = contents()->GetSiteInstance();
    942 
    943   EXPECT_FALSE(contents()->cross_navigation_pending());
    944   EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
    945   EXPECT_EQ(instance2, instance3);
    946   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    947   EXPECT_EQ(url3, entry3->GetURL());
    948   EXPECT_EQ(instance3,
    949             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
    950 
    951   // Go back within the site.
    952   controller().GoBack();
    953   EXPECT_FALSE(contents()->cross_navigation_pending());
    954   EXPECT_EQ(entry2, controller().GetPendingEntry());
    955 
    956   // Before that commits, go back again.
    957   controller().GoBack();
    958   EXPECT_TRUE(contents()->cross_navigation_pending());
    959   EXPECT_TRUE(contents()->GetPendingRenderViewHost());
    960   EXPECT_EQ(entry1, controller().GetPendingEntry());
    961 
    962   // Simulate beforeunload approval.
    963   EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
    964   now = base::TimeTicks::Now();
    965   google_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
    966 
    967   // DidNavigate from the first back. This aborts the second back's pending RVH.
    968   contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    969 
    970   // We should commit this page and forget about the second back.
    971   EXPECT_FALSE(contents()->cross_navigation_pending());
    972   EXPECT_FALSE(controller().GetPendingEntry());
    973   EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
    974   EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
    975 
    976   // We should not have corrupted the NTP entry.
    977   EXPECT_EQ(instance3,
    978             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
    979   EXPECT_EQ(instance2,
    980             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
    981   EXPECT_EQ(instance1,
    982             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
    983   EXPECT_EQ(url1, entry1->GetURL());
    984 }
    985 
    986 // Test that during a slow cross-site navigation, a sub-frame navigation in the
    987 // original renderer will not cancel the slow navigation (bug 42029).
    988 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
    989   contents()->transition_cross_site = true;
    990   TestRenderViewHost* orig_rvh = test_rvh();
    991 
    992   // Navigate to URL.  First URL should use first RenderViewHost.
    993   const GURL url("http://www.google.com");
    994   controller().LoadURL(
    995       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    996   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    997   EXPECT_FALSE(contents()->cross_navigation_pending());
    998   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    999 
   1000   // Start navigating to new site.
   1001   const GURL url2("http://www.yahoo.com");
   1002   controller().LoadURL(
   1003       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1004 
   1005   // Simulate a sub-frame navigation arriving and ensure the RVH is still
   1006   // waiting for a before unload response.
   1007   orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
   1008                                        PAGE_TRANSITION_AUTO_SUBFRAME);
   1009   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
   1010 
   1011   // Now simulate the onbeforeunload approval and verify the navigation is
   1012   // not canceled.
   1013   base::TimeTicks now = base::TimeTicks::Now();
   1014   orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
   1015   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
   1016   EXPECT_TRUE(contents()->cross_navigation_pending());
   1017 }
   1018 
   1019 // Test that a cross-site navigation is not preempted if the previous
   1020 // renderer sends a FrameNavigate message just before being told to stop.
   1021 // We should only preempt the cross-site navigation if the previous renderer
   1022 // has started a new navigation.  See http://crbug.com/79176.
   1023 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
   1024   contents()->transition_cross_site = true;
   1025 
   1026   // Navigate to NTP URL.
   1027   const GURL url("chrome://blah");
   1028   controller().LoadURL(
   1029       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1030   TestRenderViewHost* orig_rvh = test_rvh();
   1031   EXPECT_FALSE(contents()->cross_navigation_pending());
   1032 
   1033   // Navigate to new site, with the beforeunload request in flight.
   1034   const GURL url2("http://www.yahoo.com");
   1035   controller().LoadURL(
   1036       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1037   TestRenderViewHost* pending_rvh =
   1038       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1039   EXPECT_TRUE(contents()->cross_navigation_pending());
   1040   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
   1041 
   1042   // Suppose the first navigation tries to commit now, with a
   1043   // ViewMsg_Stop in flight.  This should not cancel the pending navigation,
   1044   // but it should act as if the beforeunload ack arrived.
   1045   orig_rvh->SendNavigate(1, GURL("chrome://blah"));
   1046   EXPECT_TRUE(contents()->cross_navigation_pending());
   1047   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1048   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
   1049 
   1050   // The pending navigation should be able to commit successfully.
   1051   contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
   1052   EXPECT_FALSE(contents()->cross_navigation_pending());
   1053   EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
   1054 }
   1055 
   1056 // Test that the original renderer cannot preempt a cross-site navigation once
   1057 // the unload request has been made.  At this point, the cross-site navigation
   1058 // is almost ready to be displayed, and the original renderer is only given a
   1059 // short chance to run an unload handler.  Prevents regression of bug 23942.
   1060 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
   1061   contents()->transition_cross_site = true;
   1062   TestRenderViewHost* orig_rvh = test_rvh();
   1063   SiteInstance* instance1 = contents()->GetSiteInstance();
   1064 
   1065   // Navigate to URL.  First URL should use first RenderViewHost.
   1066   const GURL url("http://www.google.com");
   1067   controller().LoadURL(
   1068       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1069   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1070   EXPECT_FALSE(contents()->cross_navigation_pending());
   1071   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1072 
   1073   // Navigate to new site, simulating an onbeforeunload approval.
   1074   const GURL url2("http://www.yahoo.com");
   1075   controller().LoadURL(
   1076       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1077   base::TimeTicks now = base::TimeTicks::Now();
   1078   orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
   1079   EXPECT_TRUE(contents()->cross_navigation_pending());
   1080   TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
   1081       contents()->GetPendingRenderViewHost());
   1082 
   1083   // Simulate the pending renderer's response, which leads to an unload request
   1084   // being sent to orig_rvh.
   1085   std::vector<GURL> url_chain;
   1086   url_chain.push_back(GURL());
   1087   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
   1088       pending_rvh, GlobalRequestID(0, 0), false, url_chain, Referrer(),
   1089       PAGE_TRANSITION_TYPED, 1, false);
   1090 
   1091   // Suppose the original renderer navigates now, while the unload request is in
   1092   // flight.  We should ignore it, wait for the unload ack, and let the pending
   1093   // request continue.  Otherwise, the contents may close spontaneously or stop
   1094   // responding to navigation requests.  (See bug 23942.)
   1095   ViewHostMsg_FrameNavigate_Params params1a;
   1096   InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
   1097                      PAGE_TRANSITION_TYPED);
   1098   orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
   1099 
   1100   // Verify that the pending navigation is still in progress.
   1101   EXPECT_TRUE(contents()->cross_navigation_pending());
   1102   EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
   1103 
   1104   // DidNavigate from the pending page should commit it.
   1105   contents()->TestDidNavigate(
   1106       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
   1107   SiteInstance* instance2 = contents()->GetSiteInstance();
   1108   EXPECT_FALSE(contents()->cross_navigation_pending());
   1109   EXPECT_EQ(pending_rvh, rvh());
   1110   EXPECT_NE(instance1, instance2);
   1111   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1112 }
   1113 
   1114 // Test that a cross-site navigation that doesn't commit after the unload
   1115 // handler doesn't leave the contents in a stuck state.  http://crbug.com/88562
   1116 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
   1117   contents()->transition_cross_site = true;
   1118   TestRenderViewHost* orig_rvh = test_rvh();
   1119   SiteInstance* instance1 = contents()->GetSiteInstance();
   1120 
   1121   // Navigate to URL.  First URL should use first RenderViewHost.
   1122   const GURL url("http://www.google.com");
   1123   controller().LoadURL(
   1124       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1125   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1126   EXPECT_FALSE(contents()->cross_navigation_pending());
   1127   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1128 
   1129   // Navigate to new site, simulating an onbeforeunload approval.
   1130   const GURL url2("http://www.yahoo.com");
   1131   controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1132   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
   1133   base::TimeTicks now = base::TimeTicks::Now();
   1134   orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
   1135   EXPECT_TRUE(contents()->cross_navigation_pending());
   1136 
   1137   // Simulate swap out message when the response arrives.
   1138   orig_rvh->set_is_swapped_out(true);
   1139 
   1140   // Suppose the navigation doesn't get a chance to commit, and the user
   1141   // navigates in the current RVH's SiteInstance.
   1142   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1143 
   1144   // Verify that the pending navigation is cancelled and the renderer is no
   1145   // longer swapped out.
   1146   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
   1147   SiteInstance* instance2 = contents()->GetSiteInstance();
   1148   EXPECT_FALSE(contents()->cross_navigation_pending());
   1149   EXPECT_EQ(orig_rvh, rvh());
   1150   EXPECT_FALSE(orig_rvh->is_swapped_out());
   1151   EXPECT_EQ(instance1, instance2);
   1152   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1153 }
   1154 
   1155 // Test that NavigationEntries have the correct page state after going
   1156 // forward and back.  Prevents regression for bug 1116137.
   1157 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
   1158   TestRenderViewHost* orig_rvh = test_rvh();
   1159 
   1160   // Navigate to URL.  There should be no committed entry yet.
   1161   const GURL url("http://www.google.com");
   1162   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1163   NavigationEntry* entry = controller().GetLastCommittedEntry();
   1164   EXPECT_TRUE(entry == NULL);
   1165 
   1166   // Committed entry should have page state after DidNavigate.
   1167   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1168   entry = controller().GetLastCommittedEntry();
   1169   EXPECT_TRUE(entry->GetPageState().IsValid());
   1170 
   1171   // Navigate to same site.
   1172   const GURL url2("http://images.google.com");
   1173   controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1174   entry = controller().GetLastCommittedEntry();
   1175   EXPECT_TRUE(entry->GetPageState().IsValid());
   1176 
   1177   // Committed entry should have page state after DidNavigate.
   1178   contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
   1179   entry = controller().GetLastCommittedEntry();
   1180   EXPECT_TRUE(entry->GetPageState().IsValid());
   1181 
   1182   // Now go back.  Committed entry should still have page state.
   1183   controller().GoBack();
   1184   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1185   entry = controller().GetLastCommittedEntry();
   1186   EXPECT_TRUE(entry->GetPageState().IsValid());
   1187 }
   1188 
   1189 // Test that NavigationEntries have the correct page state and SiteInstance
   1190 // state after opening a new window to about:blank.  Prevents regression for
   1191 // bugs b/1116137 and http://crbug.com/111975.
   1192 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
   1193   TestRenderViewHost* orig_rvh = test_rvh();
   1194 
   1195   // When opening a new window, it is navigated to about:blank internally.
   1196   // Currently, this results in two DidNavigate events.
   1197   const GURL url(kAboutBlankURL);
   1198   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1199   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1200 
   1201   // Should have a page state here.
   1202   NavigationEntry* entry = controller().GetLastCommittedEntry();
   1203   EXPECT_TRUE(entry->GetPageState().IsValid());
   1204 
   1205   // The SiteInstance should be available for other navigations to use.
   1206   NavigationEntryImpl* entry_impl =
   1207       NavigationEntryImpl::FromNavigationEntry(entry);
   1208   EXPECT_FALSE(entry_impl->site_instance()->HasSite());
   1209   int32 site_instance_id = entry_impl->site_instance()->GetId();
   1210 
   1211   // Navigating to a normal page should not cause a process swap.
   1212   const GURL new_url("http://www.google.com");
   1213   controller().LoadURL(new_url, Referrer(),
   1214                        PAGE_TRANSITION_TYPED, std::string());
   1215   EXPECT_FALSE(contents()->cross_navigation_pending());
   1216   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1217   contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
   1218   NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
   1219       controller().GetLastCommittedEntry());
   1220   EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
   1221   EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
   1222 }
   1223 
   1224 ////////////////////////////////////////////////////////////////////////////////
   1225 // Interstitial Tests
   1226 ////////////////////////////////////////////////////////////////////////////////
   1227 
   1228 // Test navigating to a page (with the navigation initiated from the browser,
   1229 // as when a URL is typed in the location bar) that shows an interstitial and
   1230 // creates a new navigation entry, then hiding it without proceeding.
   1231 TEST_F(WebContentsImplTest,
   1232        ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
   1233   // Navigate to a page.
   1234   GURL url1("http://www.google.com");
   1235   test_rvh()->SendNavigate(1, url1);
   1236   EXPECT_EQ(1, controller().GetEntryCount());
   1237 
   1238   // Initiate a browser navigation that will trigger the interstitial
   1239   controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
   1240                         PAGE_TRANSITION_TYPED, std::string());
   1241 
   1242   // Show an interstitial.
   1243   TestInterstitialPage::InterstitialState state =
   1244       TestInterstitialPage::INVALID;
   1245   bool deleted = false;
   1246   GURL url2("http://interstitial");
   1247   TestInterstitialPage* interstitial =
   1248       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1249   TestInterstitialPageStateGuard state_guard(interstitial);
   1250   interstitial->Show();
   1251   // The interstitial should not show until its navigation has committed.
   1252   EXPECT_FALSE(interstitial->is_showing());
   1253   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1254   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1255   // Let's commit the interstitial navigation.
   1256   interstitial->TestDidNavigate(1, url2);
   1257   EXPECT_TRUE(interstitial->is_showing());
   1258   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1259   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1260   NavigationEntry* entry = controller().GetVisibleEntry();
   1261   ASSERT_TRUE(entry != NULL);
   1262   EXPECT_TRUE(entry->GetURL() == url2);
   1263 
   1264   // Now don't proceed.
   1265   interstitial->DontProceed();
   1266   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1267   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1268   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1269   entry = controller().GetVisibleEntry();
   1270   ASSERT_TRUE(entry != NULL);
   1271   EXPECT_TRUE(entry->GetURL() == url1);
   1272   EXPECT_EQ(1, controller().GetEntryCount());
   1273 
   1274   RunAllPendingInMessageLoop();
   1275   EXPECT_TRUE(deleted);
   1276 }
   1277 
   1278 // Test navigating to a page (with the navigation initiated from the renderer,
   1279 // as when clicking on a link in the page) that shows an interstitial and
   1280 // creates a new navigation entry, then hiding it without proceeding.
   1281 TEST_F(WebContentsImplTest,
   1282        ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
   1283   // Navigate to a page.
   1284   GURL url1("http://www.google.com");
   1285   test_rvh()->SendNavigate(1, url1);
   1286   EXPECT_EQ(1, controller().GetEntryCount());
   1287 
   1288   // Show an interstitial (no pending entry, the interstitial would have been
   1289   // triggered by clicking on a link).
   1290   TestInterstitialPage::InterstitialState state =
   1291       TestInterstitialPage::INVALID;
   1292   bool deleted = false;
   1293   GURL url2("http://interstitial");
   1294   TestInterstitialPage* interstitial =
   1295       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1296   TestInterstitialPageStateGuard state_guard(interstitial);
   1297   interstitial->Show();
   1298   // The interstitial should not show until its navigation has committed.
   1299   EXPECT_FALSE(interstitial->is_showing());
   1300   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1301   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1302   // Let's commit the interstitial navigation.
   1303   interstitial->TestDidNavigate(1, url2);
   1304   EXPECT_TRUE(interstitial->is_showing());
   1305   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1306   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1307   NavigationEntry* entry = controller().GetVisibleEntry();
   1308   ASSERT_TRUE(entry != NULL);
   1309   EXPECT_TRUE(entry->GetURL() == url2);
   1310 
   1311   // Now don't proceed.
   1312   interstitial->DontProceed();
   1313   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1314   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1315   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1316   entry = controller().GetVisibleEntry();
   1317   ASSERT_TRUE(entry != NULL);
   1318   EXPECT_TRUE(entry->GetURL() == url1);
   1319   EXPECT_EQ(1, controller().GetEntryCount());
   1320 
   1321   RunAllPendingInMessageLoop();
   1322   EXPECT_TRUE(deleted);
   1323 }
   1324 
   1325 // Test navigating to a page that shows an interstitial without creating a new
   1326 // navigation entry (this happens when the interstitial is triggered by a
   1327 // sub-resource in the page), then hiding it without proceeding.
   1328 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
   1329   // Navigate to a page.
   1330   GURL url1("http://www.google.com");
   1331   test_rvh()->SendNavigate(1, url1);
   1332   EXPECT_EQ(1, controller().GetEntryCount());
   1333 
   1334   // Show an interstitial.
   1335   TestInterstitialPage::InterstitialState state =
   1336       TestInterstitialPage::INVALID;
   1337   bool deleted = false;
   1338   GURL url2("http://interstitial");
   1339   TestInterstitialPage* interstitial =
   1340       new TestInterstitialPage(contents(), false, url2, &state, &deleted);
   1341   TestInterstitialPageStateGuard state_guard(interstitial);
   1342   interstitial->Show();
   1343   // The interstitial should not show until its navigation has committed.
   1344   EXPECT_FALSE(interstitial->is_showing());
   1345   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1346   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1347   // Let's commit the interstitial navigation.
   1348   interstitial->TestDidNavigate(1, url2);
   1349   EXPECT_TRUE(interstitial->is_showing());
   1350   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1351   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1352   NavigationEntry* entry = controller().GetVisibleEntry();
   1353   ASSERT_TRUE(entry != NULL);
   1354   // The URL specified to the interstitial should have been ignored.
   1355   EXPECT_TRUE(entry->GetURL() == url1);
   1356 
   1357   // Now don't proceed.
   1358   interstitial->DontProceed();
   1359   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1360   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1361   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1362   entry = controller().GetVisibleEntry();
   1363   ASSERT_TRUE(entry != NULL);
   1364   EXPECT_TRUE(entry->GetURL() == url1);
   1365   EXPECT_EQ(1, controller().GetEntryCount());
   1366 
   1367   RunAllPendingInMessageLoop();
   1368   EXPECT_TRUE(deleted);
   1369 }
   1370 
   1371 // Test navigating to a page (with the navigation initiated from the browser,
   1372 // as when a URL is typed in the location bar) that shows an interstitial and
   1373 // creates a new navigation entry, then proceeding.
   1374 TEST_F(WebContentsImplTest,
   1375        ShowInterstitialFromBrowserNewNavigationProceed) {
   1376   // Navigate to a page.
   1377   GURL url1("http://www.google.com");
   1378   test_rvh()->SendNavigate(1, url1);
   1379   EXPECT_EQ(1, controller().GetEntryCount());
   1380 
   1381   // Initiate a browser navigation that will trigger the interstitial
   1382   controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
   1383                         PAGE_TRANSITION_TYPED, std::string());
   1384 
   1385   // Show an interstitial.
   1386   TestInterstitialPage::InterstitialState state =
   1387       TestInterstitialPage::INVALID;
   1388   bool deleted = false;
   1389   GURL url2("http://interstitial");
   1390   TestInterstitialPage* interstitial =
   1391       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1392   TestInterstitialPageStateGuard state_guard(interstitial);
   1393   interstitial->Show();
   1394   // The interstitial should not show until its navigation has committed.
   1395   EXPECT_FALSE(interstitial->is_showing());
   1396   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1397   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1398   // Let's commit the interstitial navigation.
   1399   interstitial->TestDidNavigate(1, url2);
   1400   EXPECT_TRUE(interstitial->is_showing());
   1401   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1402   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1403   NavigationEntry* entry = controller().GetVisibleEntry();
   1404   ASSERT_TRUE(entry != NULL);
   1405   EXPECT_TRUE(entry->GetURL() == url2);
   1406 
   1407   // Then proceed.
   1408   interstitial->Proceed();
   1409   // The interstitial should show until the new navigation commits.
   1410   RunAllPendingInMessageLoop();
   1411   ASSERT_FALSE(deleted);
   1412   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1413   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1414   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1415 
   1416   // Simulate the navigation to the page, that's when the interstitial gets
   1417   // hidden.
   1418   GURL url3("http://www.thepage.com");
   1419   test_rvh()->SendNavigate(2, url3);
   1420 
   1421   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1422   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1423   entry = controller().GetVisibleEntry();
   1424   ASSERT_TRUE(entry != NULL);
   1425   EXPECT_TRUE(entry->GetURL() == url3);
   1426 
   1427   EXPECT_EQ(2, controller().GetEntryCount());
   1428 
   1429   RunAllPendingInMessageLoop();
   1430   EXPECT_TRUE(deleted);
   1431 }
   1432 
   1433 // Test navigating to a page (with the navigation initiated from the renderer,
   1434 // as when clicking on a link in the page) that shows an interstitial and
   1435 // creates a new navigation entry, then proceeding.
   1436 TEST_F(WebContentsImplTest,
   1437        ShowInterstitialFromRendererNewNavigationProceed) {
   1438   // Navigate to a page.
   1439   GURL url1("http://www.google.com");
   1440   test_rvh()->SendNavigate(1, url1);
   1441   EXPECT_EQ(1, controller().GetEntryCount());
   1442 
   1443   // Show an interstitial.
   1444   TestInterstitialPage::InterstitialState state =
   1445       TestInterstitialPage::INVALID;
   1446   bool deleted = false;
   1447   GURL url2("http://interstitial");
   1448   TestInterstitialPage* interstitial =
   1449       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1450   TestInterstitialPageStateGuard state_guard(interstitial);
   1451   interstitial->Show();
   1452   // The interstitial should not show until its navigation has committed.
   1453   EXPECT_FALSE(interstitial->is_showing());
   1454   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1455   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1456   // Let's commit the interstitial navigation.
   1457   interstitial->TestDidNavigate(1, url2);
   1458   EXPECT_TRUE(interstitial->is_showing());
   1459   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1460   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1461   NavigationEntry* entry = controller().GetVisibleEntry();
   1462   ASSERT_TRUE(entry != NULL);
   1463   EXPECT_TRUE(entry->GetURL() == url2);
   1464 
   1465   // Then proceed.
   1466   interstitial->Proceed();
   1467   // The interstitial should show until the new navigation commits.
   1468   RunAllPendingInMessageLoop();
   1469   ASSERT_FALSE(deleted);
   1470   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1471   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1472   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1473 
   1474   // Simulate the navigation to the page, that's when the interstitial gets
   1475   // hidden.
   1476   GURL url3("http://www.thepage.com");
   1477   test_rvh()->SendNavigate(2, url3);
   1478 
   1479   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1480   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1481   entry = controller().GetVisibleEntry();
   1482   ASSERT_TRUE(entry != NULL);
   1483   EXPECT_TRUE(entry->GetURL() == url3);
   1484 
   1485   EXPECT_EQ(2, controller().GetEntryCount());
   1486 
   1487   RunAllPendingInMessageLoop();
   1488   EXPECT_TRUE(deleted);
   1489 }
   1490 
   1491 // Test navigating to a page that shows an interstitial without creating a new
   1492 // navigation entry (this happens when the interstitial is triggered by a
   1493 // sub-resource in the page), then proceeding.
   1494 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
   1495   // Navigate to a page so we have a navigation entry in the controller.
   1496   GURL url1("http://www.google.com");
   1497   test_rvh()->SendNavigate(1, url1);
   1498   EXPECT_EQ(1, controller().GetEntryCount());
   1499 
   1500   // Show an interstitial.
   1501   TestInterstitialPage::InterstitialState state =
   1502       TestInterstitialPage::INVALID;
   1503   bool deleted = false;
   1504   GURL url2("http://interstitial");
   1505   TestInterstitialPage* interstitial =
   1506       new TestInterstitialPage(contents(), false, url2, &state, &deleted);
   1507   TestInterstitialPageStateGuard state_guard(interstitial);
   1508   interstitial->Show();
   1509   // The interstitial should not show until its navigation has committed.
   1510   EXPECT_FALSE(interstitial->is_showing());
   1511   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1512   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1513   // Let's commit the interstitial navigation.
   1514   interstitial->TestDidNavigate(1, url2);
   1515   EXPECT_TRUE(interstitial->is_showing());
   1516   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1517   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1518   NavigationEntry* entry = controller().GetVisibleEntry();
   1519   ASSERT_TRUE(entry != NULL);
   1520   // The URL specified to the interstitial should have been ignored.
   1521   EXPECT_TRUE(entry->GetURL() == url1);
   1522 
   1523   // Then proceed.
   1524   interstitial->Proceed();
   1525   // Since this is not a new navigation, the previous page is dismissed right
   1526   // away and shows the original page.
   1527   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1528   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1529   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1530   entry = controller().GetVisibleEntry();
   1531   ASSERT_TRUE(entry != NULL);
   1532   EXPECT_TRUE(entry->GetURL() == url1);
   1533 
   1534   EXPECT_EQ(1, controller().GetEntryCount());
   1535 
   1536   RunAllPendingInMessageLoop();
   1537   EXPECT_TRUE(deleted);
   1538 }
   1539 
   1540 // Test navigating to a page that shows an interstitial, then navigating away.
   1541 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
   1542   // Show interstitial.
   1543   TestInterstitialPage::InterstitialState state =
   1544       TestInterstitialPage::INVALID;
   1545   bool deleted = false;
   1546   GURL url("http://interstitial");
   1547   TestInterstitialPage* interstitial =
   1548       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1549   TestInterstitialPageStateGuard state_guard(interstitial);
   1550   interstitial->Show();
   1551   interstitial->TestDidNavigate(1, url);
   1552 
   1553   // While interstitial showing, navigate to a new URL.
   1554   const GURL url2("http://www.yahoo.com");
   1555   test_rvh()->SendNavigate(1, url2);
   1556 
   1557   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1558 
   1559   RunAllPendingInMessageLoop();
   1560   EXPECT_TRUE(deleted);
   1561 }
   1562 
   1563 // Test navigating to a page that shows an interstitial, then going back.
   1564 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
   1565   // Navigate to a page so we have a navigation entry in the controller.
   1566   GURL url1("http://www.google.com");
   1567   test_rvh()->SendNavigate(1, url1);
   1568   EXPECT_EQ(1, controller().GetEntryCount());
   1569 
   1570   // Show interstitial.
   1571   TestInterstitialPage::InterstitialState state =
   1572       TestInterstitialPage::INVALID;
   1573   bool deleted = false;
   1574   GURL interstitial_url("http://interstitial");
   1575   TestInterstitialPage* interstitial =
   1576       new TestInterstitialPage(contents(), true, interstitial_url,
   1577                                &state, &deleted);
   1578   TestInterstitialPageStateGuard state_guard(interstitial);
   1579   interstitial->Show();
   1580   interstitial->TestDidNavigate(2, interstitial_url);
   1581 
   1582   // While the interstitial is showing, go back.
   1583   controller().GoBack();
   1584   test_rvh()->SendNavigate(1, url1);
   1585 
   1586   // Make sure we are back to the original page and that the interstitial is
   1587   // gone.
   1588   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1589   NavigationEntry* entry = controller().GetVisibleEntry();
   1590   ASSERT_TRUE(entry);
   1591   EXPECT_EQ(url1.spec(), entry->GetURL().spec());
   1592 
   1593   RunAllPendingInMessageLoop();
   1594   EXPECT_TRUE(deleted);
   1595 }
   1596 
   1597 // Test navigating to a page that shows an interstitial, has a renderer crash,
   1598 // and then goes back.
   1599 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
   1600   // Navigate to a page so we have a navigation entry in the controller.
   1601   GURL url1("http://www.google.com");
   1602   test_rvh()->SendNavigate(1, url1);
   1603   EXPECT_EQ(1, controller().GetEntryCount());
   1604 
   1605   // Show interstitial.
   1606   TestInterstitialPage::InterstitialState state =
   1607       TestInterstitialPage::INVALID;
   1608   bool deleted = false;
   1609   GURL interstitial_url("http://interstitial");
   1610   TestInterstitialPage* interstitial =
   1611       new TestInterstitialPage(contents(), true, interstitial_url,
   1612                                &state, &deleted);
   1613   TestInterstitialPageStateGuard state_guard(interstitial);
   1614   interstitial->Show();
   1615   interstitial->TestDidNavigate(2, interstitial_url);
   1616 
   1617   // Crash the renderer
   1618   test_rvh()->OnMessageReceived(
   1619       ViewHostMsg_RenderProcessGone(
   1620           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1621 
   1622   // While the interstitial is showing, go back.
   1623   controller().GoBack();
   1624   test_rvh()->SendNavigate(1, url1);
   1625 
   1626   // Make sure we are back to the original page and that the interstitial is
   1627   // gone.
   1628   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1629   NavigationEntry* entry = controller().GetVisibleEntry();
   1630   ASSERT_TRUE(entry);
   1631   EXPECT_EQ(url1.spec(), entry->GetURL().spec());
   1632 
   1633   RunAllPendingInMessageLoop();
   1634   EXPECT_TRUE(deleted);
   1635 }
   1636 
   1637 // Test navigating to a page that shows an interstitial, has the renderer crash,
   1638 // and then navigates to the interstitial.
   1639 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
   1640   // Navigate to a page so we have a navigation entry in the controller.
   1641   GURL url1("http://www.google.com");
   1642   test_rvh()->SendNavigate(1, url1);
   1643   EXPECT_EQ(1, controller().GetEntryCount());
   1644 
   1645   // Show interstitial.
   1646   TestInterstitialPage::InterstitialState state =
   1647       TestInterstitialPage::INVALID;
   1648   bool deleted = false;
   1649   GURL interstitial_url("http://interstitial");
   1650   TestInterstitialPage* interstitial =
   1651       new TestInterstitialPage(contents(), true, interstitial_url,
   1652                                &state, &deleted);
   1653   TestInterstitialPageStateGuard state_guard(interstitial);
   1654   interstitial->Show();
   1655 
   1656   // Crash the renderer
   1657   test_rvh()->OnMessageReceived(
   1658       ViewHostMsg_RenderProcessGone(
   1659           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1660 
   1661   interstitial->TestDidNavigate(2, interstitial_url);
   1662 }
   1663 
   1664 // Test navigating to a page that shows an interstitial, then close the
   1665 // contents.
   1666 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
   1667   // Show interstitial.
   1668   TestInterstitialPage::InterstitialState state =
   1669       TestInterstitialPage::INVALID;
   1670   bool deleted = false;
   1671   GURL url("http://interstitial");
   1672   TestInterstitialPage* interstitial =
   1673       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1674   TestInterstitialPageStateGuard state_guard(interstitial);
   1675   interstitial->Show();
   1676   interstitial->TestDidNavigate(1, url);
   1677 
   1678   // Now close the contents.
   1679   DeleteContents();
   1680   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1681 
   1682   RunAllPendingInMessageLoop();
   1683   EXPECT_TRUE(deleted);
   1684 }
   1685 
   1686 // Test navigating to a page that shows an interstitial, then close the
   1687 // contents.
   1688 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
   1689   // Show interstitial.
   1690   TestInterstitialPage::InterstitialState state =
   1691       TestInterstitialPage::INVALID;
   1692   bool deleted = false;
   1693   GURL url("http://interstitial");
   1694   TestInterstitialPage* interstitial =
   1695       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1696   TestInterstitialPageStateGuard state_guard(interstitial);
   1697   interstitial->Show();
   1698   interstitial->TestDidNavigate(1, url);
   1699   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
   1700       interstitial->GetRenderViewHostForTesting());
   1701 
   1702   // Now close the contents.
   1703   DeleteContents();
   1704   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1705 
   1706   // Before the interstitial has a chance to process its shutdown task,
   1707   // simulate quitting the browser.  This goes through all processes and
   1708   // tells them to destruct.
   1709   rvh->OnMessageReceived(
   1710         ViewHostMsg_RenderProcessGone(0, 0, 0));
   1711 
   1712   RunAllPendingInMessageLoop();
   1713   EXPECT_TRUE(deleted);
   1714 }
   1715 
   1716 // Test that after Proceed is called and an interstitial is still shown, no more
   1717 // commands get executed.
   1718 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
   1719   // Navigate to a page so we have a navigation entry in the controller.
   1720   GURL url1("http://www.google.com");
   1721   test_rvh()->SendNavigate(1, url1);
   1722   EXPECT_EQ(1, controller().GetEntryCount());
   1723 
   1724   // Show an interstitial.
   1725   TestInterstitialPage::InterstitialState state =
   1726       TestInterstitialPage::INVALID;
   1727   bool deleted = false;
   1728   GURL url2("http://interstitial");
   1729   TestInterstitialPage* interstitial =
   1730       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1731   TestInterstitialPageStateGuard state_guard(interstitial);
   1732   interstitial->Show();
   1733   interstitial->TestDidNavigate(1, url2);
   1734 
   1735   // Run a command.
   1736   EXPECT_EQ(0, interstitial->command_received_count());
   1737   interstitial->TestDomOperationResponse("toto");
   1738   EXPECT_EQ(1, interstitial->command_received_count());
   1739 
   1740   // Then proceed.
   1741   interstitial->Proceed();
   1742   RunAllPendingInMessageLoop();
   1743   ASSERT_FALSE(deleted);
   1744 
   1745   // While the navigation to the new page is pending, send other commands, they
   1746   // should be ignored.
   1747   interstitial->TestDomOperationResponse("hello");
   1748   interstitial->TestDomOperationResponse("hi");
   1749   EXPECT_EQ(1, interstitial->command_received_count());
   1750 }
   1751 
   1752 // Test showing an interstitial while another interstitial is already showing.
   1753 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
   1754   // Navigate to a page so we have a navigation entry in the controller.
   1755   GURL start_url("http://www.google.com");
   1756   test_rvh()->SendNavigate(1, start_url);
   1757   EXPECT_EQ(1, controller().GetEntryCount());
   1758 
   1759   // Show an interstitial.
   1760   TestInterstitialPage::InterstitialState state1 =
   1761       TestInterstitialPage::INVALID;
   1762   bool deleted1 = false;
   1763   GURL url1("http://interstitial1");
   1764   TestInterstitialPage* interstitial1 =
   1765       new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
   1766   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1767   interstitial1->Show();
   1768   interstitial1->TestDidNavigate(1, url1);
   1769 
   1770   // Now show another interstitial.
   1771   TestInterstitialPage::InterstitialState state2 =
   1772       TestInterstitialPage::INVALID;
   1773   bool deleted2 = false;
   1774   GURL url2("http://interstitial2");
   1775   TestInterstitialPage* interstitial2 =
   1776       new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
   1777   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1778   interstitial2->Show();
   1779   interstitial2->TestDidNavigate(1, url2);
   1780 
   1781   // Showing interstitial2 should have caused interstitial1 to go away.
   1782   EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
   1783   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1784 
   1785   RunAllPendingInMessageLoop();
   1786   EXPECT_TRUE(deleted1);
   1787   ASSERT_FALSE(deleted2);
   1788 
   1789   // Let's make sure interstitial2 is working as intended.
   1790   interstitial2->Proceed();
   1791   GURL landing_url("http://www.thepage.com");
   1792   test_rvh()->SendNavigate(2, landing_url);
   1793 
   1794   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1795   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1796   NavigationEntry* entry = controller().GetVisibleEntry();
   1797   ASSERT_TRUE(entry != NULL);
   1798   EXPECT_TRUE(entry->GetURL() == landing_url);
   1799   EXPECT_EQ(2, controller().GetEntryCount());
   1800   RunAllPendingInMessageLoop();
   1801   EXPECT_TRUE(deleted2);
   1802 }
   1803 
   1804 // Test showing an interstitial, proceeding and then navigating to another
   1805 // interstitial.
   1806 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
   1807   // Navigate to a page so we have a navigation entry in the controller.
   1808   GURL start_url("http://www.google.com");
   1809   test_rvh()->SendNavigate(1, start_url);
   1810   EXPECT_EQ(1, controller().GetEntryCount());
   1811 
   1812   // Show an interstitial.
   1813   TestInterstitialPage::InterstitialState state1 =
   1814       TestInterstitialPage::INVALID;
   1815   bool deleted1 = false;
   1816   GURL url1("http://interstitial1");
   1817   TestInterstitialPage* interstitial1 =
   1818       new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
   1819   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1820   interstitial1->Show();
   1821   interstitial1->TestDidNavigate(1, url1);
   1822 
   1823   // Take action.  The interstitial won't be hidden until the navigation is
   1824   // committed.
   1825   interstitial1->Proceed();
   1826   EXPECT_EQ(TestInterstitialPage::OKED, state1);
   1827 
   1828   // Now show another interstitial (simulating the navigation causing another
   1829   // interstitial).
   1830   TestInterstitialPage::InterstitialState state2 =
   1831       TestInterstitialPage::INVALID;
   1832   bool deleted2 = false;
   1833   GURL url2("http://interstitial2");
   1834   TestInterstitialPage* interstitial2 =
   1835       new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
   1836   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1837   interstitial2->Show();
   1838   interstitial2->TestDidNavigate(1, url2);
   1839 
   1840   // Showing interstitial2 should have caused interstitial1 to go away.
   1841   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1842   RunAllPendingInMessageLoop();
   1843   EXPECT_TRUE(deleted1);
   1844   ASSERT_FALSE(deleted2);
   1845 
   1846   // Let's make sure interstitial2 is working as intended.
   1847   interstitial2->Proceed();
   1848   GURL landing_url("http://www.thepage.com");
   1849   test_rvh()->SendNavigate(2, landing_url);
   1850 
   1851   RunAllPendingInMessageLoop();
   1852   EXPECT_TRUE(deleted2);
   1853   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1854   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1855   NavigationEntry* entry = controller().GetVisibleEntry();
   1856   ASSERT_TRUE(entry != NULL);
   1857   EXPECT_TRUE(entry->GetURL() == landing_url);
   1858   EXPECT_EQ(2, controller().GetEntryCount());
   1859 }
   1860 
   1861 // Test that navigating away from an interstitial while it's loading cause it
   1862 // not to show.
   1863 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
   1864   // Show an interstitial.
   1865   TestInterstitialPage::InterstitialState state =
   1866       TestInterstitialPage::INVALID;
   1867   bool deleted = false;
   1868   GURL interstitial_url("http://interstitial");
   1869   TestInterstitialPage* interstitial =
   1870       new TestInterstitialPage(contents(), true, interstitial_url,
   1871                                &state, &deleted);
   1872   TestInterstitialPageStateGuard state_guard(interstitial);
   1873   interstitial->Show();
   1874 
   1875   // Let's simulate a navigation initiated from the browser before the
   1876   // interstitial finishes loading.
   1877   const GURL url("http://www.google.com");
   1878   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1879   EXPECT_FALSE(interstitial->is_showing());
   1880   RunAllPendingInMessageLoop();
   1881   ASSERT_FALSE(deleted);
   1882 
   1883   // Now let's make the interstitial navigation commit.
   1884   interstitial->TestDidNavigate(1, interstitial_url);
   1885 
   1886   // After it loaded the interstitial should be gone.
   1887   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1888 
   1889   RunAllPendingInMessageLoop();
   1890   EXPECT_TRUE(deleted);
   1891 }
   1892 
   1893 // Test that a new request to show an interstitial while an interstitial is
   1894 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
   1895 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
   1896   GURL interstitial_url("http://interstitial");
   1897 
   1898   // Show a first interstitial.
   1899   TestInterstitialPage::InterstitialState state1 =
   1900       TestInterstitialPage::INVALID;
   1901   bool deleted1 = false;
   1902   TestInterstitialPage* interstitial1 =
   1903       new TestInterstitialPage(contents(), true, interstitial_url,
   1904                                &state1, &deleted1);
   1905   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1906   interstitial1->Show();
   1907 
   1908   // Show another interstitial on that same contents before the first one had
   1909   // time to load.
   1910   TestInterstitialPage::InterstitialState state2 =
   1911       TestInterstitialPage::INVALID;
   1912   bool deleted2 = false;
   1913   TestInterstitialPage* interstitial2 =
   1914       new TestInterstitialPage(contents(), true, interstitial_url,
   1915                                &state2, &deleted2);
   1916   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1917   interstitial2->Show();
   1918 
   1919   // The first interstitial should have been closed and deleted.
   1920   EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
   1921   // The 2nd one should still be OK.
   1922   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1923 
   1924   RunAllPendingInMessageLoop();
   1925   EXPECT_TRUE(deleted1);
   1926   ASSERT_FALSE(deleted2);
   1927 
   1928   // Make the interstitial navigation commit it should be showing.
   1929   interstitial2->TestDidNavigate(1, interstitial_url);
   1930   EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
   1931 }
   1932 
   1933 // Test showing an interstitial and have its renderer crash.
   1934 TEST_F(WebContentsImplTest, InterstitialCrasher) {
   1935   // Show an interstitial.
   1936   TestInterstitialPage::InterstitialState state =
   1937       TestInterstitialPage::INVALID;
   1938   bool deleted = false;
   1939   GURL url("http://interstitial");
   1940   TestInterstitialPage* interstitial =
   1941       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1942   TestInterstitialPageStateGuard state_guard(interstitial);
   1943   interstitial->Show();
   1944   // Simulate a renderer crash before the interstitial is shown.
   1945   interstitial->TestRenderViewTerminated(
   1946       base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
   1947   // The interstitial should have been dismissed.
   1948   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1949   RunAllPendingInMessageLoop();
   1950   EXPECT_TRUE(deleted);
   1951 
   1952   // Now try again but this time crash the intersitial after it was shown.
   1953   interstitial =
   1954       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1955   interstitial->Show();
   1956   interstitial->TestDidNavigate(1, url);
   1957   // Simulate a renderer crash.
   1958   interstitial->TestRenderViewTerminated(
   1959       base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
   1960   // The interstitial should have been dismissed.
   1961   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1962   RunAllPendingInMessageLoop();
   1963   EXPECT_TRUE(deleted);
   1964 }
   1965 
   1966 // Tests that showing an interstitial as a result of a browser initiated
   1967 // navigation while an interstitial is showing does not remove the pending
   1968 // entry (see http://crbug.com/9791).
   1969 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
   1970   const char kUrl[] = "http://www.badguys.com/";
   1971   const GURL kGURL(kUrl);
   1972 
   1973   // Start a navigation to a page
   1974   contents()->GetController().LoadURL(
   1975       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1976 
   1977   // Simulate that navigation triggering an interstitial.
   1978   TestInterstitialPage::InterstitialState state =
   1979       TestInterstitialPage::INVALID;
   1980   bool deleted = false;
   1981   TestInterstitialPage* interstitial =
   1982       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   1983   TestInterstitialPageStateGuard state_guard(interstitial);
   1984   interstitial->Show();
   1985   interstitial->TestDidNavigate(1, kGURL);
   1986 
   1987   // Initiate a new navigation from the browser that also triggers an
   1988   // interstitial.
   1989   contents()->GetController().LoadURL(
   1990       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1991   TestInterstitialPage::InterstitialState state2 =
   1992       TestInterstitialPage::INVALID;
   1993   bool deleted2 = false;
   1994   TestInterstitialPage* interstitial2 =
   1995       new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
   1996   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1997   interstitial2->Show();
   1998   interstitial2->TestDidNavigate(1, kGURL);
   1999 
   2000   // Make sure we still have an entry.
   2001   NavigationEntry* entry = contents()->GetController().GetPendingEntry();
   2002   ASSERT_TRUE(entry);
   2003   EXPECT_EQ(kUrl, entry->GetURL().spec());
   2004 
   2005   // And that the first interstitial is gone, but not the second.
   2006   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   2007   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   2008   RunAllPendingInMessageLoop();
   2009   EXPECT_TRUE(deleted);
   2010   EXPECT_FALSE(deleted2);
   2011 }
   2012 
   2013 // Tests that Javascript messages are not shown while an interstitial is
   2014 // showing.
   2015 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
   2016   const char kUrl[] = "http://www.badguys.com/";
   2017   const GURL kGURL(kUrl);
   2018 
   2019   // Start a navigation to a page
   2020   contents()->GetController().LoadURL(
   2021       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2022   // DidNavigate from the page
   2023   contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
   2024 
   2025   // Simulate showing an interstitial while the page is showing.
   2026   TestInterstitialPage::InterstitialState state =
   2027       TestInterstitialPage::INVALID;
   2028   bool deleted = false;
   2029   TestInterstitialPage* interstitial =
   2030       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   2031   TestInterstitialPageStateGuard state_guard(interstitial);
   2032   interstitial->Show();
   2033   interstitial->TestDidNavigate(1, kGURL);
   2034 
   2035   // While the interstitial is showing, let's simulate the hidden page
   2036   // attempting to show a JS message.
   2037   IPC::Message* dummy_message = new IPC::Message;
   2038   bool did_suppress_message = false;
   2039   contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
   2040       ASCIIToUTF16("This is an informative message"), ASCIIToUTF16("OK"),
   2041       kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
   2042       &did_suppress_message);
   2043   EXPECT_TRUE(did_suppress_message);
   2044 }
   2045 
   2046 // Makes sure that if the source passed to CopyStateFromAndPrune has an
   2047 // interstitial it isn't copied over to the destination.
   2048 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
   2049   // Navigate to a page.
   2050   GURL url1("http://www.google.com");
   2051   test_rvh()->SendNavigate(1, url1);
   2052   EXPECT_EQ(1, controller().GetEntryCount());
   2053 
   2054   // Initiate a browser navigation that will trigger the interstitial
   2055   controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
   2056                         PAGE_TRANSITION_TYPED, std::string());
   2057 
   2058   // Show an interstitial.
   2059   TestInterstitialPage::InterstitialState state =
   2060       TestInterstitialPage::INVALID;
   2061   bool deleted = false;
   2062   GURL url2("http://interstitial");
   2063   TestInterstitialPage* interstitial =
   2064       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   2065   TestInterstitialPageStateGuard state_guard(interstitial);
   2066   interstitial->Show();
   2067   interstitial->TestDidNavigate(1, url2);
   2068   EXPECT_TRUE(interstitial->is_showing());
   2069   EXPECT_EQ(2, controller().GetEntryCount());
   2070 
   2071   // Create another NavigationController.
   2072   GURL url3("http://foo2");
   2073   scoped_ptr<TestWebContents> other_contents(
   2074       static_cast<TestWebContents*>(CreateTestWebContents()));
   2075   NavigationControllerImpl& other_controller = other_contents->GetController();
   2076   other_contents->NavigateAndCommit(url3);
   2077   other_contents->ExpectSetHistoryLengthAndPrune(
   2078       NavigationEntryImpl::FromNavigationEntry(
   2079           other_controller.GetEntryAtIndex(0))->site_instance(), 1,
   2080       other_controller.GetEntryAtIndex(0)->GetPageID());
   2081   other_controller.CopyStateFromAndPrune(&controller(), false);
   2082 
   2083   // The merged controller should only have two entries: url1 and url2.
   2084   ASSERT_EQ(2, other_controller.GetEntryCount());
   2085   EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
   2086   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   2087   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
   2088 
   2089   // And the merged controller shouldn't be showing an interstitial.
   2090   EXPECT_FALSE(other_contents->ShowingInterstitialPage());
   2091 }
   2092 
   2093 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
   2094 // showing an interstitial.
   2095 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
   2096   // Navigate to a page.
   2097   GURL url1("http://www.google.com");
   2098   contents()->NavigateAndCommit(url1);
   2099 
   2100   // Create another NavigationController.
   2101   scoped_ptr<TestWebContents> other_contents(
   2102       static_cast<TestWebContents*>(CreateTestWebContents()));
   2103   NavigationControllerImpl& other_controller = other_contents->GetController();
   2104 
   2105   // Navigate it to url2.
   2106   GURL url2("http://foo2");
   2107   other_contents->NavigateAndCommit(url2);
   2108 
   2109   // Show an interstitial.
   2110   TestInterstitialPage::InterstitialState state =
   2111       TestInterstitialPage::INVALID;
   2112   bool deleted = false;
   2113   GURL url3("http://interstitial");
   2114   TestInterstitialPage* interstitial =
   2115       new TestInterstitialPage(other_contents.get(), true, url3, &state,
   2116                                &deleted);
   2117   TestInterstitialPageStateGuard state_guard(interstitial);
   2118   interstitial->Show();
   2119   interstitial->TestDidNavigate(1, url3);
   2120   EXPECT_TRUE(interstitial->is_showing());
   2121   EXPECT_EQ(2, other_controller.GetEntryCount());
   2122 
   2123   // Ensure that we do not allow calling CopyStateFromAndPrune when an
   2124   // interstitial is showing in the target.
   2125   EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
   2126 }
   2127 
   2128 // Regression test for http://crbug.com/168611 - the URLs passed by the
   2129 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
   2130 TEST_F(WebContentsImplTest, FilterURLs) {
   2131   TestWebContentsObserver observer(contents());
   2132 
   2133   // A navigation to about:whatever should always look like a navigation to
   2134   // about:blank
   2135   GURL url_normalized(kAboutBlankURL);
   2136   GURL url_from_ipc("about:whatever");
   2137 
   2138   // We navigate the test WebContents to about:blank, since NavigateAndCommit
   2139   // will use the given URL to create the NavigationEntry as well, and that
   2140   // entry should contain the filtered URL.
   2141   contents()->NavigateAndCommit(url_normalized);
   2142 
   2143   // Check that an IPC with about:whatever is correctly normalized.
   2144   contents()->TestDidFinishLoad(1, url_from_ipc, true);
   2145 
   2146   EXPECT_EQ(url_normalized, observer.last_url());
   2147 
   2148   // Create and navigate another WebContents.
   2149   scoped_ptr<TestWebContents> other_contents(
   2150       static_cast<TestWebContents*>(CreateTestWebContents()));
   2151   TestWebContentsObserver other_observer(other_contents.get());
   2152   other_contents->NavigateAndCommit(url_normalized);
   2153 
   2154   // Check that an IPC with about:whatever is correctly normalized.
   2155   other_contents->TestDidFailLoadWithError(
   2156       1, url_from_ipc, true, 1, base::string16());
   2157   EXPECT_EQ(url_normalized, other_observer.last_url());
   2158 }
   2159 
   2160 // Test that if a pending contents is deleted before it is shown, we don't
   2161 // crash.
   2162 TEST_F(WebContentsImplTest, PendingContents) {
   2163   scoped_ptr<TestWebContents> other_contents(
   2164       static_cast<TestWebContents*>(CreateTestWebContents()));
   2165   contents()->AddPendingContents(other_contents.get());
   2166   int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
   2167   other_contents.reset();
   2168   EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
   2169 }
   2170 
   2171 }  // namespace content
   2172