1 // Copyright 2013 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/files/file_path.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/test/histogram_tester.h"
9 #include "base/time/time.h"
10 #include "content/browser/frame_host/cross_site_transferring_request.h"
11 #include "content/browser/frame_host/navigation_controller_impl.h"
12 #include "content/browser/frame_host/navigation_entry_impl.h"
13 #include "content/browser/frame_host/navigation_request.h"
14 #include "content/browser/frame_host/navigator.h"
15 #include "content/browser/frame_host/render_frame_host_manager.h"
16 #include "content/browser/frame_host/render_frame_proxy_host.h"
17 #include "content/browser/site_instance_impl.h"
18 #include "content/browser/webui/web_ui_controller_factory_registry.h"
19 #include "content/common/frame_messages.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/render_widget_host_iterator.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/browser/web_ui_controller.h"
30 #include "content/public/common/bindings_policy.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/common/javascript_message_type.h"
33 #include "content/public/common/url_constants.h"
34 #include "content/public/common/url_utils.h"
35 #include "content/public/test/mock_render_process_host.h"
36 #include "content/public/test/test_notification_tracker.h"
37 #include "content/test/test_content_browser_client.h"
38 #include "content/test/test_content_client.h"
39 #include "content/test/test_render_frame_host.h"
40 #include "content/test/test_render_view_host.h"
41 #include "content/test/test_web_contents.h"
42 #include "net/base/load_flags.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "ui/base/page_transition_types.h"
49 class RenderFrameHostManagerTestWebUIControllerFactory
50 : public WebUIControllerFactory
{
52 RenderFrameHostManagerTestWebUIControllerFactory()
53 : should_create_webui_(false) {
55 ~RenderFrameHostManagerTestWebUIControllerFactory() override
{}
57 void set_should_create_webui(bool should_create_webui
) {
58 should_create_webui_
= should_create_webui
;
61 // WebUIFactory implementation.
62 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
63 const GURL
& url
) const override
{
64 if (!(should_create_webui_
&& HasWebUIScheme(url
)))
66 return new WebUIController(web_ui
);
69 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
70 const GURL
& url
) const override
{
71 return WebUI::kNoWebUI
;
74 bool UseWebUIForURL(BrowserContext
* browser_context
,
75 const GURL
& url
) const override
{
76 return HasWebUIScheme(url
);
79 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
80 const GURL
& url
) const override
{
81 return HasWebUIScheme(url
);
85 bool should_create_webui_
;
87 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManagerTestWebUIControllerFactory
);
90 class BeforeUnloadFiredWebContentsDelegate
: public WebContentsDelegate
{
92 BeforeUnloadFiredWebContentsDelegate() {}
93 ~BeforeUnloadFiredWebContentsDelegate() override
{}
95 void BeforeUnloadFired(WebContents
* web_contents
,
97 bool* proceed_to_fire_unload
) override
{
98 *proceed_to_fire_unload
= proceed
;
102 DISALLOW_COPY_AND_ASSIGN(BeforeUnloadFiredWebContentsDelegate
);
105 class CloseWebContentsDelegate
: public WebContentsDelegate
{
107 CloseWebContentsDelegate() : close_called_(false) {}
108 ~CloseWebContentsDelegate() override
{}
110 void CloseContents(WebContents
* web_contents
) override
{
111 close_called_
= true;
114 bool is_closed() { return close_called_
; }
117 DISALLOW_COPY_AND_ASSIGN(CloseWebContentsDelegate
);
122 // This observer keeps track of the last deleted RenderViewHost to avoid
123 // accessing it and causing use-after-free condition.
124 class RenderViewHostDeletedObserver
: public WebContentsObserver
{
126 RenderViewHostDeletedObserver(RenderViewHost
* rvh
)
127 : WebContentsObserver(WebContents::FromRenderViewHost(rvh
)),
128 process_id_(rvh
->GetProcess()->GetID()),
129 routing_id_(rvh
->GetRoutingID()),
133 void RenderViewDeleted(RenderViewHost
* render_view_host
) override
{
134 if (render_view_host
->GetProcess()->GetID() == process_id_
&&
135 render_view_host
->GetRoutingID() == routing_id_
) {
149 DISALLOW_COPY_AND_ASSIGN(RenderViewHostDeletedObserver
);
152 // This observer keeps track of the last created RenderFrameHost to allow tests
153 // to ensure that no RenderFrameHost objects are created when not expected.
154 class RenderFrameHostCreatedObserver
: public WebContentsObserver
{
156 RenderFrameHostCreatedObserver(WebContents
* web_contents
)
157 : WebContentsObserver(web_contents
),
161 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
{
172 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver
);
175 // This observer keeps track of the last deleted RenderFrameHost to avoid
176 // accessing it and causing use-after-free condition.
177 class RenderFrameHostDeletedObserver
: public WebContentsObserver
{
179 RenderFrameHostDeletedObserver(RenderFrameHost
* rfh
)
180 : WebContentsObserver(WebContents::FromRenderFrameHost(rfh
)),
181 process_id_(rfh
->GetProcess()->GetID()),
182 routing_id_(rfh
->GetRoutingID()),
186 void RenderFrameDeleted(RenderFrameHost
* render_frame_host
) override
{
187 if (render_frame_host
->GetProcess()->GetID() == process_id_
&&
188 render_frame_host
->GetRoutingID() == routing_id_
) {
202 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver
);
205 // This observer is used to check whether IPC messages are being filtered for
206 // swapped out RenderFrameHost objects. It observes the plugin crash and favicon
207 // update events, which the FilterMessagesWhileSwappedOut test simulates being
208 // sent. The test is successful if the event is not observed.
209 // See http://crbug.com/351815
210 class PluginFaviconMessageObserver
: public WebContentsObserver
{
212 PluginFaviconMessageObserver(WebContents
* web_contents
)
213 : WebContentsObserver(web_contents
),
214 plugin_crashed_(false),
215 favicon_received_(false) { }
217 void PluginCrashed(const base::FilePath
& plugin_path
,
218 base::ProcessId plugin_pid
) override
{
219 plugin_crashed_
= true;
222 void DidUpdateFaviconURL(const std::vector
<FaviconURL
>& candidates
) override
{
223 favicon_received_
= true;
226 bool plugin_crashed() {
227 return plugin_crashed_
;
230 bool favicon_received() {
231 return favicon_received_
;
235 bool plugin_crashed_
;
236 bool favicon_received_
;
238 DISALLOW_COPY_AND_ASSIGN(PluginFaviconMessageObserver
);
243 class RenderFrameHostManagerTest
: public RenderViewHostImplTestHarness
{
245 void SetUp() override
{
246 RenderViewHostImplTestHarness::SetUp();
247 WebUIControllerFactory::RegisterFactory(&factory_
);
250 void TearDown() override
{
251 RenderViewHostImplTestHarness::TearDown();
252 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_
);
255 void set_should_create_webui(bool should_create_webui
) {
256 factory_
.set_should_create_webui(should_create_webui
);
259 void NavigateActiveAndCommit(const GURL
& url
) {
260 // Note: we navigate the active RenderFrameHost because previous navigations
261 // won't have committed yet, so NavigateAndCommit does the wrong thing
263 controller().LoadURL(
264 url
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
266 // Simulate the BeforeUnload_ACK that is received from the current renderer
267 // for a cross-site navigation.
268 // PlzNavigate: it is necessary to call PrepareForCommit before getting the
269 // main and the pending frame because when we are trying to navigate to a
270 // WebUI from a new tab, a RenderFrameHost is created to display it that is
271 // committed immediately (since it is a new tab). Therefore the main frame
272 // is replaced without a pending frame being created, and we don't get the
273 // right values for the RFH to navigate: we try to use the old one that has
274 // been deleted in the meantime.
275 contents()->GetMainFrame()->PrepareForCommit();
277 TestRenderFrameHost
* old_rfh
= contents()->GetMainFrame();
278 TestRenderFrameHost
* active_rfh
= contents()->GetPendingMainFrame()
279 ? contents()->GetPendingMainFrame()
281 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, old_rfh
->rfh_state());
283 // Commit the navigation with a new page ID.
284 int32 max_page_id
= contents()->GetMaxPageIDForSiteInstance(
285 active_rfh
->GetSiteInstance());
287 // Use an observer to avoid accessing a deleted renderer later on when the
288 // state is being checked.
289 RenderFrameHostDeletedObserver
rfh_observer(old_rfh
);
290 RenderViewHostDeletedObserver
rvh_observer(old_rfh
->GetRenderViewHost());
291 active_rfh
->SendNavigate(max_page_id
+ 1, url
);
293 // Make sure that we start to run the unload handler at the time of commit.
294 bool expecting_rfh_shutdown
= false;
295 if (old_rfh
!= active_rfh
&& !rfh_observer
.deleted()) {
296 EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT
,
297 old_rfh
->rfh_state());
298 if (!old_rfh
->GetSiteInstance()->active_frame_count()) {
299 expecting_rfh_shutdown
= true;
301 old_rfh
->frame_tree_node()->render_manager()->IsPendingDeletion(
306 // Simulate the swap out ACK coming from the pending renderer. This should
307 // either shut down the old RFH or leave it in a swapped out state.
308 if (old_rfh
!= active_rfh
) {
309 old_rfh
->OnSwappedOut();
310 if (expecting_rfh_shutdown
) {
311 EXPECT_TRUE(rfh_observer
.deleted());
312 EXPECT_TRUE(rvh_observer
.deleted());
314 EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT
,
315 old_rfh
->rfh_state());
318 EXPECT_EQ(active_rfh
, contents()->GetMainFrame());
319 EXPECT_EQ(NULL
, contents()->GetPendingMainFrame());
322 bool ShouldSwapProcesses(RenderFrameHostManager
* manager
,
323 const NavigationEntryImpl
* current_entry
,
324 const NavigationEntryImpl
* new_entry
) const {
326 BrowserContext
* browser_context
=
327 manager
->delegate_
->GetControllerForRenderManager().GetBrowserContext();
328 const GURL
& current_effective_url
= current_entry
?
329 SiteInstanceImpl::GetEffectiveURL(browser_context
,
330 current_entry
->GetURL()) :
331 manager
->render_frame_host_
->GetSiteInstance()->GetSiteURL();
332 bool current_is_view_source_mode
= current_entry
?
333 current_entry
->IsViewSourceMode() : new_entry
->IsViewSourceMode();
334 return manager
->ShouldSwapBrowsingInstancesForNavigation(
335 current_effective_url
,
336 current_is_view_source_mode
,
337 new_entry
->site_instance(),
338 SiteInstanceImpl::GetEffectiveURL(browser_context
, new_entry
->GetURL()),
339 new_entry
->IsViewSourceMode());
342 // Creates a test RenderFrameHost that's swapped out.
343 TestRenderFrameHost
* CreateSwappedOutRenderFrameHost() {
344 const GURL
kChromeURL("chrome://foo");
345 const GURL
kDestUrl("http://www.google.com/");
347 // Navigate our first tab to a chrome url and then to the destination.
348 NavigateActiveAndCommit(kChromeURL
);
349 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
351 // Navigate to a cross-site URL.
352 contents()->GetController().LoadURL(
353 kDestUrl
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
354 contents()->GetMainFrame()->PrepareForCommit();
355 EXPECT_TRUE(contents()->cross_navigation_pending());
357 // Manually increase the number of active frames in the
358 // SiteInstance that ntp_rfh belongs to, to prevent it from being
359 // destroyed when it gets swapped out.
360 ntp_rfh
->GetSiteInstance()->increment_active_frame_count();
362 TestRenderFrameHost
* dest_rfh
= contents()->GetPendingMainFrame();
364 EXPECT_NE(ntp_rfh
, dest_rfh
);
366 // BeforeUnload finishes.
367 ntp_rfh
->SendBeforeUnloadACK(true);
369 dest_rfh
->SendNavigate(101, kDestUrl
);
370 ntp_rfh
->OnSwappedOut();
372 EXPECT_TRUE(ntp_rfh
->is_swapped_out());
376 // Returns the RenderFrameHost that should be used in the navigation to
378 RenderFrameHostImpl
* GetFrameHostForNavigation(
379 RenderFrameHostManager
* manager
,
380 const NavigationEntryImpl
& entry
) {
381 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
382 switches::kEnableBrowserSideNavigation
)) {
383 scoped_ptr
<NavigationRequest
> navigation_request
=
384 NavigationRequest::CreateBrowserInitiated(
385 manager
->frame_tree_node_
, entry
, FrameMsg_Navigate_Type::NORMAL
,
386 base::TimeTicks::Now(),
387 static_cast<NavigationControllerImpl
*>(&controller()));
388 return manager
->GetFrameHostForNavigation(*navigation_request
);
390 return manager
->Navigate(entry
);
393 // Returns the pending RenderFrameHost.
394 // PlzNavigate: returns the speculative RenderFrameHost.
395 RenderFrameHostImpl
* GetPendingFrameHost(
396 RenderFrameHostManager
* manager
) {
397 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
398 switches::kEnableBrowserSideNavigation
)) {
399 return manager
->speculative_render_frame_host_
.get();
401 return manager
->pending_frame_host();
404 void CrashFrame(TestRenderFrameHost
* frame
) {
405 // TODO(nick): Standardize how we simulate crashes in content unittests. The
406 // test method |set_render_view_created| should probably be eliminated
407 // altogether, and maybe there should be a CrashProcess() method on
408 // MockRenderProcessHost.
409 ASSERT_TRUE(frame
->IsRenderFrameLive());
410 frame
->OnMessageReceived(FrameHostMsg_RenderProcessGone(
411 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
412 RenderProcessHost::RendererClosedDetails
details(
413 base::TERMINATION_STATUS_PROCESS_CRASHED
, 0);
414 NotificationService::current()->Notify(
415 NOTIFICATION_RENDERER_PROCESS_CLOSED
,
416 Source
<RenderProcessHost
>(frame
->GetProcess()),
417 Details
<RenderProcessHost::RendererClosedDetails
>(&details
));
418 frame
->GetRenderViewHost()->set_render_view_created(false);
419 ASSERT_FALSE(frame
->IsRenderFrameLive());
423 RenderFrameHostManagerTestWebUIControllerFactory factory_
;
426 // Tests that when you navigate from a chrome:// url to another page, and
427 // then do that same thing in another tab, that the two resulting pages have
428 // different SiteInstances, BrowsingInstances, and RenderProcessHosts. This is
429 // a regression test for bug 9364.
430 TEST_F(RenderFrameHostManagerTest
, NewTabPageProcesses
) {
431 set_should_create_webui(true);
432 const GURL
kChromeUrl("chrome://foo");
433 const GURL
kDestUrl("http://www.google.com/");
435 // Navigate our first tab to the chrome url and then to the destination,
436 // ensuring we grant bindings to the chrome URL.
437 NavigateActiveAndCommit(kChromeUrl
);
438 EXPECT_TRUE(active_rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
439 NavigateActiveAndCommit(kDestUrl
);
441 EXPECT_FALSE(contents()->GetPendingMainFrame());
443 // Make a second tab.
444 scoped_ptr
<TestWebContents
> contents2(
445 TestWebContents::Create(browser_context(), NULL
));
447 // Load the two URLs in the second tab. Note that the first navigation creates
448 // a RFH that's not pending (since there is no cross-site transition), so
449 // we use the committed one.
450 contents2
->GetController().LoadURL(
451 kChromeUrl
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
452 contents2
->GetMainFrame()->PrepareForCommit();
453 TestRenderFrameHost
* ntp_rfh2
= contents2
->GetMainFrame();
454 EXPECT_FALSE(contents2
->cross_navigation_pending());
455 ntp_rfh2
->SendNavigate(100, kChromeUrl
);
457 // The second one is the opposite, creating a cross-site transition and
458 // requiring a beforeunload ack.
459 contents2
->GetController().LoadURL(
460 kDestUrl
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
461 contents2
->GetMainFrame()->PrepareForCommit();
462 EXPECT_TRUE(contents2
->cross_navigation_pending());
463 TestRenderFrameHost
* dest_rfh2
= contents2
->GetPendingMainFrame();
464 ASSERT_TRUE(dest_rfh2
);
466 dest_rfh2
->SendNavigate(101, kDestUrl
);
468 // The two RFH's should be different in every way.
469 EXPECT_NE(contents()->GetMainFrame()->GetProcess(), dest_rfh2
->GetProcess());
470 EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
471 dest_rfh2
->GetSiteInstance());
472 EXPECT_FALSE(dest_rfh2
->GetSiteInstance()->IsRelatedSiteInstance(
473 contents()->GetMainFrame()->GetSiteInstance()));
475 // Navigate both to the new tab page, and verify that they share a
476 // RenderProcessHost (not a SiteInstance).
477 NavigateActiveAndCommit(kChromeUrl
);
478 EXPECT_FALSE(contents()->GetPendingMainFrame());
480 contents2
->GetController().LoadURL(
481 kChromeUrl
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
482 contents2
->GetMainFrame()->PrepareForCommit();
483 contents2
->GetPendingMainFrame()->SendNavigate(102, kChromeUrl
);
485 EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
486 contents2
->GetMainFrame()->GetSiteInstance());
487 EXPECT_EQ(contents()->GetMainFrame()->GetSiteInstance()->GetProcess(),
488 contents2
->GetMainFrame()->GetSiteInstance()->GetProcess());
491 // Ensure that the browser ignores most IPC messages that arrive from a
492 // RenderViewHost that has been swapped out. We do not want to take
493 // action on requests from a non-active renderer. The main exception is
494 // for synchronous messages, which cannot be ignored without leaving the
495 // renderer in a stuck state. See http://crbug.com/93427.
496 TEST_F(RenderFrameHostManagerTest
, FilterMessagesWhileSwappedOut
) {
497 const GURL
kChromeURL("chrome://foo");
498 const GURL
kDestUrl("http://www.google.com/");
499 std::vector
<FaviconURL
> icons
;
501 // Navigate our first tab to a chrome url and then to the destination.
502 NavigateActiveAndCommit(kChromeURL
);
503 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
505 // Send an update favicon message and make sure it works.
506 const base::string16 ntp_title
= base::ASCIIToUTF16("NTP Title");
508 PluginFaviconMessageObserver
observer(contents());
509 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->OnMessageReceived(
510 ViewHostMsg_UpdateFaviconURL(
511 ntp_rfh
->GetRenderViewHost()->GetRoutingID(), icons
)));
512 EXPECT_TRUE(observer
.favicon_received());
514 // Create one more frame in the same SiteInstance where ntp_rfh
515 // exists so that it doesn't get deleted on navigation to another
517 ntp_rfh
->GetSiteInstance()->increment_active_frame_count();
520 // Navigate to a cross-site URL.
521 NavigateActiveAndCommit(kDestUrl
);
522 TestRenderFrameHost
* dest_rfh
= contents()->GetMainFrame();
523 ASSERT_TRUE(dest_rfh
);
524 EXPECT_NE(ntp_rfh
, dest_rfh
);
526 // The new RVH should be able to update its favicon.
527 const base::string16 dest_title
= base::ASCIIToUTF16("Google");
529 PluginFaviconMessageObserver
observer(contents());
531 dest_rfh
->GetRenderViewHost()->OnMessageReceived(
532 ViewHostMsg_UpdateFaviconURL(
533 dest_rfh
->GetRenderViewHost()->GetRoutingID(), icons
)));
534 EXPECT_TRUE(observer
.favicon_received());
537 // The old renderer, being slow, now updates the favicon. It should be
538 // filtered out and not take effect.
539 EXPECT_TRUE(ntp_rfh
->is_swapped_out());
541 PluginFaviconMessageObserver
observer(contents());
543 ntp_rfh
->GetRenderViewHost()->OnMessageReceived(
544 ViewHostMsg_UpdateFaviconURL(
545 dest_rfh
->GetRenderViewHost()->GetRoutingID(), icons
)));
546 EXPECT_FALSE(observer
.favicon_received());
549 #if defined(ENABLE_PLUGINS)
550 // The same logic should apply to RenderFrameHosts as well and routing through
551 // swapped out RFH shouldn't be allowed. Use a PluginCrashObserver to check
552 // if the IPC message is allowed through or not.
554 PluginFaviconMessageObserver
observer(contents());
555 EXPECT_TRUE(ntp_rfh
->OnMessageReceived(
556 FrameHostMsg_PluginCrashed(
557 ntp_rfh
->GetRoutingID(), base::FilePath(), 0)));
558 EXPECT_FALSE(observer
.plugin_crashed());
562 // We cannot filter out synchronous IPC messages, because the renderer would
563 // be left waiting for a reply. We pick RunBeforeUnloadConfirm as an example
564 // that can run easily within a unit test, and that needs to receive a reply
565 // without showing an actual dialog.
566 MockRenderProcessHost
* ntp_process_host
=
567 static_cast<MockRenderProcessHost
*>(ntp_rfh
->GetProcess());
568 ntp_process_host
->sink().ClearMessages();
569 const base::string16 msg
= base::ASCIIToUTF16("Message");
571 base::string16 unused
;
572 FrameHostMsg_RunBeforeUnloadConfirm
before_unload_msg(
573 ntp_rfh
->GetRoutingID(), kChromeURL
, msg
, false, &result
, &unused
);
574 // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
575 before_unload_msg
.EnableMessagePumping();
576 EXPECT_TRUE(ntp_rfh
->OnMessageReceived(before_unload_msg
));
577 EXPECT_TRUE(ntp_process_host
->sink().GetUniqueMessageMatching(IPC_REPLY_ID
));
579 // Also test RunJavaScriptMessage.
580 ntp_process_host
->sink().ClearMessages();
581 FrameHostMsg_RunJavaScriptMessage
js_msg(
582 ntp_rfh
->GetRoutingID(), msg
, msg
, kChromeURL
,
583 JAVASCRIPT_MESSAGE_TYPE_CONFIRM
, &result
, &unused
);
584 js_msg
.EnableMessagePumping();
585 EXPECT_TRUE(ntp_rfh
->OnMessageReceived(js_msg
));
586 EXPECT_TRUE(ntp_process_host
->sink().GetUniqueMessageMatching(IPC_REPLY_ID
));
589 // Ensure that frames aren't added to the frame tree, if the message is coming
590 // from a process different than the parent frame's current RenderFrameHost
591 // process. Otherwise it is possible to have collisions of routing ids, as they
592 // are scoped per process. See https://crbug.com/415059.
593 TEST_F(RenderFrameHostManagerTest
, DropCreateChildFrameWhileSwappedOut
) {
594 const GURL
kUrl1("http://foo.com");
595 const GURL
kUrl2("http://www.google.com/");
597 // Navigate to the first site.
598 NavigateActiveAndCommit(kUrl1
);
599 TestRenderFrameHost
* initial_rfh
= contents()->GetMainFrame();
601 RenderFrameHostCreatedObserver
observer(contents());
602 initial_rfh
->OnCreateChildFrame(
603 initial_rfh
->GetProcess()->GetNextRoutingID(), std::string(),
605 EXPECT_TRUE(observer
.created());
608 // Create one more frame in the same SiteInstance where initial_rfh
609 // exists so that initial_rfh doesn't get deleted on navigation to another
611 initial_rfh
->GetSiteInstance()->increment_active_frame_count();
613 // Navigate to a cross-site URL.
614 NavigateActiveAndCommit(kUrl2
);
615 EXPECT_TRUE(initial_rfh
->is_swapped_out());
617 TestRenderFrameHost
* dest_rfh
= contents()->GetMainFrame();
618 ASSERT_TRUE(dest_rfh
);
619 EXPECT_NE(initial_rfh
, dest_rfh
);
622 // Since the old RFH is now swapped out, it shouldn't process any messages
623 // to create child frames.
624 RenderFrameHostCreatedObserver
observer(contents());
625 initial_rfh
->OnCreateChildFrame(
626 initial_rfh
->GetProcess()->GetNextRoutingID(), std::string(),
628 EXPECT_FALSE(observer
.created());
632 TEST_F(RenderFrameHostManagerTest
, WhiteListSwapCompositorFrame
) {
633 TestRenderFrameHost
* swapped_out_rfh
= CreateSwappedOutRenderFrameHost();
634 TestRenderWidgetHostView
* swapped_out_rwhv
=
635 static_cast<TestRenderWidgetHostView
*>(
636 swapped_out_rfh
->GetRenderViewHost()->GetView());
637 EXPECT_FALSE(swapped_out_rwhv
->did_swap_compositor_frame());
639 MockRenderProcessHost
* process_host
=
640 static_cast<MockRenderProcessHost
*>(swapped_out_rfh
->GetProcess());
641 process_host
->sink().ClearMessages();
643 cc::CompositorFrame frame
;
644 ViewHostMsg_SwapCompositorFrame
msg(
645 rvh()->GetRoutingID(), 0, frame
, std::vector
<IPC::Message
>());
647 EXPECT_TRUE(swapped_out_rfh
->render_view_host()->OnMessageReceived(msg
));
648 EXPECT_TRUE(swapped_out_rwhv
->did_swap_compositor_frame());
651 // Test if RenderViewHost::GetRenderWidgetHosts() only returns active
653 TEST_F(RenderFrameHostManagerTest
, GetRenderWidgetHostsReturnsActiveViews
) {
654 TestRenderFrameHost
* swapped_out_rfh
= CreateSwappedOutRenderFrameHost();
655 EXPECT_TRUE(swapped_out_rfh
->is_swapped_out());
657 scoped_ptr
<RenderWidgetHostIterator
> widgets(
658 RenderWidgetHost::GetRenderWidgetHosts());
659 // We know that there is the only one active widget. Another view is
660 // now swapped out, so the swapped out view is not included in the
662 RenderWidgetHost
* widget
= widgets
->GetNextHost();
663 EXPECT_FALSE(widgets
->GetNextHost());
664 RenderViewHost
* rvh
= RenderViewHost::From(widget
);
665 EXPECT_TRUE(static_cast<RenderViewHostImpl
*>(rvh
)->is_active());
668 // Test if RenderViewHost::GetRenderWidgetHosts() returns a subset of
669 // RenderViewHostImpl::GetAllRenderWidgetHosts().
670 // RenderViewHost::GetRenderWidgetHosts() returns only active widgets, but
671 // RenderViewHostImpl::GetAllRenderWidgetHosts() returns everything
672 // including swapped out ones.
673 TEST_F(RenderFrameHostManagerTest
,
674 GetRenderWidgetHostsWithinGetAllRenderWidgetHosts
) {
675 TestRenderFrameHost
* swapped_out_rfh
= CreateSwappedOutRenderFrameHost();
676 EXPECT_TRUE(swapped_out_rfh
->is_swapped_out());
678 scoped_ptr
<RenderWidgetHostIterator
> widgets(
679 RenderWidgetHost::GetRenderWidgetHosts());
681 while (RenderWidgetHost
* w
= widgets
->GetNextHost()) {
683 scoped_ptr
<RenderWidgetHostIterator
> all_widgets(
684 RenderWidgetHostImpl::GetAllRenderWidgetHosts());
685 while (RenderWidgetHost
* widget
= all_widgets
->GetNextHost()) {
695 // Test if SiteInstanceImpl::active_frame_count() is correctly updated
696 // as frames in a SiteInstance get swapped out and in.
697 TEST_F(RenderFrameHostManagerTest
, ActiveFrameCountWhileSwappingInAndOut
) {
698 const GURL
kUrl1("http://www.google.com/");
699 const GURL
kUrl2("http://www.chromium.org/");
701 // Navigate to an initial URL.
702 contents()->NavigateAndCommit(kUrl1
);
703 TestRenderFrameHost
* rfh1
= main_test_rfh();
705 SiteInstanceImpl
* instance1
= rfh1
->GetSiteInstance();
706 EXPECT_EQ(instance1
->active_frame_count(), 1U);
708 // Create 2 new tabs and simulate them being the opener chain for the main
709 // tab. They should be in the same SiteInstance.
710 scoped_ptr
<TestWebContents
> opener1(
711 TestWebContents::Create(browser_context(), instance1
));
712 contents()->SetOpener(opener1
.get());
714 scoped_ptr
<TestWebContents
> opener2(
715 TestWebContents::Create(browser_context(), instance1
));
716 opener1
->SetOpener(opener2
.get());
718 EXPECT_EQ(instance1
->active_frame_count(), 3U);
720 // Navigate to a cross-site URL (different SiteInstance but same
721 // BrowsingInstance).
722 contents()->NavigateAndCommit(kUrl2
);
723 TestRenderFrameHost
* rfh2
= main_test_rfh();
724 SiteInstanceImpl
* instance2
= rfh2
->GetSiteInstance();
726 // rvh2 is on chromium.org which is different from google.com on
727 // which other tabs are.
728 EXPECT_EQ(instance2
->active_frame_count(), 1U);
730 // There are two active views on google.com now.
731 EXPECT_EQ(instance1
->active_frame_count(), 2U);
733 // Navigate to the original origin (google.com).
734 contents()->NavigateAndCommit(kUrl1
);
736 EXPECT_EQ(instance1
->active_frame_count(), 3U);
739 // This deletes a WebContents when the given RVH is deleted. This is
740 // only for testing whether deleting an RVH does not cause any UaF in
741 // other parts of the system. For now, this class is only used for the
742 // next test cases to detect the bug mentioned at
743 // http://crbug.com/259859.
744 class RenderViewHostDestroyer
: public WebContentsObserver
{
746 RenderViewHostDestroyer(RenderViewHost
* render_view_host
,
747 WebContents
* web_contents
)
748 : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host
)),
749 render_view_host_(render_view_host
),
750 web_contents_(web_contents
) {}
752 void RenderViewDeleted(RenderViewHost
* render_view_host
) override
{
753 if (render_view_host
== render_view_host_
)
754 delete web_contents_
;
758 RenderViewHost
* render_view_host_
;
759 WebContents
* web_contents_
;
761 DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestroyer
);
764 // Test if ShutdownRenderViewHostsInSiteInstance() does not touch any
765 // RenderWidget that has been freed while deleting a RenderViewHost in
766 // a previous iteration. This is a regression test for
767 // http://crbug.com/259859.
768 TEST_F(RenderFrameHostManagerTest
,
769 DetectUseAfterFreeInShutdownRenderViewHostsInSiteInstance
) {
770 const GURL
kChromeURL("chrome://newtab");
771 const GURL
kUrl1("http://www.google.com");
772 const GURL
kUrl2("http://www.chromium.org");
774 // Navigate our first tab to a chrome url and then to the destination.
775 NavigateActiveAndCommit(kChromeURL
);
776 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
778 // Create one more tab and navigate to kUrl1. web_contents is not
779 // wrapped as scoped_ptr since it intentionally deleted by destroyer
780 // below as part of this test.
781 TestWebContents
* web_contents
=
782 TestWebContents::Create(browser_context(), ntp_rfh
->GetSiteInstance());
783 web_contents
->NavigateAndCommit(kUrl1
);
784 RenderViewHostDestroyer
destroyer(ntp_rfh
->GetRenderViewHost(),
787 // This causes the first tab to navigate to kUrl2, which destroys
788 // the ntp_rfh in ShutdownRenderViewHostsInSiteInstance(). When
789 // ntp_rfh is destroyed, it also destroys the RVHs in web_contents
790 // too. This can test whether
791 // SiteInstanceImpl::ShutdownRenderViewHostsInSiteInstance() can
792 // touch any object freed in this way or not while iterating through
794 contents()->NavigateAndCommit(kUrl2
);
797 // When there is an error with the specified page, renderer exits view-source
798 // mode. See WebFrameImpl::DidFail(). We check by this test that
799 // EnableViewSourceMode message is sent on every navigation regardless
800 // RenderView is being newly created or reused.
801 TEST_F(RenderFrameHostManagerTest
, AlwaysSendEnableViewSourceMode
) {
802 const GURL
kChromeUrl("chrome://foo");
803 const GURL
kUrl("view-source:http://foo");
805 // We have to navigate to some page at first since without this, the first
806 // navigation will reuse the SiteInstance created by Init(), and the second
807 // one will create a new SiteInstance. Because current_instance and
808 // new_instance will be different, a new RenderViewHost will be created for
809 // the second navigation. We have to avoid this in order to exercise the
810 // target code patch.
811 NavigateActiveAndCommit(kChromeUrl
);
814 controller().LoadURL(
815 kUrl
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
816 // Simulate response from RenderFrame for DispatchBeforeUnload.
817 contents()->GetMainFrame()->PrepareForCommit();
818 ASSERT_TRUE(contents()->GetPendingMainFrame())
819 << "Expected new pending RenderFrameHost to be created.";
820 RenderFrameHost
* last_rfh
= contents()->GetPendingMainFrame();
822 contents()->GetMaxPageIDForSiteInstance(last_rfh
->GetSiteInstance()) + 1;
823 contents()->GetPendingMainFrame()->SendNavigate(new_id
, kUrl
);
824 EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
825 ASSERT_TRUE(controller().GetLastCommittedEntry());
826 EXPECT_TRUE(kUrl
== controller().GetLastCommittedEntry()->GetURL());
827 EXPECT_FALSE(controller().GetPendingEntry());
828 // Because we're using TestWebContents and TestRenderViewHost in this
829 // unittest, no one calls WebContentsImpl::RenderViewCreated(). So, we see no
830 // EnableViewSourceMode message, here.
832 // Clear queued messages before load.
833 process()->sink().ClearMessages();
835 controller().LoadURL(
836 kUrl
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
837 contents()->GetMainFrame()->PrepareForCommit();
838 // The same RenderViewHost should be reused.
839 EXPECT_FALSE(contents()->GetPendingMainFrame());
840 EXPECT_TRUE(last_rfh
== contents()->GetMainFrame());
841 // Navigate using the returned page_id.
842 contents()->GetMainFrame()->SendNavigate(new_id
, kUrl
);
843 EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
844 EXPECT_FALSE(controller().GetPendingEntry());
845 // New message should be sent out to make sure to enter view-source mode.
846 EXPECT_TRUE(process()->sink().GetUniqueMessageMatching(
847 ViewMsg_EnableViewSourceMode::ID
));
850 // Tests the Init function by checking the initial RenderViewHost.
851 TEST_F(RenderFrameHostManagerTest
, Init
) {
852 // Using TestBrowserContext.
853 SiteInstanceImpl
* instance
=
854 static_cast<SiteInstanceImpl
*>(SiteInstance::Create(browser_context()));
855 EXPECT_FALSE(instance
->HasSite());
857 scoped_ptr
<TestWebContents
> web_contents(
858 TestWebContents::Create(browser_context(), instance
));
860 RenderFrameHostManager
* manager
= web_contents
->GetRenderManagerForTesting();
861 RenderViewHostImpl
* rvh
= manager
->current_host();
862 RenderFrameHostImpl
* rfh
= manager
->current_frame_host();
865 EXPECT_EQ(rvh
, rfh
->render_view_host());
866 EXPECT_EQ(instance
, rvh
->GetSiteInstance());
867 EXPECT_EQ(web_contents
.get(), rvh
->GetDelegate());
868 EXPECT_EQ(web_contents
.get(), rfh
->delegate());
869 EXPECT_TRUE(manager
->GetRenderWidgetHostView());
870 EXPECT_FALSE(manager
->pending_render_view_host());
873 // Tests the Navigate function. We navigate three sites consecutively and check
874 // how the pending/committed RenderViewHost are modified.
875 TEST_F(RenderFrameHostManagerTest
, Navigate
) {
876 TestNotificationTracker notifications
;
878 SiteInstance
* instance
= SiteInstance::Create(browser_context());
880 scoped_ptr
<TestWebContents
> web_contents(
881 TestWebContents::Create(browser_context(), instance
));
882 notifications
.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
883 Source
<WebContents
>(web_contents
.get()));
885 RenderFrameHostManager
* manager
= web_contents
->GetRenderManagerForTesting();
886 RenderFrameHostImpl
* host
= NULL
;
888 // 1) The first navigation. --------------------------
889 const GURL
kUrl1("http://www.google.com/");
890 NavigationEntryImpl
entry1(
891 NULL
/* instance */, -1 /* page_id */, kUrl1
, Referrer(),
892 base::string16() /* title */, ui::PAGE_TRANSITION_TYPED
,
893 false /* is_renderer_init */);
894 host
= GetFrameHostForNavigation(manager
, entry1
);
896 // The RenderFrameHost created in Init will be reused.
897 EXPECT_TRUE(host
== manager
->current_frame_host());
898 EXPECT_FALSE(GetPendingFrameHost(manager
));
901 manager
->DidNavigateFrame(host
, true);
902 // Commit to SiteInstance should be delayed until RenderFrame commit.
903 EXPECT_TRUE(host
== manager
->current_frame_host());
905 EXPECT_FALSE(host
->GetSiteInstance()->HasSite());
906 host
->GetSiteInstance()->SetSite(kUrl1
);
908 // 2) Navigate to next site. -------------------------
909 const GURL
kUrl2("http://www.google.com/foo");
910 NavigationEntryImpl
entry2(
911 NULL
/* instance */, -1 /* page_id */, kUrl2
,
912 Referrer(kUrl1
, blink::WebReferrerPolicyDefault
),
913 base::string16() /* title */, ui::PAGE_TRANSITION_LINK
,
914 true /* is_renderer_init */);
915 host
= GetFrameHostForNavigation(manager
, entry2
);
917 // The RenderFrameHost created in Init will be reused.
918 EXPECT_TRUE(host
== manager
->current_frame_host());
919 EXPECT_FALSE(GetPendingFrameHost(manager
));
922 manager
->DidNavigateFrame(host
, true);
923 EXPECT_TRUE(host
== manager
->current_frame_host());
925 EXPECT_TRUE(host
->GetSiteInstance()->HasSite());
927 // 3) Cross-site navigate to next site. --------------
928 const GURL
kUrl3("http://webkit.org/");
929 NavigationEntryImpl
entry3(
930 NULL
/* instance */, -1 /* page_id */, kUrl3
,
931 Referrer(kUrl2
, blink::WebReferrerPolicyDefault
),
932 base::string16() /* title */, ui::PAGE_TRANSITION_LINK
,
933 false /* is_renderer_init */);
934 host
= GetFrameHostForNavigation(manager
, entry3
);
936 // A new RenderFrameHost should be created.
937 EXPECT_TRUE(GetPendingFrameHost(manager
));
938 ASSERT_EQ(host
, GetPendingFrameHost(manager
));
940 notifications
.Reset();
943 manager
->DidNavigateFrame(GetPendingFrameHost(manager
), true);
944 EXPECT_TRUE(host
== manager
->current_frame_host());
946 EXPECT_TRUE(host
->GetSiteInstance()->HasSite());
947 // Check the pending RenderFrameHost has been committed.
948 EXPECT_FALSE(GetPendingFrameHost(manager
));
950 // We should observe a notification.
952 notifications
.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED
));
955 // Tests WebUI creation.
956 TEST_F(RenderFrameHostManagerTest
, WebUI
) {
957 set_should_create_webui(true);
958 SiteInstance
* instance
= SiteInstance::Create(browser_context());
960 scoped_ptr
<TestWebContents
> web_contents(
961 TestWebContents::Create(browser_context(), instance
));
962 RenderFrameHostManager
* manager
= web_contents
->GetRenderManagerForTesting();
963 RenderFrameHostImpl
* initial_rfh
= manager
->current_frame_host();
965 EXPECT_FALSE(manager
->current_host()->IsRenderViewLive());
966 EXPECT_FALSE(manager
->web_ui());
967 EXPECT_TRUE(initial_rfh
);
969 const GURL
kUrl("chrome://foo");
970 NavigationEntryImpl
entry(NULL
/* instance */, -1 /* page_id */, kUrl
,
971 Referrer(), base::string16() /* title */,
972 ui::PAGE_TRANSITION_TYPED
,
973 false /* is_renderer_init */);
974 RenderFrameHostImpl
* host
= GetFrameHostForNavigation(manager
, entry
);
976 // We commit the pending RenderFrameHost immediately because the previous
977 // RenderFrameHost was not live. We test a case where it is live in
980 EXPECT_NE(initial_rfh
, host
);
981 EXPECT_EQ(host
, manager
->current_frame_host());
982 EXPECT_FALSE(GetPendingFrameHost(manager
));
984 // It's important that the SiteInstance get set on the Web UI page as soon
985 // as the navigation starts, rather than lazily after it commits, so we don't
986 // try to re-use the SiteInstance/process for non Web UI things that may
987 // get loaded in between.
988 EXPECT_TRUE(host
->GetSiteInstance()->HasSite());
989 EXPECT_EQ(kUrl
, host
->GetSiteInstance()->GetSiteURL());
991 // The Web UI is committed immediately because the RenderViewHost has not been
992 // used yet. UpdateStateForNavigate() took the short cut path.
993 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
994 switches::kEnableBrowserSideNavigation
)) {
995 EXPECT_FALSE(manager
->speculative_web_ui());
997 EXPECT_FALSE(manager
->pending_web_ui());
999 EXPECT_TRUE(manager
->web_ui());
1002 manager
->DidNavigateFrame(host
, true);
1004 host
->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1007 // Tests that we can open a WebUI link in a new tab from a WebUI page and still
1008 // grant the correct bindings. http://crbug.com/189101.
1009 TEST_F(RenderFrameHostManagerTest
, WebUIInNewTab
) {
1010 set_should_create_webui(true);
1011 SiteInstance
* blank_instance
= SiteInstance::Create(browser_context());
1013 // Create a blank tab.
1014 scoped_ptr
<TestWebContents
> web_contents1(
1015 TestWebContents::Create(browser_context(), blank_instance
));
1016 RenderFrameHostManager
* manager1
=
1017 web_contents1
->GetRenderManagerForTesting();
1018 // Test the case that new RVH is considered live.
1019 manager1
->current_host()->CreateRenderView(
1020 base::string16(), -1, MSG_ROUTING_NONE
, -1, false);
1021 EXPECT_TRUE(manager1
->current_host()->IsRenderViewLive());
1022 EXPECT_TRUE(manager1
->current_frame_host()->IsRenderFrameLive());
1024 // Navigate to a WebUI page.
1025 const GURL
kUrl1("chrome://foo");
1026 NavigationEntryImpl
entry1(NULL
/* instance */, -1 /* page_id */, kUrl1
,
1027 Referrer(), base::string16() /* title */,
1028 ui::PAGE_TRANSITION_TYPED
,
1029 false /* is_renderer_init */);
1030 RenderFrameHostImpl
* host1
= GetFrameHostForNavigation(manager1
, entry1
);
1032 // We should have a pending navigation to the WebUI RenderViewHost.
1033 // It should already have bindings.
1034 EXPECT_EQ(host1
, GetPendingFrameHost(manager1
));
1035 EXPECT_NE(host1
, manager1
->current_frame_host());
1037 host1
->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1039 // Commit and ensure we still have bindings.
1040 manager1
->DidNavigateFrame(host1
, true);
1041 SiteInstance
* webui_instance
= host1
->GetSiteInstance();
1042 EXPECT_EQ(host1
, manager1
->current_frame_host());
1044 host1
->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1046 // Now simulate clicking a link that opens in a new tab.
1047 scoped_ptr
<TestWebContents
> web_contents2(
1048 TestWebContents::Create(browser_context(), webui_instance
));
1049 RenderFrameHostManager
* manager2
=
1050 web_contents2
->GetRenderManagerForTesting();
1051 // Make sure the new RVH is considered live. This is usually done in
1052 // RenderWidgetHost::Init when opening a new tab from a link.
1053 manager2
->current_host()->CreateRenderView(
1054 base::string16(), -1, MSG_ROUTING_NONE
, -1, false);
1055 EXPECT_TRUE(manager2
->current_host()->IsRenderViewLive());
1057 const GURL
kUrl2("chrome://foo/bar");
1058 NavigationEntryImpl
entry2(NULL
/* instance */, -1 /* page_id */, kUrl2
,
1059 Referrer(), base::string16() /* title */,
1060 ui::PAGE_TRANSITION_LINK
,
1061 true /* is_renderer_init */);
1062 RenderFrameHostImpl
* host2
= GetFrameHostForNavigation(manager2
, entry2
);
1064 // No cross-process transition happens because we are already in the right
1065 // SiteInstance. We should grant bindings immediately.
1066 EXPECT_EQ(host2
, manager2
->current_frame_host());
1067 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1068 switches::kEnableBrowserSideNavigation
)) {
1069 EXPECT_TRUE(manager2
->speculative_web_ui());
1071 EXPECT_TRUE(manager2
->pending_web_ui());
1074 host2
->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1076 manager2
->DidNavigateFrame(host2
, true);
1079 // Tests that we don't end up in an inconsistent state if a page does a back and
1080 // then reload. http://crbug.com/51680
1081 // Also tests that only user-gesture navigations can interrupt cross-process
1082 // navigations. http://crbug.com/75195
1083 TEST_F(RenderFrameHostManagerTest
, PageDoesBackAndReload
) {
1084 const GURL
kUrl1("http://www.google.com/");
1085 const GURL
kUrl2("http://www.evil-site.com/");
1087 // Navigate to a safe site, then an evil site.
1088 // This will switch RenderFrameHosts. We cannot assert that the first and
1089 // second RFHs are different, though, because the first one may be promptly
1091 contents()->NavigateAndCommit(kUrl1
);
1092 contents()->NavigateAndCommit(kUrl2
);
1093 TestRenderFrameHost
* evil_rfh
= contents()->GetMainFrame();
1095 // Now let's simulate the evil page calling history.back().
1096 contents()->OnGoToEntryAtOffset(-1);
1097 contents()->GetMainFrame()->PrepareForCommit();
1098 // We should have a new pending RFH.
1099 // Note that in this case, the navigation has not committed, so evil_rfh will
1100 // not be deleted yet.
1101 EXPECT_NE(evil_rfh
, contents()->GetPendingMainFrame());
1102 EXPECT_NE(evil_rfh
->GetRenderViewHost(),
1103 contents()->GetPendingMainFrame()->GetRenderViewHost());
1105 // Before that RFH has committed, the evil page reloads itself.
1106 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1109 params
.transition
= ui::PAGE_TRANSITION_CLIENT_REDIRECT
;
1110 params
.should_update_history
= false;
1111 params
.gesture
= NavigationGestureAuto
;
1112 params
.was_within_same_page
= false;
1113 params
.is_post
= false;
1114 params
.page_state
= PageState::CreateFromURL(kUrl2
);
1116 contents()->GetFrameTree()->root()->navigator()->DidNavigate(evil_rfh
,
1119 // That should NOT have cancelled the pending RFH, because the reload did
1120 // not have a user gesture. Thus, the pending back navigation will still
1121 // eventually commit.
1122 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
1123 pending_render_view_host() != NULL
);
1124 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->pending_frame_host() !=
1127 contents()->GetRenderManagerForTesting()->current_frame_host());
1128 EXPECT_EQ(evil_rfh
->GetRenderViewHost(),
1129 contents()->GetRenderManagerForTesting()->current_host());
1131 // Also we should not have a pending navigation entry.
1132 EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL
);
1133 NavigationEntry
* entry
= contents()->GetController().GetVisibleEntry();
1134 ASSERT_TRUE(entry
!= NULL
);
1135 EXPECT_EQ(kUrl2
, entry
->GetURL());
1137 // Now do the same but as a user gesture.
1138 params
.gesture
= NavigationGestureUser
;
1139 contents()->GetFrameTree()->root()->navigator()->DidNavigate(evil_rfh
,
1142 // User navigation should have cancelled the pending RFH.
1143 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
1144 pending_render_view_host() == NULL
);
1145 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->pending_frame_host() ==
1148 contents()->GetRenderManagerForTesting()->current_frame_host());
1149 EXPECT_EQ(evil_rfh
->GetRenderViewHost(),
1150 contents()->GetRenderManagerForTesting()->current_host());
1152 // Also we should not have a pending navigation entry.
1153 EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL
);
1154 entry
= contents()->GetController().GetVisibleEntry();
1155 ASSERT_TRUE(entry
!= NULL
);
1156 EXPECT_EQ(kUrl2
, entry
->GetURL());
1159 // Ensure that we can go back and forward even if a SwapOut ACK isn't received.
1160 // See http://crbug.com/93427.
1161 TEST_F(RenderFrameHostManagerTest
, NavigateAfterMissingSwapOutACK
) {
1162 const GURL
kUrl1("http://www.google.com/");
1163 const GURL
kUrl2("http://www.chromium.org/");
1165 // Navigate to two pages.
1166 contents()->NavigateAndCommit(kUrl1
);
1167 TestRenderFrameHost
* rfh1
= main_test_rfh();
1169 // Keep active_frame_count nonzero so that no swapped out frames in
1170 // this SiteInstance get forcefully deleted.
1171 rfh1
->GetSiteInstance()->increment_active_frame_count();
1173 contents()->NavigateAndCommit(kUrl2
);
1174 TestRenderFrameHost
* rfh2
= main_test_rfh();
1175 rfh2
->GetSiteInstance()->increment_active_frame_count();
1177 // Now go back, but suppose the SwapOut_ACK isn't received. This shouldn't
1178 // happen, but we have seen it when going back quickly across many entries
1179 // (http://crbug.com/93427).
1180 contents()->GetController().GoBack();
1181 EXPECT_TRUE(rfh2
->IsWaitingForBeforeUnloadACK());
1182 contents()->GetMainFrame()->PrepareForCommit();
1183 EXPECT_FALSE(rfh2
->IsWaitingForBeforeUnloadACK());
1185 // The back navigation commits.
1186 const NavigationEntry
* entry1
= contents()->GetController().GetPendingEntry();
1187 rfh1
->SendNavigate(entry1
->GetPageID(), entry1
->GetURL());
1188 EXPECT_TRUE(rfh2
->IsWaitingForUnloadACK());
1189 EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT
, rfh2
->rfh_state());
1191 // We should be able to navigate forward.
1192 contents()->GetController().GoForward();
1193 contents()->GetMainFrame()->PrepareForCommit();
1194 const NavigationEntry
* entry2
= contents()->GetController().GetPendingEntry();
1195 rfh2
->SendNavigate(entry2
->GetPageID(), entry2
->GetURL());
1196 EXPECT_EQ(rfh2
, main_test_rfh());
1197 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh2
->rfh_state());
1198 EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT
, rfh1
->rfh_state());
1199 rfh1
->OnSwappedOut();
1200 EXPECT_TRUE(rfh1
->is_swapped_out());
1201 EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT
, rfh1
->rfh_state());
1204 // Test that we create swapped out RFHs for the opener chain when navigating an
1205 // opened tab cross-process. This allows us to support certain cross-process
1206 // JavaScript calls (http://crbug.com/99202).
1207 TEST_F(RenderFrameHostManagerTest
, CreateSwappedOutOpenerRFHs
) {
1208 const GURL
kUrl1("http://www.google.com/");
1209 const GURL
kUrl2("http://www.chromium.org/");
1210 const GURL
kChromeUrl("chrome://foo");
1212 // Navigate to an initial URL.
1213 contents()->NavigateAndCommit(kUrl1
);
1214 RenderFrameHostManager
* manager
= contents()->GetRenderManagerForTesting();
1215 TestRenderFrameHost
* rfh1
= main_test_rfh();
1216 TestRenderViewHost
* rvh1
= test_rvh();
1218 // Create 2 new tabs and simulate them being the opener chain for the main
1219 // tab. They should be in the same SiteInstance.
1220 scoped_ptr
<TestWebContents
> opener1(
1221 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1222 RenderFrameHostManager
* opener1_manager
=
1223 opener1
->GetRenderManagerForTesting();
1224 contents()->SetOpener(opener1
.get());
1226 scoped_ptr
<TestWebContents
> opener2(
1227 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1228 RenderFrameHostManager
* opener2_manager
=
1229 opener2
->GetRenderManagerForTesting();
1230 opener1
->SetOpener(opener2
.get());
1232 // Navigate to a cross-site URL (different SiteInstance but same
1233 // BrowsingInstance).
1234 contents()->NavigateAndCommit(kUrl2
);
1235 TestRenderFrameHost
* rfh2
= main_test_rfh();
1236 TestRenderViewHost
* rvh2
= test_rvh();
1237 EXPECT_NE(rfh1
->GetSiteInstance(), rfh2
->GetSiteInstance());
1238 EXPECT_TRUE(rfh1
->GetSiteInstance()->IsRelatedSiteInstance(
1239 rfh2
->GetSiteInstance()));
1241 // Ensure rvh1 is placed on swapped out list of the current tab.
1242 EXPECT_TRUE(manager
->IsOnSwappedOutList(rfh1
));
1243 EXPECT_TRUE(manager
->IsRVHOnSwappedOutList(rvh1
));
1245 manager
->GetRenderFrameProxyHost(rfh1
->GetSiteInstance())
1246 ->render_frame_host());
1248 manager
->GetSwappedOutRenderViewHost(rvh1
->GetSiteInstance()));
1250 // Ensure a swapped out RFH and RFH is created in the first opener tab.
1251 RenderFrameProxyHost
* opener1_proxy
=
1252 opener1_manager
->GetRenderFrameProxyHost(rfh2
->GetSiteInstance());
1253 RenderFrameHostImpl
* opener1_rfh
= opener1_proxy
->render_frame_host();
1254 TestRenderViewHost
* opener1_rvh
= static_cast<TestRenderViewHost
*>(
1255 opener1_manager
->GetSwappedOutRenderViewHost(rvh2
->GetSiteInstance()));
1256 EXPECT_TRUE(opener1_manager
->IsOnSwappedOutList(opener1_rfh
));
1257 EXPECT_TRUE(opener1_manager
->IsRVHOnSwappedOutList(opener1_rvh
));
1258 EXPECT_TRUE(opener1_rfh
->is_swapped_out());
1259 EXPECT_FALSE(opener1_rvh
->is_active());
1261 // Ensure a swapped out RFH and RVH is created in the second opener tab.
1262 RenderFrameProxyHost
* opener2_proxy
=
1263 opener2_manager
->GetRenderFrameProxyHost(rfh2
->GetSiteInstance());
1264 RenderFrameHostImpl
* opener2_rfh
= opener2_proxy
->render_frame_host();
1265 TestRenderViewHost
* opener2_rvh
= static_cast<TestRenderViewHost
*>(
1266 opener2_manager
->GetSwappedOutRenderViewHost(rvh2
->GetSiteInstance()));
1267 EXPECT_TRUE(opener2_manager
->IsOnSwappedOutList(opener2_rfh
));
1268 EXPECT_TRUE(opener2_manager
->IsRVHOnSwappedOutList(opener2_rvh
));
1269 EXPECT_TRUE(opener2_rfh
->is_swapped_out());
1270 EXPECT_FALSE(opener2_rvh
->is_active());
1272 // Navigate to a cross-BrowsingInstance URL.
1273 contents()->NavigateAndCommit(kChromeUrl
);
1274 TestRenderFrameHost
* rfh3
= main_test_rfh();
1275 EXPECT_NE(rfh1
->GetSiteInstance(), rfh3
->GetSiteInstance());
1276 EXPECT_FALSE(rfh1
->GetSiteInstance()->IsRelatedSiteInstance(
1277 rfh3
->GetSiteInstance()));
1279 // No scripting is allowed across BrowsingInstances, so we should not create
1280 // swapped out RVHs for the opener chain in this case.
1281 EXPECT_FALSE(opener1_manager
->GetRenderFrameProxyHost(
1282 rfh3
->GetSiteInstance()));
1283 EXPECT_FALSE(opener1_manager
->GetSwappedOutRenderViewHost(
1284 rfh3
->GetSiteInstance()));
1285 EXPECT_FALSE(opener2_manager
->GetRenderFrameProxyHost(
1286 rfh3
->GetSiteInstance()));
1287 EXPECT_FALSE(opener2_manager
->GetSwappedOutRenderViewHost(
1288 rfh3
->GetSiteInstance()));
1291 // Test that a page can disown the opener of the WebContents.
1292 TEST_F(RenderFrameHostManagerTest
, DisownOpener
) {
1293 const GURL
kUrl1("http://www.google.com/");
1294 const GURL
kUrl2("http://www.chromium.org/");
1296 // Navigate to an initial URL.
1297 contents()->NavigateAndCommit(kUrl1
);
1298 TestRenderFrameHost
* rfh1
= main_test_rfh();
1300 // Create a new tab and simulate having it be the opener for the main tab.
1301 scoped_ptr
<TestWebContents
> opener1(
1302 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1303 contents()->SetOpener(opener1
.get());
1304 EXPECT_TRUE(contents()->HasOpener());
1306 // Navigate to a cross-site URL (different SiteInstance but same
1307 // BrowsingInstance).
1308 contents()->NavigateAndCommit(kUrl2
);
1309 TestRenderFrameHost
* rfh2
= main_test_rfh();
1310 EXPECT_NE(rfh1
->GetSiteInstance(), rfh2
->GetSiteInstance());
1312 // Disown the opener from rfh2.
1313 rfh2
->DidDisownOpener();
1315 // Ensure the opener is cleared.
1316 EXPECT_FALSE(contents()->HasOpener());
1319 // Test that a page can disown a same-site opener of the WebContents.
1320 TEST_F(RenderFrameHostManagerTest
, DisownSameSiteOpener
) {
1321 const GURL
kUrl1("http://www.google.com/");
1323 // Navigate to an initial URL.
1324 contents()->NavigateAndCommit(kUrl1
);
1325 TestRenderFrameHost
* rfh1
= main_test_rfh();
1327 // Create a new tab and simulate having it be the opener for the main tab.
1328 scoped_ptr
<TestWebContents
> opener1(
1329 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1330 contents()->SetOpener(opener1
.get());
1331 EXPECT_TRUE(contents()->HasOpener());
1333 // Disown the opener from rfh1.
1334 rfh1
->DidDisownOpener();
1336 // Ensure the opener is cleared even if it is in the same process.
1337 EXPECT_FALSE(contents()->HasOpener());
1340 // Test that a page can disown the opener just as a cross-process navigation is
1342 TEST_F(RenderFrameHostManagerTest
, DisownOpenerDuringNavigation
) {
1343 const GURL
kUrl1("http://www.google.com/");
1344 const GURL
kUrl2("http://www.chromium.org/");
1346 // Navigate to an initial URL.
1347 contents()->NavigateAndCommit(kUrl1
);
1348 TestRenderFrameHost
* rfh1
= main_test_rfh();
1350 // Create a new tab and simulate having it be the opener for the main tab.
1351 scoped_ptr
<TestWebContents
> opener1(
1352 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1353 contents()->SetOpener(opener1
.get());
1354 EXPECT_TRUE(contents()->HasOpener());
1356 // Navigate to a cross-site URL (different SiteInstance but same
1357 // BrowsingInstance).
1358 contents()->NavigateAndCommit(kUrl2
);
1359 TestRenderFrameHost
* rfh2
= main_test_rfh();
1360 EXPECT_NE(rfh1
->GetSiteInstance(), rfh2
->GetSiteInstance());
1362 // Start a back navigation so that rfh1 becomes the pending RFH.
1363 contents()->GetController().GoBack();
1364 contents()->GetMainFrame()->PrepareForCommit();
1366 // Disown the opener from rfh2.
1367 rfh2
->DidDisownOpener();
1369 // Ensure the opener is cleared.
1370 EXPECT_FALSE(contents()->HasOpener());
1372 // The back navigation commits.
1373 const NavigationEntry
* entry1
= contents()->GetController().GetPendingEntry();
1374 rfh1
->SendNavigate(entry1
->GetPageID(), entry1
->GetURL());
1376 // Ensure the opener is still cleared.
1377 EXPECT_FALSE(contents()->HasOpener());
1380 // Test that a page can disown the opener just after a cross-process navigation
1382 TEST_F(RenderFrameHostManagerTest
, DisownOpenerAfterNavigation
) {
1383 const GURL
kUrl1("http://www.google.com/");
1384 const GURL
kUrl2("http://www.chromium.org/");
1386 // Navigate to an initial URL.
1387 contents()->NavigateAndCommit(kUrl1
);
1388 TestRenderFrameHost
* rfh1
= main_test_rfh();
1390 // Create a new tab and simulate having it be the opener for the main tab.
1391 scoped_ptr
<TestWebContents
> opener1(
1392 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1393 contents()->SetOpener(opener1
.get());
1394 EXPECT_TRUE(contents()->HasOpener());
1396 // Navigate to a cross-site URL (different SiteInstance but same
1397 // BrowsingInstance).
1398 contents()->NavigateAndCommit(kUrl2
);
1399 TestRenderFrameHost
* rfh2
= main_test_rfh();
1400 EXPECT_NE(rfh1
->GetSiteInstance(), rfh2
->GetSiteInstance());
1402 // Commit a back navigation before the DidDisownOpener message arrives.
1403 // rfh1 will be kept alive because of the opener tab.
1404 contents()->GetController().GoBack();
1405 contents()->GetMainFrame()->PrepareForCommit();
1406 const NavigationEntry
* entry1
= contents()->GetController().GetPendingEntry();
1407 rfh1
->SendNavigate(entry1
->GetPageID(), entry1
->GetURL());
1409 // Disown the opener from rfh2.
1410 rfh2
->DidDisownOpener();
1411 EXPECT_FALSE(contents()->HasOpener());
1414 // Test that we clean up swapped out RenderViewHosts when a process hosting
1415 // those associated RenderViews crashes. http://crbug.com/258993
1416 TEST_F(RenderFrameHostManagerTest
, CleanUpSwappedOutRVHOnProcessCrash
) {
1417 const GURL
kUrl1("http://www.google.com/");
1418 const GURL
kUrl2("http://www.chromium.org/");
1420 // Navigate to an initial URL.
1421 contents()->NavigateAndCommit(kUrl1
);
1422 TestRenderFrameHost
* rfh1
= contents()->GetMainFrame();
1424 // Create a new tab as an opener for the main tab.
1425 scoped_ptr
<TestWebContents
> opener1(
1426 TestWebContents::Create(browser_context(), rfh1
->GetSiteInstance()));
1427 RenderFrameHostManager
* opener1_manager
=
1428 opener1
->GetRenderManagerForTesting();
1429 contents()->SetOpener(opener1
.get());
1431 // Make sure the new opener RVH is considered live.
1432 opener1_manager
->current_host()->CreateRenderView(
1433 base::string16(), -1, MSG_ROUTING_NONE
, -1, false);
1434 EXPECT_TRUE(opener1_manager
->current_host()->IsRenderViewLive());
1435 EXPECT_TRUE(opener1_manager
->current_frame_host()->IsRenderFrameLive());
1437 // Use a cross-process navigation in the opener to swap out the old RVH.
1439 opener1_manager
->GetSwappedOutRenderViewHost(rfh1
->GetSiteInstance()));
1440 opener1
->NavigateAndCommit(kUrl2
);
1442 opener1_manager
->GetSwappedOutRenderViewHost(rfh1
->GetSiteInstance()));
1444 // Fake a process crash.
1447 // Ensure that the RenderFrameProxyHost stays around and the RenderFrameProxy
1449 RenderFrameProxyHost
* render_frame_proxy_host
=
1450 opener1_manager
->GetRenderFrameProxyHost(rfh1
->GetSiteInstance());
1451 EXPECT_TRUE(render_frame_proxy_host
);
1452 EXPECT_FALSE(render_frame_proxy_host
->is_render_frame_proxy_live());
1454 // Expect the swapped out RVH to exist.
1456 opener1_manager
->GetSwappedOutRenderViewHost(rfh1
->GetSiteInstance()));
1458 // Reload the initial tab. This should recreate the opener's swapped out RVH
1459 // in the original SiteInstance.
1460 contents()->GetController().Reload(true);
1461 contents()->GetMainFrame()->PrepareForCommit();
1462 EXPECT_EQ(opener1_manager
->GetSwappedOutRenderViewHost(
1463 rfh1
->GetSiteInstance())->GetRoutingID(),
1464 contents()->GetMainFrame()->GetRenderViewHost()->opener_route_id());
1467 // Test that RenderViewHosts created for WebUI navigations are properly
1468 // granted WebUI bindings even if an unprivileged swapped out RenderViewHost
1469 // is in the same process (http://crbug.com/79918).
1470 TEST_F(RenderFrameHostManagerTest
, EnableWebUIWithSwappedOutOpener
) {
1471 set_should_create_webui(true);
1472 const GURL
kSettingsUrl("chrome://chrome/settings");
1473 const GURL
kPluginUrl("chrome://plugins");
1475 // Navigate to an initial WebUI URL.
1476 contents()->NavigateAndCommit(kSettingsUrl
);
1478 // Ensure the RVH has WebUI bindings.
1479 TestRenderViewHost
* rvh1
= test_rvh();
1480 EXPECT_TRUE(rvh1
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1482 // Create a new tab and simulate it being the opener for the main
1483 // tab. It should be in the same SiteInstance.
1484 scoped_ptr
<TestWebContents
> opener1(
1485 TestWebContents::Create(browser_context(), rvh1
->GetSiteInstance()));
1486 RenderFrameHostManager
* opener1_manager
=
1487 opener1
->GetRenderManagerForTesting();
1488 contents()->SetOpener(opener1
.get());
1490 // Navigate to a different WebUI URL (different SiteInstance, same
1491 // BrowsingInstance).
1492 contents()->NavigateAndCommit(kPluginUrl
);
1493 TestRenderViewHost
* rvh2
= test_rvh();
1494 EXPECT_NE(rvh1
->GetSiteInstance(), rvh2
->GetSiteInstance());
1495 EXPECT_TRUE(rvh1
->GetSiteInstance()->IsRelatedSiteInstance(
1496 rvh2
->GetSiteInstance()));
1498 // Ensure a swapped out RFH and RVH is created in the first opener tab.
1499 RenderFrameProxyHost
* opener1_proxy
=
1500 opener1_manager
->GetRenderFrameProxyHost(rvh2
->GetSiteInstance());
1501 RenderFrameHostImpl
* opener1_rfh
= opener1_proxy
->render_frame_host();
1502 TestRenderViewHost
* opener1_rvh
= static_cast<TestRenderViewHost
*>(
1503 opener1_manager
->GetSwappedOutRenderViewHost(rvh2
->GetSiteInstance()));
1504 EXPECT_TRUE(opener1_manager
->IsOnSwappedOutList(opener1_rfh
));
1505 EXPECT_TRUE(opener1_manager
->IsRVHOnSwappedOutList(opener1_rvh
));
1506 EXPECT_TRUE(opener1_rfh
->is_swapped_out());
1507 EXPECT_FALSE(opener1_rvh
->is_active());
1509 // Ensure the new RVH has WebUI bindings.
1510 EXPECT_TRUE(rvh2
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1513 // Test that we reuse the same guest SiteInstance if we navigate across sites.
1514 TEST_F(RenderFrameHostManagerTest
, NoSwapOnGuestNavigations
) {
1515 TestNotificationTracker notifications
;
1517 GURL
guest_url(std::string(kGuestScheme
).append("://abc123"));
1518 SiteInstance
* instance
=
1519 SiteInstance::CreateForURL(browser_context(), guest_url
);
1520 scoped_ptr
<TestWebContents
> web_contents(
1521 TestWebContents::Create(browser_context(), instance
));
1523 RenderFrameHostManager
* manager
= web_contents
->GetRenderManagerForTesting();
1525 RenderFrameHostImpl
* host
= NULL
;
1527 // 1) The first navigation. --------------------------
1528 const GURL
kUrl1("http://www.google.com/");
1529 NavigationEntryImpl
entry1(
1530 NULL
/* instance */, -1 /* page_id */, kUrl1
, Referrer(),
1531 base::string16() /* title */, ui::PAGE_TRANSITION_TYPED
,
1532 false /* is_renderer_init */);
1533 host
= manager
->Navigate(entry1
);
1535 // The RenderFrameHost created in Init will be reused.
1536 EXPECT_TRUE(host
== manager
->current_frame_host());
1537 EXPECT_FALSE(manager
->pending_frame_host());
1538 EXPECT_EQ(manager
->current_frame_host()->GetSiteInstance(), instance
);
1541 manager
->DidNavigateFrame(host
, true);
1542 // Commit to SiteInstance should be delayed until RenderFrame commit.
1543 EXPECT_EQ(host
, manager
->current_frame_host());
1545 EXPECT_TRUE(host
->GetSiteInstance()->HasSite());
1547 // 2) Navigate to a different domain. -------------------------
1548 // Guests stay in the same process on navigation.
1549 const GURL
kUrl2("http://www.chromium.org");
1550 NavigationEntryImpl
entry2(
1551 NULL
/* instance */, -1 /* page_id */, kUrl2
,
1552 Referrer(kUrl1
, blink::WebReferrerPolicyDefault
),
1553 base::string16() /* title */, ui::PAGE_TRANSITION_LINK
,
1554 true /* is_renderer_init */);
1555 host
= manager
->Navigate(entry2
);
1557 // The RenderFrameHost created in Init will be reused.
1558 EXPECT_EQ(host
, manager
->current_frame_host());
1559 EXPECT_FALSE(manager
->pending_frame_host());
1562 manager
->DidNavigateFrame(host
, true);
1563 EXPECT_EQ(host
, manager
->current_frame_host());
1565 EXPECT_EQ(host
->GetSiteInstance(), instance
);
1568 // Test that we cancel a pending RVH if we close the tab while it's pending.
1569 // http://crbug.com/294697.
1570 TEST_F(RenderFrameHostManagerTest
, NavigateWithEarlyClose
) {
1571 TestNotificationTracker notifications
;
1573 SiteInstance
* instance
= SiteInstance::Create(browser_context());
1575 BeforeUnloadFiredWebContentsDelegate delegate
;
1576 scoped_ptr
<TestWebContents
> web_contents(
1577 TestWebContents::Create(browser_context(), instance
));
1578 web_contents
->SetDelegate(&delegate
);
1579 notifications
.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
1580 Source
<WebContents
>(web_contents
.get()));
1582 RenderFrameHostManager
* manager
= web_contents
->GetRenderManagerForTesting();
1584 // 1) The first navigation. --------------------------
1585 const GURL
kUrl1("http://www.google.com/");
1586 NavigationEntryImpl
entry1(NULL
/* instance */, -1 /* page_id */, kUrl1
,
1587 Referrer(), base::string16() /* title */,
1588 ui::PAGE_TRANSITION_TYPED
,
1589 false /* is_renderer_init */);
1590 RenderFrameHostImpl
* host
= manager
->Navigate(entry1
);
1592 // The RenderFrameHost created in Init will be reused.
1593 EXPECT_EQ(host
, manager
->current_frame_host());
1594 EXPECT_FALSE(manager
->pending_frame_host());
1596 // We should observe a notification.
1598 notifications
.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED
));
1599 notifications
.Reset();
1602 manager
->DidNavigateFrame(host
, true);
1604 // Commit to SiteInstance should be delayed until RenderFrame commits.
1605 EXPECT_EQ(host
, manager
->current_frame_host());
1606 EXPECT_FALSE(host
->GetSiteInstance()->HasSite());
1607 host
->GetSiteInstance()->SetSite(kUrl1
);
1609 // 2) Cross-site navigate to next site. -------------------------
1610 const GURL
kUrl2("http://www.example.com");
1611 NavigationEntryImpl
entry2(
1612 NULL
/* instance */, -1 /* page_id */, kUrl2
, Referrer(),
1613 base::string16() /* title */, ui::PAGE_TRANSITION_TYPED
,
1614 false /* is_renderer_init */);
1615 RenderFrameHostImpl
* host2
= manager
->Navigate(entry2
);
1617 // A new RenderFrameHost should be created.
1618 ASSERT_EQ(host2
, manager
->pending_frame_host());
1619 EXPECT_NE(host2
, host
);
1621 EXPECT_EQ(host
, manager
->current_frame_host());
1622 EXPECT_FALSE(manager
->current_frame_host()->is_swapped_out());
1623 EXPECT_EQ(host2
, manager
->pending_frame_host());
1625 // 3) Close the tab. -------------------------
1626 notifications
.ListenFor(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED
,
1627 Source
<RenderWidgetHost
>(host2
->render_view_host()));
1628 manager
->OnBeforeUnloadACK(false, true, base::TimeTicks());
1631 notifications
.Check1AndReset(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED
));
1632 EXPECT_FALSE(manager
->pending_frame_host());
1633 EXPECT_EQ(host
, manager
->current_frame_host());
1636 TEST_F(RenderFrameHostManagerTest
, CloseWithPendingWhileUnresponsive
) {
1637 const GURL
kUrl1("http://www.google.com/");
1638 const GURL
kUrl2("http://www.chromium.org/");
1640 CloseWebContentsDelegate close_delegate
;
1641 contents()->SetDelegate(&close_delegate
);
1643 // Navigate to the first page.
1644 contents()->NavigateAndCommit(kUrl1
);
1645 TestRenderFrameHost
* rfh1
= contents()->GetMainFrame();
1647 // Start to close the tab, but assume it's unresponsive.
1648 rfh1
->render_view_host()->ClosePage();
1649 EXPECT_TRUE(rfh1
->render_view_host()->is_waiting_for_close_ack());
1651 // Start a navigation to a new site.
1652 controller().LoadURL(
1653 kUrl2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1654 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1655 switches::kEnableBrowserSideNavigation
)) {
1656 rfh1
->PrepareForCommit();
1658 EXPECT_TRUE(contents()->cross_navigation_pending());
1660 // Simulate the unresponsiveness timer. The tab should close.
1661 contents()->RendererUnresponsive(rfh1
->render_view_host());
1662 EXPECT_TRUE(close_delegate
.is_closed());
1665 // Tests that the RenderFrameHost is properly deleted when the SwapOutACK is
1666 // received. (SwapOut and the corresponding ACK always occur after commit.)
1667 // Also tests that an early SwapOutACK is properly ignored.
1668 TEST_F(RenderFrameHostManagerTest
, DeleteFrameAfterSwapOutACK
) {
1669 const GURL
kUrl1("http://www.google.com/");
1670 const GURL
kUrl2("http://www.chromium.org/");
1672 // Navigate to the first page.
1673 contents()->NavigateAndCommit(kUrl1
);
1674 TestRenderFrameHost
* rfh1
= contents()->GetMainFrame();
1675 RenderFrameHostDeletedObserver
rfh_deleted_observer(rfh1
);
1676 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1678 // Navigate to new site, simulating onbeforeunload approval.
1679 controller().LoadURL(
1680 kUrl2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1681 contents()->GetMainFrame()->PrepareForCommit();
1682 EXPECT_TRUE(contents()->cross_navigation_pending());
1683 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1684 TestRenderFrameHost
* rfh2
= contents()->GetPendingMainFrame();
1686 // Simulate the swap out ack, unexpectedly early (before commit). It should
1688 rfh1
->OnSwappedOut();
1689 EXPECT_TRUE(contents()->cross_navigation_pending());
1690 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1692 // The new page commits.
1693 contents()->TestDidNavigate(rfh2
, 1, kUrl2
, ui::PAGE_TRANSITION_TYPED
);
1694 EXPECT_FALSE(contents()->cross_navigation_pending());
1695 EXPECT_EQ(rfh2
, contents()->GetMainFrame());
1696 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1697 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh2
->rfh_state());
1698 EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT
, rfh1
->rfh_state());
1700 rfh1
->frame_tree_node()->render_manager()->IsPendingDeletion(rfh1
));
1702 // Simulate the swap out ack.
1703 rfh1
->OnSwappedOut();
1705 // rfh1 should have been deleted.
1706 EXPECT_TRUE(rfh_deleted_observer
.deleted());
1710 // Tests that the RenderFrameHost is properly swapped out when the SwapOut ACK
1711 // is received. (SwapOut and the corresponding ACK always occur after commit.)
1712 TEST_F(RenderFrameHostManagerTest
, SwapOutFrameAfterSwapOutACK
) {
1713 const GURL
kUrl1("http://www.google.com/");
1714 const GURL
kUrl2("http://www.chromium.org/");
1716 // Navigate to the first page.
1717 contents()->NavigateAndCommit(kUrl1
);
1718 TestRenderFrameHost
* rfh1
= contents()->GetMainFrame();
1719 RenderFrameHostDeletedObserver
rfh_deleted_observer(rfh1
);
1720 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1722 // Increment the number of active frames in SiteInstanceImpl so that rfh1 is
1723 // not deleted on swap out.
1724 rfh1
->GetSiteInstance()->increment_active_frame_count();
1726 // Navigate to new site, simulating onbeforeunload approval.
1727 controller().LoadURL(
1728 kUrl2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1729 contents()->GetMainFrame()->PrepareForCommit();
1730 EXPECT_TRUE(contents()->cross_navigation_pending());
1731 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1732 TestRenderFrameHost
* rfh2
= contents()->GetPendingMainFrame();
1734 // The new page commits.
1735 contents()->TestDidNavigate(rfh2
, 1, kUrl2
, ui::PAGE_TRANSITION_TYPED
);
1736 EXPECT_FALSE(contents()->cross_navigation_pending());
1737 EXPECT_EQ(rfh2
, contents()->GetMainFrame());
1738 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1739 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh2
->rfh_state());
1740 EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT
, rfh1
->rfh_state());
1742 // Simulate the swap out ack.
1743 rfh1
->OnSwappedOut();
1745 // rfh1 should be swapped out.
1746 EXPECT_FALSE(rfh_deleted_observer
.deleted());
1747 EXPECT_TRUE(rfh1
->is_swapped_out());
1750 // Test that the RenderViewHost is properly swapped out if a navigation in the
1751 // new renderer commits before sending the SwapOut message to the old renderer.
1752 // This simulates a cross-site navigation to a synchronously committing URL
1753 // (e.g., a data URL) and ensures it works properly.
1754 TEST_F(RenderFrameHostManagerTest
,
1755 CommitNewNavigationBeforeSendingSwapOut
) {
1756 const GURL
kUrl1("http://www.google.com/");
1757 const GURL
kUrl2("http://www.chromium.org/");
1759 // Navigate to the first page.
1760 contents()->NavigateAndCommit(kUrl1
);
1761 TestRenderFrameHost
* rfh1
= contents()->GetMainFrame();
1762 RenderFrameHostDeletedObserver
rfh_deleted_observer(rfh1
);
1763 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1765 // Increment the number of active frames in SiteInstanceImpl so that rfh1 is
1766 // not deleted on swap out.
1767 rfh1
->GetSiteInstance()->increment_active_frame_count();
1769 // Navigate to new site, simulating onbeforeunload approval.
1770 controller().LoadURL(
1771 kUrl2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1772 rfh1
->PrepareForCommit();
1773 EXPECT_TRUE(contents()->cross_navigation_pending());
1774 TestRenderFrameHost
* rfh2
= contents()->GetPendingMainFrame();
1776 // The new page commits.
1777 contents()->TestDidNavigate(rfh2
, 1, kUrl2
, ui::PAGE_TRANSITION_TYPED
);
1778 EXPECT_FALSE(contents()->cross_navigation_pending());
1779 EXPECT_EQ(rfh2
, contents()->GetMainFrame());
1780 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1781 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh2
->rfh_state());
1782 EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT
, rfh1
->rfh_state());
1784 // Simulate the swap out ack.
1785 rfh1
->OnSwappedOut();
1787 // rfh1 should be swapped out.
1788 EXPECT_FALSE(rfh_deleted_observer
.deleted());
1789 EXPECT_TRUE(rfh1
->is_swapped_out());
1792 // Test that a RenderFrameHost is properly deleted or swapped out when a
1793 // cross-site navigation is cancelled.
1794 TEST_F(RenderFrameHostManagerTest
,
1795 CancelPendingProperlyDeletesOrSwaps
) {
1796 const GURL
kUrl1("http://www.google.com/");
1797 const GURL
kUrl2("http://www.chromium.org/");
1798 RenderFrameHostImpl
* pending_rfh
= NULL
;
1799 base::TimeTicks now
= base::TimeTicks::Now();
1801 // Navigate to the first page.
1802 contents()->NavigateAndCommit(kUrl1
);
1803 TestRenderFrameHost
* rfh1
= main_test_rfh();
1804 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
1806 // Navigate to a new site, starting a cross-site navigation.
1807 controller().LoadURL(
1808 kUrl2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1810 pending_rfh
= contents()->GetFrameTree()->root()->render_manager()
1811 ->pending_frame_host();
1812 RenderFrameHostDeletedObserver
rfh_deleted_observer(pending_rfh
);
1814 // Cancel the navigation by simulating a declined beforeunload dialog.
1815 contents()->GetMainFrame()->OnMessageReceived(
1816 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1817 EXPECT_FALSE(contents()->cross_navigation_pending());
1819 // Since the pending RFH is the only one for the new SiteInstance, it should
1821 EXPECT_TRUE(rfh_deleted_observer
.deleted());
1824 // Start another cross-site navigation.
1825 controller().LoadURL(
1826 kUrl2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1828 pending_rfh
= contents()->GetFrameTree()->root()->render_manager()
1829 ->pending_frame_host();
1830 RenderFrameHostDeletedObserver
rfh_deleted_observer(pending_rfh
);
1832 // Increment the number of active frames in the new SiteInstance, which will
1833 // cause the pending RFH to be swapped out instead of deleted.
1834 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
1836 contents()->GetMainFrame()->OnMessageReceived(
1837 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1838 EXPECT_FALSE(contents()->cross_navigation_pending());
1839 EXPECT_FALSE(rfh_deleted_observer
.deleted());
1843 // Test that a pending RenderFrameHost in a non-root frame tree node is properly
1844 // deleted when the node is detached. Motivated by http://crbug.com/441357 and
1845 // http://crbug.com/444955.
1846 TEST_F(RenderFrameHostManagerTest
, DetachPendingChild
) {
1847 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1848 switches::kSitePerProcess
);
1850 const GURL
kUrlA("http://www.google.com/");
1851 const GURL
kUrlB("http://webkit.org/");
1853 // Create a page with two child frames.
1854 contents()->NavigateAndCommit(kUrlA
);
1855 contents()->GetMainFrame()->OnCreateChildFrame(
1856 contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
1857 std::string("frame_name"), SandboxFlags::NONE
);
1858 contents()->GetMainFrame()->OnCreateChildFrame(
1859 contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
1860 std::string("frame_name"), SandboxFlags::NONE
);
1861 RenderFrameHostManager
* root_manager
=
1862 contents()->GetFrameTree()->root()->render_manager();
1863 RenderFrameHostManager
* iframe1
=
1864 contents()->GetFrameTree()->root()->child_at(0)->render_manager();
1865 RenderFrameHostManager
* iframe2
=
1866 contents()->GetFrameTree()->root()->child_at(1)->render_manager();
1868 // 1) The first navigation.
1869 NavigationEntryImpl
entryA(NULL
/* instance */, -1 /* page_id */, kUrlA
,
1870 Referrer(), base::string16() /* title */,
1871 ui::PAGE_TRANSITION_TYPED
,
1872 false /* is_renderer_init */);
1873 RenderFrameHostImpl
* host1
= GetFrameHostForNavigation(iframe1
, entryA
);
1875 // The RenderFrameHost created in Init will be reused.
1876 EXPECT_TRUE(host1
== iframe1
->current_frame_host());
1877 EXPECT_FALSE(GetPendingFrameHost(iframe1
));
1880 iframe1
->DidNavigateFrame(host1
, true);
1881 // Commit to SiteInstance should be delayed until RenderFrame commit.
1882 EXPECT_TRUE(host1
== iframe1
->current_frame_host());
1884 EXPECT_TRUE(host1
->GetSiteInstance()->HasSite());
1886 // 2) Cross-site navigate both frames to next site.
1887 NavigationEntryImpl
entryB(NULL
/* instance */, -1 /* page_id */, kUrlB
,
1888 Referrer(kUrlA
, blink::WebReferrerPolicyDefault
),
1889 base::string16() /* title */,
1890 ui::PAGE_TRANSITION_LINK
,
1891 false /* is_renderer_init */);
1892 host1
= GetFrameHostForNavigation(iframe1
, entryB
);
1893 RenderFrameHostImpl
* host2
= GetFrameHostForNavigation(iframe2
, entryB
);
1895 // A new, pending RenderFrameHost should be created in each FrameTreeNode.
1896 EXPECT_TRUE(GetPendingFrameHost(iframe1
));
1897 EXPECT_TRUE(GetPendingFrameHost(iframe2
));
1898 EXPECT_EQ(host1
, GetPendingFrameHost(iframe1
));
1899 EXPECT_EQ(host2
, GetPendingFrameHost(iframe2
));
1900 EXPECT_TRUE(RenderFrameHostImpl::IsRFHStateActive(
1901 GetPendingFrameHost(iframe1
)->rfh_state()));
1902 EXPECT_TRUE(RenderFrameHostImpl::IsRFHStateActive(
1903 GetPendingFrameHost(iframe2
)->rfh_state()));
1904 EXPECT_NE(GetPendingFrameHost(iframe1
), GetPendingFrameHost(iframe2
));
1905 EXPECT_EQ(GetPendingFrameHost(iframe1
)->GetSiteInstance(),
1906 GetPendingFrameHost(iframe2
)->GetSiteInstance());
1907 EXPECT_NE(iframe1
->current_frame_host(), GetPendingFrameHost(iframe1
));
1908 EXPECT_NE(iframe2
->current_frame_host(), GetPendingFrameHost(iframe2
));
1909 EXPECT_FALSE(contents()->cross_navigation_pending())
1910 << "There should be no top-level pending navigation.";
1912 RenderFrameHostDeletedObserver
delete_watcher1(GetPendingFrameHost(iframe1
));
1913 RenderFrameHostDeletedObserver
delete_watcher2(GetPendingFrameHost(iframe2
));
1914 EXPECT_FALSE(delete_watcher1
.deleted());
1915 EXPECT_FALSE(delete_watcher2
.deleted());
1917 // Keep the SiteInstance alive for testing.
1918 scoped_refptr
<SiteInstanceImpl
> site_instance
=
1919 GetPendingFrameHost(iframe1
)->GetSiteInstance();
1920 EXPECT_TRUE(site_instance
->HasSite());
1921 EXPECT_NE(site_instance
, contents()->GetSiteInstance());
1922 EXPECT_EQ(2U, site_instance
->active_frame_count());
1924 // Proxies should exist.
1926 root_manager
->GetRenderFrameProxyHost(site_instance
.get()));
1928 iframe1
->GetRenderFrameProxyHost(site_instance
.get()));
1930 iframe2
->GetRenderFrameProxyHost(site_instance
.get()));
1932 // Detach the first child FrameTreeNode. This should kill the pending host but
1933 // not yet destroy proxies in |site_instance| since the other child remains.
1934 iframe1
->current_frame_host()->OnMessageReceived(
1935 FrameHostMsg_Detach(iframe1
->current_frame_host()->GetRoutingID()));
1936 iframe1
= NULL
; // Was just destroyed.
1938 EXPECT_TRUE(delete_watcher1
.deleted());
1939 EXPECT_FALSE(delete_watcher2
.deleted());
1940 EXPECT_EQ(1U, site_instance
->active_frame_count());
1942 // Proxies should still exist.
1944 root_manager
->GetRenderFrameProxyHost(site_instance
.get()));
1946 iframe2
->GetRenderFrameProxyHost(site_instance
.get()));
1948 // Detach the second child FrameTreeNode. This should trigger cleanup of
1949 // RenderFrameProxyHosts in |site_instance|.
1950 iframe2
->current_frame_host()->OnMessageReceived(
1951 FrameHostMsg_Detach(iframe2
->current_frame_host()->GetRoutingID()));
1952 iframe2
= NULL
; // Was just destroyed.
1954 EXPECT_TRUE(delete_watcher1
.deleted());
1955 EXPECT_TRUE(delete_watcher2
.deleted());
1957 EXPECT_EQ(0U, site_instance
->active_frame_count());
1959 root_manager
->GetRenderFrameProxyHost(site_instance
.get()))
1960 << "Proxies should have been cleaned up";
1961 EXPECT_TRUE(site_instance
->HasOneRef())
1962 << "This SiteInstance should be destroyable now.";
1965 // Two tabs in the same process crash. The first tab is reloaded, and the second
1966 // tab navigates away without reloading. The second tab's navigation shouldn't
1967 // mess with the first tab's content. Motivated by http://crbug.com/473714.
1968 TEST_F(RenderFrameHostManagerTest
, TwoTabsCrashOneReloadsOneLeaves
) {
1969 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1970 switches::kSitePerProcess
);
1972 const GURL
kUrl1("http://www.google.com/");
1973 const GURL
kUrl2("http://webkit.org/");
1974 const GURL
kUrl3("http://whatwg.org/");
1976 // |contents1| and |contents2| navigate to the same page and then crash.
1977 TestWebContents
* contents1
= contents();
1978 scoped_ptr
<TestWebContents
> contents2(
1979 TestWebContents::Create(browser_context(), contents1
->GetSiteInstance()));
1980 contents1
->NavigateAndCommit(kUrl1
);
1981 contents2
->NavigateAndCommit(kUrl1
);
1982 CrashFrame(contents1
->GetMainFrame());
1983 CrashFrame(contents2
->GetMainFrame());
1985 EXPECT_EQ(contents1
->GetSiteInstance(), contents2
->GetSiteInstance());
1987 // Reload |contents1|.
1988 contents1
->NavigateAndCommit(kUrl1
);
1989 EXPECT_TRUE(contents1
->GetMainFrame()->IsRenderFrameLive());
1990 EXPECT_FALSE(contents2
->GetMainFrame()->IsRenderFrameLive());
1991 EXPECT_EQ(contents1
->GetSiteInstance(), contents2
->GetSiteInstance());
1993 // |contents1| creates an out of process iframe.
1994 contents1
->GetMainFrame()->OnCreateChildFrame(
1995 contents1
->GetMainFrame()->GetProcess()->GetNextRoutingID(),
1996 std::string("frame_name"), SandboxFlags::NONE
);
1997 RenderFrameHostManager
* iframe
=
1998 contents()->GetFrameTree()->root()->child_at(0)->render_manager();
1999 NavigationEntryImpl
entry(NULL
/* instance */, -1 /* page_id */, kUrl2
,
2000 Referrer(kUrl1
, blink::WebReferrerPolicyDefault
),
2001 base::string16() /* title */,
2002 ui::PAGE_TRANSITION_LINK
,
2003 false /* is_renderer_init */);
2004 RenderFrameHostImpl
* cross_site
= GetFrameHostForNavigation(iframe
, entry
);
2005 iframe
->DidNavigateFrame(cross_site
, true);
2007 // A proxy to the iframe should now exist in the SiteInstance of the main
2009 EXPECT_NE(cross_site
->GetSiteInstance(), contents1
->GetSiteInstance());
2011 iframe
->GetRenderFrameProxyHost(contents1
->GetSiteInstance()));
2013 iframe
->GetRenderFrameProxyHost(contents2
->GetSiteInstance()));
2015 // Navigate |contents2| away from the sad tab (and thus away from the
2016 // SiteInstance of |contents1|). This should not destroy the proxies needed by
2017 // |contents1| -- that was http://crbug.com/473714.
2018 EXPECT_FALSE(contents2
->GetMainFrame()->IsRenderFrameLive());
2019 contents2
->NavigateAndCommit(kUrl3
);
2020 EXPECT_TRUE(contents2
->GetMainFrame()->IsRenderFrameLive());
2022 iframe
->GetRenderFrameProxyHost(contents1
->GetSiteInstance()));
2024 iframe
->GetRenderFrameProxyHost(contents2
->GetSiteInstance()));
2027 } // namespace content