Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(861)

Unified Diff: chrome/browser/renderer_host/resource_dispatcher_host.cc

Issue 6532073: Move core pieces of browser\renderer_host to src\content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;

Powered by Google App Engine
This is Rietveld 408576698