Index: content/browser/web_contents/render_view_host_manager.cc |
diff --git a/content/browser/web_contents/render_view_host_manager.cc b/content/browser/web_contents/render_view_host_manager.cc |
index 3fefe30241ef9c98825750560d2ce6cf831e8f3b..64c16f46858c085e2ab3eddb1c9c016aa3732251 100644 |
--- a/content/browser/web_contents/render_view_host_manager.cc |
+++ b/content/browser/web_contents/render_view_host_manager.cc |
@@ -32,6 +32,14 @@ |
namespace content { |
+RenderViewHostManager::PendingNavigationParams::PendingNavigationParams() { |
+} |
+ |
+RenderViewHostManager::PendingNavigationParams::PendingNavigationParams( |
+ const GlobalRequestID& global_request_id) |
+ : global_request_id(global_request_id) { |
+} |
+ |
RenderViewHostManager::RenderViewHostManager( |
RenderViewHostDelegate* render_view_delegate, |
RenderWidgetHostDelegate* render_widget_delegate, |
@@ -188,11 +196,17 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { |
if (!cross_navigation_pending_) |
return true; |
- // If the tab becomes unresponsive during unload while doing a |
+ // If the tab becomes unresponsive during {before}unload while doing a |
// cross-site navigation, proceed with the navigation. (This assumes that |
// the pending RenderViewHost is still responsive.) |
- int pending_request_id = pending_render_view_host_->GetPendingRequestId(); |
- if (pending_request_id == -1) { |
+ if (render_view_host_->is_waiting_for_unload_ack()) { |
+ // The request has been started and paused while we're waiting for the |
+ // unload handler to finish. We'll pretend that it did. The pending |
+ // renderer will then be swapped in as part of the usual DidNavigate logic. |
+ // (If the unload handler later finishes, this call will be ignored because |
+ // the pending_nav_params_ state will already be cleaned up.) |
+ current_host()->OnSwappedOut(true); |
+ } else if (render_view_host_->is_waiting_for_beforeunload_ack()) { |
// Haven't gotten around to starting the request, because we're still |
// waiting for the beforeunload handler to finish. We'll pretend that it |
// did finish, to let the navigation proceed. Note that there's a danger |
@@ -202,24 +216,31 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { |
if (pending_render_view_host_->are_navigations_suspended()) |
pending_render_view_host_->SetNavigationsSuspended( |
false, base::TimeTicks::Now()); |
- } else { |
- // The request has been started and paused while we're waiting for the |
- // unload handler to finish. We'll pretend that it did, by notifying the |
- // IO thread to let the response continue. The pending renderer will then |
- // be swapped in as part of the usual DidNavigate logic. (If the unload |
- // handler later finishes, this call will be ignored because the state in |
- // CrossSiteResourceHandler will already be cleaned up.) |
- ViewMsg_SwapOut_Params params; |
- params.closing_process_id = render_view_host_->GetProcess()->GetID(); |
- params.closing_route_id = render_view_host_->GetRoutingID(); |
- params.new_render_process_host_id = |
- pending_render_view_host_->GetProcess()->GetID(); |
- params.new_request_id = pending_request_id; |
- current_host()->GetProcess()->SimulateSwapOutACK(params); |
} |
return false; |
} |
+void RenderViewHostManager::SwappedOut(RenderViewHost* render_view_host) { |
+ // Make sure this is from our current RVH, and that we have a pending |
+ // navigation from OnCrossSiteResponse. (There may be no pending navigation |
+ // for data URLs that don't make network requests, for example.) If not, |
+ // just return early and ignore. |
+ if (render_view_host != render_view_host_ || !pending_nav_params_.get()) { |
+ pending_nav_params_.reset(); |
+ return; |
+ } |
+ |
+ // Now that the unload handler has run, we need to resume the paused response. |
+ if (pending_render_view_host_) { |
+ RenderProcessHostImpl* pending_process = |
+ static_cast<RenderProcessHostImpl*>( |
+ pending_render_view_host_->GetProcess()); |
+ pending_process->ResumeDeferredNavigation( |
+ pending_nav_params_->global_request_id); |
+ } |
+ pending_nav_params_.reset(); |
+} |
+ |
void RenderViewHostManager::DidNavigateMainFrame( |
RenderViewHost* render_view_host) { |
if (!cross_navigation_pending_) { |
@@ -239,10 +260,8 @@ void RenderViewHostManager::DidNavigateMainFrame( |
// If it committed without sending network requests (e.g., data URLs), |
// then we still need to swap out the old RVH first and run its unload |
// handler. OK for that to happen in the background. |
- if (pending_render_view_host_->GetPendingRequestId() == -1) { |
- OnCrossSiteResponse(pending_render_view_host_->GetProcess()->GetID(), |
- pending_render_view_host_->GetRoutingID()); |
- } |
+ if (pending_render_view_host_->HasPendingCrossSiteRequest()) |
+ SwapOutOldPage(); |
CommitPending(); |
cross_navigation_pending_ = false; |
@@ -340,8 +359,20 @@ void RenderViewHostManager::ShouldClosePage( |
} |
} |
-void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, |
- int new_request_id) { |
+void RenderViewHostManager::OnCrossSiteResponse( |
+ RenderViewHost* pending_render_view_host, |
+ const GlobalRequestID& global_request_id) { |
+ // This should be called when the pending RVH is ready to commit. |
+ DCHECK_EQ(pending_render_view_host_, pending_render_view_host); |
+ |
+ // Remember the request ID until the unload handler has run. |
+ pending_nav_params_.reset(new PendingNavigationParams(global_request_id)); |
+ |
+ // Run the unload handler of the current page. |
+ SwapOutOldPage(); |
+} |
+ |
+void RenderViewHostManager::SwapOutOldPage() { |
// Should only see this while we have a pending renderer. |
if (!cross_navigation_pending_) |
return; |
@@ -350,16 +381,15 @@ void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, |
// Tell the old renderer it is being swapped out. This will fire the unload |
// handler (without firing the beforeunload handler a second time). When the |
// unload handler finishes and the navigation completes, we will send a |
- // message to the ResourceDispatcherHost with the given pending request IDs, |
- // allowing the pending RVH's response to resume. |
- render_view_host_->SwapOut(new_render_process_host_id, new_request_id); |
+ // message to the ResourceDispatcherHost, allowing the pending RVH's response |
+ // to resume. |
+ render_view_host_->SwapOut(); |
// ResourceDispatcherHost has told us to run the onunload handler, which |
// means it is not a download or unsafe page, and we are going to perform the |
// navigation. Thus, we no longer need to remember that the RenderViewHost |
// is part of a pending cross-site request. |
- pending_render_view_host_->SetHasPendingCrossSiteRequest(false, |
- new_request_id); |
+ pending_render_view_host_->SetHasPendingCrossSiteRequest(false); |
} |
void RenderViewHostManager::Observe( |
@@ -858,7 +888,7 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( |
// Tell the CrossSiteRequestManager that this RVH has a pending cross-site |
// request, so that ResourceDispatcherHost will know to tell us to run the |
// old page's unload handler before it sends the response. |
- pending_render_view_host_->SetHasPendingCrossSiteRequest(true, -1); |
+ pending_render_view_host_->SetHasPendingCrossSiteRequest(true); |
// We now have a pending RVH. |
DCHECK(!cross_navigation_pending_); |
@@ -920,9 +950,7 @@ void RenderViewHostManager::CancelPending() { |
// Any currently suspended navigations are no longer needed. |
pending_render_view_host->CancelSuspendedNavigations(); |
- // We can pass -1,-1 because there is no pending response in the |
- // ResourceDispatcherHost to unpause. |
- pending_render_view_host->SwapOut(-1, -1); |
+ pending_render_view_host->SwapOut(); |
} else { |
// We won't be coming back, so shut this one down. |
pending_render_view_host->Shutdown(); |