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 3 // found in the LICENSE file. 4 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading 6 7 #include "content/browser/loader/resource_dispatcher_host_impl.h" 8 9 #include <algorithm> 10 #include <set> 11 #include <vector> 12 13 #include "base/bind.h" 14 #include "base/bind_helpers.h" 15 #include "base/command_line.h" 16 #include "base/compiler_specific.h" 17 #include "base/debug/alias.h" 18 #include "base/logging.h" 19 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/shared_memory.h" 21 #include "base/message_loop/message_loop.h" 22 #include "base/metrics/histogram.h" 23 #include "base/metrics/sparse_histogram.h" 24 #include "base/stl_util.h" 25 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 26 #include "content/browser/appcache/appcache_interceptor.h" 27 #include "content/browser/appcache/chrome_appcache_service.h" 28 #include "content/browser/cert_store_impl.h" 29 #include "content/browser/child_process_security_policy_impl.h" 30 #include "content/browser/cross_site_request_manager.h" 31 #include "content/browser/download/download_resource_handler.h" 32 #include "content/browser/download/save_file_manager.h" 33 #include "content/browser/download/save_file_resource_handler.h" 34 #include "content/browser/fileapi/chrome_blob_storage_context.h" 35 #include "content/browser/loader/async_resource_handler.h" 36 #include "content/browser/loader/buffered_resource_handler.h" 37 #include "content/browser/loader/cross_site_resource_handler.h" 38 #include "content/browser/loader/detachable_resource_handler.h" 39 #include "content/browser/loader/power_save_block_resource_throttle.h" 40 #include "content/browser/loader/redirect_to_file_resource_handler.h" 41 #include "content/browser/loader/resource_message_filter.h" 42 #include "content/browser/loader/resource_request_info_impl.h" 43 #include "content/browser/loader/stream_resource_handler.h" 44 #include "content/browser/loader/sync_resource_handler.h" 45 #include "content/browser/loader/throttling_resource_handler.h" 46 #include "content/browser/loader/upload_data_stream_builder.h" 47 #include "content/browser/plugin_service_impl.h" 48 #include "content/browser/renderer_host/render_view_host_delegate.h" 49 #include "content/browser/renderer_host/render_view_host_impl.h" 50 #include "content/browser/resource_context_impl.h" 51 #include "content/browser/service_worker/service_worker_request_handler.h" 52 #include "content/browser/streams/stream.h" 53 #include "content/browser/streams/stream_context.h" 54 #include "content/browser/streams/stream_registry.h" 55 #include "content/browser/worker_host/worker_service_impl.h" 56 #include "content/browser/web_contents/web_contents_impl.h" 57 #include "content/common/resource_messages.h" 58 #include "content/common/resource_request_body.h" 59 #include "content/common/ssl_status_serialization.h" 60 #include "content/common/view_messages.h" 61 #include "content/public/browser/browser_thread.h" 62 #include "content/public/browser/content_browser_client.h" 63 #include "content/public/browser/download_manager.h" 64 #include "content/public/browser/download_url_parameters.h" 65 #include "content/public/browser/global_request_id.h" 66 #include "content/public/browser/resource_dispatcher_host_delegate.h" 67 #include "content/public/browser/resource_request_details.h" 68 #include "content/public/browser/resource_throttle.h" 69 #include "content/public/browser/stream_handle.h" 70 #include "content/public/browser/user_metrics.h" 71 #include "content/public/common/content_switches.h" 72 #include "content/public/common/process_type.h" 73 #include "ipc/ipc_message_macros.h" 74 #include "ipc/ipc_message_start.h" 75 #include "net/base/auth.h" 76 #include "net/base/load_flags.h" 77 #include "net/base/mime_util.h" 78 #include "net/base/net_errors.h" 79 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 80 #include "net/base/request_priority.h" 81 #include "net/base/upload_data_stream.h" 82 #include "net/cert/cert_status_flags.h" 83 #include "net/cookies/cookie_monster.h" 84 #include "net/http/http_response_headers.h" 85 #include "net/http/http_response_info.h" 86 #include "net/ssl/ssl_cert_request_info.h" 87 #include "net/url_request/url_request.h" 88 #include "net/url_request/url_request_context.h" 89 #include "net/url_request/url_request_job_factory.h" 90 #include "url/url_constants.h" 91 #include "webkit/common/blob/blob_data.h" 92 #include "webkit/browser/blob/blob_data_handle.h" 93 #include "webkit/browser/blob/blob_storage_context.h" 94 #include "webkit/browser/blob/blob_url_request_job_factory.h" 95 #include "webkit/browser/fileapi/file_permission_policy.h" 96 #include "webkit/browser/fileapi/file_system_context.h" 97 #include "webkit/common/appcache/appcache_interfaces.h" 98 #include "webkit/common/blob/shareable_file_reference.h" 99 100 using base::Time; 101 using base::TimeDelta; 102 using base::TimeTicks; 103 using webkit_blob::ShareableFileReference; 104 105 // ---------------------------------------------------------------------------- 106 107 namespace content { 108 109 namespace { 110 111 static ResourceDispatcherHostImpl* g_resource_dispatcher_host; 112 113 // The interval for calls to ResourceDispatcherHostImpl::UpdateLoadStates 114 const int kUpdateLoadStatesIntervalMsec = 100; 115 116 // Maximum byte "cost" of all the outstanding requests for a renderer. 117 // See delcaration of |max_outstanding_requests_cost_per_process_| for details. 118 // This bound is 25MB, which allows for around 6000 outstanding requests. 119 const int kMaxOutstandingRequestsCostPerProcess = 26214400; 120 121 // The number of milliseconds after noting a user gesture that we will 122 // tag newly-created URLRequest objects with the 123 // net::LOAD_MAYBE_USER_GESTURE load flag. This is a fairly arbitrary 124 // guess at how long to expect direct impact from a user gesture, but 125 // this should be OK as the load flag is a best-effort thing only, 126 // rather than being intended as fully accurate. 127 const int kUserGestureWindowMs = 3500; 128 129 // Ratio of |max_num_in_flight_requests_| that any one renderer is allowed to 130 // use. Arbitrarily chosen. 131 const double kMaxRequestsPerProcessRatio = 0.45; 132 133 // TODO(jkarlin): The value is high to reduce the chance of the detachable 134 // request timing out, forcing a blocked second request to open a new connection 135 // and start over. Reduce this value once we have a better idea of what it 136 // should be and once we stop blocking multiple simultaneous requests for the 137 // same resource (see bugs 46104 and 31014). 138 const int kDefaultDetachableCancelDelayMs = 30000; 139 140 bool IsDetachableResourceType(ResourceType::Type type) { 141 switch (type) { 142 case ResourceType::PREFETCH: 143 case ResourceType::PING: 144 return true; 145 default: 146 return false; 147 } 148 } 149 150 // Aborts a request before an URLRequest has actually been created. 151 void AbortRequestBeforeItStarts(ResourceMessageFilter* filter, 152 IPC::Message* sync_result, 153 int request_id) { 154 if (sync_result) { 155 SyncLoadResult result; 156 result.error_code = net::ERR_ABORTED; 157 ResourceHostMsg_SyncLoad::WriteReplyParams(sync_result, result); 158 filter->Send(sync_result); 159 } else { 160 // Tell the renderer that this request was disallowed. 161 ResourceMsg_RequestCompleteData request_complete_data; 162 request_complete_data.error_code = net::ERR_ABORTED; 163 request_complete_data.was_ignored_by_handler = false; 164 request_complete_data.exists_in_cache = false; 165 // No security info needed, connection not established. 166 request_complete_data.completion_time = base::TimeTicks(); 167 request_complete_data.encoded_data_length = 0; 168 filter->Send(new ResourceMsg_RequestComplete( 169 request_id, request_complete_data)); 170 } 171 } 172 173 void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) { 174 if (!referrer.url.is_valid() || 175 CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoReferrers)) { 176 request->SetReferrer(std::string()); 177 } else { 178 request->SetReferrer(referrer.url.spec()); 179 } 180 181 net::URLRequest::ReferrerPolicy net_referrer_policy = 182 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; 183 switch (referrer.policy) { 184 case blink::WebReferrerPolicyDefault: 185 net_referrer_policy = 186 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; 187 break; 188 case blink::WebReferrerPolicyAlways: 189 case blink::WebReferrerPolicyNever: 190 case blink::WebReferrerPolicyOrigin: 191 net_referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER; 192 break; 193 } 194 request->set_referrer_policy(net_referrer_policy); 195 } 196 197 // Consults the RendererSecurity policy to determine whether the 198 // ResourceDispatcherHostImpl should service this request. A request might be 199 // disallowed if the renderer is not authorized to retrieve the request URL or 200 // if the renderer is attempting to upload an unauthorized file. 201 bool ShouldServiceRequest(int process_type, 202 int child_id, 203 const ResourceHostMsg_Request& request_data, 204 fileapi::FileSystemContext* file_system_context) { 205 if (process_type == PROCESS_TYPE_PLUGIN) 206 return true; 207 208 ChildProcessSecurityPolicyImpl* policy = 209 ChildProcessSecurityPolicyImpl::GetInstance(); 210 211 // Check if the renderer is permitted to request the requested URL. 212 if (!policy->CanRequestURL(child_id, request_data.url)) { 213 VLOG(1) << "Denied unauthorized request for " 214 << request_data.url.possibly_invalid_spec(); 215 return false; 216 } 217 218 // Check if the renderer is permitted to upload the requested files. 219 if (request_data.request_body.get()) { 220 const std::vector<ResourceRequestBody::Element>* uploads = 221 request_data.request_body->elements(); 222 std::vector<ResourceRequestBody::Element>::const_iterator iter; 223 for (iter = uploads->begin(); iter != uploads->end(); ++iter) { 224 if (iter->type() == ResourceRequestBody::Element::TYPE_FILE && 225 !policy->CanReadFile(child_id, iter->path())) { 226 NOTREACHED() << "Denied unauthorized upload of " 227 << iter->path().value(); 228 return false; 229 } 230 if (iter->type() == ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM) { 231 fileapi::FileSystemURL url = 232 file_system_context->CrackURL(iter->filesystem_url()); 233 if (!policy->CanReadFileSystemFile(child_id, url)) { 234 NOTREACHED() << "Denied unauthorized upload of " 235 << iter->filesystem_url().spec(); 236 return false; 237 } 238 } 239 } 240 } 241 242 return true; 243 } 244 245 void RemoveDownloadFileFromChildSecurityPolicy(int child_id, 246 const base::FilePath& path) { 247 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile( 248 child_id, path); 249 } 250 251 #if defined(OS_WIN) 252 #pragma warning(disable: 4748) 253 #pragma optimize("", off) 254 #endif 255 256 #if defined(OS_WIN) 257 #pragma optimize("", on) 258 #pragma warning(default: 4748) 259 #endif 260 261 DownloadInterruptReason CallbackAndReturn( 262 const DownloadUrlParameters::OnStartedCallback& started_cb, 263 DownloadInterruptReason interrupt_reason) { 264 if (started_cb.is_null()) 265 return interrupt_reason; 266 BrowserThread::PostTask( 267 BrowserThread::UI, 268 FROM_HERE, 269 base::Bind( 270 started_cb, static_cast<DownloadItem*>(NULL), interrupt_reason)); 271 272 return interrupt_reason; 273 } 274 275 int GetCertID(net::URLRequest* request, int child_id) { 276 if (request->ssl_info().cert.get()) { 277 return CertStore::GetInstance()->StoreCert(request->ssl_info().cert.get(), 278 child_id); 279 } 280 return 0; 281 } 282 283 void NotifyRedirectOnUI(int render_process_id, 284 int render_frame_host, 285 scoped_ptr<ResourceRedirectDetails> details) { 286 RenderFrameHostImpl* host = 287 RenderFrameHostImpl::FromID(render_process_id, render_frame_host); 288 WebContentsImpl* web_contents = 289 static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host)); 290 if (!web_contents) 291 return; 292 web_contents->DidGetRedirectForResourceRequest( 293 host->render_view_host(), *details.get()); 294 } 295 296 void NotifyResponseOnUI(int render_process_id, 297 int render_frame_host, 298 scoped_ptr<ResourceRequestDetails> details) { 299 RenderFrameHostImpl* host = 300 RenderFrameHostImpl::FromID(render_process_id, render_frame_host); 301 WebContentsImpl* web_contents = 302 static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host)); 303 if (!web_contents) 304 return; 305 web_contents->DidGetResourceResponseStart(*details.get()); 306 } 307 308 bool IsValidatedSCT( 309 const net::SignedCertificateTimestampAndStatus& sct_status) { 310 return sct_status.status == net::ct::SCT_STATUS_OK; 311 } 312 313 webkit_blob::BlobStorageContext* GetBlobStorageContext( 314 ResourceMessageFilter* filter) { 315 if (!filter->blob_storage_context()) 316 return NULL; 317 return filter->blob_storage_context()->context(); 318 } 319 320 } // namespace 321 322 // static 323 ResourceDispatcherHost* ResourceDispatcherHost::Get() { 324 return g_resource_dispatcher_host; 325 } 326 327 ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() 328 : save_file_manager_(new SaveFileManager()), 329 request_id_(-1), 330 is_shutdown_(false), 331 num_in_flight_requests_(0), 332 max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()), 333 max_num_in_flight_requests_per_process_( 334 static_cast<int>( 335 max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), 336 max_outstanding_requests_cost_per_process_( 337 kMaxOutstandingRequestsCostPerProcess), 338 filter_(NULL), 339 delegate_(NULL), 340 allow_cross_origin_auth_prompt_(false) { 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 342 DCHECK(!g_resource_dispatcher_host); 343 g_resource_dispatcher_host = this; 344 345 GetContentClient()->browser()->ResourceDispatcherHostCreated(); 346 347 ANNOTATE_BENIGN_RACE( 348 &last_user_gesture_time_, 349 "We don't care about the precise value, see http://crbug.com/92889"); 350 351 BrowserThread::PostTask(BrowserThread::IO, 352 FROM_HERE, 353 base::Bind(&ResourceDispatcherHostImpl::OnInit, 354 base::Unretained(this))); 355 356 update_load_states_timer_.reset( 357 new base::RepeatingTimer<ResourceDispatcherHostImpl>()); 358 } 359 360 ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() { 361 DCHECK(outstanding_requests_stats_map_.empty()); 362 DCHECK(g_resource_dispatcher_host); 363 g_resource_dispatcher_host = NULL; 364 } 365 366 // static 367 ResourceDispatcherHostImpl* ResourceDispatcherHostImpl::Get() { 368 return g_resource_dispatcher_host; 369 } 370 371 void ResourceDispatcherHostImpl::SetDelegate( 372 ResourceDispatcherHostDelegate* delegate) { 373 delegate_ = delegate; 374 } 375 376 void ResourceDispatcherHostImpl::SetAllowCrossOriginAuthPrompt(bool value) { 377 allow_cross_origin_auth_prompt_ = value; 378 } 379 380 void ResourceDispatcherHostImpl::AddResourceContext(ResourceContext* context) { 381 active_resource_contexts_.insert(context); 382 } 383 384 void ResourceDispatcherHostImpl::RemoveResourceContext( 385 ResourceContext* context) { 386 CHECK(ContainsKey(active_resource_contexts_, context)); 387 active_resource_contexts_.erase(context); 388 } 389 390 void ResourceDispatcherHostImpl::CancelRequestsForContext( 391 ResourceContext* context) { 392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 393 DCHECK(context); 394 395 CHECK(ContainsKey(active_resource_contexts_, context)); 396 397 // Note that request cancellation has side effects. Therefore, we gather all 398 // the requests to cancel first, and then we start cancelling. We assert at 399 // the end that there are no more to cancel since the context is about to go 400 // away. 401 typedef std::vector<linked_ptr<ResourceLoader> > LoaderList; 402 LoaderList loaders_to_cancel; 403 404 for (LoaderMap::iterator i = pending_loaders_.begin(); 405 i != pending_loaders_.end();) { 406 if (i->second->GetRequestInfo()->GetContext() == context) { 407 loaders_to_cancel.push_back(i->second); 408 IncrementOutstandingRequestsMemory(-1, *i->second->GetRequestInfo()); 409 pending_loaders_.erase(i++); 410 } else { 411 ++i; 412 } 413 } 414 415 for (BlockedLoadersMap::iterator i = blocked_loaders_map_.begin(); 416 i != blocked_loaders_map_.end();) { 417 BlockedLoadersList* loaders = i->second; 418 if (loaders->empty()) { 419 // This can happen if BlockRequestsForRoute() has been called for a route, 420 // but we haven't blocked any matching requests yet. 421 ++i; 422 continue; 423 } 424 ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo(); 425 if (info->GetContext() == context) { 426 blocked_loaders_map_.erase(i++); 427 for (BlockedLoadersList::const_iterator it = loaders->begin(); 428 it != loaders->end(); ++it) { 429 linked_ptr<ResourceLoader> loader = *it; 430 info = loader->GetRequestInfo(); 431 // We make the assumption that all requests on the list have the same 432 // ResourceContext. 433 DCHECK_EQ(context, info->GetContext()); 434 IncrementOutstandingRequestsMemory(-1, *info); 435 loaders_to_cancel.push_back(loader); 436 } 437 delete loaders; 438 } else { 439 ++i; 440 } 441 } 442 443 #ifndef NDEBUG 444 for (LoaderList::iterator i = loaders_to_cancel.begin(); 445 i != loaders_to_cancel.end(); ++i) { 446 // There is no strict requirement that this be the case, but currently 447 // downloads, streams, detachable requests, and transferred requests are the 448 // only requests that aren't cancelled when the associated processes go 449 // away. It may be OK for this invariant to change in the future, but if 450 // this assertion fires without the invariant changing, then it's indicative 451 // of a leak. 452 DCHECK((*i)->GetRequestInfo()->IsDownload() || 453 (*i)->GetRequestInfo()->is_stream() || 454 ((*i)->GetRequestInfo()->detachable_handler() && 455 (*i)->GetRequestInfo()->detachable_handler()->is_detached()) || 456 (*i)->is_transferring()); 457 } 458 #endif 459 460 loaders_to_cancel.clear(); 461 462 // Validate that no more requests for this context were added. 463 for (LoaderMap::const_iterator i = pending_loaders_.begin(); 464 i != pending_loaders_.end(); ++i) { 465 // http://crbug.com/90971 466 CHECK_NE(i->second->GetRequestInfo()->GetContext(), context); 467 } 468 469 for (BlockedLoadersMap::const_iterator i = blocked_loaders_map_.begin(); 470 i != blocked_loaders_map_.end(); ++i) { 471 BlockedLoadersList* loaders = i->second; 472 if (!loaders->empty()) { 473 ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo(); 474 // http://crbug.com/90971 475 CHECK_NE(info->GetContext(), context); 476 } 477 } 478 } 479 480 DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload( 481 scoped_ptr<net::URLRequest> request, 482 const Referrer& referrer, 483 bool is_content_initiated, 484 ResourceContext* context, 485 int child_id, 486 int route_id, 487 bool prefer_cache, 488 scoped_ptr<DownloadSaveInfo> save_info, 489 uint32 download_id, 490 const DownloadStartedCallback& started_callback) { 491 if (is_shutdown_) 492 return CallbackAndReturn(started_callback, 493 DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN); 494 495 const GURL& url = request->original_url(); 496 497 // http://crbug.com/90971 498 char url_buf[128]; 499 base::strlcpy(url_buf, url.spec().c_str(), arraysize(url_buf)); 500 base::debug::Alias(url_buf); 501 CHECK(ContainsKey(active_resource_contexts_, context)); 502 503 SetReferrerForRequest(request.get(), referrer); 504 505 int extra_load_flags = net::LOAD_IS_DOWNLOAD; 506 if (prefer_cache) { 507 // If there is upload data attached, only retrieve from cache because there 508 // is no current mechanism to prompt the user for their consent for a 509 // re-post. For GETs, try to retrieve data from the cache and skip 510 // validating the entry if present. 511 if (request->get_upload() != NULL) 512 extra_load_flags |= net::LOAD_ONLY_FROM_CACHE; 513 else 514 extra_load_flags |= net::LOAD_PREFERRING_CACHE; 515 } else { 516 extra_load_flags |= net::LOAD_DISABLE_CACHE; 517 } 518 request->SetLoadFlags(request->load_flags() | extra_load_flags); 519 520 // Check if the renderer is permitted to request the requested URL. 521 if (!ChildProcessSecurityPolicyImpl::GetInstance()-> 522 CanRequestURL(child_id, url)) { 523 VLOG(1) << "Denied unauthorized download request for " 524 << url.possibly_invalid_spec(); 525 return CallbackAndReturn(started_callback, 526 DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST); 527 } 528 529 request_id_--; 530 531 const net::URLRequestContext* request_context = context->GetRequestContext(); 532 if (!request_context->job_factory()->IsHandledURL(url)) { 533 VLOG(1) << "Download request for unsupported protocol: " 534 << url.possibly_invalid_spec(); 535 return CallbackAndReturn(started_callback, 536 DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST); 537 } 538 539 ResourceRequestInfoImpl* extra_info = 540 CreateRequestInfo(child_id, route_id, true, context); 541 extra_info->AssociateWithRequest(request.get()); // Request takes ownership. 542 543 if (request->url().SchemeIs(url::kBlobScheme)) { 544 ChromeBlobStorageContext* blob_context = 545 GetChromeBlobStorageContextForResourceContext(context); 546 webkit_blob::BlobProtocolHandler::SetRequestedBlobDataHandle( 547 request.get(), 548 blob_context->context()->GetBlobDataFromPublicURL(request->url())); 549 } 550 551 // From this point forward, the |DownloadResourceHandler| is responsible for 552 // |started_callback|. 553 scoped_ptr<ResourceHandler> handler( 554 CreateResourceHandlerForDownload(request.get(), is_content_initiated, 555 true, download_id, save_info.Pass(), 556 started_callback)); 557 558 BeginRequestInternal(request.Pass(), handler.Pass()); 559 560 return DOWNLOAD_INTERRUPT_REASON_NONE; 561 } 562 563 void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( 564 net::URLRequest* request) { 565 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); 566 if (info) { 567 ResourceLoader* loader = GetLoader(info->GetGlobalRequestID()); 568 if (loader) 569 loader->ClearLoginDelegate(); 570 } 571 } 572 573 void ResourceDispatcherHostImpl::Shutdown() { 574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 575 BrowserThread::PostTask(BrowserThread::IO, 576 FROM_HERE, 577 base::Bind(&ResourceDispatcherHostImpl::OnShutdown, 578 base::Unretained(this))); 579 } 580 581 scoped_ptr<ResourceHandler> 582 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload( 583 net::URLRequest* request, 584 bool is_content_initiated, 585 bool must_download, 586 uint32 id, 587 scoped_ptr<DownloadSaveInfo> save_info, 588 const DownloadUrlParameters::OnStartedCallback& started_cb) { 589 scoped_ptr<ResourceHandler> handler( 590 new DownloadResourceHandler(id, request, started_cb, save_info.Pass())); 591 if (delegate_) { 592 const ResourceRequestInfo* request_info( 593 ResourceRequestInfo::ForRequest(request)); 594 595 ScopedVector<ResourceThrottle> throttles; 596 delegate_->DownloadStarting( 597 request, request_info->GetContext(), request_info->GetChildID(), 598 request_info->GetRouteID(), request_info->GetRequestID(), 599 is_content_initiated, must_download, &throttles); 600 if (!throttles.empty()) { 601 handler.reset( 602 new ThrottlingResourceHandler( 603 handler.Pass(), request, throttles.Pass())); 604 } 605 } 606 return handler.Pass(); 607 } 608 609 scoped_ptr<ResourceHandler> 610 ResourceDispatcherHostImpl::MaybeInterceptAsStream(net::URLRequest* request, 611 ResourceResponse* response, 612 std::string* payload) { 613 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); 614 const std::string& mime_type = response->head.mime_type; 615 616 GURL origin; 617 if (!delegate_ || 618 !delegate_->ShouldInterceptResourceAsStream(request, 619 mime_type, 620 &origin, 621 payload)) { 622 return scoped_ptr<ResourceHandler>(); 623 } 624 625 StreamContext* stream_context = 626 GetStreamContextForResourceContext(info->GetContext()); 627 628 scoped_ptr<StreamResourceHandler> handler( 629 new StreamResourceHandler(request, 630 stream_context->registry(), 631 origin)); 632 633 info->set_is_stream(true); 634 delegate_->OnStreamCreated( 635 request, 636 handler->stream()->CreateHandle( 637 request->url(), 638 mime_type, 639 response->head.headers)); 640 return handler.PassAs<ResourceHandler>(); 641 } 642 643 void ResourceDispatcherHostImpl::ClearSSLClientAuthHandlerForRequest( 644 net::URLRequest* request) { 645 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); 646 if (info) { 647 ResourceLoader* loader = GetLoader(info->GetGlobalRequestID()); 648 if (loader) 649 loader->ClearSSLClientAuthHandler(); 650 } 651 } 652 653 ResourceDispatcherHostLoginDelegate* 654 ResourceDispatcherHostImpl::CreateLoginDelegate( 655 ResourceLoader* loader, 656 net::AuthChallengeInfo* auth_info) { 657 if (!delegate_) 658 return NULL; 659 660 return delegate_->CreateLoginDelegate(auth_info, loader->request()); 661 } 662 663 bool ResourceDispatcherHostImpl::HandleExternalProtocol(ResourceLoader* loader, 664 const GURL& url) { 665 if (!delegate_) 666 return false; 667 668 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); 669 670 if (!ResourceType::IsFrame(info->GetResourceType())) 671 return false; 672 673 const net::URLRequestJobFactory* job_factory = 674 info->GetContext()->GetRequestContext()->job_factory(); 675 if (job_factory->IsHandledURL(url)) 676 return false; 677 678 return delegate_->HandleExternalProtocol( 679 url, info->GetChildID(), info->GetRouteID()); 680 } 681 682 void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) { 683 // Make sure we have the load state monitor running 684 if (!update_load_states_timer_->IsRunning()) { 685 update_load_states_timer_->Start(FROM_HERE, 686 TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec), 687 this, &ResourceDispatcherHostImpl::UpdateLoadStates); 688 } 689 } 690 691 void ResourceDispatcherHostImpl::DidReceiveRedirect(ResourceLoader* loader, 692 const GURL& new_url) { 693 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); 694 695 int render_process_id, render_frame_host; 696 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host)) 697 return; 698 699 // Notify the observers on the UI thread. 700 scoped_ptr<ResourceRedirectDetails> detail(new ResourceRedirectDetails( 701 loader->request(), 702 GetCertID(loader->request(), info->GetChildID()), 703 new_url)); 704 BrowserThread::PostTask( 705 BrowserThread::UI, FROM_HERE, 706 base::Bind( 707 &NotifyRedirectOnUI, 708 render_process_id, render_frame_host, base::Passed(&detail))); 709 } 710 711 void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) { 712 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); 713 714 if (loader->request()->was_fetched_via_proxy() && 715 loader->request()->was_fetched_via_spdy() && 716 loader->request()->url().SchemeIs("http")) { 717 scheduler_->OnReceivedSpdyProxiedHttpResponse( 718 info->GetChildID(), info->GetRouteID()); 719 } 720 721 int render_process_id, render_frame_host; 722 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host)) 723 return; 724 725 // Notify the observers on the UI thread. 726 scoped_ptr<ResourceRequestDetails> detail(new ResourceRequestDetails( 727 loader->request(), 728 GetCertID(loader->request(), info->GetChildID()))); 729 BrowserThread::PostTask( 730 BrowserThread::UI, FROM_HERE, 731 base::Bind( 732 &NotifyResponseOnUI, 733 render_process_id, render_frame_host, base::Passed(&detail))); 734 } 735 736 void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) { 737 ResourceRequestInfo* info = loader->GetRequestInfo(); 738 739 // Record final result of all resource loads. 740 if (info->GetResourceType() == ResourceType::MAIN_FRAME) { 741 // This enumeration has "3" appended to its name to distinguish it from 742 // older versions. 743 UMA_HISTOGRAM_SPARSE_SLOWLY( 744 "Net.ErrorCodesForMainFrame3", 745 -loader->request()->status().error()); 746 747 if (loader->request()->url().SchemeIsSecure()) { 748 if (loader->request()->url().host() == "www.google.com") { 749 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.ErrorCodesForHTTPSGoogleMainFrame2", 750 -loader->request()->status().error()); 751 } 752 753 int num_valid_scts = std::count_if( 754 loader->request()->ssl_info().signed_certificate_timestamps.begin(), 755 loader->request()->ssl_info().signed_certificate_timestamps.end(), 756 IsValidatedSCT); 757 UMA_HISTOGRAM_COUNTS_100( 758 "Net.CertificateTransparency.MainFrameValidSCTCount", num_valid_scts); 759 } 760 } else { 761 if (info->GetResourceType() == ResourceType::IMAGE) { 762 UMA_HISTOGRAM_SPARSE_SLOWLY( 763 "Net.ErrorCodesForImages", 764 -loader->request()->status().error()); 765 } 766 // This enumeration has "2" appended to distinguish it from older versions. 767 UMA_HISTOGRAM_SPARSE_SLOWLY( 768 "Net.ErrorCodesForSubresources2", 769 -loader->request()->status().error()); 770 } 771 772 if (delegate_) 773 delegate_->RequestComplete(loader->request()); 774 775 // Destroy the ResourceLoader. 776 RemovePendingRequest(info->GetChildID(), info->GetRequestID()); 777 } 778 779 void ResourceDispatcherHostImpl::OnInit() { 780 scheduler_.reset(new ResourceScheduler); 781 AppCacheInterceptor::EnsureRegistered(); 782 } 783 784 void ResourceDispatcherHostImpl::OnShutdown() { 785 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 786 787 is_shutdown_ = true; 788 pending_loaders_.clear(); 789 790 // Make sure we shutdown the timer now, otherwise by the time our destructor 791 // runs if the timer is still running the Task is deleted twice (once by 792 // the MessageLoop and the second time by RepeatingTimer). 793 update_load_states_timer_.reset(); 794 795 // Clear blocked requests if any left. 796 // Note that we have to do this in 2 passes as we cannot call 797 // CancelBlockedRequestsForRoute while iterating over 798 // blocked_loaders_map_, as it modifies it. 799 std::set<GlobalRoutingID> ids; 800 for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin(); 801 iter != blocked_loaders_map_.end(); ++iter) { 802 std::pair<std::set<GlobalRoutingID>::iterator, bool> result = 803 ids.insert(iter->first); 804 // We should not have duplicates. 805 DCHECK(result.second); 806 } 807 for (std::set<GlobalRoutingID>::const_iterator iter = ids.begin(); 808 iter != ids.end(); ++iter) { 809 CancelBlockedRequestsForRoute(iter->child_id, iter->route_id); 810 } 811 812 scheduler_.reset(); 813 } 814 815 bool ResourceDispatcherHostImpl::OnMessageReceived( 816 const IPC::Message& message, 817 ResourceMessageFilter* filter) { 818 filter_ = filter; 819 bool handled = true; 820 IPC_BEGIN_MESSAGE_MAP(ResourceDispatcherHostImpl, message) 821 IPC_MESSAGE_HANDLER(ResourceHostMsg_RequestResource, OnRequestResource) 822 IPC_MESSAGE_HANDLER_DELAY_REPLY(ResourceHostMsg_SyncLoad, OnSyncLoad) 823 IPC_MESSAGE_HANDLER(ResourceHostMsg_ReleaseDownloadedFile, 824 OnReleaseDownloadedFile) 825 IPC_MESSAGE_HANDLER(ResourceHostMsg_DataDownloaded_ACK, OnDataDownloadedACK) 826 IPC_MESSAGE_HANDLER(ResourceHostMsg_UploadProgress_ACK, OnUploadProgressACK) 827 IPC_MESSAGE_HANDLER(ResourceHostMsg_CancelRequest, OnCancelRequest) 828 IPC_MESSAGE_UNHANDLED(handled = false) 829 IPC_END_MESSAGE_MAP() 830 831 if (!handled && IPC_MESSAGE_ID_CLASS(message.type()) == ResourceMsgStart) { 832 PickleIterator iter(message); 833 int request_id = -1; 834 bool ok = iter.ReadInt(&request_id); 835 DCHECK(ok); 836 GlobalRequestID id(filter_->child_id(), request_id); 837 DelegateMap::iterator it = delegate_map_.find(id); 838 if (it != delegate_map_.end()) { 839 ObserverList<ResourceMessageDelegate>::Iterator del_it(*it->second); 840 ResourceMessageDelegate* delegate; 841 while (!handled && (delegate = del_it.GetNext()) != NULL) { 842 handled = delegate->OnMessageReceived(message); 843 } 844 } 845 846 // As the unhandled resource message effectively has no consumer, mark it as 847 // handled to prevent needless propagation through the filter pipeline. 848 handled = true; 849 } 850 851 filter_ = NULL; 852 return handled; 853 } 854 855 void ResourceDispatcherHostImpl::OnRequestResource( 856 int routing_id, 857 int request_id, 858 const ResourceHostMsg_Request& request_data) { 859 BeginRequest(request_id, request_data, NULL, routing_id); 860 } 861 862 // Begins a resource request with the given params on behalf of the specified 863 // child process. Responses will be dispatched through the given receiver. The 864 // process ID is used to lookup WebContentsImpl from routing_id's in the case of 865 // a request from a renderer. request_context is the cookie/cache context to be 866 // used for this request. 867 // 868 // If sync_result is non-null, then a SyncLoad reply will be generated, else 869 // a normal asynchronous set of response messages will be generated. 870 void ResourceDispatcherHostImpl::OnSyncLoad( 871 int request_id, 872 const ResourceHostMsg_Request& request_data, 873 IPC::Message* sync_result) { 874 BeginRequest(request_id, request_data, sync_result, 875 sync_result->routing_id()); 876 } 877 878 void ResourceDispatcherHostImpl::UpdateRequestForTransfer( 879 int child_id, 880 int route_id, 881 int request_id, 882 const ResourceHostMsg_Request& request_data, 883 const linked_ptr<ResourceLoader>& loader) { 884 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); 885 GlobalRoutingID old_routing_id( 886 request_data.transferred_request_child_id, info->GetRouteID()); 887 GlobalRequestID old_request_id(request_data.transferred_request_child_id, 888 request_data.transferred_request_request_id); 889 GlobalRoutingID new_routing_id(child_id, route_id); 890 GlobalRequestID new_request_id(child_id, request_id); 891 892 // Clear out data that depends on |info| before updating it. 893 IncrementOutstandingRequestsMemory(-1, *info); 894 OustandingRequestsStats empty_stats = { 0, 0 }; 895 OustandingRequestsStats old_stats = GetOutstandingRequestsStats(*info); 896 UpdateOutstandingRequestsStats(*info, empty_stats); 897 pending_loaders_.erase(old_request_id); 898 899 // ResourceHandlers should always get state related to the request from the 900 // ResourceRequestInfo rather than caching it locally. This lets us update 901 // the info object when a transfer occurs. 902 info->UpdateForTransfer(child_id, route_id, request_data.origin_pid, 903 request_id, request_data.parent_render_frame_id, 904 filter_->GetWeakPtr()); 905 906 // Update maps that used the old IDs, if necessary. Some transfers in tests 907 // do not actually use a different ID, so not all maps need to be updated. 908 pending_loaders_[new_request_id] = loader; 909 UpdateOutstandingRequestsStats(*info, old_stats); 910 IncrementOutstandingRequestsMemory(1, *info); 911 if (old_routing_id != new_routing_id) { 912 if (blocked_loaders_map_.find(old_routing_id) != 913 blocked_loaders_map_.end()) { 914 blocked_loaders_map_[new_routing_id] = 915 blocked_loaders_map_[old_routing_id]; 916 blocked_loaders_map_.erase(old_routing_id); 917 } 918 } 919 if (old_request_id != new_request_id) { 920 DelegateMap::iterator it = delegate_map_.find(old_request_id); 921 if (it != delegate_map_.end()) { 922 // Tell each delegate that the request ID has changed. 923 ObserverList<ResourceMessageDelegate>::Iterator del_it(*it->second); 924 ResourceMessageDelegate* delegate; 925 while ((delegate = del_it.GetNext()) != NULL) { 926 delegate->set_request_id(new_request_id); 927 } 928 // Now store the observer list under the new request ID. 929 delegate_map_[new_request_id] = delegate_map_[old_request_id]; 930 delegate_map_.erase(old_request_id); 931 } 932 } 933 934 AppCacheInterceptor::CompleteCrossSiteTransfer( 935 loader->request(), 936 child_id, 937 request_data.appcache_host_id); 938 939 // We should have a CrossSiteResourceHandler to finish the transfer. 940 DCHECK(info->cross_site_handler()); 941 } 942 943 void ResourceDispatcherHostImpl::BeginRequest( 944 int request_id, 945 const ResourceHostMsg_Request& request_data, 946 IPC::Message* sync_result, // only valid for sync 947 int route_id) { 948 int process_type = filter_->process_type(); 949 int child_id = filter_->child_id(); 950 951 // Reject invalid priority. 952 if (request_data.priority < net::MINIMUM_PRIORITY || 953 request_data.priority > net::MAXIMUM_PRIORITY) { 954 RecordAction(base::UserMetricsAction("BadMessageTerminate_RDH")); 955 filter_->BadMessageReceived(); 956 return; 957 } 958 959 // If we crash here, figure out what URL the renderer was requesting. 960 // http://crbug.com/91398 961 char url_buf[128]; 962 base::strlcpy(url_buf, request_data.url.spec().c_str(), arraysize(url_buf)); 963 base::debug::Alias(url_buf); 964 965 // If the request that's coming in is being transferred from another process, 966 // we want to reuse and resume the old loader rather than start a new one. 967 { 968 LoaderMap::iterator it = pending_loaders_.find( 969 GlobalRequestID(request_data.transferred_request_child_id, 970 request_data.transferred_request_request_id)); 971 if (it != pending_loaders_.end()) { 972 // If the request is transferring to a new process, we can update our 973 // state and let it resume with its existing ResourceHandlers. 974 if (it->second->is_transferring()) { 975 linked_ptr<ResourceLoader> deferred_loader = it->second; 976 UpdateRequestForTransfer(child_id, route_id, request_id, 977 request_data, deferred_loader); 978 979 deferred_loader->CompleteTransfer(); 980 } else { 981 RecordAction(base::UserMetricsAction("BadMessageTerminate_RDH")); 982 filter_->BadMessageReceived(); 983 } 984 return; 985 } 986 } 987 988 ResourceContext* resource_context = NULL; 989 net::URLRequestContext* request_context = NULL; 990 filter_->GetContexts(request_data, &resource_context, &request_context); 991 // http://crbug.com/90971 992 CHECK(ContainsKey(active_resource_contexts_, resource_context)); 993 994 if (is_shutdown_ || 995 !ShouldServiceRequest(process_type, child_id, request_data, 996 filter_->file_system_context())) { 997 AbortRequestBeforeItStarts(filter_, sync_result, request_id); 998 return; 999 } 1000 1001 // Allow the observer to block/handle the request. 1002 if (delegate_ && !delegate_->ShouldBeginRequest(child_id, 1003 route_id, 1004 request_data.method, 1005 request_data.url, 1006 request_data.resource_type, 1007 resource_context)) { 1008 AbortRequestBeforeItStarts(filter_, sync_result, request_id); 1009 return; 1010 } 1011 1012 bool is_sync_load = sync_result != NULL; 1013 int load_flags = 1014 BuildLoadFlagsForRequest(request_data, child_id, is_sync_load); 1015 1016 // Sync loads should have maximum priority and should be the only 1017 // requets that have the ignore limits flag set. 1018 if (is_sync_load) { 1019 DCHECK_EQ(request_data.priority, net::MAXIMUM_PRIORITY); 1020 DCHECK_NE(load_flags & net::LOAD_IGNORE_LIMITS, 0); 1021 } else { 1022 DCHECK_EQ(load_flags & net::LOAD_IGNORE_LIMITS, 0); 1023 } 1024 1025 // Construct the request. 1026 net::CookieStore* cookie_store = 1027 GetContentClient()->browser()->OverrideCookieStoreForRenderProcess( 1028 child_id); 1029 scoped_ptr<net::URLRequest> new_request; 1030 new_request = request_context->CreateRequest( 1031 request_data.url, request_data.priority, NULL, cookie_store); 1032 1033 new_request->set_method(request_data.method); 1034 new_request->set_first_party_for_cookies( 1035 request_data.first_party_for_cookies); 1036 1037 const Referrer referrer(request_data.referrer, request_data.referrer_policy); 1038 SetReferrerForRequest(new_request.get(), referrer); 1039 1040 net::HttpRequestHeaders headers; 1041 headers.AddHeadersFromString(request_data.headers); 1042 new_request->SetExtraRequestHeaders(headers); 1043 1044 new_request->SetLoadFlags(load_flags); 1045 1046 // Resolve elements from request_body and prepare upload data. 1047 if (request_data.request_body.get()) { 1048 new_request->set_upload(UploadDataStreamBuilder::Build( 1049 request_data.request_body.get(), 1050 GetBlobStorageContext(filter_), 1051 filter_->file_system_context(), 1052 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) 1053 .get())); 1054 } 1055 1056 bool allow_download = request_data.allow_download && 1057 ResourceType::IsFrame(request_data.resource_type); 1058 1059 // Make extra info and read footer (contains request ID). 1060 ResourceRequestInfoImpl* extra_info = 1061 new ResourceRequestInfoImpl( 1062 process_type, 1063 child_id, 1064 route_id, 1065 request_data.origin_pid, 1066 request_id, 1067 request_data.render_frame_id, 1068 request_data.is_main_frame, 1069 request_data.parent_is_main_frame, 1070 request_data.parent_render_frame_id, 1071 request_data.resource_type, 1072 request_data.transition_type, 1073 request_data.should_replace_current_entry, 1074 false, // is download 1075 false, // is stream 1076 allow_download, 1077 request_data.has_user_gesture, 1078 request_data.referrer_policy, 1079 request_data.visiblity_state, 1080 resource_context, 1081 filter_->GetWeakPtr(), 1082 !is_sync_load); 1083 // Request takes ownership. 1084 extra_info->AssociateWithRequest(new_request.get()); 1085 1086 if (new_request->url().SchemeIs(url::kBlobScheme)) { 1087 // Hang on to a reference to ensure the blob is not released prior 1088 // to the job being started. 1089 webkit_blob::BlobProtocolHandler::SetRequestedBlobDataHandle( 1090 new_request.get(), 1091 filter_->blob_storage_context()->context()-> 1092 GetBlobDataFromPublicURL(new_request->url())); 1093 } 1094 1095 // Initialize the service worker handler for the request. 1096 ServiceWorkerRequestHandler::InitializeHandler( 1097 new_request.get(), 1098 filter_->service_worker_context(), 1099 GetBlobStorageContext(filter_), 1100 child_id, 1101 request_data.service_worker_provider_id, 1102 request_data.resource_type); 1103 1104 // Have the appcache associate its extra info with the request. 1105 AppCacheInterceptor::SetExtraRequestInfo( 1106 new_request.get(), filter_->appcache_service(), child_id, 1107 request_data.appcache_host_id, request_data.resource_type); 1108 1109 scoped_ptr<ResourceHandler> handler( 1110 CreateResourceHandler( 1111 new_request.get(), 1112 request_data, sync_result, route_id, process_type, child_id, 1113 resource_context)); 1114 1115 if (handler) 1116 BeginRequestInternal(new_request.Pass(), handler.Pass()); 1117 } 1118 1119 scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler( 1120 net::URLRequest* request, 1121 const ResourceHostMsg_Request& request_data, 1122 IPC::Message* sync_result, 1123 int route_id, 1124 int process_type, 1125 int child_id, 1126 ResourceContext* resource_context) { 1127 // Construct the IPC resource handler. 1128 scoped_ptr<ResourceHandler> handler; 1129 if (sync_result) { 1130 // download_to_file is not supported for synchronous requests. 1131 if (request_data.download_to_file) { 1132 RecordAction(base::UserMetricsAction("BadMessageTerminate_RDH")); 1133 filter_->BadMessageReceived(); 1134 return scoped_ptr<ResourceHandler>(); 1135 } 1136 1137 handler.reset(new SyncResourceHandler(request, sync_result, this)); 1138 } else { 1139 handler.reset(new AsyncResourceHandler(request, this)); 1140 1141 // The RedirectToFileResourceHandler depends on being next in the chain. 1142 if (request_data.download_to_file) { 1143 handler.reset( 1144 new RedirectToFileResourceHandler(handler.Pass(), request)); 1145 } 1146 } 1147 1148 // Prefetches and <a ping> requests outlive their child process. 1149 if (!sync_result && IsDetachableResourceType(request_data.resource_type)) { 1150 handler.reset(new DetachableResourceHandler( 1151 request, 1152 base::TimeDelta::FromMilliseconds(kDefaultDetachableCancelDelayMs), 1153 handler.Pass())); 1154 } 1155 1156 // Install a CrossSiteResourceHandler for all main frame requests. This will 1157 // let us check whether a transfer is required and pause for the unload 1158 // handler either if so or if a cross-process navigation is already under way. 1159 bool is_swappable_navigation = 1160 request_data.resource_type == ResourceType::MAIN_FRAME; 1161 // If we are using --site-per-process, install it for subframes as well. 1162 if (!is_swappable_navigation && 1163 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) { 1164 is_swappable_navigation = 1165 request_data.resource_type == ResourceType::SUB_FRAME; 1166 } 1167 if (is_swappable_navigation && process_type == PROCESS_TYPE_RENDERER) 1168 handler.reset(new CrossSiteResourceHandler(handler.Pass(), request)); 1169 1170 // Insert a buffered event handler before the actual one. 1171 handler.reset( 1172 new BufferedResourceHandler(handler.Pass(), this, request)); 1173 1174 ScopedVector<ResourceThrottle> throttles; 1175 if (delegate_) { 1176 delegate_->RequestBeginning(request, 1177 resource_context, 1178 filter_->appcache_service(), 1179 request_data.resource_type, 1180 child_id, 1181 route_id, 1182 &throttles); 1183 } 1184 1185 if (request->has_upload()) { 1186 // Block power save while uploading data. 1187 throttles.push_back(new PowerSaveBlockResourceThrottle()); 1188 } 1189 1190 throttles.push_back( 1191 scheduler_->ScheduleRequest(child_id, route_id, request).release()); 1192 1193 handler.reset( 1194 new ThrottlingResourceHandler(handler.Pass(), request, throttles.Pass())); 1195 1196 return handler.Pass(); 1197 } 1198 1199 void ResourceDispatcherHostImpl::OnReleaseDownloadedFile(int request_id) { 1200 UnregisterDownloadedTempFile(filter_->child_id(), request_id); 1201 } 1202 1203 void ResourceDispatcherHostImpl::OnDataDownloadedACK(int request_id) { 1204 // TODO(michaeln): maybe throttle DataDownloaded messages 1205 } 1206 1207 void ResourceDispatcherHostImpl::RegisterDownloadedTempFile( 1208 int child_id, int request_id, const base::FilePath& file_path) { 1209 scoped_refptr<ShareableFileReference> reference = 1210 ShareableFileReference::Get(file_path); 1211 DCHECK(reference); 1212 1213 registered_temp_files_[child_id][request_id] = reference; 1214 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( 1215 child_id, reference->path()); 1216 1217 // When the temp file is deleted, revoke permissions that the renderer has 1218 // to that file. This covers an edge case where the file is deleted and then 1219 // the same name is re-used for some other purpose, we don't want the old 1220 // renderer to still have access to it. 1221 // 1222 // We do this when the file is deleted because the renderer can take a blob 1223 // reference to the temp file that outlives the url loaded that it was 1224 // loaded with to keep the file (and permissions) alive. 1225 reference->AddFinalReleaseCallback( 1226 base::Bind(&RemoveDownloadFileFromChildSecurityPolicy, 1227 child_id)); 1228 } 1229 1230 void ResourceDispatcherHostImpl::UnregisterDownloadedTempFile( 1231 int child_id, int request_id) { 1232 DeletableFilesMap& map = registered_temp_files_[child_id]; 1233 DeletableFilesMap::iterator found = map.find(request_id); 1234 if (found == map.end()) 1235 return; 1236 1237 map.erase(found); 1238 1239 // Note that we don't remove the security bits here. This will be done 1240 // when all file refs are deleted (see RegisterDownloadedTempFile). 1241 } 1242 1243 bool ResourceDispatcherHostImpl::Send(IPC::Message* message) { 1244 delete message; 1245 return false; 1246 } 1247 1248 void ResourceDispatcherHostImpl::OnUploadProgressACK(int request_id) { 1249 ResourceLoader* loader = GetLoader(filter_->child_id(), request_id); 1250 if (loader) 1251 loader->OnUploadProgressACK(); 1252 } 1253 1254 // Note that this cancel is subtly different from the other 1255 // CancelRequest methods in this file, which also tear down the loader. 1256 void ResourceDispatcherHostImpl::OnCancelRequest(int request_id) { 1257 int child_id = filter_->child_id(); 1258 1259 // When the old renderer dies, it sends a message to us to cancel its 1260 // requests. 1261 if (IsTransferredNavigation(GlobalRequestID(child_id, request_id))) 1262 return; 1263 1264 ResourceLoader* loader = GetLoader(child_id, request_id); 1265 if (!loader) { 1266 // We probably want to remove this warning eventually, but I wanted to be 1267 // able to notice when this happens during initial development since it 1268 // should be rare and may indicate a bug. 1269 DVLOG(1) << "Canceling a request that wasn't found"; 1270 return; 1271 } 1272 1273 loader->CancelRequest(true); 1274 } 1275 1276 ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo( 1277 int child_id, 1278 int route_id, 1279 bool download, 1280 ResourceContext* context) { 1281 return new ResourceRequestInfoImpl( 1282 PROCESS_TYPE_RENDERER, 1283 child_id, 1284 route_id, 1285 0, 1286 request_id_, 1287 MSG_ROUTING_NONE, // render_frame_id 1288 false, // is_main_frame 1289 false, // parent_is_main_frame 1290 -1, // parent_render_frame_id 1291 ResourceType::SUB_RESOURCE, 1292 PAGE_TRANSITION_LINK, 1293 false, // should_replace_current_entry 1294 download, // is_download 1295 false, // is_stream 1296 download, // allow_download 1297 false, // has_user_gesture 1298 blink::WebReferrerPolicyDefault, 1299 blink::WebPageVisibilityStateVisible, 1300 context, 1301 base::WeakPtr<ResourceMessageFilter>(), // filter 1302 true); // is_async 1303 } 1304 1305 void ResourceDispatcherHostImpl::OnRenderViewHostCreated( 1306 int child_id, 1307 int route_id) { 1308 scheduler_->OnClientCreated(child_id, route_id); 1309 } 1310 1311 void ResourceDispatcherHostImpl::OnRenderViewHostDeleted( 1312 int child_id, 1313 int route_id) { 1314 scheduler_->OnClientDeleted(child_id, route_id); 1315 CancelRequestsForRoute(child_id, route_id); 1316 } 1317 1318 // This function is only used for saving feature. 1319 void ResourceDispatcherHostImpl::BeginSaveFile( 1320 const GURL& url, 1321 const Referrer& referrer, 1322 int child_id, 1323 int route_id, 1324 ResourceContext* context) { 1325 if (is_shutdown_) 1326 return; 1327 1328 // http://crbug.com/90971 1329 char url_buf[128]; 1330 base::strlcpy(url_buf, url.spec().c_str(), arraysize(url_buf)); 1331 base::debug::Alias(url_buf); 1332 CHECK(ContainsKey(active_resource_contexts_, context)); 1333 1334 request_id_--; 1335 1336 const net::URLRequestContext* request_context = context->GetRequestContext(); 1337 bool known_proto = 1338 request_context->job_factory()->IsHandledURL(url); 1339 if (!known_proto) { 1340 // Since any URLs which have non-standard scheme have been filtered 1341 // by save manager(see GURL::SchemeIsStandard). This situation 1342 // should not happen. 1343 NOTREACHED(); 1344 return; 1345 } 1346 1347 net::CookieStore* cookie_store = 1348 GetContentClient()->browser()->OverrideCookieStoreForRenderProcess( 1349 child_id); 1350 scoped_ptr<net::URLRequest> request( 1351 request_context->CreateRequest(url, net::DEFAULT_PRIORITY, NULL, 1352 cookie_store)); 1353 1354 request->set_method("GET"); 1355 SetReferrerForRequest(request.get(), referrer); 1356 1357 // So far, for saving page, we need fetch content from cache, in the 1358 // future, maybe we can use a configuration to configure this behavior. 1359 request->SetLoadFlags(net::LOAD_PREFERRING_CACHE); 1360 1361 // Since we're just saving some resources we need, disallow downloading. 1362 ResourceRequestInfoImpl* extra_info = 1363 CreateRequestInfo(child_id, route_id, false, context); 1364 extra_info->AssociateWithRequest(request.get()); // Request takes ownership. 1365 1366 scoped_ptr<ResourceHandler> handler( 1367 new SaveFileResourceHandler(request.get(), 1368 child_id, 1369 route_id, 1370 url, 1371 save_file_manager_.get())); 1372 1373 BeginRequestInternal(request.Pass(), handler.Pass()); 1374 } 1375 1376 void ResourceDispatcherHostImpl::MarkAsTransferredNavigation( 1377 const GlobalRequestID& id) { 1378 GetLoader(id)->MarkAsTransferring(); 1379 } 1380 1381 void ResourceDispatcherHostImpl::CancelTransferringNavigation( 1382 const GlobalRequestID& id) { 1383 // Request should still exist and be in the middle of a transfer. 1384 DCHECK(IsTransferredNavigation(id)); 1385 RemovePendingRequest(id.child_id, id.request_id); 1386 } 1387 1388 void ResourceDispatcherHostImpl::ResumeDeferredNavigation( 1389 const GlobalRequestID& id) { 1390 ResourceLoader* loader = GetLoader(id); 1391 if (loader) { 1392 // The response we were meant to resume could have already been canceled. 1393 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); 1394 if (info->cross_site_handler()) 1395 info->cross_site_handler()->ResumeResponse(); 1396 } 1397 } 1398 1399 // The object died, so cancel and detach all requests associated with it except 1400 // for downloads and detachable resources, which belong to the browser process 1401 // even if initiated via a renderer. 1402 void ResourceDispatcherHostImpl::CancelRequestsForProcess(int child_id) { 1403 CancelRequestsForRoute(child_id, -1 /* cancel all */); 1404 registered_temp_files_.erase(child_id); 1405 } 1406 1407 void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id, 1408 int route_id) { 1409 // Since pending_requests_ is a map, we first build up a list of all of the 1410 // matching requests to be cancelled, and then we cancel them. Since there 1411 // may be more than one request to cancel, we cannot simply hold onto the map 1412 // iterators found in the first loop. 1413 1414 // Find the global ID of all matching elements. 1415 bool any_requests_transferring = false; 1416 std::vector<GlobalRequestID> matching_requests; 1417 for (LoaderMap::const_iterator i = pending_loaders_.begin(); 1418 i != pending_loaders_.end(); ++i) { 1419 if (i->first.child_id != child_id) 1420 continue; 1421 1422 ResourceRequestInfoImpl* info = i->second->GetRequestInfo(); 1423 1424 GlobalRequestID id(child_id, i->first.request_id); 1425 DCHECK(id == i->first); 1426 // Don't cancel navigations that are expected to live beyond this process. 1427 if (IsTransferredNavigation(id)) 1428 any_requests_transferring = true; 1429 if (info->detachable_handler()) { 1430 info->detachable_handler()->Detach(); 1431 } else if (!info->IsDownload() && !info->is_stream() && 1432 !IsTransferredNavigation(id) && 1433 (route_id == -1 || route_id == info->GetRouteID())) { 1434 matching_requests.push_back(id); 1435 } 1436 } 1437 1438 // Remove matches. 1439 for (size_t i = 0; i < matching_requests.size(); ++i) { 1440 LoaderMap::iterator iter = pending_loaders_.find(matching_requests[i]); 1441 // Although every matching request was in pending_requests_ when we built 1442 // matching_requests, it is normal for a matching request to be not found 1443 // in pending_requests_ after we have removed some matching requests from 1444 // pending_requests_. For example, deleting a net::URLRequest that has 1445 // exclusive (write) access to an HTTP cache entry may unblock another 1446 // net::URLRequest that needs exclusive access to the same cache entry, and 1447 // that net::URLRequest may complete and remove itself from 1448 // pending_requests_. So we need to check that iter is not equal to 1449 // pending_requests_.end(). 1450 if (iter != pending_loaders_.end()) 1451 RemovePendingLoader(iter); 1452 } 1453 1454 // Don't clear the blocked loaders or offline policy maps if any of the 1455 // requests in route_id are being transferred to a new process, since those 1456 // maps will be updated with the new route_id after the transfer. Otherwise 1457 // we will lose track of this info when the old route goes away, before the 1458 // new one is created. 1459 if (any_requests_transferring) 1460 return; 1461 1462 // Now deal with blocked requests if any. 1463 if (route_id != -1) { 1464 if (blocked_loaders_map_.find(GlobalRoutingID(child_id, route_id)) != 1465 blocked_loaders_map_.end()) { 1466 CancelBlockedRequestsForRoute(child_id, route_id); 1467 } 1468 } else { 1469 // We have to do all render views for the process |child_id|. 1470 // Note that we have to do this in 2 passes as we cannot call 1471 // CancelBlockedRequestsForRoute while iterating over 1472 // blocked_loaders_map_, as it modifies it. 1473 std::set<int> route_ids; 1474 for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin(); 1475 iter != blocked_loaders_map_.end(); ++iter) { 1476 if (iter->first.child_id == child_id) 1477 route_ids.insert(iter->first.route_id); 1478 } 1479 for (std::set<int>::const_iterator iter = route_ids.begin(); 1480 iter != route_ids.end(); ++iter) { 1481 CancelBlockedRequestsForRoute(child_id, *iter); 1482 } 1483 } 1484 } 1485 1486 // Cancels the request and removes it from the list. 1487 void ResourceDispatcherHostImpl::RemovePendingRequest(int child_id, 1488 int request_id) { 1489 LoaderMap::iterator i = pending_loaders_.find( 1490 GlobalRequestID(child_id, request_id)); 1491 if (i == pending_loaders_.end()) { 1492 NOTREACHED() << "Trying to remove a request that's not here"; 1493 return; 1494 } 1495 RemovePendingLoader(i); 1496 } 1497 1498 void ResourceDispatcherHostImpl::RemovePendingLoader( 1499 const LoaderMap::iterator& iter) { 1500 ResourceRequestInfoImpl* info = iter->second->GetRequestInfo(); 1501 1502 // Remove the memory credit that we added when pushing the request onto 1503 // the pending list. 1504 IncrementOutstandingRequestsMemory(-1, *info); 1505 1506 pending_loaders_.erase(iter); 1507 1508 // If we have no more pending requests, then stop the load state monitor 1509 if (pending_loaders_.empty() && update_load_states_timer_) 1510 update_load_states_timer_->Stop(); 1511 } 1512 1513 void ResourceDispatcherHostImpl::CancelRequest(int child_id, 1514 int request_id) { 1515 ResourceLoader* loader = GetLoader(child_id, request_id); 1516 if (!loader) { 1517 // We probably want to remove this warning eventually, but I wanted to be 1518 // able to notice when this happens during initial development since it 1519 // should be rare and may indicate a bug. 1520 DVLOG(1) << "Canceling a request that wasn't found"; 1521 return; 1522 } 1523 1524 RemovePendingRequest(child_id, request_id); 1525 } 1526 1527 ResourceDispatcherHostImpl::OustandingRequestsStats 1528 ResourceDispatcherHostImpl::GetOutstandingRequestsStats( 1529 const ResourceRequestInfoImpl& info) { 1530 OutstandingRequestsStatsMap::iterator entry = 1531 outstanding_requests_stats_map_.find(info.GetChildID()); 1532 OustandingRequestsStats stats = { 0, 0 }; 1533 if (entry != outstanding_requests_stats_map_.end()) 1534 stats = entry->second; 1535 return stats; 1536 } 1537 1538 void ResourceDispatcherHostImpl::UpdateOutstandingRequestsStats( 1539 const ResourceRequestInfoImpl& info, 1540 const OustandingRequestsStats& stats) { 1541 if (stats.memory_cost == 0 && stats.num_requests == 0) 1542 outstanding_requests_stats_map_.erase(info.GetChildID()); 1543 else 1544 outstanding_requests_stats_map_[info.GetChildID()] = stats; 1545 } 1546 1547 ResourceDispatcherHostImpl::OustandingRequestsStats 1548 ResourceDispatcherHostImpl::IncrementOutstandingRequestsMemory( 1549 int count, 1550 const ResourceRequestInfoImpl& info) { 1551 DCHECK_EQ(1, abs(count)); 1552 1553 // Retrieve the previous value (defaulting to 0 if not found). 1554 OustandingRequestsStats stats = GetOutstandingRequestsStats(info); 1555 1556 // Insert/update the total; delete entries when their count reaches 0. 1557 stats.memory_cost += count * info.memory_cost(); 1558 DCHECK_GE(stats.memory_cost, 0); 1559 UpdateOutstandingRequestsStats(info, stats); 1560 1561 return stats; 1562 } 1563 1564 ResourceDispatcherHostImpl::OustandingRequestsStats 1565 ResourceDispatcherHostImpl::IncrementOutstandingRequestsCount( 1566 int count, 1567 const ResourceRequestInfoImpl& info) { 1568 DCHECK_EQ(1, abs(count)); 1569 num_in_flight_requests_ += count; 1570 1571 OustandingRequestsStats stats = GetOutstandingRequestsStats(info); 1572 stats.num_requests += count; 1573 DCHECK_GE(stats.num_requests, 0); 1574 UpdateOutstandingRequestsStats(info, stats); 1575 1576 return stats; 1577 } 1578 1579 bool ResourceDispatcherHostImpl::HasSufficientResourcesForRequest( 1580 const net::URLRequest* request_) { 1581 const ResourceRequestInfoImpl* info = 1582 ResourceRequestInfoImpl::ForRequest(request_); 1583 OustandingRequestsStats stats = IncrementOutstandingRequestsCount(1, *info); 1584 1585 if (stats.num_requests > max_num_in_flight_requests_per_process_) 1586 return false; 1587 if (num_in_flight_requests_ > max_num_in_flight_requests_) 1588 return false; 1589 1590 return true; 1591 } 1592 1593 void ResourceDispatcherHostImpl::FinishedWithResourcesForRequest( 1594 const net::URLRequest* request_) { 1595 const ResourceRequestInfoImpl* info = 1596 ResourceRequestInfoImpl::ForRequest(request_); 1597 IncrementOutstandingRequestsCount(-1, *info); 1598 } 1599 1600 // static 1601 int ResourceDispatcherHostImpl::CalculateApproximateMemoryCost( 1602 net::URLRequest* request) { 1603 // The following fields should be a minor size contribution (experimentally 1604 // on the order of 100). However since they are variable length, it could 1605 // in theory be a sizeable contribution. 1606 int strings_cost = request->extra_request_headers().ToString().size() + 1607 request->original_url().spec().size() + 1608 request->referrer().size() + 1609 request->method().size(); 1610 1611 // Note that this expression will typically be dominated by: 1612 // |kAvgBytesPerOutstandingRequest|. 1613 return kAvgBytesPerOutstandingRequest + strings_cost; 1614 } 1615 1616 void ResourceDispatcherHostImpl::BeginRequestInternal( 1617 scoped_ptr<net::URLRequest> request, 1618 scoped_ptr<ResourceHandler> handler) { 1619 DCHECK(!request->is_pending()); 1620 ResourceRequestInfoImpl* info = 1621 ResourceRequestInfoImpl::ForRequest(request.get()); 1622 1623 if ((TimeTicks::Now() - last_user_gesture_time_) < 1624 TimeDelta::FromMilliseconds(kUserGestureWindowMs)) { 1625 request->SetLoadFlags( 1626 request->load_flags() | net::LOAD_MAYBE_USER_GESTURE); 1627 } 1628 1629 // Add the memory estimate that starting this request will consume. 1630 info->set_memory_cost(CalculateApproximateMemoryCost(request.get())); 1631 1632 // If enqueing/starting this request will exceed our per-process memory 1633 // bound, abort it right away. 1634 OustandingRequestsStats stats = IncrementOutstandingRequestsMemory(1, *info); 1635 if (stats.memory_cost > max_outstanding_requests_cost_per_process_) { 1636 // We call "CancelWithError()" as a way of setting the net::URLRequest's 1637 // status -- it has no effect beyond this, since the request hasn't started. 1638 request->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); 1639 1640 bool defer = false; 1641 handler->OnResponseCompleted(request->status(), std::string(), &defer); 1642 if (defer) { 1643 // TODO(darin): The handler is not ready for us to kill the request. Oops! 1644 NOTREACHED(); 1645 } 1646 1647 IncrementOutstandingRequestsMemory(-1, *info); 1648 1649 // A ResourceHandler must not outlive its associated URLRequest. 1650 handler.reset(); 1651 return; 1652 } 1653 1654 linked_ptr<ResourceLoader> loader( 1655 new ResourceLoader(request.Pass(), handler.Pass(), this)); 1656 1657 GlobalRoutingID id(info->GetGlobalRoutingID()); 1658 BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.find(id); 1659 if (iter != blocked_loaders_map_.end()) { 1660 // The request should be blocked. 1661 iter->second->push_back(loader); 1662 return; 1663 } 1664 1665 StartLoading(info, loader); 1666 } 1667 1668 void ResourceDispatcherHostImpl::StartLoading( 1669 ResourceRequestInfoImpl* info, 1670 const linked_ptr<ResourceLoader>& loader) { 1671 pending_loaders_[info->GetGlobalRequestID()] = loader; 1672 1673 loader->StartRequest(); 1674 } 1675 1676 void ResourceDispatcherHostImpl::OnUserGesture(WebContentsImpl* contents) { 1677 last_user_gesture_time_ = TimeTicks::Now(); 1678 } 1679 1680 net::URLRequest* ResourceDispatcherHostImpl::GetURLRequest( 1681 const GlobalRequestID& id) { 1682 ResourceLoader* loader = GetLoader(id); 1683 if (!loader) 1684 return NULL; 1685 1686 return loader->request(); 1687 } 1688 1689 namespace { 1690 1691 // This function attempts to return the "more interesting" load state of |a| 1692 // and |b|. We don't have temporal information about these load states 1693 // (meaning we don't know when we transitioned into these states), so we just 1694 // rank them according to how "interesting" the states are. 1695 // 1696 // We take advantage of the fact that the load states are an enumeration listed 1697 // in the order in which they occur during the lifetime of a request, so we can 1698 // regard states with larger numeric values as being further along toward 1699 // completion. We regard those states as more interesting to report since they 1700 // represent progress. 1701 // 1702 // For example, by this measure "tranferring data" is a more interesting state 1703 // than "resolving host" because when we are transferring data we are actually 1704 // doing something that corresponds to changes that the user might observe, 1705 // whereas waiting for a host name to resolve implies being stuck. 1706 // 1707 const net::LoadStateWithParam& MoreInterestingLoadState( 1708 const net::LoadStateWithParam& a, const net::LoadStateWithParam& b) { 1709 return (a.state < b.state) ? b : a; 1710 } 1711 1712 // Carries information about a load state change. 1713 struct LoadInfo { 1714 GURL url; 1715 net::LoadStateWithParam load_state; 1716 uint64 upload_position; 1717 uint64 upload_size; 1718 }; 1719 1720 // Map from ProcessID+RouteID pair to LoadState 1721 typedef std::map<GlobalRoutingID, LoadInfo> LoadInfoMap; 1722 1723 // Used to marshal calls to LoadStateChanged from the IO to UI threads. We do 1724 // them all as a single callback to avoid spamming the UI thread. 1725 void LoadInfoUpdateCallback(const LoadInfoMap& info_map) { 1726 LoadInfoMap::const_iterator i; 1727 for (i = info_map.begin(); i != info_map.end(); ++i) { 1728 RenderViewHostImpl* view = 1729 RenderViewHostImpl::FromID(i->first.child_id, i->first.route_id); 1730 if (view) // The view could be gone at this point. 1731 view->LoadStateChanged(i->second.url, i->second.load_state, 1732 i->second.upload_position, 1733 i->second.upload_size); 1734 } 1735 } 1736 1737 } // namespace 1738 1739 void ResourceDispatcherHostImpl::UpdateLoadStates() { 1740 // Populate this map with load state changes, and then send them on to the UI 1741 // thread where they can be passed along to the respective RVHs. 1742 LoadInfoMap info_map; 1743 1744 LoaderMap::const_iterator i; 1745 1746 // Determine the largest upload size of all requests 1747 // in each View (good chance it's zero). 1748 std::map<GlobalRoutingID, uint64> largest_upload_size; 1749 for (i = pending_loaders_.begin(); i != pending_loaders_.end(); ++i) { 1750 net::URLRequest* request = i->second->request(); 1751 ResourceRequestInfoImpl* info = i->second->GetRequestInfo(); 1752 uint64 upload_size = request->GetUploadProgress().size(); 1753 if (request->GetLoadState().state != net::LOAD_STATE_SENDING_REQUEST) 1754 upload_size = 0; 1755 GlobalRoutingID id(info->GetGlobalRoutingID()); 1756 if (upload_size && largest_upload_size[id] < upload_size) 1757 largest_upload_size[id] = upload_size; 1758 } 1759 1760 for (i = pending_loaders_.begin(); i != pending_loaders_.end(); ++i) { 1761 net::URLRequest* request = i->second->request(); 1762 ResourceRequestInfoImpl* info = i->second->GetRequestInfo(); 1763 net::LoadStateWithParam load_state = request->GetLoadState(); 1764 net::UploadProgress progress = request->GetUploadProgress(); 1765 1766 // We also poll for upload progress on this timer and send upload 1767 // progress ipc messages to the plugin process. 1768 i->second->ReportUploadProgress(); 1769 1770 GlobalRoutingID id(info->GetGlobalRoutingID()); 1771 1772 // If a request is uploading data, ignore all other requests so that the 1773 // upload progress takes priority for being shown in the status bar. 1774 if (largest_upload_size.find(id) != largest_upload_size.end() && 1775 progress.size() < largest_upload_size[id]) 1776 continue; 1777 1778 net::LoadStateWithParam to_insert = load_state; 1779 LoadInfoMap::iterator existing = info_map.find(id); 1780 if (existing != info_map.end()) { 1781 to_insert = 1782 MoreInterestingLoadState(existing->second.load_state, load_state); 1783 if (to_insert.state == existing->second.load_state.state) 1784 continue; 1785 } 1786 LoadInfo& load_info = info_map[id]; 1787 load_info.url = request->url(); 1788 load_info.load_state = to_insert; 1789 load_info.upload_size = progress.size(); 1790 load_info.upload_position = progress.position(); 1791 } 1792 1793 if (info_map.empty()) 1794 return; 1795 1796 BrowserThread::PostTask( 1797 BrowserThread::UI, FROM_HERE, 1798 base::Bind(&LoadInfoUpdateCallback, info_map)); 1799 } 1800 1801 void ResourceDispatcherHostImpl::BlockRequestsForRoute(int child_id, 1802 int route_id) { 1803 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1804 GlobalRoutingID key(child_id, route_id); 1805 DCHECK(blocked_loaders_map_.find(key) == blocked_loaders_map_.end()) << 1806 "BlockRequestsForRoute called multiple time for the same RVH"; 1807 blocked_loaders_map_[key] = new BlockedLoadersList(); 1808 } 1809 1810 void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute(int child_id, 1811 int route_id) { 1812 ProcessBlockedRequestsForRoute(child_id, route_id, false); 1813 } 1814 1815 void ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute(int child_id, 1816 int route_id) { 1817 ProcessBlockedRequestsForRoute(child_id, route_id, true); 1818 } 1819 1820 void ResourceDispatcherHostImpl::ProcessBlockedRequestsForRoute( 1821 int child_id, 1822 int route_id, 1823 bool cancel_requests) { 1824 BlockedLoadersMap::iterator iter = blocked_loaders_map_.find( 1825 GlobalRoutingID(child_id, route_id)); 1826 if (iter == blocked_loaders_map_.end()) { 1827 // It's possible to reach here if the renderer crashed while an interstitial 1828 // page was showing. 1829 return; 1830 } 1831 1832 BlockedLoadersList* loaders = iter->second; 1833 1834 // Removing the vector from the map unblocks any subsequent requests. 1835 blocked_loaders_map_.erase(iter); 1836 1837 for (BlockedLoadersList::iterator loaders_iter = loaders->begin(); 1838 loaders_iter != loaders->end(); ++loaders_iter) { 1839 linked_ptr<ResourceLoader> loader = *loaders_iter; 1840 ResourceRequestInfoImpl* info = loader->GetRequestInfo(); 1841 if (cancel_requests) { 1842 IncrementOutstandingRequestsMemory(-1, *info); 1843 } else { 1844 StartLoading(info, loader); 1845 } 1846 } 1847 1848 delete loaders; 1849 } 1850 1851 ResourceDispatcherHostImpl::HttpAuthRelationType 1852 ResourceDispatcherHostImpl::HttpAuthRelationTypeOf( 1853 const GURL& request_url, 1854 const GURL& first_party) { 1855 if (!first_party.is_valid()) 1856 return HTTP_AUTH_RELATION_TOP; 1857 1858 if (net::registry_controlled_domains::SameDomainOrHost( 1859 first_party, request_url, 1860 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) 1861 return HTTP_AUTH_RELATION_SAME_DOMAIN; 1862 1863 if (allow_cross_origin_auth_prompt()) 1864 return HTTP_AUTH_RELATION_ALLOWED_CROSS; 1865 1866 return HTTP_AUTH_RELATION_BLOCKED_CROSS; 1867 } 1868 1869 bool ResourceDispatcherHostImpl::allow_cross_origin_auth_prompt() { 1870 return allow_cross_origin_auth_prompt_; 1871 } 1872 1873 bool ResourceDispatcherHostImpl::IsTransferredNavigation( 1874 const GlobalRequestID& id) const { 1875 ResourceLoader* loader = GetLoader(id); 1876 return loader ? loader->is_transferring() : false; 1877 } 1878 1879 ResourceLoader* ResourceDispatcherHostImpl::GetLoader( 1880 const GlobalRequestID& id) const { 1881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1882 1883 LoaderMap::const_iterator i = pending_loaders_.find(id); 1884 if (i == pending_loaders_.end()) 1885 return NULL; 1886 1887 return i->second.get(); 1888 } 1889 1890 ResourceLoader* ResourceDispatcherHostImpl::GetLoader(int child_id, 1891 int request_id) const { 1892 return GetLoader(GlobalRequestID(child_id, request_id)); 1893 } 1894 1895 void ResourceDispatcherHostImpl::RegisterResourceMessageDelegate( 1896 const GlobalRequestID& id, ResourceMessageDelegate* delegate) { 1897 DelegateMap::iterator it = delegate_map_.find(id); 1898 if (it == delegate_map_.end()) { 1899 it = delegate_map_.insert( 1900 std::make_pair(id, new ObserverList<ResourceMessageDelegate>)).first; 1901 } 1902 it->second->AddObserver(delegate); 1903 } 1904 1905 void ResourceDispatcherHostImpl::UnregisterResourceMessageDelegate( 1906 const GlobalRequestID& id, ResourceMessageDelegate* delegate) { 1907 DCHECK(ContainsKey(delegate_map_, id)); 1908 DelegateMap::iterator it = delegate_map_.find(id); 1909 DCHECK(it->second->HasObserver(delegate)); 1910 it->second->RemoveObserver(delegate); 1911 if (!it->second->might_have_observers()) { 1912 delete it->second; 1913 delegate_map_.erase(it); 1914 } 1915 } 1916 1917 int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest( 1918 const ResourceHostMsg_Request& request_data, 1919 int child_id, 1920 bool is_sync_load) { 1921 int load_flags = request_data.load_flags; 1922 1923 // Although EV status is irrelevant to sub-frames and sub-resources, we have 1924 // to perform EV certificate verification on all resources because an HTTP 1925 // keep-alive connection created to load a sub-frame or a sub-resource could 1926 // be reused to load a main frame. 1927 load_flags |= net::LOAD_VERIFY_EV_CERT; 1928 if (request_data.resource_type == ResourceType::MAIN_FRAME) { 1929 load_flags |= net::LOAD_MAIN_FRAME; 1930 } else if (request_data.resource_type == ResourceType::SUB_FRAME) { 1931 load_flags |= net::LOAD_SUB_FRAME; 1932 } else if (request_data.resource_type == ResourceType::PREFETCH) { 1933 load_flags |= (net::LOAD_PREFETCH | net::LOAD_DO_NOT_PROMPT_FOR_LOGIN); 1934 } else if (request_data.resource_type == ResourceType::FAVICON) { 1935 load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN; 1936 } else if (request_data.resource_type == ResourceType::IMAGE) { 1937 // Prevent third-party image content from prompting for login, as this 1938 // is often a scam to extract credentials for another domain from the user. 1939 // Only block image loads, as the attack applies largely to the "src" 1940 // property of the <img> tag. It is common for web properties to allow 1941 // untrusted values for <img src>; this is considered a fair thing for an 1942 // HTML sanitizer to do. Conversely, any HTML sanitizer that didn't 1943 // filter sources for <script>, <link>, <embed>, <object>, <iframe> tags 1944 // would be considered vulnerable in and of itself. 1945 HttpAuthRelationType relation_type = HttpAuthRelationTypeOf( 1946 request_data.url, request_data.first_party_for_cookies); 1947 if (relation_type == HTTP_AUTH_RELATION_BLOCKED_CROSS) { 1948 load_flags |= (net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY | 1949 net::LOAD_DO_NOT_PROMPT_FOR_LOGIN); 1950 } 1951 } 1952 1953 if (is_sync_load) 1954 load_flags |= net::LOAD_IGNORE_LIMITS; 1955 1956 ChildProcessSecurityPolicyImpl* policy = 1957 ChildProcessSecurityPolicyImpl::GetInstance(); 1958 if (!policy->CanSendCookiesForOrigin(child_id, request_data.url)) { 1959 load_flags |= (net::LOAD_DO_NOT_SEND_COOKIES | 1960 net::LOAD_DO_NOT_SEND_AUTH_DATA | 1961 net::LOAD_DO_NOT_SAVE_COOKIES); 1962 } 1963 1964 // Raw headers are sensitive, as they include Cookie/Set-Cookie, so only 1965 // allow requesting them if requester has ReadRawCookies permission. 1966 if ((load_flags & net::LOAD_REPORT_RAW_HEADERS) 1967 && !policy->CanReadRawCookies(child_id)) { 1968 VLOG(1) << "Denied unauthorized request for raw headers"; 1969 load_flags &= ~net::LOAD_REPORT_RAW_HEADERS; 1970 } 1971 1972 return load_flags; 1973 } 1974 1975 } // namespace content 1976