Chromium Code Reviews| Index: content/browser/frame_host/render_frame_host_manager_unittest.cc |
| diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc |
| index d43c63fc23c91f69dcc3bd98f34885fce3894da5..4cfd82e077a4fb90e7118d9b5891fea8377c7698 100644 |
| --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc |
| +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc |
| @@ -125,6 +125,37 @@ class RenderViewHostDeletedObserver : public WebContentsObserver { |
| }; |
| +// This observer keeps track of the last deleted RenderViewHost to avoid |
| +// accessing it and causing use-after-free condition. |
| +class RenderFrameHostDeletedObserver : public WebContentsObserver { |
| + public: |
| + RenderFrameHostDeletedObserver(RenderFrameHost* rfh) |
| + : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)), |
| + process_id_(rfh->GetProcess()->GetID()), |
| + routing_id_(rfh->GetRoutingID()), |
| + deleted_(false) { |
| + } |
| + |
| + virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE { |
| + if (render_frame_host->GetProcess()->GetID() == process_id_ && |
| + render_frame_host->GetRoutingID() == routing_id_) { |
| + deleted_ = true; |
| + } |
| + } |
| + |
| + bool deleted() { |
| + return deleted_; |
| + } |
| + |
| + private: |
| + int process_id_; |
| + int routing_id_; |
| + bool deleted_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver); |
| +}; |
| + |
| + |
| // This observer is used to check whether IPC messages are being filtered for |
| // swapped out RenderFrameHost objects. It observes the plugin crash and favicon |
| // update events, which the FilterMessagesWhileSwappedOut test simulates being |
| @@ -1765,4 +1796,55 @@ TEST_F(RenderFrameHostManagerTest, |
| EXPECT_TRUE(rvh1->IsSwappedOut()); |
| } |
| +// Test that a RenderFrameHost is properly deleted or swapped out when a |
| +// cross-site navigation is cancelled. |
| +TEST_F(RenderFrameHostManagerTest, |
| + CancelPendingProperlyDeletesOrSwaps) { |
| + const GURL kUrl1("http://www.google.com/"); |
| + const GURL kUrl2("http://www.chromium.org/"); |
| + RenderFrameHostImpl* pending_rfh; |
|
Charlie Reis
2014/04/11 17:42:53
= NULL;
nasko
2014/04/11 18:11:21
Done.
|
| + base::TimeTicks now = base::TimeTicks::Now(); |
| + |
| + // Navigate to the first page. |
| + contents()->NavigateAndCommit(kUrl1); |
| + TestRenderViewHost* rvh1 = test_rvh(); |
| + EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state()); |
| + |
| + // Navigate to a new site, starting a cross-site navigation. |
| + controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string()); |
| + { |
| + pending_rfh = contents()->GetFrameTree()->root()->render_manager() |
| + ->pending_frame_host(); |
|
Charlie Reis
2014/04/11 17:42:53
I would have put -> on the previous line, but I de
nasko
2014/04/11 18:11:21
clang-format dictates this :( I dislike it too.
|
| + RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh); |
| + |
| + // Cancel the navigation by simulating user cancelled through beforeunload |
|
Charlie Reis
2014/04/11 17:42:53
by simulating a declined beforeunload dialog.
nasko
2014/04/11 18:11:21
Done.
|
| + // event handler. |
| + main_test_rfh()->OnMessageReceived( |
| + FrameHostMsg_BeforeUnload_ACK(0, false, now, now)); |
| + EXPECT_FALSE(contents()->cross_navigation_pending()); |
| + |
| + // Since the pending RFH is the only one for the new SiteInstance, it should |
| + // be deleted. |
| + EXPECT_TRUE(rvh_deleted_observer.deleted()); |
| + } |
| + |
| + // Start another cross-site navigation |
|
Charlie Reis
2014/04/11 17:42:53
nit: End with period.
nasko
2014/04/11 18:11:21
Done.
|
| + controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string()); |
| + { |
| + pending_rfh = contents()->GetFrameTree()->root()->render_manager() |
| + ->pending_frame_host(); |
| + RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh); |
| + |
| + // Increment the number of active views in the new SiteInstance, which will |
| + // cause the pending RFH to be swapped out instead of deleted. |
| + static_cast<SiteInstanceImpl*>( |
| + pending_rfh->GetSiteInstance())->increment_active_view_count(); |
| + |
| + main_test_rfh()->OnMessageReceived( |
| + FrameHostMsg_BeforeUnload_ACK(0, false, now, now)); |
| + EXPECT_FALSE(contents()->cross_navigation_pending()); |
| + EXPECT_FALSE(rvh_deleted_observer.deleted()); |
| + } |
| +} |
| + |
| } // namespace content |