Chromium Code Reviews| 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..8213b6dd72cb4579fa3594e4651f2b60b3148d4d 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,36 @@ void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( |
| } |
| } |
| +void ResourceDispatcherHostImpl::RegisterInterceptor( |
| + const std::string& http_header, |
| + const std::string& starts_with, |
| + ResourceDispatcherHostInterceptor* 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::UnregisterInterceptor( |
| + const std::string& http_header, |
| + ResourceDispatcherHostInterceptor* interceptor) { |
| + HeaderInterceptorMap::iterator index = |
| + http_header_interceptor_map_.find(http_header); |
| + if (index == http_header_interceptor_map_.end() || |
| + index->second.interceptor != interceptor) { |
| + NOTREACHED() << "Invalid http header or interceptor passed in."; |
| + return; |
| + } |
| + http_header_interceptor_map_.erase(index); |
| +} |
| + |
| void ResourceDispatcherHostImpl::Shutdown() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| BrowserThread::PostTask(BrowserThread::IO, |
| @@ -1357,13 +1331,55 @@ 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; |
| + base::Callback<void(bool)> callback; |
| + if (!is_shutdown_) { |
| + ResourceDispatcherHostInterceptor::OnHeaderProcessedCallback 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) { |
| + ContinuePendingBeginRequest(request_id, request_data, sync_result, route_id, |
|
jam
2016/08/09 01:36:24
nit: to avoid duplicating this from line 1337, can
ananta
2016/08/09 05:47:47
Done.
|
| + headers, 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)); |
| 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 +2621,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, |
| + ResourceDispatcherHostInterceptor::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->OnHttpHeaderReceived( |
| + it.name(), it.value(), child_id, resource_context, callback); |
| + return PENDING; |
| + } |
| + } |
| + } |
| + return CONTINUE; |
| +} |
| + |
| } // namespace content |