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 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 | 288 |
289 // Consults the RendererSecurity policy to determine whether the | 289 // Consults the RendererSecurity policy to determine whether the |
290 // ResourceDispatcherHostImpl should service this request. A request might be | 290 // ResourceDispatcherHostImpl should service this request. A request might be |
291 // disallowed if the renderer is not authorized to retrieve the request URL or | 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. | 292 // if the renderer is attempting to upload an unauthorized file. |
293 bool ShouldServiceRequest(int process_type, | 293 bool ShouldServiceRequest(int process_type, |
294 int child_id, | 294 int child_id, |
295 const ResourceRequest& request_data, | 295 const ResourceRequest& request_data, |
296 const net::HttpRequestHeaders& headers, | 296 const net::HttpRequestHeaders& headers, |
297 ResourceMessageFilter* filter, | 297 ResourceMessageFilter* filter, |
298 ResourceContext* resource_context) { | 298 ResourceContext* resource_context, |
| 299 ResourceDispatcherHostImpl* host) { |
299 ChildProcessSecurityPolicyImpl* policy = | 300 ChildProcessSecurityPolicyImpl* policy = |
300 ChildProcessSecurityPolicyImpl::GetInstance(); | 301 ChildProcessSecurityPolicyImpl::GetInstance(); |
301 | 302 |
302 // Check if the renderer is permitted to request the requested URL. | 303 // Check if the renderer is permitted to request the requested URL. |
303 if (!policy->CanRequestURL(child_id, request_data.url)) { | 304 if (!policy->CanRequestURL(child_id, request_data.url)) { |
304 VLOG(1) << "Denied unauthorized request for " | 305 VLOG(1) << "Denied unauthorized request for " |
305 << request_data.url.possibly_invalid_spec(); | 306 << request_data.url.possibly_invalid_spec(); |
306 return false; | 307 return false; |
307 } | 308 } |
308 | 309 |
309 // Check if the renderer is using an illegal Origin header. If so, kill it. | 310 // Check if the renderer is using an illegal Origin header. If so, kill it. |
310 std::string origin_string; | 311 std::string origin_string; |
311 bool has_origin = headers.GetHeader("Origin", &origin_string) && | 312 bool has_origin = headers.GetHeader("Origin", &origin_string) && |
312 origin_string != "null"; | 313 origin_string != "null"; |
313 if (has_origin) { | 314 if (has_origin) { |
314 GURL origin(origin_string); | 315 GURL origin(origin_string); |
315 if (!policy->CanCommitURL(child_id, origin) || | 316 if (!policy->CanCommitURL(child_id, origin) || |
316 GetContentClient()->browser()->IsIllegalOrigin(resource_context, | 317 host->IsIllegalOrigin(resource_context, origin, child_id)) { |
317 child_id, origin)) { | |
318 VLOG(1) << "Killed renderer for illegal origin: " << origin_string; | 318 VLOG(1) << "Killed renderer for illegal origin: " << origin_string; |
319 bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); | 319 bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); |
320 return false; | 320 return false; |
321 } | 321 } |
322 } | 322 } |
323 | 323 |
324 // Check if the renderer is permitted to upload the requested files. | 324 // Check if the renderer is permitted to upload the requested files. |
325 if (request_data.request_body.get()) { | 325 if (request_data.request_body.get()) { |
326 const std::vector<ResourceRequestBodyImpl::Element>* uploads = | 326 const std::vector<ResourceRequestBodyImpl::Element>* uploads = |
327 request_data.request_body->elements(); | 327 request_data.request_body->elements(); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 if (pending_frame_host) | 486 if (pending_frame_host) |
487 routing_ids->insert(pending_frame_host->GetGlobalFrameRoutingId()); | 487 routing_ids->insert(pending_frame_host->GetGlobalFrameRoutingId()); |
488 } | 488 } |
489 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 489 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
490 base::Bind(&NotifyForRouteSetOnIO, frame_callback, | 490 base::Bind(&NotifyForRouteSetOnIO, frame_callback, |
491 base::Passed(std::move(routing_ids)))); | 491 base::Passed(std::move(routing_ids)))); |
492 } | 492 } |
493 | 493 |
494 } // namespace | 494 } // namespace |
495 | 495 |
| 496 ResourceDispatcherHostImpl::OriginAccessInfo::OriginAccessInfo() { |
| 497 } |
| 498 |
| 499 ResourceDispatcherHostImpl::OriginAccessInfo::~OriginAccessInfo() { |
| 500 } |
| 501 |
| 502 ResourceDispatcherHostImpl::OriginAccessInfo::OriginAccessInfo( |
| 503 const OriginAccessInfo& other) { |
| 504 } |
| 505 |
496 // static | 506 // static |
497 ResourceDispatcherHost* ResourceDispatcherHost::Get() { | 507 ResourceDispatcherHost* ResourceDispatcherHost::Get() { |
498 return g_resource_dispatcher_host; | 508 return g_resource_dispatcher_host; |
499 } | 509 } |
500 | 510 |
501 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() | 511 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() |
502 : save_file_manager_(new SaveFileManager()), | 512 : save_file_manager_(new SaveFileManager()), |
503 request_id_(-1), | 513 request_id_(-1), |
504 is_shutdown_(false), | 514 is_shutdown_(false), |
505 num_in_flight_requests_(0), | 515 num_in_flight_requests_(0), |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
744 void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( | 754 void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( |
745 net::URLRequest* request) { | 755 net::URLRequest* request) { |
746 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); | 756 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); |
747 if (info) { | 757 if (info) { |
748 ResourceLoader* loader = GetLoader(info->GetGlobalRequestID()); | 758 ResourceLoader* loader = GetLoader(info->GetGlobalRequestID()); |
749 if (loader) | 759 if (loader) |
750 loader->ClearLoginDelegate(); | 760 loader->ClearLoginDelegate(); |
751 } | 761 } |
752 } | 762 } |
753 | 763 |
| 764 void ResourceDispatcherHostImpl::AddSchemeForAccessCheck( |
| 765 const std::string& scheme) { |
| 766 origins_for_access_check_.insert(scheme); |
| 767 } |
| 768 |
| 769 void ResourceDispatcherHostImpl::RegisterOriginForAccessChecks( |
| 770 const ResourceContext* context, |
| 771 const std::string& origin, |
| 772 OriginAccessCheckMask access_check_mask) { |
| 773 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 774 |
| 775 GURL url(origin); |
| 776 // The following conditions need to apply before we can add access |
| 777 // information for an origin. |
| 778 // 1. The URL has to be valid. |
| 779 // 2. It has to have a valid host. |
| 780 // 3. The scheme has to be registered in the list of schemes being access |
| 781 // checked. |
| 782 if (!url.is_valid() || !url.has_host() || |
| 783 origins_for_access_check_.find(url.scheme()) == |
| 784 origins_for_access_check_.end()) { |
| 785 NOTREACHED() << "Invalid URL or unregistered scheme."; |
| 786 return; |
| 787 } |
| 788 |
| 789 OriginAccessInfoMap* origin_access_info_map = |
| 790 GetOriginAccessMapForResourceContext(context); |
| 791 DCHECK(origin_access_info_map->find(url.host()) == |
| 792 origin_access_info_map->end()); |
| 793 |
| 794 OriginAccessInfo access_info; |
| 795 access_info.access_check_mask = access_check_mask; |
| 796 |
| 797 (*origin_access_info_map)[url.host()] = access_info; |
| 798 } |
| 799 |
| 800 void ResourceDispatcherHostImpl::UnregisterOriginForAccessChecks( |
| 801 const ResourceContext* context, |
| 802 const std::string& origin) { |
| 803 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 804 |
| 805 GURL url(origin); |
| 806 // The scheme has to be registered in the list of schemes being access |
| 807 // checked. |
| 808 if (origins_for_access_check_.find(url.scheme()) == |
| 809 origins_for_access_check_.end()) { |
| 810 NOTREACHED() << "Unregistered scheme for access check"; |
| 811 return; |
| 812 } |
| 813 OriginAccessInfoMap* origin_access_info_map = |
| 814 GetOriginAccessMapForResourceContext(context); |
| 815 OriginAccessInfoMap::iterator index = origin_access_info_map->find( |
| 816 url.host()); |
| 817 if (index != origin_access_info_map->end()) |
| 818 origin_access_info_map->erase(index); |
| 819 } |
| 820 |
| 821 void ResourceDispatcherHostImpl::AddProcessForOrigin( |
| 822 const ResourceContext* context, |
| 823 const std::string& origin, |
| 824 int process_id, |
| 825 bool owner_process) { |
| 826 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 827 |
| 828 GURL url(origin); |
| 829 // The following conditions need to apply before we can add the process to |
| 830 // the list of allowed processes for an origin. |
| 831 // 1. The URL has to be valid. |
| 832 // 2. It has to have a valid host. |
| 833 // 3. The scheme has to be registered in the list of schemes being access |
| 834 // checked. |
| 835 if (!url.is_valid() || !url.has_host() || |
| 836 origins_for_access_check_.find(url.scheme()) == |
| 837 origins_for_access_check_.end()) { |
| 838 NOTREACHED() << "Invalid URL or unregistered scheme."; |
| 839 return; |
| 840 } |
| 841 |
| 842 OriginAccessInfoMap* origin_access_info_map = |
| 843 GetOriginAccessMapForResourceContext(context); |
| 844 DCHECK(origin_access_info_map); |
| 845 |
| 846 OriginAccessInfoMap::iterator index = origin_access_info_map->find( |
| 847 url.host()); |
| 848 // No need to add access information for an unregistered host. |
| 849 if (index == origin_access_info_map->end()) |
| 850 return; |
| 851 |
| 852 OriginAccessInfo& access_info = index->second; |
| 853 if (owner_process) { |
| 854 access_info.owner_processes[process_id]++; |
| 855 } else { |
| 856 access_info.other_processes[process_id]++; |
| 857 } |
| 858 } |
| 859 |
| 860 void ResourceDispatcherHostImpl::RemoveProcessForOrigin( |
| 861 const ResourceContext* context, |
| 862 const std::string& origin, |
| 863 int process_id, |
| 864 bool owner_process) { |
| 865 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 866 |
| 867 GURL url(origin); |
| 868 // The scheme has to be registered in the list of schemes being access |
| 869 // checked. |
| 870 if (origins_for_access_check_.find(url.scheme()) == |
| 871 origins_for_access_check_.end()) { |
| 872 DCHECK(false); |
| 873 return; |
| 874 } |
| 875 |
| 876 OriginAccessInfoMap* origin_access_info_map = |
| 877 GetOriginAccessMapForResourceContext(context); |
| 878 DCHECK(origin_access_info_map); |
| 879 |
| 880 OriginAccessInfoMap::iterator index = origin_access_info_map->find( |
| 881 url.host()); |
| 882 // No need to add access information for an unregistered host. |
| 883 if (index == origin_access_info_map->end()) |
| 884 return; |
| 885 |
| 886 OriginAccessInfo& access_info = index->second; |
| 887 |
| 888 std::map<int, int>::iterator process_index; |
| 889 std::map<int, int>* process_map = nullptr; |
| 890 if (owner_process) { |
| 891 process_map = &access_info.owner_processes; |
| 892 } else { |
| 893 process_map = &access_info.other_processes; |
| 894 } |
| 895 process_index = process_map->find(process_id); |
| 896 // The process has to be there in the list. |
| 897 DCHECK(process_index != process_map->end()); |
| 898 process_index->second--; |
| 899 if (process_index->second == 0) |
| 900 process_map->erase(process_index); |
| 901 } |
| 902 |
754 void ResourceDispatcherHostImpl::Shutdown() { | 903 void ResourceDispatcherHostImpl::Shutdown() { |
755 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 904 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
756 BrowserThread::PostTask(BrowserThread::IO, | 905 BrowserThread::PostTask(BrowserThread::IO, |
757 FROM_HERE, | 906 FROM_HERE, |
758 base::Bind(&ResourceDispatcherHostImpl::OnShutdown, | 907 base::Bind(&ResourceDispatcherHostImpl::OnShutdown, |
759 base::Unretained(this))); | 908 base::Unretained(this))); |
760 } | 909 } |
761 | 910 |
762 std::unique_ptr<ResourceHandler> | 911 std::unique_ptr<ResourceHandler> |
763 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload( | 912 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload( |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1354 filter_->GetContexts(request_data.resource_type, &resource_context, | 1503 filter_->GetContexts(request_data.resource_type, &resource_context, |
1355 &request_context); | 1504 &request_context); |
1356 | 1505 |
1357 // Parse the headers before calling ShouldServiceRequest, so that they are | 1506 // Parse the headers before calling ShouldServiceRequest, so that they are |
1358 // available to be validated. | 1507 // available to be validated. |
1359 net::HttpRequestHeaders headers; | 1508 net::HttpRequestHeaders headers; |
1360 headers.AddHeadersFromString(request_data.headers); | 1509 headers.AddHeadersFromString(request_data.headers); |
1361 | 1510 |
1362 if (is_shutdown_ || | 1511 if (is_shutdown_ || |
1363 !ShouldServiceRequest(process_type, child_id, request_data, headers, | 1512 !ShouldServiceRequest(process_type, child_id, request_data, headers, |
1364 filter_, resource_context)) { | 1513 filter_, resource_context, this)) { |
1365 AbortRequestBeforeItStarts(filter_, sync_result, request_id); | 1514 AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
1366 return; | 1515 return; |
1367 } | 1516 } |
1368 | 1517 |
1369 // Allow the observer to block/handle the request. | 1518 // Allow the observer to block/handle the request. |
1370 if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method, | 1519 if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method, |
1371 request_data.url, | 1520 request_data.url, |
1372 request_data.resource_type, | 1521 request_data.resource_type, |
1373 resource_context)) { | 1522 resource_context)) { |
1374 AbortRequestBeforeItStarts(filter_, sync_result, request_id); | 1523 AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
(...skipping 1225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2600 DCHECK(deserialized); | 2749 DCHECK(deserialized); |
2601 ssl.cert_id = GetCertStore()->StoreCert(ssl_info.cert.get(), child_id); | 2750 ssl.cert_id = GetCertStore()->StoreCert(ssl_info.cert.get(), child_id); |
2602 response->head.security_info = SerializeSecurityInfo(ssl); | 2751 response->head.security_info = SerializeSecurityInfo(ssl); |
2603 } | 2752 } |
2604 | 2753 |
2605 CertStore* ResourceDispatcherHostImpl::GetCertStore() { | 2754 CertStore* ResourceDispatcherHostImpl::GetCertStore() { |
2606 return cert_store_for_testing_ ? cert_store_for_testing_ | 2755 return cert_store_for_testing_ ? cert_store_for_testing_ |
2607 : CertStore::GetInstance(); | 2756 : CertStore::GetInstance(); |
2608 } | 2757 } |
2609 | 2758 |
| 2759 ResourceDispatcherHostImpl::OriginAccessInfoMap* |
| 2760 ResourceDispatcherHostImpl::GetOriginAccessMapForResourceContext( |
| 2761 const ResourceContext* context) { |
| 2762 ResourceContextOriginMap::iterator context_index = |
| 2763 context_origin_access_info_map_.find(context); |
| 2764 if (context_index != context_origin_access_info_map_.end()) |
| 2765 return context_index->second.get(); |
| 2766 |
| 2767 context_origin_access_info_map_[context].reset(new OriginAccessInfoMap); |
| 2768 return context_origin_access_info_map_[context].get(); |
| 2769 } |
| 2770 |
| 2771 bool ResourceDispatcherHostImpl::IsIllegalOrigin(ResourceContext* context, |
| 2772 const GURL& origin, |
| 2773 int child_process_id) { |
| 2774 if (origins_for_access_check_.find(origin.scheme()) == |
| 2775 origins_for_access_check_.end()) { |
| 2776 return false; |
| 2777 } |
| 2778 |
| 2779 OriginAccessInfoMap* origin_access_info_map = |
| 2780 GetOriginAccessMapForResourceContext( |
| 2781 const_cast<const ResourceContext*>(context)); |
| 2782 DCHECK(origin_access_info_map); |
| 2783 |
| 2784 // If the origin is not found then this URL cannot be committed. |
| 2785 OriginAccessInfoMap::iterator index = |
| 2786 origin_access_info_map->find(origin.host()); |
| 2787 if (index == origin_access_info_map->end()) |
| 2788 return false; |
| 2789 |
| 2790 OriginAccessInfo& access_info = index->second; |
| 2791 // Owner processes are allowed access by default. |
| 2792 if (access_info.owner_processes.find(child_process_id) != |
| 2793 access_info.owner_processes.end()) { |
| 2794 return false; |
| 2795 } |
| 2796 |
| 2797 DCHECK(access_info.access_check_mask >= DENY_FOR_NON_OWNERS && |
| 2798 access_info.access_check_mask <= ACCESS_CHECK_MASK_LAST); |
| 2799 |
| 2800 if (access_info.access_check_mask == DENY_FOR_NON_OWNERS) |
| 2801 return true; |
| 2802 |
| 2803 // No need to check for other processes here. |
| 2804 if (access_info.access_check_mask == ALLOW_EVERYTHING) |
| 2805 return false; |
| 2806 |
| 2807 // Processes in the other_processes list are allowed. |
| 2808 if (access_info.other_processes.find(child_process_id) != |
| 2809 access_info.other_processes.end()) { |
| 2810 return false; |
| 2811 } |
| 2812 // The origin being accessed is not allowed for the |child_process_id|. |
| 2813 return true; |
| 2814 } |
| 2815 |
2610 } // namespace content | 2816 } // namespace content |
OLD | NEW |