This source file includes following definitions.
- OnCrossSiteResponseHelper
- did_defer_
- OnRequestRedirected
- OnResponseStarted
- OnReadCompleted
- OnResponseCompleted
- ResumeResponse
- SetLeakRequestsForTesting
- StartCrossSiteTransition
- ResumeIfDeferred
- OnDidDefer
#include "content/browser/loader/cross_site_resource_handler.h"
#include <string>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/cross_site_request_manager.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_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/browser/site_instance.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/resource_response.h"
#include "content/public/common/url_constants.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
namespace content {
namespace {
bool leak_requests_for_testing_ = false;
struct CrossSiteResponseParams {
CrossSiteResponseParams(
int render_frame_id,
const GlobalRequestID& global_request_id,
bool is_transfer,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
PageTransition page_transition,
bool should_replace_current_entry)
: render_frame_id(render_frame_id),
global_request_id(global_request_id),
is_transfer(is_transfer),
transfer_url_chain(transfer_url_chain),
referrer(referrer),
page_transition(page_transition),
should_replace_current_entry(should_replace_current_entry) {
}
int render_frame_id;
GlobalRequestID global_request_id;
bool is_transfer;
std::vector<GURL> transfer_url_chain;
Referrer referrer;
PageTransition page_transition;
bool should_replace_current_entry;
};
void OnCrossSiteResponseHelper(const CrossSiteResponseParams& params) {
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request;
if (params.is_transfer) {
cross_site_transferring_request.reset(new CrossSiteTransferringRequest(
params.global_request_id));
}
RenderFrameHostImpl* rfh =
RenderFrameHostImpl::FromID(params.global_request_id.child_id,
params.render_frame_id);
if (rfh) {
rfh->OnCrossSiteResponse(
params.global_request_id, cross_site_transferring_request.Pass(),
params.transfer_url_chain, params.referrer,
params.page_transition, params.should_replace_current_entry);
} else if (leak_requests_for_testing_ && cross_site_transferring_request) {
cross_site_transferring_request->ReleaseRequest();
}
}
}
CrossSiteResourceHandler::CrossSiteResourceHandler(
scoped_ptr<ResourceHandler> next_handler,
net::URLRequest* request)
: LayeredResourceHandler(request, next_handler.Pass()),
has_started_response_(false),
in_cross_site_transition_(false),
completed_during_transition_(false),
did_defer_(false) {
}
CrossSiteResourceHandler::~CrossSiteResourceHandler() {
GetRequestInfo()->set_cross_site_handler(NULL);
}
bool CrossSiteResourceHandler::OnRequestRedirected(
int request_id,
const GURL& new_url,
ResourceResponse* response,
bool* defer) {
DCHECK(!in_cross_site_transition_);
return next_handler_->OnRequestRedirected(
request_id, new_url, response, defer);
}
bool CrossSiteResourceHandler::OnResponseStarted(
int request_id,
ResourceResponse* response,
bool* defer) {
DCHECK(!in_cross_site_transition_);
has_started_response_ = true;
ResourceRequestInfoImpl* info = GetRequestInfo();
bool should_transfer =
GetContentClient()->browser()->ShouldSwapProcessesForRedirect(
info->GetContext(), request()->original_url(), request()->url());
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) {
GURL referrer(request()->referrer());
bool is_webui_process = ChildProcessSecurityPolicyImpl::GetInstance()->
HasWebUIBindings(info->GetChildID());
if (info->GetResourceType() == ResourceType::SUB_FRAME &&
!is_webui_process &&
!SiteInstance::IsSameWebSite(NULL, request()->url(), referrer)) {
should_transfer = true;
}
}
bool swap_needed = should_transfer ||
CrossSiteRequestManager::GetInstance()->
HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID());
if (!swap_needed || info->IsDownload() || info->is_stream() ||
(response->head.headers.get() &&
response->head.headers->response_code() == 204)) {
return next_handler_->OnResponseStarted(request_id, response, defer);
}
StartCrossSiteTransition(request_id, response, should_transfer);
*defer = true;
OnDidDefer();
return true;
}
bool CrossSiteResourceHandler::OnReadCompleted(int request_id,
int bytes_read,
bool* defer) {
CHECK(!in_cross_site_transition_);
return next_handler_->OnReadCompleted(request_id, bytes_read, defer);
}
void CrossSiteResourceHandler::OnResponseCompleted(
int request_id,
const net::URLRequestStatus& status,
const std::string& security_info,
bool* defer) {
if (!in_cross_site_transition_) {
ResourceRequestInfoImpl* info = GetRequestInfo();
if (has_started_response_ ||
status.status() != net::URLRequestStatus::FAILED ||
!CrossSiteRequestManager::GetInstance()->HasPendingCrossSiteRequest(
info->GetChildID(), info->GetRouteID())) {
next_handler_->OnResponseCompleted(request_id, status,
security_info, defer);
return;
}
StartCrossSiteTransition(request_id, NULL, false);
}
completed_during_transition_ = true;
completed_status_ = status;
completed_security_info_ = security_info;
*defer = true;
OnDidDefer();
}
void CrossSiteResourceHandler::ResumeResponse() {
DCHECK(request());
DCHECK(in_cross_site_transition_);
in_cross_site_transition_ = false;
ResourceRequestInfoImpl* info = GetRequestInfo();
if (has_started_response_) {
DCHECK(response_);
bool defer = false;
if (!next_handler_->OnResponseStarted(info->GetRequestID(), response_.get(),
&defer)) {
controller()->Cancel();
} else if (!defer) {
ResumeIfDeferred();
}
}
info->set_cross_site_handler(NULL);
if (completed_during_transition_) {
bool defer = false;
next_handler_->OnResponseCompleted(info->GetRequestID(),
completed_status_,
completed_security_info_,
&defer);
if (!defer)
ResumeIfDeferred();
}
}
void CrossSiteResourceHandler::SetLeakRequestsForTesting(
bool leak_requests_for_testing) {
leak_requests_for_testing_ = leak_requests_for_testing;
}
void CrossSiteResourceHandler::StartCrossSiteTransition(
int request_id,
ResourceResponse* response,
bool should_transfer) {
in_cross_site_transition_ = true;
response_ = response;
ResourceRequestInfoImpl* info = GetRequestInfo();
info->set_cross_site_handler(this);
DCHECK_EQ(request_id, info->GetRequestID());
GlobalRequestID global_id(info->GetChildID(), info->GetRequestID());
std::vector<GURL> transfer_url_chain;
Referrer referrer;
int render_frame_id = info->GetRenderFrameID();
if (should_transfer) {
transfer_url_chain = request()->url_chain();
referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
AppCacheInterceptor::PrepareForCrossSiteTransfer(
request(), global_id.child_id);
ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id);
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(
&OnCrossSiteResponseHelper,
CrossSiteResponseParams(render_frame_id,
global_id,
should_transfer,
transfer_url_chain,
referrer,
info->GetPageTransition(),
info->should_replace_current_entry())));
}
void CrossSiteResourceHandler::ResumeIfDeferred() {
if (did_defer_) {
request()->LogUnblocked();
did_defer_ = false;
controller()->Resume();
}
}
void CrossSiteResourceHandler::OnDidDefer() {
did_defer_ = true;
request()->LogBlockedBy("CrossSiteResourceHandler");
}
}