| 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..72e8b3accc38dbd8bab9b008473666feab175525 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,54 @@ 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 = NULL;
|
| + 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();
|
| + RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
|
| +
|
| + // Cancel the navigation by simulating a declined beforeunload dialog.
|
| + 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.
|
| + 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
|
|
|