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