Index: content/browser/loader/resource_dispatcher_host_impl.cc |
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc |
index d0bc8a67002d511ddb64e84c43f2877d24a3344c..9218ffb4fcb1ba39209ce165d9f03810dc933515 100644 |
--- a/content/browser/loader/resource_dispatcher_host_impl.cc |
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc |
@@ -286,69 +286,6 @@ void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) { |
request->set_referrer_policy(net_referrer_policy); |
} |
-// Consults the RendererSecurity policy to determine whether the |
-// ResourceDispatcherHostImpl should service this request. A request might be |
-// disallowed if the renderer is not authorized to retrieve the request URL or |
-// if the renderer is attempting to upload an unauthorized file. |
-bool ShouldServiceRequest(int process_type, |
- int child_id, |
- const ResourceRequest& request_data, |
- const net::HttpRequestHeaders& headers, |
- ResourceMessageFilter* filter, |
- ResourceContext* resource_context) { |
- ChildProcessSecurityPolicyImpl* policy = |
- ChildProcessSecurityPolicyImpl::GetInstance(); |
- |
- // Check if the renderer is permitted to request the requested URL. |
- if (!policy->CanRequestURL(child_id, request_data.url)) { |
- VLOG(1) << "Denied unauthorized request for " |
- << request_data.url.possibly_invalid_spec(); |
- return false; |
- } |
- |
- // Check if the renderer is using an illegal Origin header. If so, kill it. |
- std::string origin_string; |
- bool has_origin = headers.GetHeader("Origin", &origin_string) && |
- origin_string != "null"; |
- if (has_origin) { |
- GURL origin(origin_string); |
- if (!policy->CanCommitURL(child_id, origin) || |
- GetContentClient()->browser()->IsIllegalOrigin(resource_context, |
- child_id, origin)) { |
- VLOG(1) << "Killed renderer for illegal origin: " << origin_string; |
- bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); |
- return false; |
- } |
- } |
- |
- // Check if the renderer is permitted to upload the requested files. |
- if (request_data.request_body.get()) { |
- const std::vector<ResourceRequestBodyImpl::Element>* uploads = |
- request_data.request_body->elements(); |
- std::vector<ResourceRequestBodyImpl::Element>::const_iterator iter; |
- for (iter = uploads->begin(); iter != uploads->end(); ++iter) { |
- if (iter->type() == ResourceRequestBodyImpl::Element::TYPE_FILE && |
- !policy->CanReadFile(child_id, iter->path())) { |
- NOTREACHED() << "Denied unauthorized upload of " |
- << iter->path().value(); |
- return false; |
- } |
- if (iter->type() == |
- ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) { |
- storage::FileSystemURL url = |
- filter->file_system_context()->CrackURL(iter->filesystem_url()); |
- if (!policy->CanReadFileSystemFile(child_id, url)) { |
- NOTREACHED() << "Denied unauthorized upload of " |
- << iter->filesystem_url().spec(); |
- return false; |
- } |
- } |
- } |
- } |
- |
- return true; |
-} |
- |
void RemoveDownloadFileFromChildSecurityPolicy(int child_id, |
const base::FilePath& path) { |
ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile( |
@@ -493,6 +430,13 @@ void NotifyForEachFrameFromUI( |
} // namespace |
+ResourceDispatcherHostImpl::HeaderInterceptorInfo::HeaderInterceptorInfo() {} |
+ |
+ResourceDispatcherHostImpl::HeaderInterceptorInfo::~HeaderInterceptorInfo() {} |
+ |
+ResourceDispatcherHostImpl::HeaderInterceptorInfo::HeaderInterceptorInfo( |
+ const HeaderInterceptorInfo& other) {} |
+ |
// static |
ResourceDispatcherHost* ResourceDispatcherHost::Get() { |
return g_resource_dispatcher_host; |
@@ -749,6 +693,23 @@ void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( |
} |
} |
+void ResourceDispatcherHostImpl::RegisterInterceptor( |
+ const std::string& http_header, |
+ const std::string& starts_with, |
+ const InterceptorCallback& interceptor) { |
+ DCHECK(!http_header.empty()); |
+ DCHECK(interceptor); |
+ // Only one interceptor per header is supported. |
+ DCHECK(http_header_interceptor_map_.find(http_header) == |
+ http_header_interceptor_map_.end()); |
+ |
+ HeaderInterceptorInfo interceptor_info; |
+ interceptor_info.starts_with = starts_with; |
+ interceptor_info.interceptor = interceptor; |
+ |
+ http_header_interceptor_map_[http_header] = interceptor_info; |
+} |
+ |
void ResourceDispatcherHostImpl::Shutdown() { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
BrowserThread::PostTask(BrowserThread::IO, |
@@ -1357,13 +1318,54 @@ void ResourceDispatcherHostImpl::BeginRequest( |
net::HttpRequestHeaders headers; |
headers.AddHeadersFromString(request_data.headers); |
- if (is_shutdown_ || |
- !ShouldServiceRequest(process_type, child_id, request_data, headers, |
- filter_, resource_context)) { |
+ BeginRequestStatus begin_request_status = CONTINUE; |
+ OnHeaderProcessedCallback callback; |
+ if (!is_shutdown_) { |
+ callback = |
+ base::Bind(&ResourceDispatcherHostImpl::ContinuePendingBeginRequest, |
+ base::Unretained(this), request_id, request_data, |
+ sync_result, route_id, headers); |
+ begin_request_status = |
+ ShouldServiceRequest(process_type, child_id, request_data, headers, |
+ filter_, resource_context, callback); |
+ } else { |
+ begin_request_status = ABORT; |
+ } |
+ if (begin_request_status == ABORT) { |
+ AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
+ return; |
+ } else if (begin_request_status == CONTINUE) { |
+ callback.Run(true, 0); |
+ } |
+} |
+ |
+void ResourceDispatcherHostImpl::ContinuePendingBeginRequest( |
+ int request_id, |
+ const ResourceRequest& request_data, |
+ IPC::Message* sync_result, // only valid for sync |
+ int route_id, |
+ const net::HttpRequestHeaders& headers, |
+ bool continue_request, |
+ int error_code) { |
+ if (!continue_request) { |
+ bad_message::ReceivedBadMessage( |
+ filter_, static_cast<bad_message::BadMessageReason>(error_code)); |
Charlie Reis
2016/08/10 20:44:02
This is not a safe cast. The INVALID_ORIGIN code
|
AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
return; |
} |
+ int process_type = filter_->process_type(); |
+ int child_id = filter_->child_id(); |
+ |
+ bool is_navigation_stream_request = |
+ IsBrowserSideNavigationEnabled() && |
+ IsResourceTypeFrame(request_data.resource_type); |
+ |
+ ResourceContext* resource_context = NULL; |
+ net::URLRequestContext* request_context = NULL; |
+ filter_->GetContexts(request_data.resource_type, &resource_context, |
+ &request_context); |
+ |
// Allow the observer to block/handle the request. |
if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method, |
request_data.url, |
@@ -2605,4 +2607,87 @@ CertStore* ResourceDispatcherHostImpl::GetCertStore() { |
: CertStore::GetInstance(); |
} |
+ResourceDispatcherHostImpl::BeginRequestStatus |
+ResourceDispatcherHostImpl::ShouldServiceRequest( |
+ int process_type, |
+ int child_id, |
+ const ResourceRequest& request_data, |
+ const net::HttpRequestHeaders& headers, |
+ ResourceMessageFilter* filter, |
+ ResourceContext* resource_context, |
+ OnHeaderProcessedCallback callback) { |
+ ChildProcessSecurityPolicyImpl* policy = |
+ ChildProcessSecurityPolicyImpl::GetInstance(); |
+ |
+ // Check if the renderer is permitted to request the requested URL. |
+ if (!policy->CanRequestURL(child_id, request_data.url)) { |
+ VLOG(1) << "Denied unauthorized request for " |
+ << request_data.url.possibly_invalid_spec(); |
+ return ABORT; |
+ } |
+ |
+ // Check if the renderer is using an illegal Origin header. If so, kill it. |
+ std::string origin_string; |
+ bool has_origin = |
+ headers.GetHeader("Origin", &origin_string) && origin_string != "null"; |
+ if (has_origin) { |
+ GURL origin(origin_string); |
+ if (!policy->CanCommitURL(child_id, origin)) { |
+ VLOG(1) << "Killed renderer for illegal origin: " << origin_string; |
+ bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); |
+ return ABORT; |
+ } |
+ } |
+ |
+ // Check if the renderer is permitted to upload the requested files. |
+ if (request_data.request_body.get()) { |
+ const std::vector<ResourceRequestBodyImpl::Element>* uploads = |
+ request_data.request_body->elements(); |
+ std::vector<ResourceRequestBodyImpl::Element>::const_iterator iter; |
+ for (iter = uploads->begin(); iter != uploads->end(); ++iter) { |
+ if (iter->type() == ResourceRequestBodyImpl::Element::TYPE_FILE && |
+ !policy->CanReadFile(child_id, iter->path())) { |
+ NOTREACHED() << "Denied unauthorized upload of " |
+ << iter->path().value(); |
+ return ABORT; |
+ } |
+ if (iter->type() == |
+ ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) { |
+ storage::FileSystemURL url = |
+ filter->file_system_context()->CrackURL(iter->filesystem_url()); |
+ if (!policy->CanReadFileSystemFile(child_id, url)) { |
+ NOTREACHED() << "Denied unauthorized upload of " |
+ << iter->filesystem_url().spec(); |
+ return ABORT; |
+ } |
+ } |
+ } |
+ } |
+ |
+ // Check if we have a registered interceptor for the headers passed in. If |
+ // yes then we need to mark the current request as pending and wait for the |
+ // interceptor to invoke the |callback| with a status code indicating whether |
+ // the request needs to be aborted or continued. |
+ for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();) { |
+ HeaderInterceptorMap::iterator index = |
+ http_header_interceptor_map_.find(it.name()); |
+ if (index != http_header_interceptor_map_.end()) { |
+ HeaderInterceptorInfo& interceptor_info = index->second; |
+ |
+ bool call_interceptor = true; |
+ if (!interceptor_info.starts_with.empty()) { |
+ call_interceptor = |
+ base::StartsWith(it.value(), interceptor_info.starts_with, |
+ base::CompareCase::INSENSITIVE_ASCII); |
+ } |
+ if (call_interceptor) { |
+ interceptor_info.interceptor.Run(it.name(), it.value(), child_id, |
+ resource_context, callback); |
+ return PENDING; |
+ } |
+ } |
+ } |
+ return CONTINUE; |
+} |
+ |
} // namespace content |