Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading | 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading |
| 6 | 6 |
| 7 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 7 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 8 | 8 |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 | 10 |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; | 279 CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; |
| 280 break; | 280 break; |
| 281 case blink::WebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin: | 281 case blink::WebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin: |
| 282 net_referrer_policy = net::URLRequest:: | 282 net_referrer_policy = net::URLRequest:: |
| 283 REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; | 283 REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
| 284 break; | 284 break; |
| 285 } | 285 } |
| 286 request->set_referrer_policy(net_referrer_policy); | 286 request->set_referrer_policy(net_referrer_policy); |
| 287 } | 287 } |
| 288 | 288 |
| 289 // Consults the RendererSecurity policy to determine whether the | |
| 290 // ResourceDispatcherHostImpl should service this request. A request might be | |
| 291 // disallowed if the renderer is not authorized to retrieve the request URL or | |
| 292 // if the renderer is attempting to upload an unauthorized file. | |
| 293 bool ShouldServiceRequest(int process_type, | |
| 294 int child_id, | |
| 295 const ResourceRequest& request_data, | |
| 296 const net::HttpRequestHeaders& headers, | |
| 297 ResourceMessageFilter* filter, | |
| 298 ResourceContext* resource_context) { | |
| 299 ChildProcessSecurityPolicyImpl* policy = | |
| 300 ChildProcessSecurityPolicyImpl::GetInstance(); | |
| 301 | |
| 302 // Check if the renderer is permitted to request the requested URL. | |
| 303 if (!policy->CanRequestURL(child_id, request_data.url)) { | |
| 304 VLOG(1) << "Denied unauthorized request for " | |
| 305 << request_data.url.possibly_invalid_spec(); | |
| 306 return false; | |
| 307 } | |
| 308 | |
| 309 // Check if the renderer is using an illegal Origin header. If so, kill it. | |
| 310 std::string origin_string; | |
| 311 bool has_origin = headers.GetHeader("Origin", &origin_string) && | |
| 312 origin_string != "null"; | |
| 313 if (has_origin) { | |
| 314 GURL origin(origin_string); | |
| 315 if (!policy->CanCommitURL(child_id, origin) || | |
| 316 GetContentClient()->browser()->IsIllegalOrigin(resource_context, | |
| 317 child_id, origin)) { | |
| 318 VLOG(1) << "Killed renderer for illegal origin: " << origin_string; | |
| 319 bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); | |
| 320 return false; | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 // Check if the renderer is permitted to upload the requested files. | |
| 325 if (request_data.request_body.get()) { | |
| 326 const std::vector<ResourceRequestBodyImpl::Element>* uploads = | |
| 327 request_data.request_body->elements(); | |
| 328 std::vector<ResourceRequestBodyImpl::Element>::const_iterator iter; | |
| 329 for (iter = uploads->begin(); iter != uploads->end(); ++iter) { | |
| 330 if (iter->type() == ResourceRequestBodyImpl::Element::TYPE_FILE && | |
| 331 !policy->CanReadFile(child_id, iter->path())) { | |
| 332 NOTREACHED() << "Denied unauthorized upload of " | |
| 333 << iter->path().value(); | |
| 334 return false; | |
| 335 } | |
| 336 if (iter->type() == | |
| 337 ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) { | |
| 338 storage::FileSystemURL url = | |
| 339 filter->file_system_context()->CrackURL(iter->filesystem_url()); | |
| 340 if (!policy->CanReadFileSystemFile(child_id, url)) { | |
| 341 NOTREACHED() << "Denied unauthorized upload of " | |
| 342 << iter->filesystem_url().spec(); | |
| 343 return false; | |
| 344 } | |
| 345 } | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 return true; | |
| 350 } | |
| 351 | |
| 352 void RemoveDownloadFileFromChildSecurityPolicy(int child_id, | 289 void RemoveDownloadFileFromChildSecurityPolicy(int child_id, |
| 353 const base::FilePath& path) { | 290 const base::FilePath& path) { |
| 354 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile( | 291 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile( |
| 355 child_id, path); | 292 child_id, path); |
| 356 } | 293 } |
| 357 | 294 |
| 358 int GetCertID(CertStore* cert_store, net::URLRequest* request, int child_id) { | 295 int GetCertID(CertStore* cert_store, net::URLRequest* request, int child_id) { |
| 359 if (request->ssl_info().cert.get()) | 296 if (request->ssl_info().cert.get()) |
| 360 return cert_store->StoreCert(request->ssl_info().cert.get(), child_id); | 297 return cert_store->StoreCert(request->ssl_info().cert.get(), child_id); |
| 361 return 0; | 298 return 0; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 486 if (pending_frame_host) | 423 if (pending_frame_host) |
| 487 routing_ids->insert(pending_frame_host->GetGlobalFrameRoutingId()); | 424 routing_ids->insert(pending_frame_host->GetGlobalFrameRoutingId()); |
| 488 } | 425 } |
| 489 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 426 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 490 base::Bind(&NotifyForRouteSetOnIO, frame_callback, | 427 base::Bind(&NotifyForRouteSetOnIO, frame_callback, |
| 491 base::Passed(std::move(routing_ids)))); | 428 base::Passed(std::move(routing_ids)))); |
| 492 } | 429 } |
| 493 | 430 |
| 494 } // namespace | 431 } // namespace |
| 495 | 432 |
| 433 ResourceDispatcherHostImpl::HeaderInterceptorInfo::HeaderInterceptorInfo() {} | |
| 434 | |
| 435 ResourceDispatcherHostImpl::HeaderInterceptorInfo::~HeaderInterceptorInfo() {} | |
| 436 | |
| 437 ResourceDispatcherHostImpl::HeaderInterceptorInfo::HeaderInterceptorInfo( | |
| 438 const HeaderInterceptorInfo& other) {} | |
| 439 | |
| 496 // static | 440 // static |
| 497 ResourceDispatcherHost* ResourceDispatcherHost::Get() { | 441 ResourceDispatcherHost* ResourceDispatcherHost::Get() { |
| 498 return g_resource_dispatcher_host; | 442 return g_resource_dispatcher_host; |
| 499 } | 443 } |
| 500 | 444 |
| 501 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() | 445 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() |
| 502 : save_file_manager_(new SaveFileManager()), | 446 : save_file_manager_(new SaveFileManager()), |
| 503 request_id_(-1), | 447 request_id_(-1), |
| 504 is_shutdown_(false), | 448 is_shutdown_(false), |
| 505 num_in_flight_requests_(0), | 449 num_in_flight_requests_(0), |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 742 void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( | 686 void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( |
| 743 net::URLRequest* request) { | 687 net::URLRequest* request) { |
| 744 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); | 688 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); |
| 745 if (info) { | 689 if (info) { |
| 746 ResourceLoader* loader = GetLoader(info->GetGlobalRequestID()); | 690 ResourceLoader* loader = GetLoader(info->GetGlobalRequestID()); |
| 747 if (loader) | 691 if (loader) |
| 748 loader->ClearLoginDelegate(); | 692 loader->ClearLoginDelegate(); |
| 749 } | 693 } |
| 750 } | 694 } |
| 751 | 695 |
| 696 void ResourceDispatcherHostImpl::RegisterInterceptor( | |
| 697 const std::string& http_header, | |
| 698 const std::string& starts_with, | |
| 699 const InterceptorCallback& interceptor) { | |
| 700 DCHECK(!http_header.empty()); | |
| 701 DCHECK(interceptor); | |
| 702 // Only one interceptor per header is supported. | |
| 703 DCHECK(http_header_interceptor_map_.find(http_header) == | |
| 704 http_header_interceptor_map_.end()); | |
| 705 | |
| 706 HeaderInterceptorInfo interceptor_info; | |
| 707 interceptor_info.starts_with = starts_with; | |
| 708 interceptor_info.interceptor = interceptor; | |
| 709 | |
| 710 http_header_interceptor_map_[http_header] = interceptor_info; | |
| 711 } | |
| 712 | |
| 752 void ResourceDispatcherHostImpl::Shutdown() { | 713 void ResourceDispatcherHostImpl::Shutdown() { |
| 753 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 714 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 754 BrowserThread::PostTask(BrowserThread::IO, | 715 BrowserThread::PostTask(BrowserThread::IO, |
| 755 FROM_HERE, | 716 FROM_HERE, |
| 756 base::Bind(&ResourceDispatcherHostImpl::OnShutdown, | 717 base::Bind(&ResourceDispatcherHostImpl::OnShutdown, |
| 757 base::Unretained(this))); | 718 base::Unretained(this))); |
| 758 } | 719 } |
| 759 | 720 |
| 760 std::unique_ptr<ResourceHandler> | 721 std::unique_ptr<ResourceHandler> |
| 761 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload( | 722 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload( |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1350 ResourceContext* resource_context = NULL; | 1311 ResourceContext* resource_context = NULL; |
| 1351 net::URLRequestContext* request_context = NULL; | 1312 net::URLRequestContext* request_context = NULL; |
| 1352 filter_->GetContexts(request_data.resource_type, &resource_context, | 1313 filter_->GetContexts(request_data.resource_type, &resource_context, |
| 1353 &request_context); | 1314 &request_context); |
| 1354 | 1315 |
| 1355 // Parse the headers before calling ShouldServiceRequest, so that they are | 1316 // Parse the headers before calling ShouldServiceRequest, so that they are |
| 1356 // available to be validated. | 1317 // available to be validated. |
| 1357 net::HttpRequestHeaders headers; | 1318 net::HttpRequestHeaders headers; |
| 1358 headers.AddHeadersFromString(request_data.headers); | 1319 headers.AddHeadersFromString(request_data.headers); |
| 1359 | 1320 |
| 1360 if (is_shutdown_ || | 1321 BeginRequestStatus begin_request_status = CONTINUE; |
| 1361 !ShouldServiceRequest(process_type, child_id, request_data, headers, | 1322 OnHeaderProcessedCallback callback; |
| 1362 filter_, resource_context)) { | 1323 if (!is_shutdown_) { |
| 1324 callback = | |
| 1325 base::Bind(&ResourceDispatcherHostImpl::ContinuePendingBeginRequest, | |
| 1326 base::Unretained(this), request_id, request_data, | |
| 1327 sync_result, route_id, headers); | |
| 1328 begin_request_status = | |
| 1329 ShouldServiceRequest(process_type, child_id, request_data, headers, | |
| 1330 filter_, resource_context, callback); | |
| 1331 } else { | |
| 1332 begin_request_status = ABORT; | |
| 1333 } | |
| 1334 if (begin_request_status == ABORT) { | |
| 1335 AbortRequestBeforeItStarts(filter_, sync_result, request_id); | |
| 1336 return; | |
| 1337 } else if (begin_request_status == CONTINUE) { | |
| 1338 callback.Run(true, 0); | |
| 1339 } | |
| 1340 } | |
| 1341 | |
| 1342 void ResourceDispatcherHostImpl::ContinuePendingBeginRequest( | |
| 1343 int request_id, | |
| 1344 const ResourceRequest& request_data, | |
| 1345 IPC::Message* sync_result, // only valid for sync | |
| 1346 int route_id, | |
| 1347 const net::HttpRequestHeaders& headers, | |
| 1348 bool continue_request, | |
| 1349 int error_code) { | |
| 1350 if (!continue_request) { | |
| 1351 bad_message::ReceivedBadMessage( | |
| 1352 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
| |
| 1363 AbortRequestBeforeItStarts(filter_, sync_result, request_id); | 1353 AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
| 1364 return; | 1354 return; |
| 1365 } | 1355 } |
| 1366 | 1356 |
| 1357 int process_type = filter_->process_type(); | |
| 1358 int child_id = filter_->child_id(); | |
| 1359 | |
| 1360 bool is_navigation_stream_request = | |
| 1361 IsBrowserSideNavigationEnabled() && | |
| 1362 IsResourceTypeFrame(request_data.resource_type); | |
| 1363 | |
| 1364 ResourceContext* resource_context = NULL; | |
| 1365 net::URLRequestContext* request_context = NULL; | |
| 1366 filter_->GetContexts(request_data.resource_type, &resource_context, | |
| 1367 &request_context); | |
| 1368 | |
| 1367 // Allow the observer to block/handle the request. | 1369 // Allow the observer to block/handle the request. |
| 1368 if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method, | 1370 if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method, |
| 1369 request_data.url, | 1371 request_data.url, |
| 1370 request_data.resource_type, | 1372 request_data.resource_type, |
| 1371 resource_context)) { | 1373 resource_context)) { |
| 1372 AbortRequestBeforeItStarts(filter_, sync_result, request_id); | 1374 AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
| 1373 return; | 1375 return; |
| 1374 } | 1376 } |
| 1375 | 1377 |
| 1376 // Construct the request. | 1378 // Construct the request. |
| (...skipping 1221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2598 DCHECK(deserialized); | 2600 DCHECK(deserialized); |
| 2599 ssl.cert_id = GetCertStore()->StoreCert(ssl_info.cert.get(), child_id); | 2601 ssl.cert_id = GetCertStore()->StoreCert(ssl_info.cert.get(), child_id); |
| 2600 response->head.security_info = SerializeSecurityInfo(ssl); | 2602 response->head.security_info = SerializeSecurityInfo(ssl); |
| 2601 } | 2603 } |
| 2602 | 2604 |
| 2603 CertStore* ResourceDispatcherHostImpl::GetCertStore() { | 2605 CertStore* ResourceDispatcherHostImpl::GetCertStore() { |
| 2604 return cert_store_for_testing_ ? cert_store_for_testing_ | 2606 return cert_store_for_testing_ ? cert_store_for_testing_ |
| 2605 : CertStore::GetInstance(); | 2607 : CertStore::GetInstance(); |
| 2606 } | 2608 } |
| 2607 | 2609 |
| 2610 ResourceDispatcherHostImpl::BeginRequestStatus | |
| 2611 ResourceDispatcherHostImpl::ShouldServiceRequest( | |
| 2612 int process_type, | |
| 2613 int child_id, | |
| 2614 const ResourceRequest& request_data, | |
| 2615 const net::HttpRequestHeaders& headers, | |
| 2616 ResourceMessageFilter* filter, | |
| 2617 ResourceContext* resource_context, | |
| 2618 OnHeaderProcessedCallback callback) { | |
| 2619 ChildProcessSecurityPolicyImpl* policy = | |
| 2620 ChildProcessSecurityPolicyImpl::GetInstance(); | |
| 2621 | |
| 2622 // Check if the renderer is permitted to request the requested URL. | |
| 2623 if (!policy->CanRequestURL(child_id, request_data.url)) { | |
| 2624 VLOG(1) << "Denied unauthorized request for " | |
| 2625 << request_data.url.possibly_invalid_spec(); | |
| 2626 return ABORT; | |
| 2627 } | |
| 2628 | |
| 2629 // Check if the renderer is using an illegal Origin header. If so, kill it. | |
| 2630 std::string origin_string; | |
| 2631 bool has_origin = | |
| 2632 headers.GetHeader("Origin", &origin_string) && origin_string != "null"; | |
| 2633 if (has_origin) { | |
| 2634 GURL origin(origin_string); | |
| 2635 if (!policy->CanCommitURL(child_id, origin)) { | |
| 2636 VLOG(1) << "Killed renderer for illegal origin: " << origin_string; | |
| 2637 bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); | |
| 2638 return ABORT; | |
| 2639 } | |
| 2640 } | |
| 2641 | |
| 2642 // Check if the renderer is permitted to upload the requested files. | |
| 2643 if (request_data.request_body.get()) { | |
| 2644 const std::vector<ResourceRequestBodyImpl::Element>* uploads = | |
| 2645 request_data.request_body->elements(); | |
| 2646 std::vector<ResourceRequestBodyImpl::Element>::const_iterator iter; | |
| 2647 for (iter = uploads->begin(); iter != uploads->end(); ++iter) { | |
| 2648 if (iter->type() == ResourceRequestBodyImpl::Element::TYPE_FILE && | |
| 2649 !policy->CanReadFile(child_id, iter->path())) { | |
| 2650 NOTREACHED() << "Denied unauthorized upload of " | |
| 2651 << iter->path().value(); | |
| 2652 return ABORT; | |
| 2653 } | |
| 2654 if (iter->type() == | |
| 2655 ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) { | |
| 2656 storage::FileSystemURL url = | |
| 2657 filter->file_system_context()->CrackURL(iter->filesystem_url()); | |
| 2658 if (!policy->CanReadFileSystemFile(child_id, url)) { | |
| 2659 NOTREACHED() << "Denied unauthorized upload of " | |
| 2660 << iter->filesystem_url().spec(); | |
| 2661 return ABORT; | |
| 2662 } | |
| 2663 } | |
| 2664 } | |
| 2665 } | |
| 2666 | |
| 2667 // Check if we have a registered interceptor for the headers passed in. If | |
| 2668 // yes then we need to mark the current request as pending and wait for the | |
| 2669 // interceptor to invoke the |callback| with a status code indicating whether | |
| 2670 // the request needs to be aborted or continued. | |
| 2671 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();) { | |
| 2672 HeaderInterceptorMap::iterator index = | |
| 2673 http_header_interceptor_map_.find(it.name()); | |
| 2674 if (index != http_header_interceptor_map_.end()) { | |
| 2675 HeaderInterceptorInfo& interceptor_info = index->second; | |
| 2676 | |
| 2677 bool call_interceptor = true; | |
| 2678 if (!interceptor_info.starts_with.empty()) { | |
| 2679 call_interceptor = | |
| 2680 base::StartsWith(it.value(), interceptor_info.starts_with, | |
| 2681 base::CompareCase::INSENSITIVE_ASCII); | |
| 2682 } | |
| 2683 if (call_interceptor) { | |
| 2684 interceptor_info.interceptor.Run(it.name(), it.value(), child_id, | |
| 2685 resource_context, callback); | |
| 2686 return PENDING; | |
| 2687 } | |
| 2688 } | |
| 2689 } | |
| 2690 return CONTINUE; | |
| 2691 } | |
| 2692 | |
| 2608 } // namespace content | 2693 } // namespace content |
| OLD | NEW |