| Index: content/browser/loader/cross_site_resource_handler.cc
|
| diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc
|
| index 90fe84a6b50515deaf3ed80b25fceffccb3ffe9c..6bac75adde6b8246e7748a8876d22973ab1c9988 100644
|
| --- a/content/browser/loader/cross_site_resource_handler.cc
|
| +++ b/content/browser/loader/cross_site_resource_handler.cc
|
| @@ -9,14 +9,17 @@
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| #include "content/browser/cross_site_request_manager.h"
|
| +#include "content/browser/loader/resource_dispatcher_host_impl.h"
|
| #include "content/browser/loader/resource_request_info_impl.h"
|
| #include "content/browser/renderer_host/render_view_host_delegate.h"
|
| #include "content/browser/renderer_host/render_view_host_impl.h"
|
| #include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/content_browser_client.h"
|
| #include "content/public/browser/global_request_id.h"
|
| #include "content/public/browser/resource_controller.h"
|
| #include "content/public/common/resource_response.h"
|
| #include "net/http/http_response_headers.h"
|
| +#include "net/url_request/url_request.h"
|
|
|
| namespace content {
|
|
|
| @@ -24,13 +27,21 @@ namespace {
|
|
|
| void OnCrossSiteResponseHelper(int render_process_id,
|
| int render_view_id,
|
| - int request_id) {
|
| + const GlobalRequestID& global_request_id,
|
| + bool is_transfer,
|
| + const GURL& transfer_url,
|
| + const Referrer& referrer,
|
| + int64 frame_id) {
|
| RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(render_process_id,
|
| render_view_id);
|
| - if (rvh && rvh->GetDelegate()->GetRendererManagementDelegate()) {
|
| - rvh->GetDelegate()->GetRendererManagementDelegate()->OnCrossSiteResponse(
|
| - rvh, GlobalRequestID(render_process_id, request_id));
|
| - }
|
| + if (!rvh)
|
| + return;
|
| + RenderViewHostDelegate* delegate = rvh->GetDelegate();
|
| + if (!delegate || !delegate->GetRendererManagementDelegate())
|
| + return;
|
| +
|
| + delegate->GetRendererManagementDelegate()->OnCrossSiteResponse(
|
| + rvh, global_request_id, is_transfer, transfer_url, referrer, frame_id);
|
| }
|
|
|
| } // namespace
|
| @@ -77,10 +88,16 @@ bool CrossSiteResourceHandler::OnResponseStarted(
|
|
|
| ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
|
|
|
| - // A swap may no longer be needed if we transferred back into the original
|
| - // process due to a redirect.
|
| - bool swap_needed = CrossSiteRequestManager::GetInstance()->
|
| - HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID());
|
| + // We will need to swap processes if either (1) a redirect that requires a
|
| + // transfer occurred before we got here, or (2) a pending cross-site request
|
| + // was already in progress. Note that a swap may no longer be needed if we
|
| + // transferred back into the original process due to a redirect.
|
| + bool should_transfer =
|
| + GetContentClient()->browser()->ShouldSwapProcessesForRedirect(
|
| + info->GetContext(), request_->original_url(), request_->url());
|
| + bool swap_needed = should_transfer ||
|
| + CrossSiteRequestManager::GetInstance()->
|
| + HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID());
|
|
|
| // If this is a download, just pass the response through without doing a
|
| // cross-site check. The renderer will see it is a download and abort the
|
| @@ -90,8 +107,9 @@ bool CrossSiteResourceHandler::OnResponseStarted(
|
| // page. We should allow the navigation to finish without running the unload
|
| // handler or swapping in the pending RenderViewHost.
|
| //
|
| - // In both cases, the pending RenderViewHost will stick around until the next
|
| - // cross-site navigation, since we are unable to tell when to destroy it.
|
| + // In both cases, any pending RenderViewHost (if one was created for this
|
| + // navigation) will stick around until the next cross-site navigation, since
|
| + // we are unable to tell when to destroy it.
|
| // See RenderViewHostManager::RendererAbortedProvisionalLoad.
|
| if (!swap_needed || info->is_download() ||
|
| (response->head.headers.get() &&
|
| @@ -99,8 +117,10 @@ bool CrossSiteResourceHandler::OnResponseStarted(
|
| return next_handler_->OnResponseStarted(request_id, response, defer);
|
| }
|
|
|
| - // Tell the renderer to run the onunload event handler.
|
| - StartCrossSiteTransition(request_id, response);
|
| + // Now that we know a swap is needed and we have something to commit, we
|
| + // pause to let the UI thread run the unload handler of the previous page
|
| + // and set up a transfer if needed.
|
| + StartCrossSiteTransition(request_id, response, should_transfer);
|
|
|
| // Defer loading until after the onunload event handler has run.
|
| did_defer_ = *defer = true;
|
| @@ -119,19 +139,24 @@ bool CrossSiteResourceHandler::OnResponseCompleted(
|
| const net::URLRequestStatus& status,
|
| const std::string& security_info) {
|
| if (!in_cross_site_transition_) {
|
| + ResourceRequestInfoImpl* info =
|
| + ResourceRequestInfoImpl::ForRequest(request_);
|
| + // If we've already completed the transition, or we're canceling the
|
| + // request, or an error occurred with no cross-process navigation in
|
| + // progress, then we should just pass this through.
|
| if (has_started_response_ ||
|
| - status.status() != net::URLRequestStatus::FAILED) {
|
| - // We've already completed the transition or we're canceling the request,
|
| - // so just pass it through.
|
| + status.status() != net::URLRequestStatus::FAILED ||
|
| + !CrossSiteRequestManager::GetInstance()->HasPendingCrossSiteRequest(
|
| + info->GetChildID(), info->GetRouteID())) {
|
| return next_handler_->OnResponseCompleted(request_id, status,
|
| security_info);
|
| }
|
|
|
| - // An error occured, we should wait now for the cross-site transition,
|
| + // An error occurred. We should wait now for the cross-process transition,
|
| // so that the error message (e.g., 404) can be displayed to the user.
|
| // Also continue with the logic below to remember that we completed
|
| // during the cross-site transition.
|
| - StartCrossSiteTransition(request_id, NULL);
|
| + StartCrossSiteTransition(request_id, NULL, false);
|
| }
|
|
|
| // We have to buffer the call until after the transition completes.
|
| @@ -186,19 +211,35 @@ void CrossSiteResourceHandler::ResumeResponse() {
|
| // telling the old RenderViewHost to run its onunload handler.
|
| void CrossSiteResourceHandler::StartCrossSiteTransition(
|
| int request_id,
|
| - ResourceResponse* response) {
|
| + ResourceResponse* response,
|
| + bool should_transfer) {
|
| in_cross_site_transition_ = true;
|
| response_ = response;
|
|
|
| // Store this handler on the ExtraRequestInfo, so that RDH can call our
|
| - // ResumeResponse method when the close ACK is received.
|
| + // ResumeResponse method when we are ready to resume.
|
| ResourceRequestInfoImpl* info =
|
| ResourceRequestInfoImpl::ForRequest(request_);
|
| info->set_cross_site_handler(this);
|
|
|
| + DCHECK_EQ(request_id, info->GetRequestID());
|
| + GlobalRequestID global_id(info->GetChildID(), info->GetRequestID());
|
| +
|
| // Tell the contents responsible for this request that a cross-site response
|
| // is starting, so that it can tell its old renderer to run its onunload
|
| - // handler now. We will wait to hear the corresponding ClosePage_ACK.
|
| + // handler now. We will wait until the unload is finished and (if a transfer
|
| + // is needed) for the new renderer's request to arrive.
|
| + GURL transfer_url;
|
| + Referrer referrer;
|
| + int frame_id = -1;
|
| + if (should_transfer) {
|
| + transfer_url = request_->url();
|
| + referrer = Referrer(GURL(request_->referrer()), info->GetReferrerPolicy());
|
| + frame_id = info->GetFrameID();
|
| +
|
| + ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(
|
| + global_id, transfer_url);
|
| + }
|
| BrowserThread::PostTask(
|
| BrowserThread::UI,
|
| FROM_HERE,
|
| @@ -206,10 +247,11 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
|
| &OnCrossSiteResponseHelper,
|
| info->GetChildID(),
|
| info->GetRouteID(),
|
| - request_id));
|
| -
|
| - // TODO(creis): If the above call should fail, then we need to notify the IO
|
| - // thread to proceed anyway, using ResourceDispatcherHost::OnClosePageACK.
|
| + global_id,
|
| + should_transfer,
|
| + transfer_url,
|
| + referrer,
|
| + frame_id));
|
| }
|
|
|
| void CrossSiteResourceHandler::ResumeIfDeferred() {
|
|
|