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