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