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