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