Index: chrome/browser/renderer_host/resource_dispatcher_host.cc |
=================================================================== |
--- chrome/browser/renderer_host/resource_dispatcher_host.cc (revision 75488) |
+++ chrome/browser/renderer_host/resource_dispatcher_host.cc (working copy) |
@@ -1,1952 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading |
- |
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h" |
- |
-#include <set> |
-#include <vector> |
- |
-#include "base/logging.h" |
-#include "base/command_line.h" |
-#include "base/message_loop.h" |
-#include "base/metrics/histogram.h" |
-#include "base/scoped_ptr.h" |
-#include "base/shared_memory.h" |
-#include "base/stl_util-inl.h" |
-#include "base/time.h" |
-#include "chrome/browser/cert_store.h" |
-#include "chrome/browser/child_process_security_policy.h" |
-#include "chrome/browser/chrome_blob_storage_context.h" |
-#include "chrome/browser/cross_site_request_manager.h" |
-#include "chrome/browser/download/download_file_manager.h" |
-#include "chrome/browser/download/download_manager.h" |
-#include "chrome/browser/download/download_request_limiter.h" |
-#include "chrome/browser/download/download_util.h" |
-#include "chrome/browser/download/save_file_manager.h" |
-#include "chrome/browser/extensions/user_script_listener.h" |
-#include "chrome/browser/external_protocol_handler.h" |
-#include "chrome/browser/in_process_webkit/webkit_thread.h" |
-#include "chrome/browser/net/chrome_url_request_context.h" |
-#include "chrome/browser/net/url_request_tracking.h" |
-#include "chrome/browser/plugin_service.h" |
-#include "chrome/browser/prerender/prerender_manager.h" |
-#include "chrome/browser/prerender/prerender_resource_handler.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/renderer_host/async_resource_handler.h" |
-#include "chrome/browser/renderer_host/buffered_resource_handler.h" |
-#include "chrome/browser/renderer_host/cross_site_resource_handler.h" |
-#include "chrome/browser/renderer_host/download_resource_handler.h" |
-#include "chrome/browser/renderer_host/global_request_id.h" |
-#include "chrome/browser/renderer_host/redirect_to_file_resource_handler.h" |
-#include "chrome/browser/renderer_host/render_view_host.h" |
-#include "chrome/browser/renderer_host/render_view_host_delegate.h" |
-#include "chrome/browser/renderer_host/render_view_host_notification_task.h" |
-#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" |
-#include "chrome/browser/renderer_host/resource_message_filter.h" |
-#include "chrome/browser/renderer_host/resource_queue.h" |
-#include "chrome/browser/renderer_host/resource_request_details.h" |
-#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h" |
-#include "chrome/browser/renderer_host/save_file_resource_handler.h" |
-#include "chrome/browser/renderer_host/sync_resource_handler.h" |
-#include "chrome/browser/safe_browsing/safe_browsing_service.h" |
-#include "chrome/browser/ssl/ssl_client_auth_handler.h" |
-#include "chrome/browser/ssl/ssl_manager.h" |
-#include "chrome/browser/ui/login/login_prompt.h" |
-#include "chrome/browser/worker_host/worker_service.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "chrome/common/notification_service.h" |
-#include "chrome/common/render_messages.h" |
-#include "chrome/common/render_messages_params.h" |
-#include "chrome/common/url_constants.h" |
-#include "net/base/auth.h" |
-#include "net/base/cert_status_flags.h" |
-#include "net/base/cookie_monster.h" |
-#include "net/base/load_flags.h" |
-#include "net/base/mime_util.h" |
-#include "net/base/net_errors.h" |
-#include "net/base/request_priority.h" |
-#include "net/base/ssl_cert_request_info.h" |
-#include "net/base/upload_data.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/url_request/url_request.h" |
-#include "net/url_request/url_request_context.h" |
-#include "webkit/appcache/appcache_interceptor.h" |
-#include "webkit/appcache/appcache_interfaces.h" |
-#include "webkit/blob/blob_storage_controller.h" |
-#include "webkit/blob/deletable_file_reference.h" |
- |
-// TODO(oshima): Enable this for other platforms. |
-#if defined(OS_CHROMEOS) |
-#include "chrome/browser/renderer_host/offline_resource_handler.h" |
-#endif |
- |
-using base::Time; |
-using base::TimeDelta; |
-using base::TimeTicks; |
-using webkit_blob::DeletableFileReference; |
- |
-// ---------------------------------------------------------------------------- |
- |
-// A ShutdownTask proxies a shutdown task from the UI thread to the IO thread. |
-// It should be constructed on the UI thread and run in the IO thread. |
-class ResourceDispatcherHost::ShutdownTask : public Task { |
- public: |
- explicit ShutdownTask(ResourceDispatcherHost* resource_dispatcher_host) |
- : rdh_(resource_dispatcher_host) { |
- } |
- |
- void Run() { |
- rdh_->OnShutdown(); |
- } |
- |
- private: |
- ResourceDispatcherHost* rdh_; |
-}; |
- |
-namespace { |
- |
-// The interval for calls to ResourceDispatcherHost::UpdateLoadStates |
-const int kUpdateLoadStatesIntervalMsec = 100; |
- |
-// Maximum number of pending data messages sent to the renderer at any |
-// given time for a given request. |
-const int kMaxPendingDataMessages = 20; |
- |
-// Maximum byte "cost" of all the outstanding requests for a renderer. |
-// See delcaration of |max_outstanding_requests_cost_per_process_| for details. |
-// This bound is 25MB, which allows for around 6000 outstanding requests. |
-const int kMaxOutstandingRequestsCostPerProcess = 26214400; |
- |
-// Consults the RendererSecurity policy to determine whether the |
-// ResourceDispatcherHost should service this request. A request might be |
-// disallowed if the renderer is not authorized to retrieve the request URL or |
-// if the renderer is attempting to upload an unauthorized file. |
-bool ShouldServiceRequest(ChildProcessInfo::ProcessType process_type, |
- int child_id, |
- const ViewHostMsg_Resource_Request& request_data) { |
- if (process_type == ChildProcessInfo::PLUGIN_PROCESS) |
- return true; |
- |
- if (request_data.resource_type == ResourceType::PREFETCH) { |
- prerender::PrerenderManager::RecordPrefetchTagObserved(); |
- if (!ResourceDispatcherHost::is_prefetch_enabled()) |
- return false; |
- } |
- |
- ChildProcessSecurityPolicy* policy = |
- ChildProcessSecurityPolicy::GetInstance(); |
- |
- // Check if the renderer is permitted to request the requested URL. |
- if (!policy->CanRequestURL(child_id, request_data.url)) { |
- VLOG(1) << "Denied unauthorized request for " |
- << request_data.url.possibly_invalid_spec(); |
- return false; |
- } |
- |
- // Check if the renderer is permitted to upload the requested files. |
- if (request_data.upload_data) { |
- const std::vector<net::UploadData::Element>* uploads = |
- request_data.upload_data->elements(); |
- std::vector<net::UploadData::Element>::const_iterator iter; |
- for (iter = uploads->begin(); iter != uploads->end(); ++iter) { |
- if (iter->type() == net::UploadData::TYPE_FILE && |
- !policy->CanReadFile(child_id, iter->file_path())) { |
- NOTREACHED() << "Denied unauthorized upload of " |
- << iter->file_path().value(); |
- return false; |
- } |
- } |
- } |
- |
- return true; |
-} |
- |
-void PopulateResourceResponse(net::URLRequest* request, |
- bool replace_extension_localization_templates, |
- ResourceResponse* response) { |
- response->response_head.status = request->status(); |
- response->response_head.request_time = request->request_time(); |
- response->response_head.response_time = request->response_time(); |
- response->response_head.headers = request->response_headers(); |
- request->GetCharset(&response->response_head.charset); |
- response->response_head.replace_extension_localization_templates = |
- replace_extension_localization_templates; |
- response->response_head.content_length = request->GetExpectedContentSize(); |
- request->GetMimeType(&response->response_head.mime_type); |
- response->response_head.was_fetched_via_spdy = |
- request->was_fetched_via_spdy(); |
- response->response_head.was_npn_negotiated = request->was_npn_negotiated(); |
- response->response_head.was_alternate_protocol_available = |
- request->was_alternate_protocol_available(); |
- response->response_head.was_fetched_via_proxy = |
- request->was_fetched_via_proxy(); |
- appcache::AppCacheInterceptor::GetExtraResponseInfo( |
- request, |
- &response->response_head.appcache_id, |
- &response->response_head.appcache_manifest_url); |
-} |
- |
-// Returns a list of all the possible error codes from the network module. |
-// Note that the error codes are all positive (since histograms expect positive |
-// sample values). |
-std::vector<int> GetAllNetErrorCodes() { |
- std::vector<int> all_error_codes; |
-#define NET_ERROR(label, value) all_error_codes.push_back(-(value)); |
-#include "net/base/net_error_list.h" |
-#undef NET_ERROR |
- return all_error_codes; |
-} |
- |
-#if defined(OS_WIN) |
-#pragma warning(disable: 4748) |
-#pragma optimize("", off) |
-#endif |
- |
-#if defined(OS_WIN) |
-#pragma optimize("", on) |
-#pragma warning(default: 4748) |
-#endif |
- |
-} // namespace |
- |
-ResourceDispatcherHost::ResourceDispatcherHost() |
- : ALLOW_THIS_IN_INITIALIZER_LIST( |
- download_file_manager_(new DownloadFileManager(this))), |
- download_request_limiter_(new DownloadRequestLimiter()), |
- ALLOW_THIS_IN_INITIALIZER_LIST( |
- save_file_manager_(new SaveFileManager(this))), |
- user_script_listener_(new UserScriptListener(&resource_queue_)), |
- safe_browsing_(SafeBrowsingService::CreateSafeBrowsingService()), |
- webkit_thread_(new WebKitThread), |
- request_id_(-1), |
- ALLOW_THIS_IN_INITIALIZER_LIST(method_runner_(this)), |
- is_shutdown_(false), |
- max_outstanding_requests_cost_per_process_( |
- kMaxOutstandingRequestsCostPerProcess), |
- filter_(NULL) { |
- ResourceQueue::DelegateSet resource_queue_delegates; |
- resource_queue_delegates.insert(user_script_listener_.get()); |
- resource_queue_.Initialize(resource_queue_delegates); |
-} |
- |
-ResourceDispatcherHost::~ResourceDispatcherHost() { |
- AsyncResourceHandler::GlobalCleanup(); |
- STLDeleteValues(&pending_requests_); |
- |
- user_script_listener_->ShutdownMainThread(); |
-} |
- |
-void ResourceDispatcherHost::Initialize() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- webkit_thread_->Initialize(); |
- safe_browsing_->Initialize(); |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- NewRunnableFunction(&appcache::AppCacheInterceptor::EnsureRegistered)); |
-} |
- |
-void ResourceDispatcherHost::Shutdown() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, new ShutdownTask(this)); |
-} |
- |
-void ResourceDispatcherHost::SetRequestInfo( |
- net::URLRequest* request, |
- ResourceDispatcherHostRequestInfo* info) { |
- request->SetUserData(NULL, info); |
-} |
- |
-void ResourceDispatcherHost::OnShutdown() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- is_shutdown_ = true; |
- resource_queue_.Shutdown(); |
- STLDeleteValues(&pending_requests_); |
- // Make sure we shutdown the timer now, otherwise by the time our destructor |
- // runs if the timer is still running the Task is deleted twice (once by |
- // the MessageLoop and the second time by RepeatingTimer). |
- update_load_states_timer_.Stop(); |
- |
- // Clear blocked requests if any left. |
- // Note that we have to do this in 2 passes as we cannot call |
- // CancelBlockedRequestsForRoute while iterating over |
- // blocked_requests_map_, as it modifies it. |
- std::set<ProcessRouteIDs> ids; |
- for (BlockedRequestMap::const_iterator iter = blocked_requests_map_.begin(); |
- iter != blocked_requests_map_.end(); ++iter) { |
- std::pair<std::set<ProcessRouteIDs>::iterator, bool> result = |
- ids.insert(iter->first); |
- // We should not have duplicates. |
- DCHECK(result.second); |
- } |
- for (std::set<ProcessRouteIDs>::const_iterator iter = ids.begin(); |
- iter != ids.end(); ++iter) { |
- CancelBlockedRequestsForRoute(iter->first, iter->second); |
- } |
-} |
- |
-bool ResourceDispatcherHost::HandleExternalProtocol(int request_id, |
- int child_id, |
- int route_id, |
- const GURL& url, |
- ResourceType::Type type, |
- ResourceHandler* handler) { |
- if (!ResourceType::IsFrame(type) || net::URLRequest::IsHandledURL(url)) |
- return false; |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableFunction( |
- &ExternalProtocolHandler::LaunchUrl, url, child_id, route_id)); |
- |
- handler->OnResponseCompleted( |
- request_id, |
- net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED), |
- std::string()); // No security info necessary. |
- return true; |
-} |
- |
-bool ResourceDispatcherHost::OnMessageReceived(const IPC::Message& message, |
- ResourceMessageFilter* filter, |
- bool* message_was_ok) { |
- filter_ = filter; |
- bool handled = true; |
- IPC_BEGIN_MESSAGE_MAP_EX(ResourceDispatcherHost, message, *message_was_ok) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource) |
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncLoad, OnSyncLoad) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_ReleaseDownloadedFile, |
- OnReleaseDownloadedFile) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_DataReceived_ACK, OnDataReceivedACK) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_DataDownloaded_ACK, OnDataDownloadedACK) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_UploadProgress_ACK, OnUploadProgressACK) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_CancelRequest, OnCancelRequest) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_FollowRedirect, OnFollowRedirect) |
- IPC_MESSAGE_HANDLER(ViewHostMsg_ClosePage_ACK, OnClosePageACK) |
- IPC_MESSAGE_UNHANDLED(handled = false) |
- IPC_END_MESSAGE_MAP_EX() |
- |
- filter_ = NULL; |
- return handled; |
-} |
- |
-void ResourceDispatcherHost::OnRequestResource( |
- const IPC::Message& message, |
- int request_id, |
- const ViewHostMsg_Resource_Request& request_data) { |
- BeginRequest(request_id, request_data, NULL, message.routing_id()); |
-} |
- |
-// Begins a resource request with the given params on behalf of the specified |
-// child process. Responses will be dispatched through the given receiver. The |
-// process ID is used to lookup TabContents from routing_id's in the case of a |
-// request from a renderer. request_context is the cookie/cache context to be |
-// used for this request. |
-// |
-// If sync_result is non-null, then a SyncLoad reply will be generated, else |
-// a normal asynchronous set of response messages will be generated. |
-void ResourceDispatcherHost::OnSyncLoad( |
- int request_id, |
- const ViewHostMsg_Resource_Request& request_data, |
- IPC::Message* sync_result) { |
- BeginRequest(request_id, request_data, sync_result, |
- sync_result->routing_id()); |
-} |
- |
-void ResourceDispatcherHost::BeginRequest( |
- int request_id, |
- const ViewHostMsg_Resource_Request& request_data, |
- IPC::Message* sync_result, // only valid for sync |
- int route_id) { |
- ChildProcessInfo::ProcessType process_type = filter_->process_type(); |
- int child_id = filter_->child_id(); |
- |
- ChromeURLRequestContext* context = filter_->GetURLRequestContext( |
- request_data); |
- |
- // Might need to resolve the blob references in the upload data. |
- if (request_data.upload_data && context) { |
- context->blob_storage_context()->controller()-> |
- ResolveBlobReferencesInUploadData(request_data.upload_data.get()); |
- } |
- |
- if (is_shutdown_ || |
- !ShouldServiceRequest(process_type, child_id, request_data)) { |
- net::URLRequestStatus status(net::URLRequestStatus::FAILED, |
- net::ERR_ABORTED); |
- if (sync_result) { |
- SyncLoadResult result; |
- result.status = status; |
- ViewHostMsg_SyncLoad::WriteReplyParams(sync_result, result); |
- filter_->Send(sync_result); |
- } else { |
- // Tell the renderer that this request was disallowed. |
- filter_->Send(new ViewMsg_Resource_RequestComplete( |
- route_id, |
- request_id, |
- status, |
- std::string(), // No security info needed, connection was not |
- base::Time())); // established. |
- } |
- return; |
- } |
- |
- // Ensure the Chrome plugins are loaded, as they may intercept network |
- // requests. Does nothing if they are already loaded. |
- // TODO(mpcomplete): This takes 200 ms! Investigate parallelizing this by |
- // starting the load earlier in a BG thread. |
- PluginService::GetInstance()->LoadChromePlugins(this); |
- |
- // Construct the event handler. |
- scoped_refptr<ResourceHandler> handler; |
- if (sync_result) { |
- handler = new SyncResourceHandler( |
- filter_, request_data.url, sync_result, this); |
- } else { |
- handler = new AsyncResourceHandler( |
- filter_, route_id, request_data.url, this); |
- } |
- |
- // The RedirectToFileResourceHandler depends on being next in the chain. |
- if (request_data.download_to_file) |
- handler = new RedirectToFileResourceHandler(handler, child_id, this); |
- |
- if (HandleExternalProtocol(request_id, child_id, route_id, |
- request_data.url, request_data.resource_type, |
- handler)) { |
- return; |
- } |
- |
- // Construct the request. |
- net::URLRequest* request = new net::URLRequest(request_data.url, this); |
- request->set_method(request_data.method); |
- request->set_first_party_for_cookies(request_data.first_party_for_cookies); |
- request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kNoReferrers) ? std::string() : request_data.referrer.spec()); |
- net::HttpRequestHeaders headers; |
- headers.AddHeadersFromString(request_data.headers); |
- request->SetExtraRequestHeaders(headers); |
- |
- int load_flags = request_data.load_flags; |
- // Although EV status is irrelevant to sub-frames and sub-resources, we have |
- // to perform EV certificate verification on all resources because an HTTP |
- // keep-alive connection created to load a sub-frame or a sub-resource could |
- // be reused to load a main frame. |
- load_flags |= net::LOAD_VERIFY_EV_CERT; |
- if (request_data.resource_type == ResourceType::MAIN_FRAME) { |
- load_flags |= net::LOAD_MAIN_FRAME; |
- } else if (request_data.resource_type == ResourceType::SUB_FRAME) { |
- load_flags |= net::LOAD_SUB_FRAME; |
- } else if (request_data.resource_type == ResourceType::PREFETCH) { |
- load_flags |= net::LOAD_PREFETCH; |
- } |
- // Raw headers are sensitive, as they inclide Cookie/Set-Cookie, so only |
- // allow requesting them if requestor has ReadRawCookies permission. |
- if ((load_flags & net::LOAD_REPORT_RAW_HEADERS) |
- && !ChildProcessSecurityPolicy::GetInstance()-> |
- CanReadRawCookies(child_id)) { |
- VLOG(1) << "Denied unathorized request for raw headers"; |
- load_flags &= ~net::LOAD_REPORT_RAW_HEADERS; |
- } |
- |
- request->set_load_flags(load_flags); |
- request->set_context(context); |
- request->set_priority(DetermineRequestPriority(request_data.resource_type)); |
- |
- // Set upload data. |
- uint64 upload_size = 0; |
- if (request_data.upload_data) { |
- request->set_upload(request_data.upload_data); |
- upload_size = request_data.upload_data->GetContentLength(); |
- } |
- |
- // Install a PrerenderResourceHandler if the requested URL could |
- // be prerendered. This should be in front of the [a]syncResourceHandler, |
- // but after the BufferedResourceHandler since it depends on the MIME |
- // sniffing capabilities in the BufferedResourceHandler. |
- prerender::PrerenderResourceHandler* pre_handler = |
- prerender::PrerenderResourceHandler::MaybeCreate(*request, |
- context, |
- handler); |
- if (pre_handler) |
- handler = pre_handler; |
- |
- // Install a CrossSiteResourceHandler if this request is coming from a |
- // RenderViewHost with a pending cross-site request. We only check this for |
- // MAIN_FRAME requests. Unblock requests only come from a blocked page, do |
- // not count as cross-site, otherwise it gets blocked indefinitely. |
- if (request_data.resource_type == ResourceType::MAIN_FRAME && |
- process_type == ChildProcessInfo::RENDER_PROCESS && |
- CrossSiteRequestManager::GetInstance()-> |
- HasPendingCrossSiteRequest(child_id, route_id)) { |
- // Wrap the event handler to be sure the current page's onunload handler |
- // has a chance to run before we render the new page. |
- handler = new CrossSiteResourceHandler(handler, |
- child_id, |
- route_id, |
- this); |
- } |
- |
- // Insert a buffered event handler before the actual one. |
- handler = new BufferedResourceHandler(handler, this, request); |
- |
- // Insert safe browsing at the front of the chain, so it gets to decide |
- // on policies first. |
- if (safe_browsing_->enabled()) { |
- handler = CreateSafeBrowsingResourceHandler(handler, child_id, route_id, |
- request_data.resource_type); |
- } |
- |
-#if defined(OS_CHROMEOS) |
- // We check offline first, then check safe browsing so that we still can block |
- // unsafe site after we remove offline page. |
- handler = |
- new OfflineResourceHandler(handler, child_id, route_id, this, request); |
-#endif |
- |
- // Make extra info and read footer (contains request ID). |
- ResourceDispatcherHostRequestInfo* extra_info = |
- new ResourceDispatcherHostRequestInfo( |
- handler, |
- process_type, |
- child_id, |
- route_id, |
- request_id, |
- request_data.resource_type, |
- upload_size, |
- false, // is download |
- ResourceType::IsFrame(request_data.resource_type), // allow_download |
- request_data.has_user_gesture, |
- request_data.host_renderer_id, |
- request_data.host_render_view_id); |
- ApplyExtensionLocalizationFilter(request_data.url, request_data.resource_type, |
- extra_info); |
- SetRequestInfo(request, extra_info); // Request takes ownership. |
- chrome_browser_net::SetOriginPIDForRequest( |
- request_data.origin_pid, request); |
- |
- if (request->url().SchemeIs(chrome::kBlobScheme) && context) { |
- // Hang on to a reference to ensure the blob is not released prior |
- // to the job being started. |
- webkit_blob::BlobStorageController* controller = |
- context->blob_storage_context()->controller(); |
- extra_info->set_requested_blob_data( |
- controller->GetBlobDataFromUrl(request->url())); |
- } |
- |
- // Have the appcache associate its extra info with the request. |
- appcache::AppCacheInterceptor::SetExtraRequestInfo( |
- request, context ? context->appcache_service() : NULL, child_id, |
- request_data.appcache_host_id, request_data.resource_type); |
- |
- BeginRequestInternal(request); |
-} |
- |
-void ResourceDispatcherHost::OnReleaseDownloadedFile(int request_id) { |
- DCHECK(pending_requests_.end() == |
- pending_requests_.find( |
- GlobalRequestID(filter_->child_id(), request_id))); |
- UnregisterDownloadedTempFile(filter_->child_id(), request_id); |
-} |
- |
-void ResourceDispatcherHost::OnDataReceivedACK(int request_id) { |
- DataReceivedACK(filter_->child_id(), request_id); |
-} |
- |
-void ResourceDispatcherHost::DataReceivedACK(int child_id, |
- int request_id) { |
- PendingRequestList::iterator i = pending_requests_.find( |
- GlobalRequestID(child_id, request_id)); |
- if (i == pending_requests_.end()) |
- return; |
- |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second); |
- |
- // Decrement the number of pending data messages. |
- info->DecrementPendingDataCount(); |
- |
- // If the pending data count was higher than the max, resume the request. |
- if (info->pending_data_count() == kMaxPendingDataMessages) { |
- // Decrement the pending data count one more time because we also |
- // incremented it before pausing the request. |
- info->DecrementPendingDataCount(); |
- |
- // Resume the request. |
- PauseRequest(child_id, request_id, false); |
- } |
-} |
- |
-void ResourceDispatcherHost::OnDataDownloadedACK(int request_id) { |
- // TODO(michaeln): maybe throttle DataDownloaded messages |
-} |
- |
-void ResourceDispatcherHost::RegisterDownloadedTempFile( |
- int child_id, int request_id, DeletableFileReference* reference) { |
- registered_temp_files_[child_id][request_id] = reference; |
- ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( |
- child_id, reference->path()); |
-} |
- |
-void ResourceDispatcherHost::UnregisterDownloadedTempFile( |
- int child_id, int request_id) { |
- DeletableFilesMap& map = registered_temp_files_[child_id]; |
- DeletableFilesMap::iterator found = map.find(request_id); |
- if (found == map.end()) |
- return; |
- |
- ChildProcessSecurityPolicy::GetInstance()->RevokeAllPermissionsForFile( |
- child_id, found->second->path()); |
- map.erase(found); |
-} |
- |
-bool ResourceDispatcherHost::Send(IPC::Message* message) { |
- delete message; |
- return false; |
-} |
- |
-void ResourceDispatcherHost::OnUploadProgressACK(int request_id) { |
- int child_id = filter_->child_id(); |
- PendingRequestList::iterator i = pending_requests_.find( |
- GlobalRequestID(child_id, request_id)); |
- if (i == pending_requests_.end()) |
- return; |
- |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second); |
- info->set_waiting_for_upload_progress_ack(false); |
-} |
- |
-void ResourceDispatcherHost::OnCancelRequest(int request_id) { |
- CancelRequest(filter_->child_id(), request_id, true); |
-} |
- |
-void ResourceDispatcherHost::OnFollowRedirect( |
- int request_id, |
- bool has_new_first_party_for_cookies, |
- const GURL& new_first_party_for_cookies) { |
- FollowDeferredRedirect(filter_->child_id(), request_id, |
- has_new_first_party_for_cookies, |
- new_first_party_for_cookies); |
-} |
- |
-ResourceHandler* ResourceDispatcherHost::CreateSafeBrowsingResourceHandler( |
- ResourceHandler* handler, int child_id, int route_id, |
- ResourceType::Type resource_type) { |
- return new SafeBrowsingResourceHandler( |
- handler, child_id, route_id, resource_type, safe_browsing_, this); |
-} |
- |
-ResourceDispatcherHostRequestInfo* |
-ResourceDispatcherHost::CreateRequestInfoForBrowserRequest( |
- ResourceHandler* handler, int child_id, int route_id, bool download) { |
- return new ResourceDispatcherHostRequestInfo(handler, |
- ChildProcessInfo::RENDER_PROCESS, |
- child_id, |
- route_id, |
- request_id_, |
- ResourceType::SUB_RESOURCE, |
- 0, // upload_size |
- download, // is_download |
- download, // allow_download |
- false, // has_user_gesture |
- -1, // host renderer id |
- -1); // host render view id |
-} |
- |
-void ResourceDispatcherHost::OnClosePageACK( |
- const ViewMsg_ClosePage_Params& params) { |
- if (params.for_cross_site_transition) { |
- // Closes for cross-site transitions are handled such that the cross-site |
- // transition continues. |
- GlobalRequestID global_id(params.new_render_process_host_id, |
- params.new_request_id); |
- PendingRequestList::iterator i = pending_requests_.find(global_id); |
- if (i != pending_requests_.end()) { |
- // The response we were meant to resume could have already been canceled. |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second); |
- if (info->cross_site_handler()) |
- info->cross_site_handler()->ResumeResponse(); |
- } |
- } else { |
- // This is a tab close, so just forward the message to close it. |
- DCHECK(params.new_render_process_host_id == -1); |
- DCHECK(params.new_request_id == -1); |
- CallRenderViewHost(params.closing_process_id, |
- params.closing_route_id, |
- &RenderViewHost::ClosePageIgnoringUnloadEvents); |
- } |
-} |
- |
-// We are explicitly forcing the download of 'url'. |
-void ResourceDispatcherHost::BeginDownload( |
- const GURL& url, |
- const GURL& referrer, |
- const DownloadSaveInfo& save_info, |
- bool prompt_for_save_location, |
- int child_id, |
- int route_id, |
- net::URLRequestContext* request_context) { |
- if (is_shutdown_) |
- return; |
- |
- // Check if the renderer is permitted to request the requested URL. |
- if (!ChildProcessSecurityPolicy::GetInstance()-> |
- CanRequestURL(child_id, url)) { |
- VLOG(1) << "Denied unauthorized download request for " |
- << url.possibly_invalid_spec(); |
- return; |
- } |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableFunction(&download_util::NotifyDownloadInitiated, |
- child_id, route_id)); |
- |
- // Ensure the Chrome plugins are loaded, as they may intercept network |
- // requests. Does nothing if they are already loaded. |
- PluginService::GetInstance()->LoadChromePlugins(this); |
- net::URLRequest* request = new net::URLRequest(url, this); |
- |
- request_id_--; |
- |
- scoped_refptr<ResourceHandler> handler( |
- new DownloadResourceHandler(this, |
- child_id, |
- route_id, |
- request_id_, |
- url, |
- download_file_manager_.get(), |
- request, |
- prompt_for_save_location, |
- save_info)); |
- |
- if (safe_browsing_->enabled()) { |
- handler = CreateSafeBrowsingResourceHandler(handler, child_id, route_id, |
- ResourceType::MAIN_FRAME); |
- } |
- |
- if (!net::URLRequest::IsHandledURL(url)) { |
- VLOG(1) << "Download request for unsupported protocol: " |
- << url.possibly_invalid_spec(); |
- return; |
- } |
- |
- request->set_method("GET"); |
- request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kNoReferrers) ? std::string() : referrer.spec()); |
- request->set_context(request_context); |
- request->set_load_flags(request->load_flags() | |
- net::LOAD_IS_DOWNLOAD); |
- |
- ResourceDispatcherHostRequestInfo* extra_info = |
- CreateRequestInfoForBrowserRequest(handler, child_id, route_id, true); |
- SetRequestInfo(request, extra_info); // Request takes ownership. |
- |
- BeginRequestInternal(request); |
-} |
- |
-// This function is only used for saving feature. |
-void ResourceDispatcherHost::BeginSaveFile( |
- const GURL& url, |
- const GURL& referrer, |
- int child_id, |
- int route_id, |
- net::URLRequestContext* request_context) { |
- if (is_shutdown_) |
- return; |
- |
- // Ensure the Chrome plugins are loaded, as they may intercept network |
- // requests. Does nothing if they are already loaded. |
- PluginService::GetInstance()->LoadChromePlugins(this); |
- |
- scoped_refptr<ResourceHandler> handler( |
- new SaveFileResourceHandler(child_id, |
- route_id, |
- url, |
- save_file_manager_.get())); |
- request_id_--; |
- |
- bool known_proto = net::URLRequest::IsHandledURL(url); |
- if (!known_proto) { |
- // Since any URLs which have non-standard scheme have been filtered |
- // by save manager(see GURL::SchemeIsStandard). This situation |
- // should not happen. |
- NOTREACHED(); |
- return; |
- } |
- |
- net::URLRequest* request = new net::URLRequest(url, this); |
- request->set_method("GET"); |
- request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kNoReferrers) ? std::string() : referrer.spec()); |
- // So far, for saving page, we need fetch content from cache, in the |
- // future, maybe we can use a configuration to configure this behavior. |
- request->set_load_flags(net::LOAD_PREFERRING_CACHE); |
- request->set_context(request_context); |
- |
- // Since we're just saving some resources we need, disallow downloading. |
- ResourceDispatcherHostRequestInfo* extra_info = |
- CreateRequestInfoForBrowserRequest(handler, child_id, route_id, false); |
- SetRequestInfo(request, extra_info); // Request takes ownership. |
- |
- BeginRequestInternal(request); |
-} |
- |
-void ResourceDispatcherHost::FollowDeferredRedirect( |
- int child_id, |
- int request_id, |
- bool has_new_first_party_for_cookies, |
- const GURL& new_first_party_for_cookies) { |
- PendingRequestList::iterator i = pending_requests_.find( |
- GlobalRequestID(child_id, request_id)); |
- if (i == pending_requests_.end() || !i->second->status().is_success()) { |
- DLOG(WARNING) << "FollowDeferredRedirect for invalid request"; |
- return; |
- } |
- |
- if (has_new_first_party_for_cookies) |
- i->second->set_first_party_for_cookies(new_first_party_for_cookies); |
- i->second->FollowDeferredRedirect(); |
-} |
- |
-void ResourceDispatcherHost::StartDeferredRequest(int process_unique_id, |
- int request_id) { |
- GlobalRequestID global_id(process_unique_id, request_id); |
- PendingRequestList::iterator i = pending_requests_.find(global_id); |
- if (i == pending_requests_.end()) { |
- // The request may have been destroyed |
- LOG(WARNING) << "Trying to resume a non-existent request (" |
- << process_unique_id << ", " << request_id << ")"; |
- return; |
- } |
- |
- // TODO(eroman): are there other considerations for paused or blocked |
- // requests? |
- |
- net::URLRequest* request = i->second; |
- InsertIntoResourceQueue(request, *InfoForRequest(request)); |
-} |
- |
-bool ResourceDispatcherHost::WillSendData(int child_id, |
- int request_id) { |
- PendingRequestList::iterator i = pending_requests_.find( |
- GlobalRequestID(child_id, request_id)); |
- if (i == pending_requests_.end()) { |
- NOTREACHED() << "WillSendData for invalid request"; |
- return false; |
- } |
- |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second); |
- |
- info->IncrementPendingDataCount(); |
- if (info->pending_data_count() > kMaxPendingDataMessages) { |
- // We reached the max number of data messages that can be sent to |
- // the renderer for a given request. Pause the request and wait for |
- // the renderer to start processing them before resuming it. |
- PauseRequest(child_id, request_id, true); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-void ResourceDispatcherHost::PauseRequest(int child_id, |
- int request_id, |
- bool pause) { |
- GlobalRequestID global_id(child_id, request_id); |
- PendingRequestList::iterator i = pending_requests_.find(global_id); |
- if (i == pending_requests_.end()) { |
- DLOG(WARNING) << "Pausing a request that wasn't found"; |
- return; |
- } |
- |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second); |
- int pause_count = info->pause_count() + (pause ? 1 : -1); |
- if (pause_count < 0) { |
- NOTREACHED(); // Unbalanced call to pause. |
- return; |
- } |
- info->set_pause_count(pause_count); |
- |
- VLOG(1) << "To pause (" << pause << "): " << i->second->url().spec(); |
- |
- // If we're resuming, kick the request to start reading again. Run the read |
- // asynchronously to avoid recursion problems. |
- if (info->pause_count() == 0) { |
- MessageLoop::current()->PostTask(FROM_HERE, |
- method_runner_.NewRunnableMethod( |
- &ResourceDispatcherHost::ResumeRequest, global_id)); |
- } |
-} |
- |
-int ResourceDispatcherHost::GetOutstandingRequestsMemoryCost( |
- int child_id) const { |
- OutstandingRequestsMemoryCostMap::const_iterator entry = |
- outstanding_requests_memory_cost_map_.find(child_id); |
- return (entry == outstanding_requests_memory_cost_map_.end()) ? |
- 0 : entry->second; |
-} |
- |
-// The object died, so cancel and detach all requests associated with it except |
-// for downloads, which belong to the browser process even if initiated via a |
-// renderer. |
-void ResourceDispatcherHost::CancelRequestsForProcess(int child_id) { |
- CancelRequestsForRoute(child_id, -1 /* cancel all */); |
- registered_temp_files_.erase(child_id); |
-} |
- |
-void ResourceDispatcherHost::CancelRequestsForRoute(int child_id, |
- int route_id) { |
- // Since pending_requests_ is a map, we first build up a list of all of the |
- // matching requests to be cancelled, and then we cancel them. Since there |
- // may be more than one request to cancel, we cannot simply hold onto the map |
- // iterators found in the first loop. |
- |
- // Find the global ID of all matching elements. |
- std::vector<GlobalRequestID> matching_requests; |
- for (PendingRequestList::const_iterator i = pending_requests_.begin(); |
- i != pending_requests_.end(); ++i) { |
- if (i->first.child_id == child_id) { |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second); |
- if (!info->is_download() && |
- (route_id == -1 || route_id == info->route_id())) { |
- matching_requests.push_back( |
- GlobalRequestID(child_id, i->first.request_id)); |
- } |
- } |
- } |
- |
- // Remove matches. |
- for (size_t i = 0; i < matching_requests.size(); ++i) { |
- PendingRequestList::iterator iter = |
- pending_requests_.find(matching_requests[i]); |
- // Although every matching request was in pending_requests_ when we built |
- // matching_requests, it is normal for a matching request to be not found |
- // in pending_requests_ after we have removed some matching requests from |
- // pending_requests_. For example, deleting a net::URLRequest that has |
- // exclusive (write) access to an HTTP cache entry may unblock another |
- // net::URLRequest that needs exclusive access to the same cache entry, and |
- // that net::URLRequest may complete and remove itself from |
- // pending_requests_. So we need to check that iter is not equal to |
- // pending_requests_.end(). |
- if (iter != pending_requests_.end()) |
- RemovePendingRequest(iter); |
- } |
- |
- // Now deal with blocked requests if any. |
- if (route_id != -1) { |
- if (blocked_requests_map_.find(std::pair<int, int>(child_id, route_id)) != |
- blocked_requests_map_.end()) { |
- CancelBlockedRequestsForRoute(child_id, route_id); |
- } |
- } else { |
- // We have to do all render views for the process |child_id|. |
- // Note that we have to do this in 2 passes as we cannot call |
- // CancelBlockedRequestsForRoute while iterating over |
- // blocked_requests_map_, as it modifies it. |
- std::set<int> route_ids; |
- for (BlockedRequestMap::const_iterator iter = blocked_requests_map_.begin(); |
- iter != blocked_requests_map_.end(); ++iter) { |
- if (iter->first.first == child_id) |
- route_ids.insert(iter->first.second); |
- } |
- for (std::set<int>::const_iterator iter = route_ids.begin(); |
- iter != route_ids.end(); ++iter) { |
- CancelBlockedRequestsForRoute(child_id, *iter); |
- } |
- } |
-} |
- |
-// Cancels the request and removes it from the list. |
-void ResourceDispatcherHost::RemovePendingRequest(int child_id, |
- int request_id) { |
- PendingRequestList::iterator i = pending_requests_.find( |
- GlobalRequestID(child_id, request_id)); |
- if (i == pending_requests_.end()) { |
- NOTREACHED() << "Trying to remove a request that's not here"; |
- return; |
- } |
- RemovePendingRequest(i); |
-} |
- |
-void ResourceDispatcherHost::RemovePendingRequest( |
- const PendingRequestList::iterator& iter) { |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(iter->second); |
- |
- // Remove the memory credit that we added when pushing the request onto |
- // the pending list. |
- IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(), |
- info->child_id()); |
- |
- // Notify interested parties that the request object is going away. |
- if (info->login_handler()) |
- info->login_handler()->OnRequestCancelled(); |
- if (info->ssl_client_auth_handler()) |
- info->ssl_client_auth_handler()->OnRequestCancelled(); |
- resource_queue_.RemoveRequest(iter->first); |
- |
- delete iter->second; |
- pending_requests_.erase(iter); |
- |
- // If we have no more pending requests, then stop the load state monitor |
- if (pending_requests_.empty()) |
- update_load_states_timer_.Stop(); |
-} |
- |
-// net::URLRequest::Delegate --------------------------------------------------- |
- |
-void ResourceDispatcherHost::OnReceivedRedirect(net::URLRequest* request, |
- const GURL& new_url, |
- bool* defer_redirect) { |
- VLOG(1) << "OnReceivedRedirect: " << request->url().spec(); |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- |
- DCHECK(request->status().is_success()); |
- |
- if (info->process_type() != ChildProcessInfo::PLUGIN_PROCESS && |
- !ChildProcessSecurityPolicy::GetInstance()-> |
- CanRequestURL(info->child_id(), new_url)) { |
- VLOG(1) << "Denied unauthorized request for " |
- << new_url.possibly_invalid_spec(); |
- |
- // Tell the renderer that this request was disallowed. |
- CancelRequestInternal(request, false); |
- return; |
- } |
- |
- NotifyReceivedRedirect(request, info->child_id(), new_url); |
- |
- if (HandleExternalProtocol(info->request_id(), info->child_id(), |
- info->route_id(), new_url, |
- info->resource_type(), info->resource_handler())) { |
- // The request is complete so we can remove it. |
- RemovePendingRequest(info->child_id(), info->request_id()); |
- return; |
- } |
- |
- scoped_refptr<ResourceResponse> response(new ResourceResponse); |
- PopulateResourceResponse(request, |
- info->replace_extension_localization_templates(), response); |
- if (!info->resource_handler()->OnRequestRedirected(info->request_id(), |
- new_url, |
- response, defer_redirect)) |
- CancelRequestInternal(request, false); |
-} |
- |
-void ResourceDispatcherHost::OnAuthRequired( |
- net::URLRequest* request, |
- net::AuthChallengeInfo* auth_info) { |
- if (request->load_flags() & net::LOAD_PREFETCH) { |
- request->CancelAuth(); |
- return; |
- } |
- // Create a login dialog on the UI thread to get authentication data, |
- // or pull from cache and continue on the IO thread. |
- // TODO(mpcomplete): We should block the parent tab while waiting for |
- // authentication. |
- // That would also solve the problem of the net::URLRequest being cancelled |
- // before we receive authentication. |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- DCHECK(!info->login_handler()) << |
- "OnAuthRequired called with login_handler pending"; |
- info->set_login_handler(CreateLoginPrompt(auth_info, request)); |
-} |
- |
-void ResourceDispatcherHost::OnCertificateRequested( |
- net::URLRequest* request, |
- net::SSLCertRequestInfo* cert_request_info) { |
- DCHECK(request); |
- |
- if (cert_request_info->client_certs.empty()) { |
- // No need to query the user if there are no certs to choose from. |
- request->ContinueWithCertificate(NULL); |
- return; |
- } |
- |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- DCHECK(!info->ssl_client_auth_handler()) << |
- "OnCertificateRequested called with ssl_client_auth_handler pending"; |
- info->set_ssl_client_auth_handler( |
- new SSLClientAuthHandler(request, cert_request_info)); |
- info->ssl_client_auth_handler()->SelectCertificate(); |
-} |
- |
-void ResourceDispatcherHost::OnSSLCertificateError( |
- net::URLRequest* request, |
- int cert_error, |
- net::X509Certificate* cert) { |
- DCHECK(request); |
- SSLManager::OnSSLCertificateError(this, request, cert_error, cert); |
-} |
- |
-void ResourceDispatcherHost::OnGetCookies( |
- net::URLRequest* request, |
- bool blocked_by_policy) { |
- VLOG(1) << "OnGetCookies: " << request->url().spec(); |
- |
- int render_process_id, render_view_id; |
- if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) |
- return; |
- |
- net::URLRequestContext* context = request->context(); |
- |
- net::CookieMonster* cookie_monster = |
- context->cookie_store()->GetCookieMonster(); |
- net::CookieList cookie_list = |
- cookie_monster->GetAllCookiesForURL(request->url()); |
- CallRenderViewHostContentSettingsDelegate( |
- render_process_id, render_view_id, |
- &RenderViewHostDelegate::ContentSettings::OnCookiesRead, |
- request->url(), cookie_list, blocked_by_policy); |
-} |
- |
-void ResourceDispatcherHost::OnSetCookie(net::URLRequest* request, |
- const std::string& cookie_line, |
- const net::CookieOptions& options, |
- bool blocked_by_policy) { |
- VLOG(1) << "OnSetCookie: " << request->url().spec(); |
- |
- int render_process_id, render_view_id; |
- if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) |
- return; |
- |
- CallRenderViewHostContentSettingsDelegate( |
- render_process_id, render_view_id, |
- &RenderViewHostDelegate::ContentSettings::OnCookieChanged, |
- request->url(), cookie_line, options, blocked_by_policy); |
-} |
- |
-void ResourceDispatcherHost::OnResponseStarted(net::URLRequest* request) { |
- VLOG(1) << "OnResponseStarted: " << request->url().spec(); |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- if (PauseRequestIfNeeded(info)) { |
- VLOG(1) << "OnResponseStarted pausing: " << request->url().spec(); |
- return; |
- } |
- |
- if (request->status().is_success()) { |
- // We want to send a final upload progress message prior to sending |
- // the response complete message even if we're waiting for an ack to |
- // to a previous upload progress message. |
- info->set_waiting_for_upload_progress_ack(false); |
- MaybeUpdateUploadProgress(info, request); |
- |
- if (!CompleteResponseStarted(request)) { |
- CancelRequestInternal(request, false); |
- } else { |
- // Check if the handler paused the request in their OnResponseStarted. |
- if (PauseRequestIfNeeded(info)) { |
- VLOG(1) << "OnResponseStarted pausing2: " << request->url().spec(); |
- return; |
- } |
- |
- StartReading(request); |
- } |
- } else { |
- OnResponseCompleted(request); |
- } |
-} |
- |
-bool ResourceDispatcherHost::CompleteResponseStarted(net::URLRequest* request) { |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- |
- scoped_refptr<ResourceResponse> response(new ResourceResponse); |
- PopulateResourceResponse(request, |
- info->replace_extension_localization_templates(), response); |
- |
- if (request->ssl_info().cert) { |
- int cert_id = |
- CertStore::GetInstance()->StoreCert(request->ssl_info().cert, |
- info->child_id()); |
- response->response_head.security_info = |
- SSLManager::SerializeSecurityInfo( |
- cert_id, request->ssl_info().cert_status, |
- request->ssl_info().security_bits, |
- request->ssl_info().connection_status); |
- } else { |
- // We should not have any SSL state. |
- DCHECK(!request->ssl_info().cert_status && |
- request->ssl_info().security_bits == -1 && |
- !request->ssl_info().connection_status); |
- } |
- |
- NotifyResponseStarted(request, info->child_id()); |
- info->set_called_on_response_started(true); |
- return info->resource_handler()->OnResponseStarted(info->request_id(), |
- response.get()); |
-} |
- |
-void ResourceDispatcherHost::CancelRequest(int child_id, |
- int request_id, |
- bool from_renderer) { |
- PendingRequestList::iterator i = pending_requests_.find( |
- GlobalRequestID(child_id, request_id)); |
- if (i == pending_requests_.end()) { |
- // We probably want to remove this warning eventually, but I wanted to be |
- // able to notice when this happens during initial development since it |
- // should be rare and may indicate a bug. |
- DLOG(WARNING) << "Canceling a request that wasn't found"; |
- return; |
- } |
- CancelRequestInternal(i->second, from_renderer); |
-} |
- |
-void ResourceDispatcherHost::CancelRequestInternal(net::URLRequest* request, |
- bool from_renderer) { |
- VLOG(1) << "CancelRequest: " << request->url().spec(); |
- |
- // WebKit will send us a cancel for downloads since it no longer handles them. |
- // In this case, ignore the cancel since we handle downloads in the browser. |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- if (!from_renderer || !info->is_download()) { |
- if (info->login_handler()) { |
- info->login_handler()->OnRequestCancelled(); |
- info->set_login_handler(NULL); |
- } |
- if (info->ssl_client_auth_handler()) { |
- info->ssl_client_auth_handler()->OnRequestCancelled(); |
- info->set_ssl_client_auth_handler(NULL); |
- } |
- request->Cancel(); |
- // Our callers assume |request| is valid after we return. |
- DCHECK(IsValidRequest(request)); |
- } |
- |
- // Do not remove from the pending requests, as the request will still |
- // call AllDataReceived, and may even have more data before it does |
- // that. |
-} |
- |
-int ResourceDispatcherHost::IncrementOutstandingRequestsMemoryCost( |
- int cost, |
- int child_id) { |
- // Retrieve the previous value (defaulting to 0 if not found). |
- OutstandingRequestsMemoryCostMap::iterator prev_entry = |
- outstanding_requests_memory_cost_map_.find(child_id); |
- int new_cost = 0; |
- if (prev_entry != outstanding_requests_memory_cost_map_.end()) |
- new_cost = prev_entry->second; |
- |
- // Insert/update the total; delete entries when their value reaches 0. |
- new_cost += cost; |
- CHECK(new_cost >= 0); |
- if (new_cost == 0) |
- outstanding_requests_memory_cost_map_.erase(prev_entry); |
- else |
- outstanding_requests_memory_cost_map_[child_id] = new_cost; |
- |
- return new_cost; |
-} |
- |
-// static |
-int ResourceDispatcherHost::CalculateApproximateMemoryCost( |
- net::URLRequest* request) { |
- // The following fields should be a minor size contribution (experimentally |
- // on the order of 100). However since they are variable length, it could |
- // in theory be a sizeable contribution. |
- int strings_cost = request->extra_request_headers().ToString().size() + |
- request->original_url().spec().size() + |
- request->referrer().size() + |
- request->method().size(); |
- |
- int upload_cost = 0; |
- |
- // TODO(eroman): don't enable the upload throttling until we have data |
- // showing what a reasonable limit is (limiting to 25MB of uploads may |
- // be too restrictive). |
-#if 0 |
- // Sum all the (non-file) upload data attached to the request, if any. |
- if (request->has_upload()) { |
- const std::vector<net::UploadData::Element>& uploads = |
- request->get_upload()->elements(); |
- std::vector<net::UploadData::Element>::const_iterator iter; |
- for (iter = uploads.begin(); iter != uploads.end(); ++iter) { |
- if (iter->type() == net::UploadData::TYPE_BYTES) { |
- int64 element_size = iter->GetContentLength(); |
- // This cast should not result in truncation. |
- upload_cost += static_cast<int>(element_size); |
- } |
- } |
- } |
-#endif |
- |
- // Note that this expression will typically be dominated by: |
- // |kAvgBytesPerOutstandingRequest|. |
- return kAvgBytesPerOutstandingRequest + strings_cost + upload_cost; |
-} |
- |
-void ResourceDispatcherHost::BeginRequestInternal(net::URLRequest* request) { |
- DCHECK(!request->is_pending()); |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- |
- // Add the memory estimate that starting this request will consume. |
- info->set_memory_cost(CalculateApproximateMemoryCost(request)); |
- int memory_cost = IncrementOutstandingRequestsMemoryCost(info->memory_cost(), |
- info->child_id()); |
- |
- // If enqueing/starting this request will exceed our per-process memory |
- // bound, abort it right away. |
- if (memory_cost > max_outstanding_requests_cost_per_process_) { |
- // We call "SimulateError()" as a way of setting the net::URLRequest's |
- // status -- it has no effect beyond this, since the request hasn't started. |
- request->SimulateError(net::ERR_INSUFFICIENT_RESOURCES); |
- |
- // TODO(eroman): this is kinda funky -- we insert the unstarted request into |
- // |pending_requests_| simply to please OnResponseCompleted(). |
- GlobalRequestID global_id(info->child_id(), info->request_id()); |
- pending_requests_[global_id] = request; |
- OnResponseCompleted(request); |
- return; |
- } |
- |
- std::pair<int, int> pair_id(info->child_id(), info->route_id()); |
- BlockedRequestMap::const_iterator iter = blocked_requests_map_.find(pair_id); |
- if (iter != blocked_requests_map_.end()) { |
- // The request should be blocked. |
- iter->second->push_back(request); |
- return; |
- } |
- |
- GlobalRequestID global_id(info->child_id(), info->request_id()); |
- pending_requests_[global_id] = request; |
- |
- // Give the resource handlers an opportunity to delay the net::URLRequest from |
- // being started. |
- // |
- // There are three cases: |
- // |
- // (1) if OnWillStart() returns false, the request is cancelled (regardless |
- // of whether |defer_start| was set). |
- // (2) If |defer_start| was set to true, then the request is not added |
- // into the resource queue, and will only be started in response to |
- // calling StartDeferredRequest(). |
- // (3) If |defer_start| is not set, then the request is inserted into |
- // the resource_queue_ (which may pause it further, or start it). |
- bool defer_start = false; |
- if (!info->resource_handler()->OnWillStart( |
- info->request_id(), request->url(), |
- &defer_start)) { |
- CancelRequestInternal(request, false); |
- return; |
- } |
- |
- if (!defer_start) { |
- InsertIntoResourceQueue(request, *info); |
- } |
-} |
- |
-void ResourceDispatcherHost::InsertIntoResourceQueue( |
- net::URLRequest* request, |
- const ResourceDispatcherHostRequestInfo& request_info) { |
- resource_queue_.AddRequest(request, request_info); |
- |
- // Make sure we have the load state monitor running |
- if (!update_load_states_timer_.IsRunning()) { |
- update_load_states_timer_.Start( |
- TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec), |
- this, &ResourceDispatcherHost::UpdateLoadStates); |
- } |
-} |
- |
-bool ResourceDispatcherHost::PauseRequestIfNeeded( |
- ResourceDispatcherHostRequestInfo* info) { |
- if (info->pause_count() > 0) |
- info->set_is_paused(true); |
- return info->is_paused(); |
-} |
- |
-void ResourceDispatcherHost::ResumeRequest(const GlobalRequestID& request_id) { |
- PendingRequestList::iterator i = pending_requests_.find(request_id); |
- if (i == pending_requests_.end()) // The request may have been destroyed |
- return; |
- |
- net::URLRequest* request = i->second; |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- if (!info->is_paused()) |
- return; |
- |
- VLOG(1) << "Resuming: " << i->second->url().spec(); |
- |
- info->set_is_paused(false); |
- |
- if (info->called_on_response_started()) { |
- if (info->has_started_reading()) { |
- OnReadCompleted(i->second, info->paused_read_bytes()); |
- } else { |
- StartReading(request); |
- } |
- } else { |
- OnResponseStarted(i->second); |
- } |
-} |
- |
-void ResourceDispatcherHost::StartReading(net::URLRequest* request) { |
- // Start reading. |
- int bytes_read = 0; |
- if (Read(request, &bytes_read)) { |
- OnReadCompleted(request, bytes_read); |
- } else if (!request->status().is_io_pending()) { |
- DCHECK(!InfoForRequest(request)->is_paused()); |
- // If the error is not an IO pending, then we're done reading. |
- OnResponseCompleted(request); |
- } |
-} |
- |
-bool ResourceDispatcherHost::Read(net::URLRequest* request, int* bytes_read) { |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- DCHECK(!info->is_paused()); |
- |
- net::IOBuffer* buf; |
- int buf_size; |
- if (!info->resource_handler()->OnWillRead(info->request_id(), |
- &buf, &buf_size, -1)) { |
- return false; |
- } |
- |
- DCHECK(buf); |
- DCHECK(buf_size > 0); |
- |
- info->set_has_started_reading(true); |
- return request->Read(buf, buf_size, bytes_read); |
-} |
- |
-void ResourceDispatcherHost::OnReadCompleted(net::URLRequest* request, |
- int bytes_read) { |
- DCHECK(request); |
- VLOG(1) << "OnReadCompleted: " << request->url().spec(); |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- |
- // OnReadCompleted can be called without Read (e.g., for chrome:// URLs). |
- // Make sure we know that a read has begun. |
- info->set_has_started_reading(true); |
- |
- if (PauseRequestIfNeeded(info)) { |
- info->set_paused_read_bytes(bytes_read); |
- VLOG(1) << "OnReadCompleted pausing: " << request->url().spec(); |
- return; |
- } |
- |
- if (request->status().is_success() && CompleteRead(request, &bytes_read)) { |
- // The request can be paused if we realize that the renderer is not |
- // servicing messages fast enough. |
- if (info->pause_count() == 0 && |
- Read(request, &bytes_read) && |
- request->status().is_success()) { |
- if (bytes_read == 0) { |
- CompleteRead(request, &bytes_read); |
- } else { |
- // Force the next CompleteRead / Read pair to run as a separate task. |
- // This avoids a fast, large network request from monopolizing the IO |
- // thread and starving other IO operations from running. |
- info->set_paused_read_bytes(bytes_read); |
- info->set_is_paused(true); |
- GlobalRequestID id(info->child_id(), info->request_id()); |
- MessageLoop::current()->PostTask( |
- FROM_HERE, |
- method_runner_.NewRunnableMethod( |
- &ResourceDispatcherHost::ResumeRequest, id)); |
- return; |
- } |
- } |
- } |
- |
- if (PauseRequestIfNeeded(info)) { |
- info->set_paused_read_bytes(bytes_read); |
- VLOG(1) << "OnReadCompleted (CompleteRead) pausing: " |
- << request->url().spec(); |
- return; |
- } |
- |
- // If the status is not IO pending then we've either finished (success) or we |
- // had an error. Either way, we're done! |
- if (!request->status().is_io_pending()) |
- OnResponseCompleted(request); |
-} |
- |
-bool ResourceDispatcherHost::CompleteRead(net::URLRequest* request, |
- int* bytes_read) { |
- if (!request || !request->status().is_success()) { |
- NOTREACHED(); |
- return false; |
- } |
- |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- if (!info->resource_handler()->OnReadCompleted(info->request_id(), |
- bytes_read)) { |
- CancelRequestInternal(request, false); |
- return false; |
- } |
- |
- return *bytes_read != 0; |
-} |
- |
-void ResourceDispatcherHost::OnResponseCompleted(net::URLRequest* request) { |
- VLOG(1) << "OnResponseCompleted: " << request->url().spec(); |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- |
- // If the load for a main frame has failed, track it in a histogram, |
- // since it will probably cause the user to see an error page. |
- if (!request->status().is_success() && |
- info->resource_type() == ResourceType::MAIN_FRAME && |
- request->status().os_error() != net::ERR_ABORTED) { |
- UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.ErrorCodesForMainFrame", |
- -request->status().os_error(), |
- GetAllNetErrorCodes()); |
- } |
- |
- std::string security_info; |
- const net::SSLInfo& ssl_info = request->ssl_info(); |
- if (ssl_info.cert != NULL) { |
- int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert, |
- info->child_id()); |
- security_info = SSLManager::SerializeSecurityInfo( |
- cert_id, ssl_info.cert_status, ssl_info.security_bits, |
- ssl_info.connection_status); |
- } |
- |
- if (info->resource_handler()->OnResponseCompleted(info->request_id(), |
- request->status(), |
- security_info)) { |
- NotifyResponseCompleted(request, info->child_id()); |
- |
- // The request is complete so we can remove it. |
- RemovePendingRequest(info->child_id(), info->request_id()); |
- } |
- // If the handler's OnResponseCompleted returns false, we are deferring the |
- // call until later. We will notify the world and clean up when we resume. |
-} |
- |
-// static |
-ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest( |
- net::URLRequest* request) { |
- // Avoid writing this function twice by casting the cosnt version. |
- const net::URLRequest* const_request = request; |
- return const_cast<ResourceDispatcherHostRequestInfo*>( |
- InfoForRequest(const_request)); |
-} |
- |
-// static |
-const ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest( |
- const net::URLRequest* request) { |
- const ResourceDispatcherHostRequestInfo* info = |
- static_cast<const ResourceDispatcherHostRequestInfo*>( |
- request->GetUserData(NULL)); |
- DLOG_IF(WARNING, !info) << "Request doesn't seem to have our data"; |
- return info; |
-} |
- |
-// static |
-bool ResourceDispatcherHost::RenderViewForRequest( |
- const net::URLRequest* request, |
- int* render_process_host_id, |
- int* render_view_host_id) { |
- const ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- if (!info) { |
- *render_process_host_id = -1; |
- *render_view_host_id = -1; |
- return false; |
- } |
- |
- // If the request is from the worker process, find a tab that owns the worker. |
- if (info->process_type() == ChildProcessInfo::WORKER_PROCESS) { |
- // Need to display some related UI for this network request - pick an |
- // arbitrary parent to do so. |
- if (!WorkerService::GetInstance()->GetRendererForWorker( |
- info->child_id(), render_process_host_id, render_view_host_id)) { |
- *render_process_host_id = -1; |
- *render_view_host_id = -1; |
- return false; |
- } |
- } else { |
- *render_process_host_id = info->child_id(); |
- *render_view_host_id = info->route_id(); |
- } |
- return true; |
-} |
- |
-void ResourceDispatcherHost::AddObserver(Observer* obs) { |
- observer_list_.AddObserver(obs); |
-} |
- |
-void ResourceDispatcherHost::RemoveObserver(Observer* obs) { |
- observer_list_.RemoveObserver(obs); |
-} |
- |
-net::URLRequest* ResourceDispatcherHost::GetURLRequest( |
- const GlobalRequestID& request_id) const { |
- // This should be running in the IO loop. |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- |
- PendingRequestList::const_iterator i = pending_requests_.find(request_id); |
- if (i == pending_requests_.end()) |
- return NULL; |
- |
- return i->second; |
-} |
- |
-static int GetCertID(net::URLRequest* request, int child_id) { |
- if (request->ssl_info().cert) { |
- return CertStore::GetInstance()->StoreCert(request->ssl_info().cert, |
- child_id); |
- } |
- return 0; |
-} |
- |
-void ResourceDispatcherHost::NotifyResponseStarted(net::URLRequest* request, |
- int child_id) { |
- // Notify the observers on the IO thread. |
- FOR_EACH_OBSERVER(Observer, observer_list_, OnRequestStarted(this, request)); |
- |
- int render_process_id, render_view_id; |
- if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) |
- return; |
- |
- // Notify the observers on the UI thread. |
- ResourceRequestDetails* detail = new ResourceRequestDetails( |
- request, GetCertID(request, child_id)); |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableFunction( |
- &ResourceDispatcherHost::NotifyOnUI<ResourceRequestDetails>, |
- NotificationType::RESOURCE_RESPONSE_STARTED, |
- render_process_id, render_view_id, detail)); |
-} |
- |
-void ResourceDispatcherHost::NotifyResponseCompleted(net::URLRequest* request, |
- int child_id) { |
- // Notify the observers on the IO thread. |
- FOR_EACH_OBSERVER(Observer, observer_list_, |
- OnResponseCompleted(this, request)); |
-} |
- |
-void ResourceDispatcherHost::NotifyReceivedRedirect(net::URLRequest* request, |
- int child_id, |
- const GURL& new_url) { |
- // Notify the observers on the IO thread. |
- FOR_EACH_OBSERVER(Observer, observer_list_, |
- OnReceivedRedirect(this, request, new_url)); |
- |
- int render_process_id, render_view_id; |
- if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) |
- return; |
- |
- // Notify the observers on the UI thread. |
- ResourceRedirectDetails* detail = new ResourceRedirectDetails( |
- request, GetCertID(request, child_id), new_url); |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- NewRunnableFunction( |
- &ResourceDispatcherHost::NotifyOnUI<ResourceRedirectDetails>, |
- NotificationType::RESOURCE_RECEIVED_REDIRECT, |
- render_process_id, render_view_id, detail)); |
-} |
- |
-template <class T> |
-void ResourceDispatcherHost::NotifyOnUI(NotificationType type, |
- int render_process_id, |
- int render_view_id, |
- T* detail) { |
- RenderViewHost* rvh = |
- RenderViewHost::FromID(render_process_id, render_view_id); |
- if (rvh) { |
- RenderViewHostDelegate* rvhd = rvh->delegate(); |
- NotificationService::current()->Notify( |
- type, Source<RenderViewHostDelegate>(rvhd), Details<T>(detail)); |
- } |
- delete detail; |
-} |
- |
-namespace { |
- |
-// This function attempts to return the "more interesting" load state of |a| |
-// and |b|. We don't have temporal information about these load states |
-// (meaning we don't know when we transitioned into these states), so we just |
-// rank them according to how "interesting" the states are. |
-// |
-// We take advantage of the fact that the load states are an enumeration listed |
-// in the order in which they occur during the lifetime of a request, so we can |
-// regard states with larger numeric values as being further along toward |
-// completion. We regard those states as more interesting to report since they |
-// represent progress. |
-// |
-// For example, by this measure "tranferring data" is a more interesting state |
-// than "resolving host" because when we are transferring data we are actually |
-// doing something that corresponds to changes that the user might observe, |
-// whereas waiting for a host name to resolve implies being stuck. |
-// |
-net::LoadState MoreInterestingLoadState(net::LoadState a, net::LoadState b) { |
- return (a < b) ? b : a; |
-} |
- |
-// Carries information about a load state change. |
-struct LoadInfo { |
- GURL url; |
- net::LoadState load_state; |
- uint64 upload_position; |
- uint64 upload_size; |
-}; |
- |
-// Map from ProcessID+ViewID pair to LoadState |
-typedef std::map<std::pair<int, int>, LoadInfo> LoadInfoMap; |
- |
-// Used to marshall calls to LoadStateChanged from the IO to UI threads. We do |
-// them all as a single task to avoid spamming the UI thread. |
-class LoadInfoUpdateTask : public Task { |
- public: |
- virtual void Run() { |
- LoadInfoMap::const_iterator i; |
- for (i = info_map.begin(); i != info_map.end(); ++i) { |
- RenderViewHost* view = |
- RenderViewHost::FromID(i->first.first, i->first.second); |
- if (view) // The view could be gone at this point. |
- view->LoadStateChanged(i->second.url, i->second.load_state, |
- i->second.upload_position, |
- i->second.upload_size); |
- } |
- } |
- LoadInfoMap info_map; |
-}; |
- |
-} // namespace |
- |
-void ResourceDispatcherHost::UpdateLoadStates() { |
- // Populate this map with load state changes, and then send them on to the UI |
- // thread where they can be passed along to the respective RVHs. |
- LoadInfoMap info_map; |
- |
- PendingRequestList::const_iterator i; |
- |
- // Determine the largest upload size of all requests |
- // in each View (good chance it's zero). |
- std::map<std::pair<int, int>, uint64> largest_upload_size; |
- for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) { |
- net::URLRequest* request = i->second; |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- uint64 upload_size = info->upload_size(); |
- if (request->GetLoadState() != net::LOAD_STATE_SENDING_REQUEST) |
- upload_size = 0; |
- std::pair<int, int> key(info->child_id(), info->route_id()); |
- if (upload_size && largest_upload_size[key] < upload_size) |
- largest_upload_size[key] = upload_size; |
- } |
- |
- for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) { |
- net::URLRequest* request = i->second; |
- net::LoadState load_state = request->GetLoadState(); |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- |
- // We also poll for upload progress on this timer and send upload |
- // progress ipc messages to the plugin process. |
- bool update_upload_progress = MaybeUpdateUploadProgress(info, request); |
- |
- if (info->last_load_state() != load_state || update_upload_progress) { |
- std::pair<int, int> key(info->child_id(), info->route_id()); |
- |
- // If a request is uploading data, ignore all other requests so that the |
- // upload progress takes priority for being shown in the status bar. |
- if (largest_upload_size.find(key) != largest_upload_size.end() && |
- info->upload_size() < largest_upload_size[key]) |
- continue; |
- |
- info->set_last_load_state(load_state); |
- |
- net::LoadState to_insert; |
- LoadInfoMap::iterator existing = info_map.find(key); |
- if (existing == info_map.end()) { |
- to_insert = load_state; |
- } else { |
- to_insert = |
- MoreInterestingLoadState(existing->second.load_state, load_state); |
- if (to_insert == existing->second.load_state) |
- continue; |
- } |
- LoadInfo& load_info = info_map[key]; |
- load_info.url = request->url(); |
- load_info.load_state = to_insert; |
- load_info.upload_size = info->upload_size(); |
- load_info.upload_position = request->GetUploadProgress(); |
- } |
- } |
- |
- if (info_map.empty()) |
- return; |
- |
- LoadInfoUpdateTask* task = new LoadInfoUpdateTask; |
- task->info_map.swap(info_map); |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task); |
-} |
- |
-// Calls the ResourceHandler to send upload progress messages to the renderer. |
-// Returns true iff an upload progress message should be sent to the UI thread. |
-bool ResourceDispatcherHost::MaybeUpdateUploadProgress( |
- ResourceDispatcherHostRequestInfo *info, |
- net::URLRequest *request) { |
- |
- if (!info->upload_size() || info->waiting_for_upload_progress_ack()) |
- return false; |
- |
- uint64 size = info->upload_size(); |
- uint64 position = request->GetUploadProgress(); |
- if (position == info->last_upload_position()) |
- return false; // no progress made since last time |
- |
- const uint64 kHalfPercentIncrements = 200; |
- const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000); |
- |
- uint64 amt_since_last = position - info->last_upload_position(); |
- TimeDelta time_since_last = TimeTicks::Now() - info->last_upload_ticks(); |
- |
- bool is_finished = (size == position); |
- bool enough_new_progress = (amt_since_last > (size / kHalfPercentIncrements)); |
- bool too_much_time_passed = time_since_last > kOneSecond; |
- |
- if (is_finished || enough_new_progress || too_much_time_passed) { |
- if (request->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) { |
- info->resource_handler()->OnUploadProgress(info->request_id(), |
- position, size); |
- info->set_waiting_for_upload_progress_ack(true); |
- } |
- info->set_last_upload_ticks(TimeTicks::Now()); |
- info->set_last_upload_position(position); |
- return true; |
- } |
- return false; |
-} |
- |
-void ResourceDispatcherHost::BlockRequestsForRoute(int child_id, int route_id) { |
- std::pair<int, int> key(child_id, route_id); |
- DCHECK(blocked_requests_map_.find(key) == blocked_requests_map_.end()) << |
- "BlockRequestsForRoute called multiple time for the same RVH"; |
- blocked_requests_map_[key] = new BlockedRequestsList(); |
-} |
- |
-void ResourceDispatcherHost::ResumeBlockedRequestsForRoute(int child_id, |
- int route_id) { |
- ProcessBlockedRequestsForRoute(child_id, route_id, false); |
-} |
- |
-void ResourceDispatcherHost::CancelBlockedRequestsForRoute(int child_id, |
- int route_id) { |
- ProcessBlockedRequestsForRoute(child_id, route_id, true); |
-} |
- |
-void ResourceDispatcherHost::ProcessBlockedRequestsForRoute( |
- int child_id, |
- int route_id, |
- bool cancel_requests) { |
- BlockedRequestMap::iterator iter = blocked_requests_map_.find( |
- std::pair<int, int>(child_id, route_id)); |
- if (iter == blocked_requests_map_.end()) { |
- // It's possible to reach here if the renderer crashed while an interstitial |
- // page was showing. |
- return; |
- } |
- |
- BlockedRequestsList* requests = iter->second; |
- |
- // Removing the vector from the map unblocks any subsequent requests. |
- blocked_requests_map_.erase(iter); |
- |
- for (BlockedRequestsList::iterator req_iter = requests->begin(); |
- req_iter != requests->end(); ++req_iter) { |
- // Remove the memory credit that we added when pushing the request onto |
- // the blocked list. |
- net::URLRequest* request = *req_iter; |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(), |
- info->child_id()); |
- if (cancel_requests) |
- delete request; |
- else |
- BeginRequestInternal(request); |
- } |
- |
- delete requests; |
-} |
- |
-bool ResourceDispatcherHost::IsValidRequest(net::URLRequest* request) { |
- if (!request) |
- return false; |
- ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); |
- return pending_requests_.find( |
- GlobalRequestID(info->child_id(), info->request_id())) != |
- pending_requests_.end(); |
-} |
- |
-// static |
-void ResourceDispatcherHost::ApplyExtensionLocalizationFilter( |
- const GURL& url, |
- const ResourceType::Type& resource_type, |
- ResourceDispatcherHostRequestInfo* request_info) { |
- // Apply filter to chrome extension CSS files. |
- if (url.SchemeIs(chrome::kExtensionScheme) && |
- resource_type == ResourceType::STYLESHEET) |
- request_info->set_replace_extension_localization_templates(); |
-} |
- |
-// static |
-net::RequestPriority ResourceDispatcherHost::DetermineRequestPriority( |
- ResourceType::Type type) { |
- // Determine request priority based on how critical this resource typically |
- // is to user-perceived page load performance. Important considerations are: |
- // * Can this resource block the download of other resources. |
- // * Can this resource block the rendering of the page. |
- // * How useful is the page to the user if this resource is not loaded yet. |
- switch (type) { |
- // Main frames are the highest priority because they can block nearly every |
- // type of other resource and there is no useful display without them. |
- // Sub frames are a close second, however it is a common pattern to wrap |
- // ads in an iframe or even in multiple nested iframes. It is worth |
- // investigating if there is a better priority for them. |
- case ResourceType::MAIN_FRAME: |
- case ResourceType::SUB_FRAME: |
- return net::HIGHEST; |
- |
- // Stylesheets and scripts can block rendering and loading of other |
- // resources. Fonts can block text from rendering. |
- case ResourceType::STYLESHEET: |
- case ResourceType::SCRIPT: |
- case ResourceType::FONT_RESOURCE: |
- return net::MEDIUM; |
- |
- // Sub resources, objects and media are lower priority than potentially |
- // blocking stylesheets, scripts and fonts, but are higher priority than |
- // images because if they exist they are probably more central to the page |
- // focus than images on the page. |
- case ResourceType::SUB_RESOURCE: |
- case ResourceType::OBJECT: |
- case ResourceType::MEDIA: |
- case ResourceType::WORKER: |
- case ResourceType::SHARED_WORKER: |
- return net::LOW; |
- |
- // Images are the "lowest" priority because they typically do not block |
- // downloads or rendering and most pages have some useful content without |
- // them. |
- case ResourceType::IMAGE: |
- return net::LOWEST; |
- |
- // Prefetches are at a lower priority than even LOWEST, since they |
- // are not even required for rendering of the current page. |
- case ResourceType::PREFETCH: |
- return net::IDLE; |
- |
- default: |
- // When new resource types are added, their priority must be considered. |
- NOTREACHED(); |
- return net::LOW; |
- } |
-} |
- |
-// static |
-bool ResourceDispatcherHost::is_prefetch_enabled() { |
- return is_prefetch_enabled_; |
-} |
- |
-// static |
-void ResourceDispatcherHost::set_is_prefetch_enabled(bool value) { |
- is_prefetch_enabled_ = value; |
-} |
- |
-// static |
-bool ResourceDispatcherHost::is_prefetch_enabled_ = false; |