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