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.
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/cross_site_transferring_request.h"
9 #include "content/browser/frame_host/interstitial_page_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/frame_host/render_frame_proxy_host.h"
13 #include "content/browser/media/audio_stream_monitor.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/webui/content_web_ui_controller_factory.h"
17 #include "content/browser/webui/web_ui_controller_factory_registry.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/input/synthetic_web_input_event_builders.h"
20 #include "content/common/site_isolation_policy.h"
21 #include "content/common/view_messages.h"
22 #include "content/public/browser/global_request_id.h"
23 #include "content/public/browser/interstitial_page_delegate.h"
24 #include "content/public/browser/navigation_details.h"
25 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_source.h"
27 #include "content/public/browser/render_widget_host_view.h"
28 #include "content/public/browser/web_contents_delegate.h"
29 #include "content/public/browser/web_contents_observer.h"
30 #include "content/public/browser/web_ui_controller.h"
31 #include "content/public/common/bindings_policy.h"
32 #include "content/public/common/content_constants.h"
33 #include "content/public/common/content_switches.h"
34 #include "content/public/common/url_constants.h"
35 #include "content/public/common/url_utils.h"
36 #include "content/public/test/mock_render_process_host.h"
37 #include "content/public/test/test_utils.h"
38 #include "content/test/test_content_browser_client.h"
39 #include "content/test/test_content_client.h"
40 #include "content/test/test_render_frame_host.h"
41 #include "content/test/test_render_view_host.h"
42 #include "content/test/test_web_contents.h"
43 #include "net/base/test_data_directory.h"
44 #include "net/test/cert_test_util.h"
45 #include "testing/gtest/include/gtest/gtest.h"
46 #include "third_party/skia/include/core/SkColor.h"
51 class TestInterstitialPage
;
53 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
55 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
56 : interstitial_page_(interstitial_page
) {}
57 void CommandReceived(const std::string
& command
) override
;
58 std::string
GetHTMLContents() override
{ return std::string(); }
59 void OnDontProceed() override
;
60 void OnProceed() override
;
63 TestInterstitialPage
* interstitial_page_
;
66 class TestInterstitialPage
: public InterstitialPageImpl
{
68 enum InterstitialState
{
69 INVALID
= 0, // Hasn't yet been initialized.
70 UNDECIDED
, // Initialized, but no decision taken yet.
71 OKED
, // Proceed was called.
72 CANCELED
// DontProceed was called.
77 virtual void TestInterstitialPageDeleted(
78 TestInterstitialPage
* interstitial
) = 0;
81 virtual ~Delegate() {}
84 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
85 // |deleted| (like all interstitial related tests do at this point), make sure
86 // to create an instance of the TestInterstitialPageStateGuard class on the
87 // stack in your test. This will ensure that the TestInterstitialPage states
88 // are cleared when the test finishes.
89 // Not doing so will cause stack trashing if your test does not hide the
90 // interstitial, as in such a case it will be destroyed in the test TearDown
91 // method and will dereference the |deleted| local variable which by then is
93 TestInterstitialPage(WebContentsImpl
* contents
,
96 InterstitialState
* state
,
98 : InterstitialPageImpl(
100 static_cast<RenderWidgetHostDelegate
*>(contents
),
101 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
104 command_received_count_(0),
110 ~TestInterstitialPage() override
{
114 delegate_
->TestInterstitialPageDeleted(this);
117 void OnDontProceed() {
126 int command_received_count() const {
127 return command_received_count_
;
130 void TestDomOperationResponse(const std::string
& json_string
) {
135 void TestDidNavigate(int page_id
,
137 bool did_create_new_entry
,
139 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
140 InitNavigateParams(¶ms
, page_id
, nav_entry_id
, did_create_new_entry
,
141 url
, ui::PAGE_TRANSITION_TYPED
);
142 DidNavigate(GetMainFrame()->GetRenderViewHost(), params
);
145 void TestRenderViewTerminated(base::TerminationStatus status
,
147 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status
,
151 bool is_showing() const {
152 return static_cast<TestRenderWidgetHostView
*>(
153 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
162 void CommandReceived() {
163 command_received_count_
++;
166 void set_delegate(Delegate
* delegate
) {
167 delegate_
= delegate
;
171 WebContentsView
* CreateWebContentsView() override
{ return nullptr; }
174 InterstitialState
* state_
;
176 int command_received_count_
;
180 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
181 interstitial_page_
->CommandReceived();
184 void TestInterstitialPageDelegate::OnDontProceed() {
185 interstitial_page_
->OnDontProceed();
188 void TestInterstitialPageDelegate::OnProceed() {
189 interstitial_page_
->OnProceed();
192 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
194 explicit TestInterstitialPageStateGuard(
195 TestInterstitialPage
* interstitial_page
)
196 : interstitial_page_(interstitial_page
) {
197 DCHECK(interstitial_page_
);
198 interstitial_page_
->set_delegate(this);
200 ~TestInterstitialPageStateGuard() override
{
201 if (interstitial_page_
)
202 interstitial_page_
->ClearStates();
205 void TestInterstitialPageDeleted(
206 TestInterstitialPage
* interstitial
) override
{
207 DCHECK(interstitial_page_
== interstitial
);
208 interstitial_page_
= nullptr;
212 TestInterstitialPage
* interstitial_page_
;
215 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
217 WebContentsImplTestBrowserClient()
218 : assign_site_for_url_(false) {}
220 ~WebContentsImplTestBrowserClient() override
{}
222 bool ShouldAssignSiteForURL(const GURL
& url
) override
{
223 return assign_site_for_url_
;
226 void set_assign_site_for_url(bool assign
) {
227 assign_site_for_url_
= assign
;
231 bool assign_site_for_url_
;
234 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
236 void SetUp() override
{
237 RenderViewHostImplTestHarness::SetUp();
238 WebUIControllerFactory::RegisterFactory(
239 ContentWebUIControllerFactory::GetInstance());
242 void TearDown() override
{
243 WebUIControllerFactory::UnregisterFactoryForTesting(
244 ContentWebUIControllerFactory::GetInstance());
245 RenderViewHostImplTestHarness::TearDown();
249 class TestWebContentsObserver
: public WebContentsObserver
{
251 explicit TestWebContentsObserver(WebContents
* contents
)
252 : WebContentsObserver(contents
),
253 last_theme_color_(SK_ColorTRANSPARENT
) {
255 ~TestWebContentsObserver() override
{}
257 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
258 const GURL
& validated_url
) override
{
259 last_url_
= validated_url
;
261 void DidFailLoad(RenderFrameHost
* render_frame_host
,
262 const GURL
& validated_url
,
264 const base::string16
& error_description
,
265 bool was_ignored_by_handler
) override
{
266 last_url_
= validated_url
;
269 void DidChangeThemeColor(SkColor theme_color
) override
{
270 last_theme_color_
= theme_color
;
273 const GURL
& last_url() const { return last_url_
; }
274 SkColor
last_theme_color() const { return last_theme_color_
; }
278 SkColor last_theme_color_
;
280 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
283 // Pretends to be a normal browser that receives toggles and transitions to/from
284 // a fullscreened state.
285 class FakeFullscreenDelegate
: public WebContentsDelegate
{
287 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
288 ~FakeFullscreenDelegate() override
{}
290 void EnterFullscreenModeForTab(WebContents
* web_contents
,
291 const GURL
& origin
) override
{
292 fullscreened_contents_
= web_contents
;
295 void ExitFullscreenModeForTab(WebContents
* web_contents
) override
{
296 fullscreened_contents_
= nullptr;
299 bool IsFullscreenForTabOrPending(
300 const WebContents
* web_contents
) const override
{
301 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
305 WebContents
* fullscreened_contents_
;
307 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
310 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
312 FakeValidationMessageDelegate()
313 : hide_validation_message_was_called_(false) {}
314 ~FakeValidationMessageDelegate() override
{}
316 void HideValidationMessage(WebContents
* web_contents
) override
{
317 hide_validation_message_was_called_
= true;
320 bool hide_validation_message_was_called() const {
321 return hide_validation_message_was_called_
;
325 bool hide_validation_message_was_called_
;
327 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
332 // Test to make sure that title updates get stripped of whitespace.
333 TEST_F(WebContentsImplTest
, UpdateTitle
) {
334 NavigationControllerImpl
& cont
=
335 static_cast<NavigationControllerImpl
&>(controller());
336 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
337 InitNavigateParams(¶ms
, 0, 0, true, GURL(url::kAboutBlankURL
),
338 ui::PAGE_TRANSITION_TYPED
);
340 LoadCommittedDetails details
;
341 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
343 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
344 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
345 base::i18n::LEFT_TO_RIGHT
);
346 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
349 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
350 const GURL
kGURL("chrome://blah");
351 controller().LoadURL(
352 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
353 EXPECT_EQ(base::string16(), contents()->GetTitle());
356 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
357 const GURL
kGURL("chrome://blah");
358 const base::string16 title
= base::ASCIIToUTF16("My Title");
359 controller().LoadURL(
360 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
362 NavigationEntry
* entry
= controller().GetVisibleEntry();
363 ASSERT_EQ(kGURL
, entry
->GetURL());
364 entry
->SetTitle(title
);
366 EXPECT_EQ(title
, contents()->GetTitle());
369 // Test view source mode for a webui page.
370 TEST_F(WebContentsImplTest
, NTPViewSource
) {
371 NavigationControllerImpl
& cont
=
372 static_cast<NavigationControllerImpl
&>(controller());
373 const char kUrl
[] = "view-source:chrome://blah";
374 const GURL
kGURL(kUrl
);
376 process()->sink().ClearMessages();
379 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
380 int entry_id
= cont
.GetPendingEntry()->GetUniqueID();
381 rvh()->GetDelegate()->RenderViewCreated(rvh());
382 // Did we get the expected message?
383 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
384 ViewMsg_EnableViewSourceMode::ID
));
386 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
387 InitNavigateParams(¶ms
, 0, entry_id
, true, kGURL
,
388 ui::PAGE_TRANSITION_TYPED
);
389 LoadCommittedDetails details
;
390 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
391 // Also check title and url.
392 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
395 // Test to ensure UpdateMaxPageID is working properly.
396 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
397 SiteInstance
* instance1
= contents()->GetSiteInstance();
398 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(nullptr));
401 EXPECT_EQ(-1, contents()->GetMaxPageID());
402 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
403 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
405 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
406 contents()->UpdateMaxPageID(3);
407 contents()->UpdateMaxPageID(1);
408 EXPECT_EQ(3, contents()->GetMaxPageID());
409 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
410 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
412 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
413 EXPECT_EQ(3, contents()->GetMaxPageID());
414 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
415 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
418 // Test simple same-SiteInstance navigation.
419 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
420 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
421 SiteInstance
* instance1
= contents()->GetSiteInstance();
422 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
425 const GURL
url("http://www.google.com");
426 controller().LoadURL(
427 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
428 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
429 main_test_rfh()->PrepareForCommit();
430 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
431 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
432 // Controller's pending entry will have a null site instance until we assign
433 // it in DidNavigate.
436 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
439 // DidNavigate from the page
440 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
441 ui::PAGE_TRANSITION_TYPED
);
442 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
443 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
444 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
445 // Controller's entry should now have the SiteInstance, or else we won't be
446 // able to find it later.
449 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
453 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
454 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
455 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
456 const GURL
url(std::string("http://example.org/").append(
457 GetMaxURLChars() + 1, 'a'));
459 controller().LoadURL(
460 url
, Referrer(), ui::PAGE_TRANSITION_GENERATED
, std::string());
461 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
464 // Test that navigating across a site boundary creates a new RenderViewHost
465 // with a new SiteInstance. Going back should do the same.
466 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
467 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
468 int orig_rvh_delete_count
= 0;
469 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
470 SiteInstance
* instance1
= contents()->GetSiteInstance();
472 // Navigate to URL. First URL should use first RenderViewHost.
473 const GURL
url("http://www.google.com");
474 controller().LoadURL(
475 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
476 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
477 orig_rfh
->PrepareForCommit();
478 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
479 ui::PAGE_TRANSITION_TYPED
);
481 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
482 // that orig_rfh doesn't get deleted when it gets swapped out.
483 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
485 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
486 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
487 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
488 EXPECT_EQ(url
, contents()->GetVisibleURL());
490 // Navigate to new site
491 const GURL
url2("http://www.yahoo.com");
492 controller().LoadURL(
493 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
494 entry_id
= controller().GetPendingEntry()->GetUniqueID();
495 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
496 switches::kEnableBrowserSideNavigation
)) {
497 orig_rfh
->PrepareForCommit();
499 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
500 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
501 EXPECT_EQ(url2
, contents()->GetVisibleURL());
502 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
503 int pending_rvh_delete_count
= 0;
504 pending_rfh
->GetRenderViewHost()->set_delete_counter(
505 &pending_rvh_delete_count
);
507 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
508 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
509 switches::kEnableBrowserSideNavigation
)) {
510 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
511 orig_rfh
->SendBeforeUnloadACK(true);
512 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
515 // DidNavigate from the pending page
516 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
517 ui::PAGE_TRANSITION_TYPED
);
518 SiteInstance
* instance2
= contents()->GetSiteInstance();
520 // Keep the number of active frames in pending_rfh's SiteInstance
521 // non-zero so that orig_rfh doesn't get deleted when it gets
523 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
525 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
526 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
527 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
528 EXPECT_EQ(url2
, contents()->GetVisibleURL());
529 EXPECT_NE(instance1
, instance2
);
530 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
531 // We keep a proxy for the original RFH's SiteInstance.
532 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
533 orig_rfh
->GetSiteInstance()));
534 EXPECT_EQ(orig_rvh_delete_count
, 0);
536 // Going back should switch SiteInstances again. The first SiteInstance is
537 // stored in the NavigationEntry, so it should be the same as at the start.
538 // We should use the same RFH as before, swapping it back in.
539 controller().GoBack();
540 entry_id
= controller().GetPendingEntry()->GetUniqueID();
541 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
542 switches::kEnableBrowserSideNavigation
)) {
543 contents()->GetMainFrame()->PrepareForCommit();
545 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
546 if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
547 // Recycling the rfh is a behavior specific to swappedout://
548 EXPECT_EQ(orig_rfh
, goback_rfh
);
550 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
552 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
553 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
554 switches::kEnableBrowserSideNavigation
)) {
555 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
556 pending_rfh
->SendBeforeUnloadACK(true);
557 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
560 // DidNavigate from the back action
561 contents()->TestDidNavigate(goback_rfh
, 1, entry_id
, false, url2
,
562 ui::PAGE_TRANSITION_TYPED
);
563 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
564 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
565 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
566 // There should be a proxy for the pending RFH SiteInstance.
567 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
568 GetRenderFrameProxyHost(pending_rfh
->GetSiteInstance()));
569 EXPECT_EQ(pending_rvh_delete_count
, 0);
570 pending_rfh
->OnSwappedOut();
572 // Close contents and ensure RVHs are deleted.
574 EXPECT_EQ(orig_rvh_delete_count
, 1);
575 EXPECT_EQ(pending_rvh_delete_count
, 1);
578 // Test that navigating across a site boundary after a crash creates a new
579 // RFH without requiring a cross-site transition (i.e., PENDING state).
580 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
581 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
583 int orig_rvh_delete_count
= 0;
584 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
585 SiteInstance
* instance1
= contents()->GetSiteInstance();
587 // Navigate to URL. First URL should use first RenderViewHost.
588 const GURL
url("http://www.google.com");
589 controller().LoadURL(
590 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
591 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
592 contents()->GetMainFrame()->PrepareForCommit();
593 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
594 ui::PAGE_TRANSITION_TYPED
);
596 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
597 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
599 // Simulate a renderer crash.
600 EXPECT_TRUE(orig_rfh
->IsRenderFrameLive());
601 orig_rfh
->GetProcess()->SimulateCrash();
602 EXPECT_FALSE(orig_rfh
->IsRenderFrameLive());
604 // Navigate to new site. We should not go into PENDING.
605 const GURL
url2("http://www.yahoo.com");
606 controller().LoadURL(
607 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
608 entry_id
= controller().GetPendingEntry()->GetUniqueID();
609 contents()->GetMainFrame()->PrepareForCommit();
610 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
611 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
612 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
613 EXPECT_NE(orig_rfh
, new_rfh
);
614 EXPECT_EQ(orig_rvh_delete_count
, 1);
616 // DidNavigate from the new page
617 contents()->TestDidNavigate(new_rfh
, 1, entry_id
, true, url2
,
618 ui::PAGE_TRANSITION_TYPED
);
619 SiteInstance
* instance2
= contents()->GetSiteInstance();
621 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
622 EXPECT_EQ(new_rfh
, main_rfh());
623 EXPECT_NE(instance1
, instance2
);
624 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
626 // Close contents and ensure RVHs are deleted.
628 EXPECT_EQ(orig_rvh_delete_count
, 1);
631 // Test that opening a new contents in the same SiteInstance and then navigating
632 // both contentses to a new site will place both contentses in a single
634 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
635 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
636 SiteInstance
* instance1
= contents()->GetSiteInstance();
638 // Navigate to URL. First URL should use first RenderViewHost.
639 const GURL
url("http://www.google.com");
640 controller().LoadURL(
641 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
642 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
643 contents()->GetMainFrame()->PrepareForCommit();
644 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
645 ui::PAGE_TRANSITION_TYPED
);
647 // Open a new contents with the same SiteInstance, navigated to the same site.
648 scoped_ptr
<TestWebContents
> contents2(
649 TestWebContents::Create(browser_context(), instance1
));
650 contents2
->GetController().LoadURL(url
, Referrer(),
651 ui::PAGE_TRANSITION_TYPED
,
653 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
654 contents2
->GetMainFrame()->PrepareForCommit();
655 // Need this page id to be 2 since the site instance is the same (which is the
656 // scope of page IDs) and we want to consider this a new page.
657 contents2
->TestDidNavigate(contents2
->GetMainFrame(), 2, entry_id
, true, url
,
658 ui::PAGE_TRANSITION_TYPED
);
660 // Navigate first contents to a new site.
661 const GURL
url2a("http://www.yahoo.com");
662 controller().LoadURL(
663 url2a
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
664 entry_id
= controller().GetPendingEntry()->GetUniqueID();
665 orig_rfh
->PrepareForCommit();
666 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
667 contents()->TestDidNavigate(pending_rfh_a
, 1, entry_id
, true, url2a
,
668 ui::PAGE_TRANSITION_TYPED
);
669 SiteInstance
* instance2a
= contents()->GetSiteInstance();
670 EXPECT_NE(instance1
, instance2a
);
672 // Navigate second contents to the same site as the first tab.
673 const GURL
url2b("http://mail.yahoo.com");
674 contents2
->GetController().LoadURL(url2b
, Referrer(),
675 ui::PAGE_TRANSITION_TYPED
,
677 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
678 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
679 rfh2
->PrepareForCommit();
680 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
681 EXPECT_NE(nullptr, pending_rfh_b
);
682 EXPECT_TRUE(contents2
->CrossProcessNavigationPending());
684 // NOTE(creis): We used to be in danger of showing a crash page here if the
685 // second contents hadn't navigated somewhere first (bug 1145430). That case
686 // is now covered by the CrossSiteBoundariesAfterCrash test.
687 contents2
->TestDidNavigate(pending_rfh_b
, 2, entry_id
, true, url2b
,
688 ui::PAGE_TRANSITION_TYPED
);
689 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
690 EXPECT_NE(instance1
, instance2b
);
692 // Both contentses should now be in the same SiteInstance.
693 EXPECT_EQ(instance2a
, instance2b
);
696 // The embedder can request sites for certain urls not be be assigned to the
697 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
698 // allowing to reuse the renderer backing certain chrome urls for subsequent
699 // navigation. The test verifies that the override is honored.
700 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
701 WebContentsImplTestBrowserClient browser_client
;
702 SetBrowserClientForTesting(&browser_client
);
704 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
705 int orig_rvh_delete_count
= 0;
706 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
707 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
709 browser_client
.set_assign_site_for_url(false);
710 // Navigate to an URL that will not assign a new SiteInstance.
711 const GURL
native_url("non-site-url://stuffandthings");
712 controller().LoadURL(
713 native_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
714 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
715 contents()->GetMainFrame()->PrepareForCommit();
716 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, native_url
,
717 ui::PAGE_TRANSITION_TYPED
);
719 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
720 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
721 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
722 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
723 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
724 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
725 EXPECT_FALSE(orig_instance
->HasSite());
727 browser_client
.set_assign_site_for_url(true);
728 // Navigate to new site (should keep same site instance).
729 const GURL
url("http://www.google.com");
730 controller().LoadURL(
731 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
732 entry_id
= controller().GetPendingEntry()->GetUniqueID();
733 contents()->GetMainFrame()->PrepareForCommit();
734 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
735 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
736 EXPECT_EQ(url
, contents()->GetVisibleURL());
737 EXPECT_FALSE(contents()->GetPendingMainFrame());
738 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url
,
739 ui::PAGE_TRANSITION_TYPED
);
741 // Keep the number of active frames in orig_rfh's SiteInstance
742 // non-zero so that orig_rfh doesn't get deleted when it gets
744 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
746 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
748 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
749 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
751 // Navigate to another new site (should create a new site instance).
752 const GURL
url2("http://www.yahoo.com");
753 controller().LoadURL(
754 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
755 entry_id
= controller().GetPendingEntry()->GetUniqueID();
756 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
757 switches::kEnableBrowserSideNavigation
)) {
758 orig_rfh
->PrepareForCommit();
760 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
761 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
762 EXPECT_EQ(url2
, contents()->GetVisibleURL());
763 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
764 int pending_rvh_delete_count
= 0;
765 pending_rfh
->GetRenderViewHost()->set_delete_counter(
766 &pending_rvh_delete_count
);
768 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
769 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
770 switches::kEnableBrowserSideNavigation
)) {
771 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
772 orig_rfh
->SendBeforeUnloadACK(true);
773 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
776 // DidNavigate from the pending page.
777 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
778 ui::PAGE_TRANSITION_TYPED
);
779 SiteInstance
* new_instance
= contents()->GetSiteInstance();
781 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
782 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
783 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
784 EXPECT_EQ(url2
, contents()->GetVisibleURL());
785 EXPECT_NE(new_instance
, orig_instance
);
786 EXPECT_FALSE(contents()->GetPendingMainFrame());
787 // We keep a proxy for the original RFH's SiteInstance.
788 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
789 orig_rfh
->GetSiteInstance()));
790 EXPECT_EQ(orig_rvh_delete_count
, 0);
791 orig_rfh
->OnSwappedOut();
793 // Close contents and ensure RVHs are deleted.
795 EXPECT_EQ(orig_rvh_delete_count
, 1);
796 EXPECT_EQ(pending_rvh_delete_count
, 1);
799 // Regression test for http://crbug.com/386542 - variation of
800 // NavigateFromSitelessUrl in which the original navigation is a session
802 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
803 WebContentsImplTestBrowserClient browser_client
;
804 SetBrowserClientForTesting(&browser_client
);
805 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
806 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
808 // Restore a navigation entry for URL that should not assign site to the
810 browser_client
.set_assign_site_for_url(false);
811 const GURL
native_url("non-site-url://stuffandthings");
812 ScopedVector
<NavigationEntry
> entries
;
813 scoped_ptr
<NavigationEntry
> new_entry
=
814 NavigationControllerImpl::CreateNavigationEntry(
815 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
816 std::string(), browser_context());
817 new_entry
->SetPageID(0);
818 entries
.push_back(new_entry
.Pass());
819 controller().Restore(
821 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
823 ASSERT_EQ(0u, entries
.size());
824 ASSERT_EQ(1, controller().GetEntryCount());
826 controller().GoToIndex(0);
827 NavigationEntry
* entry
= controller().GetPendingEntry();
828 orig_rfh
->PrepareForCommit();
829 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
830 native_url
, ui::PAGE_TRANSITION_RELOAD
);
831 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
832 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
833 EXPECT_FALSE(orig_instance
->HasSite());
835 // Navigate to a regular site and verify that the SiteInstance was kept.
836 browser_client
.set_assign_site_for_url(true);
837 const GURL
url("http://www.google.com");
838 controller().LoadURL(
839 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
840 entry
= controller().GetPendingEntry();
841 orig_rfh
->PrepareForCommit();
842 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, url
,
843 ui::PAGE_TRANSITION_TYPED
);
844 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
850 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
851 // tab is restored, the SiteInstance will change upon navigation.
852 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
853 WebContentsImplTestBrowserClient browser_client
;
854 SetBrowserClientForTesting(&browser_client
);
855 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
856 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
858 // Restore a navigation entry for a regular URL ensuring that the embedder
859 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
860 browser_client
.set_assign_site_for_url(true);
861 const GURL
regular_url("http://www.yahoo.com");
862 ScopedVector
<NavigationEntry
> entries
;
863 scoped_ptr
<NavigationEntry
> new_entry
=
864 NavigationControllerImpl::CreateNavigationEntry(
865 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
866 std::string(), browser_context());
867 new_entry
->SetPageID(0);
868 entries
.push_back(new_entry
.Pass());
869 controller().Restore(
871 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
873 ASSERT_EQ(0u, entries
.size());
875 ASSERT_EQ(1, controller().GetEntryCount());
876 controller().GoToIndex(0);
877 NavigationEntry
* entry
= controller().GetPendingEntry();
878 orig_rfh
->PrepareForCommit();
879 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
880 regular_url
, ui::PAGE_TRANSITION_RELOAD
);
881 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
882 EXPECT_TRUE(orig_instance
->HasSite());
884 // Navigate to another site and verify that a new SiteInstance was created.
885 const GURL
url("http://www.google.com");
886 controller().LoadURL(
887 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
888 entry
= controller().GetPendingEntry();
889 orig_rfh
->PrepareForCommit();
890 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
891 entry
->GetUniqueID(), true, url
,
892 ui::PAGE_TRANSITION_TYPED
);
893 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
899 // Test that we can find an opener RVH even if it's pending.
900 // http://crbug.com/176252.
901 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
902 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
904 // Navigate to a URL.
905 const GURL
url("http://www.google.com");
906 controller().LoadURL(
907 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
908 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
909 orig_rfh
->PrepareForCommit();
910 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
911 ui::PAGE_TRANSITION_TYPED
);
913 // Start to navigate first tab to a new site, so that it has a pending RVH.
914 const GURL
url2("http://www.yahoo.com");
915 controller().LoadURL(
916 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
917 orig_rfh
->PrepareForCommit();
918 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
919 SiteInstance
* instance
= pending_rfh
->GetSiteInstance();
921 // While it is still pending, simulate opening a new tab with the first tab
922 // as its opener. This will call CreateOpenerProxies on the opener to ensure
923 // that an RVH exists.
924 scoped_ptr
<TestWebContents
> popup(
925 TestWebContents::Create(browser_context(), instance
));
926 popup
->SetOpener(contents());
927 contents()->GetRenderManager()->CreateOpenerProxies(instance
, nullptr);
929 // If swapped out is forbidden, a new proxy should be created for the opener
930 // in |instance|, and we should ensure that its routing ID is returned here.
931 // Otherwise, we should find the pending RFH and not create a new proxy.
932 int opener_frame_routing_id
=
933 popup
->GetRenderManager()->GetOpenerRoutingID(instance
);
934 RenderFrameProxyHost
* proxy
=
935 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance
);
936 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
938 EXPECT_EQ(proxy
->GetRoutingID(), opener_frame_routing_id
);
940 // Ensure that committing the navigation removes the proxy.
941 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
942 contents()->TestDidNavigate(pending_rfh
, 2, entry_id
, true, url2
,
943 ui::PAGE_TRANSITION_TYPED
);
945 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance
));
948 EXPECT_EQ(pending_rfh
->GetRoutingID(), opener_frame_routing_id
);
952 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
953 // to determine whether a navigation is cross-site.
954 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
955 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
956 SiteInstance
* instance1
= contents()->GetSiteInstance();
959 const GURL
url("http://www.google.com");
960 controller().LoadURL(
961 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
962 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
963 contents()->GetMainFrame()->PrepareForCommit();
964 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
965 ui::PAGE_TRANSITION_TYPED
);
967 // Open a related contents to a second site.
968 scoped_ptr
<TestWebContents
> contents2(
969 TestWebContents::Create(browser_context(), instance1
));
970 const GURL
url2("http://www.yahoo.com");
971 contents2
->GetController().LoadURL(url2
, Referrer(),
972 ui::PAGE_TRANSITION_TYPED
,
974 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
975 contents2
->GetMainFrame()->PrepareForCommit();
977 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
979 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
980 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
981 contents2
->TestDidNavigate(rfh2
, 2, entry_id
, true, url2
,
982 ui::PAGE_TRANSITION_TYPED
);
983 SiteInstance
* instance2
= contents2
->GetSiteInstance();
984 EXPECT_NE(instance1
, instance2
);
985 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
987 // Simulate a link click in first contents to second site. Doesn't switch
988 // SiteInstances, because we don't intercept Blink navigations.
989 orig_rfh
->SendRendererInitiatedNavigationRequest(url2
, true);
990 orig_rfh
->PrepareForCommit();
991 contents()->TestDidNavigate(orig_rfh
, 2, 0, true, url2
,
992 ui::PAGE_TRANSITION_TYPED
);
993 SiteInstance
* instance3
= contents()->GetSiteInstance();
994 EXPECT_EQ(instance1
, instance3
);
995 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
997 // Navigate to the new site. Doesn't switch SiteInstancees, because we
998 // compare against the current URL, not the SiteInstance's site.
999 const GURL
url3("http://mail.yahoo.com");
1000 controller().LoadURL(
1001 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1002 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1003 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1004 contents()->GetMainFrame()->PrepareForCommit();
1005 contents()->TestDidNavigate(orig_rfh
, 3, entry_id
, true, url3
,
1006 ui::PAGE_TRANSITION_TYPED
);
1007 SiteInstance
* instance4
= contents()->GetSiteInstance();
1008 EXPECT_EQ(instance1
, instance4
);
1011 // Test that the onbeforeunload and onunload handlers run when navigating
1012 // across site boundaries.
1013 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
1014 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1015 SiteInstance
* instance1
= contents()->GetSiteInstance();
1017 // Navigate to URL. First URL should use first RenderViewHost.
1018 const GURL
url("http://www.google.com");
1019 controller().LoadURL(
1020 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1021 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1022 contents()->GetMainFrame()->PrepareForCommit();
1023 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1024 ui::PAGE_TRANSITION_TYPED
);
1025 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1026 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1028 // Navigate to new site, but simulate an onbeforeunload denial.
1029 const GURL
url2("http://www.yahoo.com");
1030 controller().LoadURL(
1031 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1032 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1033 base::TimeTicks now
= base::TimeTicks::Now();
1034 orig_rfh
->OnMessageReceived(
1035 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1036 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1037 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1038 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1040 // Navigate again, but simulate an onbeforeunload approval.
1041 controller().LoadURL(
1042 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1043 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1044 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1045 now
= base::TimeTicks::Now();
1046 orig_rfh
->PrepareForCommit();
1047 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1048 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1049 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1051 // We won't hear DidNavigate until the onunload handler has finished running.
1053 // DidNavigate from the pending page.
1054 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1055 ui::PAGE_TRANSITION_TYPED
);
1056 SiteInstance
* instance2
= contents()->GetSiteInstance();
1057 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1058 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1059 EXPECT_NE(instance1
, instance2
);
1060 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1063 // Test that during a slow cross-site navigation, the original renderer can
1064 // navigate to a different URL and have it displayed, canceling the slow
1066 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1067 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1068 SiteInstance
* instance1
= contents()->GetSiteInstance();
1070 // Navigate to URL. First URL should use first RenderFrameHost.
1071 const GURL
url("http://www.google.com");
1072 controller().LoadURL(
1073 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1074 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1075 contents()->GetMainFrame()->PrepareForCommit();
1076 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1077 ui::PAGE_TRANSITION_TYPED
);
1078 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1079 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1081 // Navigate to new site, simulating an onbeforeunload approval.
1082 const GURL
url2("http://www.yahoo.com");
1083 controller().LoadURL(
1084 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1085 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1086 orig_rfh
->PrepareForCommit();
1087 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1089 // Suppose the original renderer navigates before the new one is ready.
1090 orig_rfh
->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1092 // Verify that the pending navigation is cancelled.
1093 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1094 SiteInstance
* instance2
= contents()->GetSiteInstance();
1095 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1096 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1097 EXPECT_EQ(instance1
, instance2
);
1098 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1101 // Tests that if we go back twice (same-site then cross-site), and the same-site
1102 // RFH commits first, the cross-site RFH's navigation is canceled.
1103 // TODO(avi,creis): Consider changing this behavior to better match the user's
1105 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1106 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1107 GURL
url1(std::string(kChromeUIScheme
) + "://" +
1108 std::string(kChromeUIGpuHost
));
1109 controller().LoadURL(
1110 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1111 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1112 TestRenderFrameHost
* webui_rfh
= contents()->GetMainFrame();
1113 webui_rfh
->PrepareForCommit();
1114 contents()->TestDidNavigate(webui_rfh
, 1, entry_id
, true, url1
,
1115 ui::PAGE_TRANSITION_TYPED
);
1116 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1117 SiteInstance
* instance1
= contents()->GetSiteInstance();
1119 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1120 EXPECT_EQ(webui_rfh
, contents()->GetMainFrame());
1121 EXPECT_EQ(url1
, entry1
->GetURL());
1122 EXPECT_EQ(instance1
,
1123 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1124 EXPECT_TRUE(webui_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1125 BINDINGS_POLICY_WEB_UI
);
1127 // Navigate to new site.
1128 const GURL
url2("http://www.google.com");
1129 controller().LoadURL(
1130 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1131 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1132 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1133 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1135 // Simulate beforeunload approval.
1136 EXPECT_TRUE(webui_rfh
->is_waiting_for_beforeunload_ack());
1137 webui_rfh
->PrepareForCommit();
1139 // DidNavigate from the pending page.
1140 contents()->TestDidNavigate(google_rfh
, 1, entry_id
, true, url2
,
1141 ui::PAGE_TRANSITION_TYPED
);
1142 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1143 SiteInstance
* instance2
= contents()->GetSiteInstance();
1145 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1146 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1147 EXPECT_NE(instance1
, instance2
);
1148 EXPECT_FALSE(contents()->GetPendingMainFrame());
1149 EXPECT_EQ(url2
, entry2
->GetURL());
1150 EXPECT_EQ(instance2
,
1151 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1152 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1153 BINDINGS_POLICY_WEB_UI
);
1155 // Navigate to third page on same site.
1156 const GURL
url3("http://news.google.com");
1157 controller().LoadURL(
1158 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1159 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1160 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1161 contents()->GetMainFrame()->PrepareForCommit();
1162 contents()->TestDidNavigate(google_rfh
, 2, entry_id
, true, url3
,
1163 ui::PAGE_TRANSITION_TYPED
);
1164 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1165 SiteInstance
* instance3
= contents()->GetSiteInstance();
1167 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1168 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1169 EXPECT_EQ(instance2
, instance3
);
1170 EXPECT_FALSE(contents()->GetPendingMainFrame());
1171 EXPECT_EQ(url3
, entry3
->GetURL());
1172 EXPECT_EQ(instance3
,
1173 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1175 // Go back within the site.
1176 controller().GoBack();
1177 NavigationEntry
* goback_entry
= controller().GetPendingEntry();
1178 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1179 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1181 // Before that commits, go back again.
1182 controller().GoBack();
1183 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1184 EXPECT_TRUE(contents()->GetPendingMainFrame());
1185 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1187 // Simulate beforeunload approval.
1188 EXPECT_TRUE(google_rfh
->is_waiting_for_beforeunload_ack());
1189 base::TimeTicks now
= base::TimeTicks::Now();
1190 google_rfh
->PrepareForCommit();
1191 google_rfh
->OnMessageReceived(
1192 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1194 // DidNavigate from the first back. This aborts the second back's pending RFH.
1195 contents()->TestDidNavigate(google_rfh
, 1, goback_entry
->GetUniqueID(), false,
1196 url2
, ui::PAGE_TRANSITION_TYPED
);
1198 // We should commit this page and forget about the second back.
1199 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1200 EXPECT_FALSE(controller().GetPendingEntry());
1201 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1202 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1204 // We should not have corrupted the NTP entry.
1205 EXPECT_EQ(instance3
,
1206 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1207 EXPECT_EQ(instance2
,
1208 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1209 EXPECT_EQ(instance1
,
1210 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1211 EXPECT_EQ(url1
, entry1
->GetURL());
1214 // Tests that if we go back twice (same-site then cross-site), and the cross-
1215 // site RFH commits first, we ignore the now-swapped-out RFH's commit.
1216 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackOldNavigationIgnored
) {
1217 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1218 GURL
url1(std::string(kChromeUIScheme
) + "://" +
1219 std::string(kChromeUIGpuHost
));
1220 controller().LoadURL(url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
,
1222 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1223 TestRenderFrameHost
* webui_rfh
= contents()->GetMainFrame();
1224 webui_rfh
->PrepareForCommit();
1225 contents()->TestDidNavigate(webui_rfh
, 1, entry_id
, true, url1
,
1226 ui::PAGE_TRANSITION_TYPED
);
1227 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1228 SiteInstance
* instance1
= contents()->GetSiteInstance();
1230 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1231 EXPECT_EQ(webui_rfh
, contents()->GetMainFrame());
1232 EXPECT_EQ(url1
, entry1
->GetURL());
1233 EXPECT_EQ(instance1
,
1234 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1235 EXPECT_TRUE(webui_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1236 BINDINGS_POLICY_WEB_UI
);
1238 // Navigate to new site.
1239 const GURL
url2("http://www.google.com");
1240 controller().LoadURL(url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
,
1242 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1243 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1244 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1246 // Simulate beforeunload approval.
1247 EXPECT_TRUE(webui_rfh
->is_waiting_for_beforeunload_ack());
1248 webui_rfh
->PrepareForCommit();
1250 // DidNavigate from the pending page.
1251 contents()->TestDidNavigate(google_rfh
, 1, entry_id
, true, url2
,
1252 ui::PAGE_TRANSITION_TYPED
);
1253 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1254 SiteInstance
* instance2
= contents()->GetSiteInstance();
1256 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1257 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1258 EXPECT_NE(instance1
, instance2
);
1259 EXPECT_FALSE(contents()->GetPendingMainFrame());
1260 EXPECT_EQ(url2
, entry2
->GetURL());
1261 EXPECT_EQ(instance2
,
1262 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1263 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1264 BINDINGS_POLICY_WEB_UI
);
1266 // Navigate to third page on same site.
1267 const GURL
url3("http://news.google.com");
1268 controller().LoadURL(url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
,
1270 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1271 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1272 contents()->GetMainFrame()->PrepareForCommit();
1273 contents()->TestDidNavigate(google_rfh
, 2, entry_id
, true, url3
,
1274 ui::PAGE_TRANSITION_TYPED
);
1275 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1276 SiteInstance
* instance3
= contents()->GetSiteInstance();
1278 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1279 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1280 EXPECT_EQ(instance2
, instance3
);
1281 EXPECT_FALSE(contents()->GetPendingMainFrame());
1282 EXPECT_EQ(url3
, entry3
->GetURL());
1283 EXPECT_EQ(instance3
,
1284 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1286 // Go back within the site.
1287 controller().GoBack();
1288 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1289 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1291 // Before that commits, go back again.
1292 controller().GoBack();
1293 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1294 EXPECT_TRUE(contents()->GetPendingMainFrame());
1295 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1296 webui_rfh
= contents()->GetPendingMainFrame();
1298 // DidNavigate from the second back.
1299 contents()->TestDidNavigate(webui_rfh
, 1, entry1
->GetUniqueID(), false, url1
,
1300 ui::PAGE_TRANSITION_TYPED
);
1302 // That should have landed us on the first entry.
1303 EXPECT_EQ(entry1
, controller().GetLastCommittedEntry());
1305 // When the second back commits, it should be ignored.
1306 contents()->TestDidNavigate(google_rfh
, 1, entry2
->GetUniqueID(), false, url2
,
1307 ui::PAGE_TRANSITION_TYPED
);
1308 EXPECT_EQ(entry1
, controller().GetLastCommittedEntry());
1311 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1312 // original renderer will not cancel the slow navigation (bug 42029).
1313 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1314 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1316 // Navigate to URL. First URL should use the original RenderFrameHost.
1317 const GURL
url("http://www.google.com");
1318 controller().LoadURL(
1319 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1320 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1321 contents()->GetMainFrame()->PrepareForCommit();
1322 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1323 ui::PAGE_TRANSITION_TYPED
);
1324 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1325 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1327 // Start navigating to new site.
1328 const GURL
url2("http://www.yahoo.com");
1329 controller().LoadURL(
1330 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1332 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1333 // waiting for a before unload response.
1334 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1335 child_rfh
->SendNavigateWithTransition(1, 0, false,
1336 GURL("http://google.com/frame"),
1337 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1338 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1340 // Now simulate the onbeforeunload approval and verify the navigation is
1342 orig_rfh
->PrepareForCommit();
1343 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1344 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1348 void SetAsNonUserGesture(FrameHostMsg_DidCommitProvisionalLoad_Params
* params
) {
1349 params
->gesture
= NavigationGestureAuto
;
1353 // Test that a cross-site navigation is not preempted if the previous
1354 // renderer sends a FrameNavigate message just before being told to stop.
1355 // We should only preempt the cross-site navigation if the previous renderer
1356 // has started a new navigation. See http://crbug.com/79176.
1357 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1358 // Navigate to WebUI URL.
1359 const GURL
url("chrome://gpu");
1360 controller().LoadURL(
1361 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1362 int entry1_id
= controller().GetPendingEntry()->GetUniqueID();
1363 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1364 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1366 // Navigate to new site, with the beforeunload request in flight.
1367 const GURL
url2("http://www.yahoo.com");
1368 controller().LoadURL(
1369 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1370 int entry2_id
= controller().GetPendingEntry()->GetUniqueID();
1371 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1372 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1373 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1374 EXPECT_NE(orig_rfh
, pending_rfh
);
1376 // Suppose the first navigation tries to commit now, with a
1377 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1378 // but it should act as if the beforeunload ack arrived.
1379 orig_rfh
->SendNavigateWithModificationCallback(
1380 1, entry1_id
, true, url
, base::Bind(SetAsNonUserGesture
));
1381 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1382 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1383 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1384 // It should commit.
1385 ASSERT_EQ(1, controller().GetEntryCount());
1386 EXPECT_EQ(url
, controller().GetLastCommittedEntry()->GetURL());
1388 // The pending navigation should be able to commit successfully.
1389 contents()->TestDidNavigate(pending_rfh
, 1, entry2_id
, true, url2
,
1390 ui::PAGE_TRANSITION_TYPED
);
1391 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1392 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1393 EXPECT_EQ(2, controller().GetEntryCount());
1396 // Test that NavigationEntries have the correct page state after going
1397 // forward and back. Prevents regression for bug 1116137.
1398 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1399 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1401 // Navigate to URL. There should be no committed entry yet.
1402 const GURL
url("http://www.google.com");
1403 controller().LoadURL(
1404 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1405 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1406 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1407 EXPECT_EQ(nullptr, entry
);
1409 // Committed entry should have page state after DidNavigate.
1410 orig_rfh
->PrepareForCommit();
1411 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1412 ui::PAGE_TRANSITION_TYPED
);
1413 entry
= controller().GetLastCommittedEntry();
1414 EXPECT_TRUE(entry
->GetPageState().IsValid());
1416 // Navigate to same site.
1417 const GURL
url2("http://images.google.com");
1418 controller().LoadURL(
1419 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1420 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1421 entry
= controller().GetLastCommittedEntry();
1422 EXPECT_TRUE(entry
->GetPageState().IsValid());
1424 // Committed entry should have page state after DidNavigate.
1425 orig_rfh
->PrepareForCommit();
1426 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1427 ui::PAGE_TRANSITION_TYPED
);
1428 entry
= controller().GetLastCommittedEntry();
1429 EXPECT_TRUE(entry
->GetPageState().IsValid());
1431 // Now go back. Committed entry should still have page state.
1432 controller().GoBack();
1433 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1434 orig_rfh
->PrepareForCommit();
1435 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, false, url
,
1436 ui::PAGE_TRANSITION_TYPED
);
1437 entry
= controller().GetLastCommittedEntry();
1438 EXPECT_TRUE(entry
->GetPageState().IsValid());
1441 // Test that NavigationEntries have the correct page state and SiteInstance
1442 // state after opening a new window to about:blank. Prevents regression for
1443 // bugs b/1116137 and http://crbug.com/111975.
1444 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1445 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1447 // Navigate to about:blank.
1448 const GURL
url(url::kAboutBlankURL
);
1449 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1450 contents()->TestDidNavigate(orig_rfh
, 1, 0, true, url
,
1451 ui::PAGE_TRANSITION_TYPED
);
1453 // Should have a page state here.
1454 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1455 EXPECT_TRUE(entry
->GetPageState().IsValid());
1457 // The SiteInstance should be available for other navigations to use.
1458 NavigationEntryImpl
* entry_impl
=
1459 NavigationEntryImpl::FromNavigationEntry(entry
);
1460 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1461 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1463 // Navigating to a normal page should not cause a process swap.
1464 const GURL
new_url("http://www.google.com");
1465 controller().LoadURL(new_url
, Referrer(),
1466 ui::PAGE_TRANSITION_TYPED
, std::string());
1467 entry
= controller().GetPendingEntry();
1468 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1469 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1470 orig_rfh
->PrepareForCommit();
1471 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, new_url
,
1472 ui::PAGE_TRANSITION_TYPED
);
1473 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1474 controller().GetLastCommittedEntry());
1475 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1476 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1479 // Tests that fullscreen is exited throughout the object hierarchy when
1480 // navigating to a new page.
1481 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1482 FakeFullscreenDelegate fake_delegate
;
1483 contents()->SetDelegate(&fake_delegate
);
1484 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1485 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1487 // Navigate to a site.
1488 const GURL
url("http://www.google.com");
1489 controller().LoadURL(
1490 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1491 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1492 contents()->GetMainFrame()->PrepareForCommit();
1493 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1494 ui::PAGE_TRANSITION_TYPED
);
1495 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1497 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1498 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1499 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1500 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1501 orig_rfh
->OnMessageReceived(
1502 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1503 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1504 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1505 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1507 // Navigate to a new site.
1508 const GURL
url2("http://www.yahoo.com");
1509 controller().LoadURL(
1510 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1511 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1512 contents()->GetMainFrame()->PrepareForCommit();
1513 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1514 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1515 ui::PAGE_TRANSITION_TYPED
);
1517 // Confirm fullscreen has exited.
1518 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1519 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1520 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1522 contents()->SetDelegate(nullptr);
1525 // Tests that fullscreen is exited throughout the object hierarchy when
1526 // instructing NavigationController to GoBack() or GoForward().
1527 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1528 FakeFullscreenDelegate fake_delegate
;
1529 contents()->SetDelegate(&fake_delegate
);
1530 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1531 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1533 // Navigate to a site.
1534 const GURL
url("http://www.google.com");
1535 controller().LoadURL(
1536 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1537 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1538 orig_rfh
->PrepareForCommit();
1539 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1540 ui::PAGE_TRANSITION_TYPED
);
1541 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1543 // Now, navigate to another page on the same site.
1544 const GURL
url2("http://www.google.com/search?q=kittens");
1545 controller().LoadURL(
1546 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1547 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1548 orig_rfh
->PrepareForCommit();
1549 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1550 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1551 ui::PAGE_TRANSITION_TYPED
);
1552 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1554 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1555 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1556 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1557 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1559 for (int i
= 0; i
< 2; ++i
) {
1560 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1561 orig_rfh
->OnMessageReceived(
1562 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1563 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1564 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1565 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1567 // Navigate backward (or forward).
1569 controller().GoBack();
1571 controller().GoForward();
1572 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1573 orig_rfh
->PrepareForCommit();
1574 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1575 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1576 contents()->TestDidNavigate(orig_rfh
, i
+ 1, entry_id
, false, url
,
1577 ui::PAGE_TRANSITION_FORWARD_BACK
);
1578 orig_rfh
->SimulateNavigationStop();
1580 // Confirm fullscreen has exited.
1581 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1582 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1583 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1586 contents()->SetDelegate(nullptr);
1589 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1590 FakeValidationMessageDelegate fake_delegate
;
1591 contents()->SetDelegate(&fake_delegate
);
1592 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1594 // Initialize the RenderFrame and then simulate crashing the renderer
1596 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1597 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1599 // Confirm HideValidationMessage was called.
1600 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1602 contents()->SetDelegate(nullptr);
1605 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1607 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1608 FakeFullscreenDelegate fake_delegate
;
1609 contents()->SetDelegate(&fake_delegate
);
1611 // Navigate to a site.
1612 const GURL
url("http://www.google.com");
1613 controller().LoadURL(
1614 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1615 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1616 main_test_rfh()->PrepareForCommit();
1617 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
1618 url
, ui::PAGE_TRANSITION_TYPED
);
1620 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1621 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1622 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1623 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1624 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1625 contents()->GetMainFrame()->GetRoutingID(), true));
1626 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1627 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1628 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1630 // Crash the renderer.
1631 main_test_rfh()->GetProcess()->SimulateCrash();
1633 // Confirm fullscreen has exited.
1634 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1635 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1636 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1638 contents()->SetDelegate(nullptr);
1641 ////////////////////////////////////////////////////////////////////////////////
1642 // Interstitial Tests
1643 ////////////////////////////////////////////////////////////////////////////////
1645 // Test navigating to a page (with the navigation initiated from the browser,
1646 // as when a URL is typed in the location bar) that shows an interstitial and
1647 // creates a new navigation entry, then hiding it without proceeding.
1648 TEST_F(WebContentsImplTest
,
1649 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1650 // Navigate to a page.
1651 GURL
url1("http://www.google.com");
1652 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1653 EXPECT_EQ(1, controller().GetEntryCount());
1655 // Initiate a browser navigation that will trigger the interstitial.
1656 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1657 ui::PAGE_TRANSITION_TYPED
, std::string());
1658 NavigationEntry
* entry
= controller().GetPendingEntry();
1660 // Show an interstitial.
1661 TestInterstitialPage::InterstitialState state
=
1662 TestInterstitialPage::INVALID
;
1663 bool deleted
= false;
1664 GURL
url2("http://interstitial");
1665 TestInterstitialPage
* interstitial
=
1666 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1667 TestInterstitialPageStateGuard
state_guard(interstitial
);
1668 interstitial
->Show();
1669 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1670 // The interstitial should not show until its navigation has committed.
1671 EXPECT_FALSE(interstitial
->is_showing());
1672 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1673 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1674 // Let's commit the interstitial navigation.
1675 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1676 EXPECT_TRUE(interstitial
->is_showing());
1677 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1678 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1679 entry
= controller().GetVisibleEntry();
1680 ASSERT_NE(nullptr, entry
);
1681 EXPECT_TRUE(entry
->GetURL() == url2
);
1683 // Now don't proceed.
1684 interstitial
->DontProceed();
1685 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1686 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1687 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1688 entry
= controller().GetVisibleEntry();
1689 ASSERT_NE(nullptr, entry
);
1690 EXPECT_TRUE(entry
->GetURL() == url1
);
1691 EXPECT_EQ(1, controller().GetEntryCount());
1693 RunAllPendingInMessageLoop();
1694 EXPECT_TRUE(deleted
);
1697 // Test navigating to a page (with the navigation initiated from the renderer,
1698 // as when clicking on a link in the page) that shows an interstitial and
1699 // creates a new navigation entry, then hiding it without proceeding.
1700 TEST_F(WebContentsImplTest
,
1701 ShowInterstitialFromRendererWithNewNavigationDontProceed
) {
1702 // Navigate to a page.
1703 GURL
url1("http://www.google.com");
1704 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1705 EXPECT_EQ(1, controller().GetEntryCount());
1707 // Show an interstitial (no pending entry, the interstitial would have been
1708 // triggered by clicking on a link).
1709 TestInterstitialPage::InterstitialState state
=
1710 TestInterstitialPage::INVALID
;
1711 bool deleted
= false;
1712 GURL
url2("http://interstitial");
1713 TestInterstitialPage
* interstitial
=
1714 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1715 TestInterstitialPageStateGuard
state_guard(interstitial
);
1716 interstitial
->Show();
1717 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1718 // The interstitial should not show until its navigation has committed.
1719 EXPECT_FALSE(interstitial
->is_showing());
1720 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1721 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1722 // Let's commit the interstitial navigation.
1723 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1724 EXPECT_TRUE(interstitial
->is_showing());
1725 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1726 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1727 NavigationEntry
* entry
= controller().GetVisibleEntry();
1728 ASSERT_NE(nullptr, entry
);
1729 EXPECT_TRUE(entry
->GetURL() == url2
);
1731 // Now don't proceed.
1732 interstitial
->DontProceed();
1733 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1734 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1735 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1736 entry
= controller().GetVisibleEntry();
1737 ASSERT_NE(nullptr, entry
);
1738 EXPECT_TRUE(entry
->GetURL() == url1
);
1739 EXPECT_EQ(1, controller().GetEntryCount());
1741 RunAllPendingInMessageLoop();
1742 EXPECT_TRUE(deleted
);
1745 // Test navigating to a page that shows an interstitial without creating a new
1746 // navigation entry (this happens when the interstitial is triggered by a
1747 // sub-resource in the page), then hiding it without proceeding.
1748 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1749 // Navigate to a page.
1750 GURL
url1("http://www.google.com");
1751 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1752 EXPECT_EQ(1, controller().GetEntryCount());
1754 // Show an interstitial.
1755 TestInterstitialPage::InterstitialState state
=
1756 TestInterstitialPage::INVALID
;
1757 bool deleted
= false;
1758 GURL
url2("http://interstitial");
1759 TestInterstitialPage
* interstitial
=
1760 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1761 TestInterstitialPageStateGuard
state_guard(interstitial
);
1762 interstitial
->Show();
1763 // The interstitial should not show until its navigation has committed.
1764 EXPECT_FALSE(interstitial
->is_showing());
1765 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1766 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1767 // Let's commit the interstitial navigation.
1768 interstitial
->TestDidNavigate(1, 0, true, url2
);
1769 EXPECT_TRUE(interstitial
->is_showing());
1770 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1771 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1772 NavigationEntry
* entry
= controller().GetVisibleEntry();
1773 ASSERT_NE(nullptr, entry
);
1774 // The URL specified to the interstitial should have been ignored.
1775 EXPECT_TRUE(entry
->GetURL() == url1
);
1777 // Now don't proceed.
1778 interstitial
->DontProceed();
1779 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1780 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1781 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1782 entry
= controller().GetVisibleEntry();
1783 ASSERT_NE(nullptr, entry
);
1784 EXPECT_TRUE(entry
->GetURL() == url1
);
1785 EXPECT_EQ(1, controller().GetEntryCount());
1787 RunAllPendingInMessageLoop();
1788 EXPECT_TRUE(deleted
);
1791 // Test navigating to a page (with the navigation initiated from the browser,
1792 // as when a URL is typed in the location bar) that shows an interstitial and
1793 // creates a new navigation entry, then proceeding.
1794 TEST_F(WebContentsImplTest
,
1795 ShowInterstitialFromBrowserNewNavigationProceed
) {
1796 // Navigate to a page.
1797 GURL
url1("http://www.google.com");
1798 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1799 EXPECT_EQ(1, controller().GetEntryCount());
1801 // Initiate a browser navigation that will trigger the interstitial
1802 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1803 ui::PAGE_TRANSITION_TYPED
, std::string());
1805 // Show an interstitial.
1806 TestInterstitialPage::InterstitialState state
=
1807 TestInterstitialPage::INVALID
;
1808 bool deleted
= false;
1809 GURL
url2("http://interstitial");
1810 TestInterstitialPage
* interstitial
=
1811 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1812 TestInterstitialPageStateGuard
state_guard(interstitial
);
1813 interstitial
->Show();
1814 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1815 // The interstitial should not show until its navigation has committed.
1816 EXPECT_FALSE(interstitial
->is_showing());
1817 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1818 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1819 // Let's commit the interstitial navigation.
1820 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1821 EXPECT_TRUE(interstitial
->is_showing());
1822 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1823 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1824 NavigationEntry
* entry
= controller().GetVisibleEntry();
1825 ASSERT_NE(nullptr, entry
);
1826 EXPECT_TRUE(entry
->GetURL() == url2
);
1829 interstitial
->Proceed();
1830 // The interstitial should show until the new navigation commits.
1831 RunAllPendingInMessageLoop();
1832 ASSERT_FALSE(deleted
);
1833 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1834 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1835 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1837 // Simulate the navigation to the page, that's when the interstitial gets
1839 GURL
url3("http://www.thepage.com");
1840 contents()->GetMainFrame()->PrepareForCommit();
1841 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3
);
1843 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1844 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1845 entry
= controller().GetVisibleEntry();
1846 ASSERT_NE(nullptr, entry
);
1847 EXPECT_TRUE(entry
->GetURL() == url3
);
1849 EXPECT_EQ(2, controller().GetEntryCount());
1851 RunAllPendingInMessageLoop();
1852 EXPECT_TRUE(deleted
);
1855 // Test navigating to a page (with the navigation initiated from the renderer,
1856 // as when clicking on a link in the page) that shows an interstitial and
1857 // creates a new navigation entry, then proceeding.
1858 TEST_F(WebContentsImplTest
,
1859 ShowInterstitialFromRendererNewNavigationProceed
) {
1860 // Navigate to a page.
1861 GURL
url1("http://www.google.com");
1862 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1863 EXPECT_EQ(1, controller().GetEntryCount());
1865 // Show an interstitial.
1866 TestInterstitialPage::InterstitialState state
=
1867 TestInterstitialPage::INVALID
;
1868 bool deleted
= false;
1869 GURL
url2("http://interstitial");
1870 TestInterstitialPage
* interstitial
=
1871 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1872 TestInterstitialPageStateGuard
state_guard(interstitial
);
1873 interstitial
->Show();
1874 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1875 // The interstitial should not show until its navigation has committed.
1876 EXPECT_FALSE(interstitial
->is_showing());
1877 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1878 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1879 // Let's commit the interstitial navigation.
1880 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1881 EXPECT_TRUE(interstitial
->is_showing());
1882 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1883 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1884 NavigationEntry
* entry
= controller().GetVisibleEntry();
1885 ASSERT_NE(nullptr, entry
);
1886 EXPECT_TRUE(entry
->GetURL() == url2
);
1889 interstitial
->Proceed();
1890 // The interstitial should show until the new navigation commits.
1891 RunAllPendingInMessageLoop();
1892 ASSERT_FALSE(deleted
);
1893 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1894 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1895 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1897 // Simulate the navigation to the page, that's when the interstitial gets
1899 GURL
url3("http://www.thepage.com");
1900 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3
);
1902 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1903 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1904 entry
= controller().GetVisibleEntry();
1905 ASSERT_NE(nullptr, entry
);
1906 EXPECT_TRUE(entry
->GetURL() == url3
);
1908 EXPECT_EQ(2, controller().GetEntryCount());
1910 RunAllPendingInMessageLoop();
1911 EXPECT_TRUE(deleted
);
1914 // Test navigating to a page that shows an interstitial without creating a new
1915 // navigation entry (this happens when the interstitial is triggered by a
1916 // sub-resource in the page), then proceeding.
1917 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1918 // Navigate to a page so we have a navigation entry in the controller.
1919 GURL
url1("http://www.google.com");
1920 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1921 EXPECT_EQ(1, controller().GetEntryCount());
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(), false, url2
, &state
, &deleted
);
1930 TestInterstitialPageStateGuard
state_guard(interstitial
);
1931 interstitial
->Show();
1932 // The interstitial should not show until its navigation has committed.
1933 EXPECT_FALSE(interstitial
->is_showing());
1934 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1935 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1936 // Let's commit the interstitial navigation.
1937 interstitial
->TestDidNavigate(1, 0, true, url2
);
1938 EXPECT_TRUE(interstitial
->is_showing());
1939 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1940 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1941 NavigationEntry
* entry
= controller().GetVisibleEntry();
1942 ASSERT_NE(nullptr, entry
);
1943 // The URL specified to the interstitial should have been ignored.
1944 EXPECT_TRUE(entry
->GetURL() == url1
);
1947 interstitial
->Proceed();
1948 // Since this is not a new navigation, the previous page is dismissed right
1949 // away and shows the original page.
1950 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1951 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1952 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1953 entry
= controller().GetVisibleEntry();
1954 ASSERT_NE(nullptr, entry
);
1955 EXPECT_TRUE(entry
->GetURL() == url1
);
1957 EXPECT_EQ(1, controller().GetEntryCount());
1959 RunAllPendingInMessageLoop();
1960 EXPECT_TRUE(deleted
);
1963 // Test navigating to a page that shows an interstitial, then navigating away.
1964 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1965 // Show interstitial.
1966 TestInterstitialPage::InterstitialState state
=
1967 TestInterstitialPage::INVALID
;
1968 bool deleted
= false;
1969 GURL
url("http://interstitial");
1970 TestInterstitialPage
* interstitial
=
1971 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1972 TestInterstitialPageStateGuard
state_guard(interstitial
);
1973 interstitial
->Show();
1974 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1975 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1977 // While interstitial showing, navigate to a new URL.
1978 const GURL
url2("http://www.yahoo.com");
1979 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2
);
1981 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1983 RunAllPendingInMessageLoop();
1984 EXPECT_TRUE(deleted
);
1987 // Test navigating to a page that shows an interstitial, then going back.
1988 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1989 // Navigate to a page so we have a navigation entry in the controller.
1990 GURL
url1("http://www.google.com");
1991 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1992 EXPECT_EQ(1, controller().GetEntryCount());
1994 // Show interstitial.
1995 TestInterstitialPage::InterstitialState state
=
1996 TestInterstitialPage::INVALID
;
1997 bool deleted
= false;
1998 GURL
interstitial_url("http://interstitial");
1999 TestInterstitialPage
* interstitial
=
2000 new TestInterstitialPage(contents(), true, interstitial_url
,
2002 TestInterstitialPageStateGuard
state_guard(interstitial
);
2003 interstitial
->Show();
2004 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2005 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
2007 EXPECT_EQ(2, controller().GetEntryCount());
2009 // While the interstitial is showing, go back. This will dismiss the
2010 // interstitial and not initiate a navigation, but just show the existing
2012 controller().GoBack();
2014 // Make sure we are back to the original page and that the interstitial is
2016 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2017 NavigationEntry
* entry
= controller().GetVisibleEntry();
2019 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
2020 EXPECT_EQ(1, controller().GetEntryCount());
2022 RunAllPendingInMessageLoop();
2023 EXPECT_TRUE(deleted
);
2026 // Test navigating to a page that shows an interstitial, has a renderer crash,
2027 // and then goes back.
2028 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
2029 // Navigate to a page so we have a navigation entry in the controller.
2030 GURL
url1("http://www.google.com");
2031 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2032 EXPECT_EQ(1, controller().GetEntryCount());
2033 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
2035 // Show interstitial.
2036 TestInterstitialPage::InterstitialState state
=
2037 TestInterstitialPage::INVALID
;
2038 bool deleted
= false;
2039 GURL
interstitial_url("http://interstitial");
2040 TestInterstitialPage
* interstitial
=
2041 new TestInterstitialPage(contents(), true, interstitial_url
,
2043 TestInterstitialPageStateGuard
state_guard(interstitial
);
2044 interstitial
->Show();
2045 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2046 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
2049 // Crash the renderer
2050 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
2052 // While the interstitial is showing, go back. This will dismiss the
2053 // interstitial and not initiate a navigation, but just show the existing
2055 controller().GoBack();
2057 // Make sure we are back to the original page and that the interstitial is
2059 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2060 entry
= controller().GetVisibleEntry();
2062 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
2064 RunAllPendingInMessageLoop();
2065 EXPECT_TRUE(deleted
);
2068 // Test navigating to a page that shows an interstitial, has the renderer crash,
2069 // and then navigates to the interstitial.
2070 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
2071 // Navigate to a page so we have a navigation entry in the controller.
2072 GURL
url1("http://www.google.com");
2073 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2074 EXPECT_EQ(1, controller().GetEntryCount());
2076 // Show interstitial.
2077 TestInterstitialPage::InterstitialState state
=
2078 TestInterstitialPage::INVALID
;
2079 bool deleted
= false;
2080 GURL
interstitial_url("http://interstitial");
2081 TestInterstitialPage
* interstitial
=
2082 new TestInterstitialPage(contents(), true, interstitial_url
,
2084 TestInterstitialPageStateGuard
state_guard(interstitial
);
2085 interstitial
->Show();
2086 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2088 // Crash the renderer
2089 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
2091 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
2095 // Test navigating to a page that shows an interstitial, then close the
2097 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
2098 // Show interstitial.
2099 TestInterstitialPage::InterstitialState state
=
2100 TestInterstitialPage::INVALID
;
2101 bool deleted
= false;
2102 GURL
url("http://interstitial");
2103 TestInterstitialPage
* interstitial
=
2104 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2105 TestInterstitialPageStateGuard
state_guard(interstitial
);
2106 interstitial
->Show();
2107 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2108 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2110 // Now close the contents.
2112 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2114 RunAllPendingInMessageLoop();
2115 EXPECT_TRUE(deleted
);
2118 // Test navigating to a page that shows an interstitial, then close the
2120 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
2121 // Show interstitial.
2122 TestInterstitialPage::InterstitialState state
=
2123 TestInterstitialPage::INVALID
;
2124 bool deleted
= false;
2125 GURL
url("http://interstitial");
2126 TestInterstitialPage
* interstitial
=
2127 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2128 TestInterstitialPageStateGuard
state_guard(interstitial
);
2129 interstitial
->Show();
2130 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2131 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2132 TestRenderFrameHost
* rfh
=
2133 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
2135 // Now close the contents.
2137 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2139 // Before the interstitial has a chance to process its shutdown task,
2140 // simulate quitting the browser. This goes through all processes and
2141 // tells them to destruct.
2142 rfh
->GetProcess()->SimulateCrash();
2144 RunAllPendingInMessageLoop();
2145 EXPECT_TRUE(deleted
);
2148 // Test that after Proceed is called and an interstitial is still shown, no more
2149 // commands get executed.
2150 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
2151 // Navigate to a page so we have a navigation entry in the controller.
2152 GURL
url1("http://www.google.com");
2153 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2154 EXPECT_EQ(1, controller().GetEntryCount());
2156 // Show an interstitial.
2157 TestInterstitialPage::InterstitialState state
=
2158 TestInterstitialPage::INVALID
;
2159 bool deleted
= false;
2160 GURL
url2("http://interstitial");
2161 TestInterstitialPage
* interstitial
=
2162 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2163 TestInterstitialPageStateGuard
state_guard(interstitial
);
2164 interstitial
->Show();
2165 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2166 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2169 EXPECT_EQ(0, interstitial
->command_received_count());
2170 interstitial
->TestDomOperationResponse("toto");
2171 EXPECT_EQ(1, interstitial
->command_received_count());
2174 interstitial
->Proceed();
2175 RunAllPendingInMessageLoop();
2176 ASSERT_FALSE(deleted
);
2178 // While the navigation to the new page is pending, send other commands, they
2179 // should be ignored.
2180 interstitial
->TestDomOperationResponse("hello");
2181 interstitial
->TestDomOperationResponse("hi");
2182 EXPECT_EQ(1, interstitial
->command_received_count());
2185 // Test showing an interstitial while another interstitial is already showing.
2186 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2187 // Navigate to a page so we have a navigation entry in the controller.
2188 GURL
start_url("http://www.google.com");
2189 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2190 EXPECT_EQ(1, controller().GetEntryCount());
2192 // Show an interstitial.
2193 TestInterstitialPage::InterstitialState state1
=
2194 TestInterstitialPage::INVALID
;
2195 bool deleted1
= false;
2196 GURL
url1("http://interstitial1");
2197 TestInterstitialPage
* interstitial1
=
2198 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2199 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2200 interstitial1
->Show();
2201 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2202 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2204 // Now show another interstitial.
2205 TestInterstitialPage::InterstitialState state2
=
2206 TestInterstitialPage::INVALID
;
2207 bool deleted2
= false;
2208 GURL
url2("http://interstitial2");
2209 TestInterstitialPage
* interstitial2
=
2210 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2211 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2212 interstitial2
->Show();
2213 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2214 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2216 // Showing interstitial2 should have caused interstitial1 to go away.
2217 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2218 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2220 RunAllPendingInMessageLoop();
2221 EXPECT_TRUE(deleted1
);
2222 ASSERT_FALSE(deleted2
);
2224 // Let's make sure interstitial2 is working as intended.
2225 interstitial2
->Proceed();
2226 GURL
landing_url("http://www.thepage.com");
2227 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2229 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2230 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2231 NavigationEntry
* entry
= controller().GetVisibleEntry();
2232 ASSERT_NE(nullptr, entry
);
2233 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2234 EXPECT_EQ(2, controller().GetEntryCount());
2235 RunAllPendingInMessageLoop();
2236 EXPECT_TRUE(deleted2
);
2239 // Test showing an interstitial, proceeding and then navigating to another
2241 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2242 // Navigate to a page so we have a navigation entry in the controller.
2243 GURL
start_url("http://www.google.com");
2244 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2245 EXPECT_EQ(1, controller().GetEntryCount());
2247 // Show an interstitial.
2248 TestInterstitialPage::InterstitialState state1
=
2249 TestInterstitialPage::INVALID
;
2250 bool deleted1
= false;
2251 GURL
url1("http://interstitial1");
2252 TestInterstitialPage
* interstitial1
=
2253 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2254 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2255 interstitial1
->Show();
2256 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2257 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2259 // Take action. The interstitial won't be hidden until the navigation is
2261 interstitial1
->Proceed();
2262 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2264 // Now show another interstitial (simulating the navigation causing another
2266 TestInterstitialPage::InterstitialState state2
=
2267 TestInterstitialPage::INVALID
;
2268 bool deleted2
= false;
2269 GURL
url2("http://interstitial2");
2270 TestInterstitialPage
* interstitial2
=
2271 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2272 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2273 interstitial2
->Show();
2274 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2275 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2277 // Showing interstitial2 should have caused interstitial1 to go away.
2278 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2279 RunAllPendingInMessageLoop();
2280 EXPECT_TRUE(deleted1
);
2281 ASSERT_FALSE(deleted2
);
2283 // Let's make sure interstitial2 is working as intended.
2284 interstitial2
->Proceed();
2285 GURL
landing_url("http://www.thepage.com");
2286 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2288 RunAllPendingInMessageLoop();
2289 EXPECT_TRUE(deleted2
);
2290 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2291 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2292 NavigationEntry
* entry
= controller().GetVisibleEntry();
2293 ASSERT_NE(nullptr, entry
);
2294 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2295 EXPECT_EQ(2, controller().GetEntryCount());
2298 // Test that navigating away from an interstitial while it's loading cause it
2300 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2301 // Show an interstitial.
2302 TestInterstitialPage::InterstitialState state
=
2303 TestInterstitialPage::INVALID
;
2304 bool deleted
= false;
2305 GURL
interstitial_url("http://interstitial");
2306 TestInterstitialPage
* interstitial
=
2307 new TestInterstitialPage(contents(), true, interstitial_url
,
2309 TestInterstitialPageStateGuard
state_guard(interstitial
);
2310 interstitial
->Show();
2311 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2313 // Let's simulate a navigation initiated from the browser before the
2314 // interstitial finishes loading.
2315 const GURL
url("http://www.google.com");
2316 controller().LoadURL(
2317 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2318 EXPECT_FALSE(interstitial
->is_showing());
2319 RunAllPendingInMessageLoop();
2320 ASSERT_FALSE(deleted
);
2322 // Now let's make the interstitial navigation commit.
2323 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true,
2326 // After it loaded the interstitial should be gone.
2327 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2329 RunAllPendingInMessageLoop();
2330 EXPECT_TRUE(deleted
);
2333 // Test that a new request to show an interstitial while an interstitial is
2334 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2335 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2336 GURL
interstitial_url("http://interstitial");
2338 // Show a first interstitial.
2339 TestInterstitialPage::InterstitialState state1
=
2340 TestInterstitialPage::INVALID
;
2341 bool deleted1
= false;
2342 TestInterstitialPage
* interstitial1
=
2343 new TestInterstitialPage(contents(), true, interstitial_url
,
2344 &state1
, &deleted1
);
2345 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2346 interstitial1
->Show();
2348 // Show another interstitial on that same contents before the first one had
2350 TestInterstitialPage::InterstitialState state2
=
2351 TestInterstitialPage::INVALID
;
2352 bool deleted2
= false;
2353 TestInterstitialPage
* interstitial2
=
2354 new TestInterstitialPage(contents(), true, interstitial_url
,
2355 &state2
, &deleted2
);
2356 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2357 interstitial2
->Show();
2358 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2360 // The first interstitial should have been closed and deleted.
2361 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2362 // The 2nd one should still be OK.
2363 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2365 RunAllPendingInMessageLoop();
2366 EXPECT_TRUE(deleted1
);
2367 ASSERT_FALSE(deleted2
);
2369 // Make the interstitial navigation commit it should be showing.
2370 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true,
2372 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2375 // Test showing an interstitial and have its renderer crash.
2376 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2377 // Show an interstitial.
2378 TestInterstitialPage::InterstitialState state
=
2379 TestInterstitialPage::INVALID
;
2380 bool deleted
= false;
2381 GURL
url("http://interstitial");
2382 TestInterstitialPage
* interstitial
=
2383 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2384 TestInterstitialPageStateGuard
state_guard(interstitial
);
2385 interstitial
->Show();
2386 // Simulate a renderer crash before the interstitial is shown.
2387 interstitial
->TestRenderViewTerminated(
2388 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2389 // The interstitial should have been dismissed.
2390 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2391 RunAllPendingInMessageLoop();
2392 EXPECT_TRUE(deleted
);
2394 // Now try again but this time crash the intersitial after it was shown.
2396 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2397 interstitial
->Show();
2398 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2399 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2400 // Simulate a renderer crash.
2401 interstitial
->TestRenderViewTerminated(
2402 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2403 // The interstitial should have been dismissed.
2404 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2405 RunAllPendingInMessageLoop();
2406 EXPECT_TRUE(deleted
);
2409 // Tests that showing an interstitial as a result of a browser initiated
2410 // navigation while an interstitial is showing does not remove the pending
2411 // entry (see http://crbug.com/9791).
2412 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2413 const char kUrl
[] = "http://www.badguys.com/";
2414 const GURL
kGURL(kUrl
);
2416 // Start a navigation to a page
2417 contents()->GetController().LoadURL(
2418 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2420 // Simulate that navigation triggering an interstitial.
2421 TestInterstitialPage::InterstitialState state
=
2422 TestInterstitialPage::INVALID
;
2423 bool deleted
= false;
2424 TestInterstitialPage
* interstitial
=
2425 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2426 TestInterstitialPageStateGuard
state_guard(interstitial
);
2427 interstitial
->Show();
2428 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2429 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2431 // Initiate a new navigation from the browser that also triggers an
2433 contents()->GetController().LoadURL(
2434 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2435 TestInterstitialPage::InterstitialState state2
=
2436 TestInterstitialPage::INVALID
;
2437 bool deleted2
= false;
2438 TestInterstitialPage
* interstitial2
=
2439 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2440 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2441 interstitial2
->Show();
2442 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2443 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2445 // Make sure we still have an entry.
2446 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2448 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2450 // And that the first interstitial is gone, but not the second.
2451 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2452 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2453 RunAllPendingInMessageLoop();
2454 EXPECT_TRUE(deleted
);
2455 EXPECT_FALSE(deleted2
);
2458 // Tests that Javascript messages are not shown while an interstitial is
2460 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2461 const char kUrl
[] = "http://www.badguys.com/";
2462 const GURL
kGURL(kUrl
);
2464 // Start a navigation to a page
2465 contents()->GetController().LoadURL(
2466 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2467 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2468 main_test_rfh()->PrepareForCommit();
2469 // DidNavigate from the page
2470 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
2471 kGURL
, ui::PAGE_TRANSITION_TYPED
);
2473 // Simulate showing an interstitial while the page is showing.
2474 TestInterstitialPage::InterstitialState state
=
2475 TestInterstitialPage::INVALID
;
2476 bool deleted
= false;
2477 TestInterstitialPage
* interstitial
=
2478 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2479 TestInterstitialPageStateGuard
state_guard(interstitial
);
2480 interstitial
->Show();
2481 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2482 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2484 // While the interstitial is showing, let's simulate the hidden page
2485 // attempting to show a JS message.
2486 IPC::Message
* dummy_message
= new IPC::Message
;
2487 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2488 base::ASCIIToUTF16("This is an informative message"),
2489 base::ASCIIToUTF16("OK"),
2490 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2491 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2494 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2495 // interstitial it isn't copied over to the destination.
2496 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2497 // Navigate to a page.
2498 GURL
url1("http://www.google.com");
2499 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2500 EXPECT_EQ(1, controller().GetEntryCount());
2502 // Initiate a browser navigation that will trigger the interstitial
2503 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2504 ui::PAGE_TRANSITION_TYPED
, std::string());
2506 // Show an interstitial.
2507 TestInterstitialPage::InterstitialState state
=
2508 TestInterstitialPage::INVALID
;
2509 bool deleted
= false;
2510 GURL
url2("http://interstitial");
2511 TestInterstitialPage
* interstitial
=
2512 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2513 TestInterstitialPageStateGuard
state_guard(interstitial
);
2514 interstitial
->Show();
2515 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2516 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2517 EXPECT_TRUE(interstitial
->is_showing());
2518 EXPECT_EQ(2, controller().GetEntryCount());
2520 // Create another NavigationController.
2521 GURL
url3("http://foo2");
2522 scoped_ptr
<TestWebContents
> other_contents(
2523 static_cast<TestWebContents
*>(CreateTestWebContents()));
2524 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2525 other_contents
->NavigateAndCommit(url3
);
2526 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2527 other_controller
.CopyStateFromAndPrune(&controller(), false);
2529 // The merged controller should only have two entries: url1 and url2.
2530 ASSERT_EQ(2, other_controller
.GetEntryCount());
2531 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2532 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2533 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2535 // And the merged controller shouldn't be showing an interstitial.
2536 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2539 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2540 // showing an interstitial.
2541 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2542 // Navigate to a page.
2543 GURL
url1("http://www.google.com");
2544 contents()->NavigateAndCommit(url1
);
2546 // Create another NavigationController.
2547 scoped_ptr
<TestWebContents
> other_contents(
2548 static_cast<TestWebContents
*>(CreateTestWebContents()));
2549 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2551 // Navigate it to url2.
2552 GURL
url2("http://foo2");
2553 other_contents
->NavigateAndCommit(url2
);
2555 // Show an interstitial.
2556 TestInterstitialPage::InterstitialState state
=
2557 TestInterstitialPage::INVALID
;
2558 bool deleted
= false;
2559 GURL
url3("http://interstitial");
2560 TestInterstitialPage
* interstitial
=
2561 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2563 TestInterstitialPageStateGuard
state_guard(interstitial
);
2564 interstitial
->Show();
2565 int interstitial_entry_id
=
2566 other_controller
.GetTransientEntry()->GetUniqueID();
2567 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url3
);
2568 EXPECT_TRUE(interstitial
->is_showing());
2569 EXPECT_EQ(2, other_controller
.GetEntryCount());
2571 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2572 // interstitial is showing in the target.
2573 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2576 // Regression test for http://crbug.com/168611 - the URLs passed by the
2577 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2578 TEST_F(WebContentsImplTest
, FilterURLs
) {
2579 TestWebContentsObserver
observer(contents());
2581 // A navigation to about:whatever should always look like a navigation to
2583 GURL
url_normalized(url::kAboutBlankURL
);
2584 GURL
url_from_ipc("about:whatever");
2586 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2587 // will use the given URL to create the NavigationEntry as well, and that
2588 // entry should contain the filtered URL.
2589 contents()->NavigateAndCommit(url_normalized
);
2591 // Check that an IPC with about:whatever is correctly normalized.
2592 contents()->TestDidFinishLoad(url_from_ipc
);
2594 EXPECT_EQ(url_normalized
, observer
.last_url());
2596 // Create and navigate another WebContents.
2597 scoped_ptr
<TestWebContents
> other_contents(
2598 static_cast<TestWebContents
*>(CreateTestWebContents()));
2599 TestWebContentsObserver
other_observer(other_contents
.get());
2600 other_contents
->NavigateAndCommit(url_normalized
);
2602 // Check that an IPC with about:whatever is correctly normalized.
2603 other_contents
->TestDidFailLoadWithError(
2604 url_from_ipc
, 1, base::string16(), false);
2605 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2608 // Test that if a pending contents is deleted before it is shown, we don't
2610 TEST_F(WebContentsImplTest
, PendingContents
) {
2611 scoped_ptr
<TestWebContents
> other_contents(
2612 static_cast<TestWebContents
*>(CreateTestWebContents()));
2613 contents()->AddPendingContents(other_contents
.get());
2614 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2615 other_contents
.reset();
2616 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2619 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2620 const gfx::Size
original_preferred_size(1024, 768);
2621 contents()->UpdatePreferredSize(original_preferred_size
);
2623 // With no capturers, expect the preferred size to be the one propagated into
2624 // WebContentsImpl via the RenderViewHostDelegate interface.
2625 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2626 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2628 // Increment capturer count, but without specifying a capture size. Expect
2629 // a "not set" preferred size.
2630 contents()->IncrementCapturerCount(gfx::Size());
2631 EXPECT_EQ(1, contents()->GetCapturerCount());
2632 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2634 // Increment capturer count again, but with an overriding capture size.
2635 // Expect preferred size to now be overridden to the capture size.
2636 const gfx::Size
capture_size(1280, 720);
2637 contents()->IncrementCapturerCount(capture_size
);
2638 EXPECT_EQ(2, contents()->GetCapturerCount());
2639 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2641 // Increment capturer count a third time, but the expect that the preferred
2642 // size is still the first capture size.
2643 const gfx::Size
another_capture_size(720, 480);
2644 contents()->IncrementCapturerCount(another_capture_size
);
2645 EXPECT_EQ(3, contents()->GetCapturerCount());
2646 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2648 // Decrement capturer count twice, but expect the preferred size to still be
2650 contents()->DecrementCapturerCount();
2651 contents()->DecrementCapturerCount();
2652 EXPECT_EQ(1, contents()->GetCapturerCount());
2653 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2655 // Decrement capturer count, and since the count has dropped to zero, the
2656 // original preferred size should be restored.
2657 contents()->DecrementCapturerCount();
2658 EXPECT_EQ(0, contents()->GetCapturerCount());
2659 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2662 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2663 const gfx::Size
original_preferred_size(1024, 768);
2664 contents()->UpdatePreferredSize(original_preferred_size
);
2666 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2667 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2669 // With no capturers, setting and un-setting occlusion should change the
2670 // view's occlusion state.
2671 EXPECT_FALSE(view
->is_showing());
2672 contents()->WasShown();
2673 EXPECT_TRUE(view
->is_showing());
2674 contents()->WasHidden();
2675 EXPECT_FALSE(view
->is_showing());
2676 contents()->WasShown();
2677 EXPECT_TRUE(view
->is_showing());
2679 // Add a capturer and try to hide the contents. The view will remain visible.
2680 contents()->IncrementCapturerCount(gfx::Size());
2681 contents()->WasHidden();
2682 EXPECT_TRUE(view
->is_showing());
2684 // Remove the capturer, and the WasHidden should take effect.
2685 contents()->DecrementCapturerCount();
2686 EXPECT_FALSE(view
->is_showing());
2689 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2690 const gfx::Size
original_preferred_size(1024, 768);
2691 contents()->UpdatePreferredSize(original_preferred_size
);
2693 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2694 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2696 // With no capturers, setting and un-setting occlusion should change the
2697 // view's occlusion state.
2698 EXPECT_FALSE(view
->is_occluded());
2699 contents()->WasOccluded();
2700 EXPECT_TRUE(view
->is_occluded());
2701 contents()->WasUnOccluded();
2702 EXPECT_FALSE(view
->is_occluded());
2703 contents()->WasOccluded();
2704 EXPECT_TRUE(view
->is_occluded());
2706 // Add a capturer. This should cause the view to be un-occluded.
2707 contents()->IncrementCapturerCount(gfx::Size());
2708 EXPECT_FALSE(view
->is_occluded());
2710 // Try to occlude the view. This will fail to propagate because of the
2712 contents()->WasOccluded();
2713 EXPECT_FALSE(view
->is_occluded());
2715 // Remove the capturer and try again.
2716 contents()->DecrementCapturerCount();
2717 EXPECT_FALSE(view
->is_occluded());
2718 contents()->WasOccluded();
2719 EXPECT_TRUE(view
->is_occluded());
2722 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2724 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2725 // The WebContents starts with a valid creation time.
2726 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2728 // Reset the last active time to a known-bad value.
2729 contents()->last_active_time_
= base::TimeTicks();
2730 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2732 // Simulate activating the WebContents. The active time should update.
2733 contents()->WasShown();
2734 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2737 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2739 ContentsZoomChangedDelegate() :
2740 contents_zoom_changed_call_count_(0),
2741 last_zoom_in_(false) {
2744 int GetAndResetContentsZoomChangedCallCount() {
2745 int count
= contents_zoom_changed_call_count_
;
2746 contents_zoom_changed_call_count_
= 0;
2750 bool last_zoom_in() const {
2751 return last_zoom_in_
;
2754 // WebContentsDelegate:
2755 void ContentsZoomChange(bool zoom_in
) override
{
2756 contents_zoom_changed_call_count_
++;
2757 last_zoom_in_
= zoom_in
;
2761 int contents_zoom_changed_call_count_
;
2764 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2767 // Tests that some mouseehweel events get turned into browser zoom requests.
2768 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2769 using blink::WebInputEvent
;
2771 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2772 new ContentsZoomChangedDelegate());
2773 contents()->SetDelegate(delegate
.get());
2776 // Verify that normal mouse wheel events do nothing to change the zoom level.
2777 blink::WebMouseWheelEvent event
=
2778 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2779 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2780 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2782 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2783 WebInputEvent::ControlKey
;
2784 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2785 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2786 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2788 // But whenever the ctrl modifier is applied with canScroll=false, they can
2789 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2791 modifiers
= WebInputEvent::ControlKey
;
2792 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2793 event
.canScroll
= false;
2794 bool handled
= contents()->HandleWheelEvent(event
);
2795 #if defined(OS_MACOSX)
2796 EXPECT_FALSE(handled
);
2797 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2799 EXPECT_TRUE(handled
);
2800 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2801 EXPECT_TRUE(delegate
->last_zoom_in());
2804 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2805 WebInputEvent::AltKey
;
2806 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2807 event
.canScroll
= false;
2808 handled
= contents()->HandleWheelEvent(event
);
2809 #if defined(OS_MACOSX)
2810 EXPECT_FALSE(handled
);
2811 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2813 EXPECT_TRUE(handled
);
2814 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2815 EXPECT_FALSE(delegate
->last_zoom_in());
2818 // Unless there is no vertical movement.
2819 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2820 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2821 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2823 // Events containing precise scrolling deltas also shouldn't result in the
2824 // zoom being adjusted, to avoid accidental adjustments caused by
2825 // two-finger-scrolling on a touchpad.
2826 modifiers
= WebInputEvent::ControlKey
;
2827 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2828 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2829 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2831 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2832 contents()->SetDelegate(nullptr);
2835 // Tests that GetRelatedActiveContentsCount is shared between related
2836 // SiteInstances and includes WebContents that have not navigated yet.
2837 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2838 scoped_refptr
<SiteInstance
> instance1(
2839 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2840 scoped_refptr
<SiteInstance
> instance2(
2841 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2843 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2844 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2846 scoped_ptr
<TestWebContents
> contents1(
2847 TestWebContents::Create(browser_context(), instance1
.get()));
2848 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2849 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2851 scoped_ptr
<TestWebContents
> contents2(
2852 TestWebContents::Create(browser_context(), instance1
.get()));
2853 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2854 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2857 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2858 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2861 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2862 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2865 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2866 // same-site and cross-site navigations.
2867 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2868 scoped_refptr
<SiteInstance
> instance(
2869 SiteInstance::Create(browser_context()));
2871 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2873 scoped_ptr
<TestWebContents
> contents(
2874 TestWebContents::Create(browser_context(), instance
.get()));
2875 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2877 // Navigate to a URL.
2878 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2880 ui::PAGE_TRANSITION_TYPED
,
2882 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2883 contents
->CommitPendingNavigation();
2884 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2886 // Navigate to a URL in the same site.
2887 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2889 ui::PAGE_TRANSITION_TYPED
,
2891 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2892 contents
->CommitPendingNavigation();
2893 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2895 // Navigate to a URL in a different site.
2896 const GURL kUrl
= GURL("http://b.com");
2897 contents
->GetController().LoadURL(kUrl
,
2899 ui::PAGE_TRANSITION_TYPED
,
2901 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2902 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2903 switches::kEnableBrowserSideNavigation
)) {
2904 contents
->GetMainFrame()->PrepareForCommit();
2906 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2907 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2908 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kUrl
);
2909 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2912 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2915 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2917 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2918 scoped_refptr
<SiteInstance
> instance(
2919 SiteInstance::Create(browser_context()));
2921 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2923 scoped_ptr
<TestWebContents
> contents(
2924 TestWebContents::Create(browser_context(), instance
.get()));
2925 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2927 // Navigate to a URL.
2928 contents
->NavigateAndCommit(GURL("http://a.com"));
2929 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2931 // Navigate to a URL which sort of looks like a chrome:// url.
2932 contents
->NavigateAndCommit(GURL("http://gpu"));
2933 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2935 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2936 const GURL kWebUIUrl
= GURL("chrome://gpu");
2937 contents
->GetController().LoadURL(kWebUIUrl
,
2939 ui::PAGE_TRANSITION_TYPED
,
2941 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2942 contents
->GetMainFrame()->PrepareForCommit();
2943 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2944 scoped_refptr
<SiteInstance
> instance_webui(
2945 contents
->GetPendingMainFrame()->GetSiteInstance());
2946 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2948 // At this point, contents still counts for the old BrowsingInstance.
2949 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2950 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2952 // Commit and contents counts for the new one.
2953 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kWebUIUrl
);
2954 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2955 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2958 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2959 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2962 class LoadingWebContentsObserver
: public WebContentsObserver
{
2964 explicit LoadingWebContentsObserver(WebContents
* contents
)
2965 : WebContentsObserver(contents
),
2966 is_loading_(false) {
2968 ~LoadingWebContentsObserver() override
{}
2970 void DidStartLoading() override
{ is_loading_
= true; }
2971 void DidStopLoading() override
{ is_loading_
= false; }
2973 bool is_loading() const { return is_loading_
; }
2978 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2981 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2982 // interleaving cross-process navigations in multiple subframes.
2983 // See https://crbug.com/448601 for details of the underlying issue. The
2984 // sequence of events that reproduce it are as follows:
2985 // * Navigate top-level frame with one subframe.
2986 // * Subframe navigates more than once before the top-level frame has had a
2987 // chance to complete the load.
2988 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2989 // to 0, while the loading_progresses_ map is not reset.
2990 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2991 // The bug manifests itself in regular mode as well, but browser-initiated
2992 // navigation of subframes is only possible in --site-per-process mode within
2994 IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
2995 const GURL
initial_url("about:blank");
2996 const GURL
main_url("http://www.chromium.org");
2997 const GURL
foo_url("http://foo.chromium.org");
2998 const GURL
bar_url("http://bar.chromium.org");
2999 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
3001 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
3002 LoadingWebContentsObserver
observer(contents());
3004 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
3005 // The frame should still be loading.
3006 controller().LoadURL(
3007 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3008 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
3009 orig_rfh
->PrepareForCommit();
3010 orig_rfh
->OnMessageReceived(
3011 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
3012 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, main_url
,
3013 ui::PAGE_TRANSITION_TYPED
);
3014 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
3015 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
3016 EXPECT_TRUE(contents()->IsLoading());
3017 EXPECT_TRUE(observer
.is_loading());
3019 // Create a child frame to navigate multiple times.
3020 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
3022 // Navigate the child frame to about:blank, which will send both
3023 // DidStartLoading and DidStopLoading messages.
3025 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
3026 subframe
->OnMessageReceived(
3027 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
3028 subframe
->SendNavigateWithTransition(1, 0, false, initial_url
,
3029 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
3030 subframe
->OnMessageReceived(
3031 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
3034 // Navigate the frame to another URL, which will send again
3035 // DidStartLoading and DidStopLoading messages.
3037 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
3038 subframe
->PrepareForCommit();
3039 subframe
->OnMessageReceived(
3040 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
3041 subframe
->SendNavigateWithTransition(1, 0, false, foo_url
,
3042 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
3043 subframe
->OnMessageReceived(
3044 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
3047 // Since the main frame hasn't sent any DidStopLoading messages, it is
3048 // expected that the WebContents is still in loading state.
3049 EXPECT_TRUE(contents()->IsLoading());
3050 EXPECT_TRUE(observer
.is_loading());
3052 // Navigate the frame again, this time using LoadURLWithParams. This causes
3053 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
3056 NavigationController::LoadURLParams
load_params(bar_url
);
3057 load_params
.referrer
=
3058 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
3059 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
3060 load_params
.extra_headers
= "content-type: text/plain";
3061 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
3062 load_params
.is_renderer_initiated
= false;
3063 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
3064 load_params
.frame_tree_node_id
=
3065 subframe
->frame_tree_node()->frame_tree_node_id();
3066 controller().LoadURLWithParams(load_params
);
3067 entry_id
= controller().GetPendingEntry()->GetUniqueID();
3069 subframe
->OnMessageReceived(
3070 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
3072 // Commit the navigation in the child frame and send the DidStopLoading
3074 subframe
->PrepareForCommit();
3075 contents()->TestDidNavigate(subframe
, 3, entry_id
, true, bar_url
,
3076 ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
3077 subframe
->OnMessageReceived(
3078 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
3081 // At this point the status should still be loading, since the main frame
3082 // hasn't sent the DidstopLoading message yet.
3083 EXPECT_TRUE(contents()->IsLoading());
3084 EXPECT_TRUE(observer
.is_loading());
3086 // Send the DidStopLoading for the main frame and ensure it isn't loading
3088 orig_rfh
->OnMessageReceived(
3089 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
3090 EXPECT_FALSE(contents()->IsLoading());
3091 EXPECT_FALSE(observer
.is_loading());
3094 // Ensure that WebContentsImpl does not stop loading too early when there still
3095 // is a pending renderer. This can happen if a same-process non user-initiated
3096 // navigation completes while there is an ongoing cross-process navigation.
3097 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
3098 // DidStopLoading are properly called.
3099 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
3100 const GURL
kUrl1("http://www.chromium.org");
3101 const GURL
kUrl2("http://www.google.com");
3102 const GURL
kUrl3("http://www.wikipedia.org");
3104 contents()->NavigateAndCommit(kUrl1
);
3106 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
3108 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
3109 // be a pending RenderFrameHost and the WebContents should be loading.
3110 controller().LoadURL(
3111 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3112 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
3113 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
3114 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
3115 ASSERT_TRUE(pending_rfh
);
3116 EXPECT_TRUE(contents()->IsLoading());
3118 // The current RenderFrameHost starts a non user-initiated render-initiated
3119 // navigation and sends a DidStartLoading IPC. The WebContents should still be
3121 current_rfh
->OnMessageReceived(
3122 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
3123 EXPECT_TRUE(contents()->IsLoading());
3125 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
3126 // a pending RenderFrameHost and the WebContents should still be loading.
3127 pending_rfh
->PrepareForCommit();
3128 pending_rfh
->OnMessageReceived(
3129 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
3130 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3131 EXPECT_TRUE(contents()->IsLoading());
3133 // Simulate the commit and DidStopLoading from the renderer-initiated
3134 // navigation in the current RenderFrameHost. There should still be a pending
3135 // RenderFrameHost and the WebContents should still be loading.
3136 current_rfh
->SendNavigateWithModificationCallback(
3137 1, 0, true, kUrl3
, base::Bind(SetAsNonUserGesture
));
3138 current_rfh
->OnMessageReceived(
3139 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
3140 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3141 EXPECT_TRUE(contents()->IsLoading());
3142 // It should commit.
3143 ASSERT_EQ(2, controller().GetEntryCount());
3144 EXPECT_EQ(kUrl3
, controller().GetLastCommittedEntry()->GetURL());
3146 // Commit the navigation. The formerly pending RenderFrameHost should now be
3147 // the current RenderFrameHost and the WebContents should still be loading.
3148 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, kUrl2
,
3149 ui::PAGE_TRANSITION_TYPED
);
3150 EXPECT_FALSE(contents()->GetPendingMainFrame());
3151 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
3152 EXPECT_EQ(new_current_rfh
, pending_rfh
);
3153 EXPECT_TRUE(contents()->IsLoading());
3154 EXPECT_EQ(3, controller().GetEntryCount());
3156 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3157 // should now have stopped loading.
3158 new_current_rfh
->OnMessageReceived(
3159 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
3160 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
3161 EXPECT_FALSE(contents()->IsLoading());
3164 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
3165 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3166 // and positive player ids don't blow up.
3167 const int kPlayerAudioVideoId
= 15;
3168 const int kPlayerAudioOnlyId
= -15;
3169 const int kPlayerVideoOnlyId
= 30;
3170 const int kPlayerRemoteId
= -30;
3172 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3173 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3175 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3176 AudioStreamMonitor
* monitor
= contents()->audio_stream_monitor();
3178 // Ensure RenderFrame is initialized before simulating events coming from it.
3179 main_test_rfh()->InitializeRenderFrameIfNeeded();
3181 // The audio power save blocker should not be based on having a media player
3182 // when audio stream monitoring is available.
3183 if (AudioStreamMonitor::monitoring_available()) {
3184 // Send a fake audio stream monitor notification. The audio power save
3185 // blocker should be created.
3186 monitor
->set_was_recently_audible_for_testing(true);
3187 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3188 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3190 // Send another fake notification, this time when WasRecentlyAudible() will
3191 // be false. The power save blocker should be released.
3192 monitor
->set_was_recently_audible_for_testing(false);
3193 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3194 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3197 // Start a player with both audio and video. A video power save blocker
3198 // should be created. If audio stream monitoring is available, an audio power
3199 // save blocker should be created too.
3200 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3201 0, kPlayerAudioVideoId
, true, true, false));
3202 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3203 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3204 !AudioStreamMonitor::monitoring_available());
3206 // Upon hiding the video power save blocker should be released.
3207 contents()->WasHidden();
3208 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3210 // Start another player that only has video. There should be no change in
3211 // the power save blockers. The notification should take into account the
3212 // visibility state of the WebContents.
3213 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3214 0, kPlayerVideoOnlyId
, true, false, false));
3215 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3216 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3217 !AudioStreamMonitor::monitoring_available());
3219 // Showing the WebContents should result in the creation of the blocker.
3220 contents()->WasShown();
3221 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3223 // Start another player that only has audio. There should be no change in
3224 // the power save blockers.
3225 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3226 0, kPlayerAudioOnlyId
, false, true, false));
3227 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3228 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3229 !AudioStreamMonitor::monitoring_available());
3231 // Start a remote player. There should be no change in the power save
3233 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3234 0, kPlayerRemoteId
, true, true, true));
3235 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3236 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3237 !AudioStreamMonitor::monitoring_available());
3239 // Destroy the original audio video player. Both power save blockers should
3241 rfh
->OnMessageReceived(
3242 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
3243 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3244 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3245 !AudioStreamMonitor::monitoring_available());
3247 // Destroy the audio only player. The video power save blocker should remain.
3248 rfh
->OnMessageReceived(
3249 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3250 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3251 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3253 // Destroy the video only player. No power save blockers should remain.
3254 rfh
->OnMessageReceived(
3255 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3256 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3257 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3259 // Destroy the remote player. No power save blockers should remain.
3260 rfh
->OnMessageReceived(
3261 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3262 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3263 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3265 // Start a player with both audio and video. A video power save blocker
3266 // should be created. If audio stream monitoring is available, an audio power
3267 // save blocker should be created too.
3268 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3269 0, kPlayerAudioVideoId
, true, true, false));
3270 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3271 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3272 !AudioStreamMonitor::monitoring_available());
3274 // Crash the renderer.
3275 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3277 // Verify that all the power save blockers have been released.
3278 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3279 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3282 TEST_F(WebContentsImplTest
, ThemeColorChangeDependingOnFirstVisiblePaint
) {
3283 TestWebContentsObserver
observer(contents());
3284 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3286 SkColor transparent
= SK_ColorTRANSPARENT
;
3288 EXPECT_EQ(transparent
, contents()->GetThemeColor());
3289 EXPECT_EQ(transparent
, observer
.last_theme_color());
3291 // Theme color changes should not propagate past the WebContentsImpl before
3292 // the first visually non-empty paint has occurred.
3293 RenderViewHostTester::TestOnMessageReceived(
3295 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorRED
));
3297 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3298 EXPECT_EQ(transparent
, observer
.last_theme_color());
3300 // Simulate that the first visually non-empty paint has occurred. This will
3301 // propagate the current theme color to the delegates.
3302 RenderViewHostTester::TestOnMessageReceived(
3304 ViewHostMsg_DidFirstVisuallyNonEmptyPaint(rfh
->GetRoutingID()));
3306 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3307 EXPECT_EQ(SK_ColorRED
, observer
.last_theme_color());
3309 // Additional changes made by the web contents should propagate as well.
3310 RenderViewHostTester::TestOnMessageReceived(
3312 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorGREEN
));
3314 EXPECT_EQ(SK_ColorGREEN
, contents()->GetThemeColor());
3315 EXPECT_EQ(SK_ColorGREEN
, observer
.last_theme_color());
3318 // Test that if a renderer reports that it has loaded a resource from
3319 // memory cache with bad security info (i.e. can't be deserialized), the
3320 // renderer gets killed.
3321 TEST_F(WebContentsImplTest
, LoadResourceFromMemoryCacheWithBadSecurityInfo
) {
3322 MockRenderProcessHost
* rph
= contents()->GetMainFrame()->GetProcess();
3323 EXPECT_EQ(0, rph
->bad_msg_count());
3325 contents()->OnDidLoadResourceFromMemoryCache(
3326 GURL("http://example.test"), "not valid security info", "GET",
3327 "mime type", RESOURCE_TYPE_MAIN_FRAME
);
3328 EXPECT_EQ(1, rph
->bad_msg_count());
3331 // Test that if a resource is loaded with empty security info, the SSLManager
3332 // does not mistakenly think it has seen a good certificate and thus forget any
3333 // user exceptions for that host. See https://crbug.com/516808.
3334 TEST_F(WebContentsImplTest
, LoadResourceFromMemoryCacheWithEmptySecurityInfo
) {
3335 scoped_refptr
<net::X509Certificate
> cert
=
3336 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
3337 SSLPolicyBackend
* backend
= contents()->controller_
.ssl_manager()->backend();
3338 const GURL
test_url("https://example.test");
3340 backend
->AllowCertForHost(*cert
, test_url
.host(), 1);
3341 EXPECT_TRUE(backend
->HasAllowException(test_url
.host()));
3343 contents()->OnDidLoadResourceFromMemoryCache(test_url
, "", "GET", "mime type",
3344 RESOURCE_TYPE_MAIN_FRAME
);
3346 EXPECT_TRUE(backend
->HasAllowException(test_url
.host()));
3349 } // namespace content