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