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