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

Unified Diff: content/browser/renderer_host/resource_dispatcher_host_impl.cc

Issue 11414299: Add content/browser/loader/ for resource loading related classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years 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: content/browser/renderer_host/resource_dispatcher_host_impl.cc
===================================================================
--- content/browser/renderer_host/resource_dispatcher_host_impl.cc (revision 171168)
+++ content/browser/renderer_host/resource_dispatcher_host_impl.cc (working copy)
@@ -1,1729 +0,0 @@
-// Copyright (c) 2012 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 "content/browser/renderer_host/resource_dispatcher_host_impl.h"
-
-#include <set>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/debug/alias.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "base/shared_memory.h"
-#include "base/stl_util.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/cert_store_impl.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/cross_site_request_manager.h"
-#include "content/browser/download/download_resource_handler.h"
-#include "content/browser/download/save_file_manager.h"
-#include "content/browser/download/save_file_resource_handler.h"
-#include "content/browser/fileapi/chrome_blob_storage_context.h"
-#include "content/browser/plugin_service_impl.h"
-#include "content/browser/renderer_host/async_resource_handler.h"
-#include "content/browser/renderer_host/buffered_resource_handler.h"
-#include "content/browser/renderer_host/cross_site_resource_handler.h"
-#include "content/browser/renderer_host/redirect_to_file_resource_handler.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/renderer_host/resource_message_filter.h"
-#include "content/browser/renderer_host/resource_request_info_impl.h"
-#include "content/browser/renderer_host/sync_resource_handler.h"
-#include "content/browser/renderer_host/throttling_resource_handler.h"
-#include "content/browser/renderer_host/transfer_navigation_resource_throttle.h"
-#include "content/browser/resource_context_impl.h"
-#include "content/browser/worker_host/worker_service_impl.h"
-#include "content/common/resource_messages.h"
-#include "content/common/ssl_status_serialization.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/download_manager.h"
-#include "content/public/browser/global_request_id.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/resource_dispatcher_host_delegate.h"
-#include "content/public/browser/resource_request_details.h"
-#include "content/public/browser/resource_throttle.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/process_type.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/auth.h"
-#include "net/base/cert_status_flags.h"
-#include "net/base/load_flags.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "net/base/request_priority.h"
-#include "net/base/ssl_cert_request_info.h"
-#include "net/base/upload_data.h"
-#include "net/cookies/cookie_monster.h"
-#include "net/http/http_cache.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_response_info.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_job_factory.h"
-#include "webkit/appcache/appcache_interceptor.h"
-#include "webkit/appcache/appcache_interfaces.h"
-#include "webkit/blob/blob_storage_controller.h"
-#include "webkit/blob/shareable_file_reference.h"
-#include "webkit/glue/resource_request_body.h"
-#include "webkit/glue/webkit_glue.h"
-
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-using webkit_blob::ShareableFileReference;
-using webkit_glue::ResourceRequestBody;
-
-// ----------------------------------------------------------------------------
-
-namespace content {
-
-namespace {
-
-static ResourceDispatcherHostImpl* g_resource_dispatcher_host;
-
-// The interval for calls to ResourceDispatcherHostImpl::UpdateLoadStates
-const int kUpdateLoadStatesIntervalMsec = 100;
-
-// 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;
-
-// The number of milliseconds after noting a user gesture that we will
-// tag newly-created URLRequest objects with the
-// net::LOAD_MAYBE_USER_GESTURE load flag. This is a fairly arbitrary
-// guess at how long to expect direct impact from a user gesture, but
-// this should be OK as the load flag is a best-effort thing only,
-// rather than being intended as fully accurate.
-const int kUserGestureWindowMs = 3500;
-
-// All possible error codes from the network module. Note that the error codes
-// are all positive (since histograms expect positive sample values).
-const int kAllNetErrorCodes[] = {
-#define NET_ERROR(label, value) -(value),
-#include "net/base/net_error_list.h"
-#undef NET_ERROR
-};
-
-// Aborts a request before an URLRequest has actually been created.
-void AbortRequestBeforeItStarts(ResourceMessageFilter* filter,
- IPC::Message* sync_result,
- int route_id,
- int request_id) {
- if (sync_result) {
- SyncLoadResult result;
- result.error_code = net::ERR_ABORTED;
- ResourceHostMsg_SyncLoad::WriteReplyParams(sync_result, result);
- filter->Send(sync_result);
- } else {
- // Tell the renderer that this request was disallowed.
- filter->Send(new ResourceMsg_RequestComplete(
- route_id,
- request_id,
- net::ERR_ABORTED,
- false,
- std::string(), // No security info needed, connection not established.
- base::TimeTicks()));
- }
-}
-
-GURL MaybeStripReferrer(const GURL& possible_referrer) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoReferrers))
- return GURL();
- return possible_referrer;
-}
-
-// Consults the RendererSecurity policy to determine whether the
-// ResourceDispatcherHostImpl 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(ProcessType process_type,
- int child_id,
- const ResourceHostMsg_Request& request_data) {
- if (process_type == PROCESS_TYPE_PLUGIN)
- return true;
-
- ChildProcessSecurityPolicyImpl* policy =
- ChildProcessSecurityPolicyImpl::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.request_body) {
- const std::vector<ResourceRequestBody::Element>* uploads =
- request_data.request_body->elements();
- std::vector<ResourceRequestBody::Element>::const_iterator iter;
- for (iter = uploads->begin(); iter != uploads->end(); ++iter) {
- if (iter->type() == ResourceRequestBody::Element::TYPE_FILE &&
- !policy->CanReadFile(child_id, iter->path())) {
- NOTREACHED() << "Denied unauthorized upload of "
- << iter->path().value();
- return false;
- }
- }
- }
-
- return true;
-}
-
-void RemoveDownloadFileFromChildSecurityPolicy(int child_id,
- const FilePath& path) {
- ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
- child_id, path);
-}
-
-#if defined(OS_WIN)
-#pragma warning(disable: 4748)
-#pragma optimize("", off)
-#endif
-
-#if defined(OS_WIN)
-#pragma optimize("", on)
-#pragma warning(default: 4748)
-#endif
-
-net::RequestPriority 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:
- case ResourceType::XHR:
- 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:
- // Favicons aren't required for rendering the current page, but
- // are user visible.
- case ResourceType::FAVICON:
- 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;
- }
-}
-
-void OnSwapOutACKHelper(int render_process_id,
- int render_view_id,
- bool timed_out) {
- RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(render_process_id,
- render_view_id);
- if (rvh)
- rvh->OnSwapOutACK(timed_out);
-}
-
-net::Error CallbackAndReturn(
- const DownloadResourceHandler::OnStartedCallback& started_cb,
- net::Error net_error) {
- if (started_cb.is_null())
- return net_error;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(started_cb, static_cast<DownloadItem*>(NULL), net_error));
-
- return net_error;
-}
-
-int BuildLoadFlagsForRequest(const ResourceHostMsg_Request& request_data,
- int child_id, bool is_sync_load) {
- 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 | net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
- } else if (request_data.resource_type == ResourceType::FAVICON) {
- load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN;
- }
-
- if (is_sync_load)
- load_flags |= net::LOAD_IGNORE_LIMITS;
-
- ChildProcessSecurityPolicyImpl* policy =
- ChildProcessSecurityPolicyImpl::GetInstance();
- if (!policy->CanSendCookiesForOrigin(child_id, request_data.url)) {
- load_flags |= (net::LOAD_DO_NOT_SEND_COOKIES |
- net::LOAD_DO_NOT_SEND_AUTH_DATA |
- net::LOAD_DO_NOT_SAVE_COOKIES);
- }
-
- // Raw headers are sensitive, as they include Cookie/Set-Cookie, so only
- // allow requesting them if requester has ReadRawCookies permission.
- if ((load_flags & net::LOAD_REPORT_RAW_HEADERS)
- && !policy->CanReadRawCookies(child_id)) {
- VLOG(1) << "Denied unauthorized request for raw headers";
- load_flags &= ~net::LOAD_REPORT_RAW_HEADERS;
- }
-
- return load_flags;
-}
-
-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;
-}
-
-template <class T>
-void NotifyOnUI(int type, int render_process_id, int render_view_id,
- scoped_ptr<T> detail) {
- RenderViewHostImpl* host =
- RenderViewHostImpl::FromID(render_process_id, render_view_id);
- if (host) {
- RenderViewHostDelegate* delegate = host->GetDelegate();
- NotificationService::current()->Notify(
- type, Source<WebContents>(delegate->GetAsWebContents()),
- Details<T>(detail.get()));
- }
-}
-
-} // namespace
-
-// static
-ResourceDispatcherHost* ResourceDispatcherHost::Get() {
- return g_resource_dispatcher_host;
-}
-
-ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
- : save_file_manager_(new SaveFileManager()),
- request_id_(-1),
- is_shutdown_(false),
- max_outstanding_requests_cost_per_process_(
- kMaxOutstandingRequestsCostPerProcess),
- filter_(NULL),
- delegate_(NULL),
- allow_cross_origin_auth_prompt_(false) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!g_resource_dispatcher_host);
- g_resource_dispatcher_host = this;
-
- GetContentClient()->browser()->ResourceDispatcherHostCreated();
-
- ANNOTATE_BENIGN_RACE(
- &last_user_gesture_time_,
- "We don't care about the precise value, see http://crbug.com/92889");
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&appcache::AppCacheInterceptor::EnsureRegistered));
-
- update_load_states_timer_.reset(
- new base::RepeatingTimer<ResourceDispatcherHostImpl>());
-}
-
-ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() {
- DCHECK(g_resource_dispatcher_host);
- g_resource_dispatcher_host = NULL;
-}
-
-// static
-ResourceDispatcherHostImpl* ResourceDispatcherHostImpl::Get() {
- return g_resource_dispatcher_host;
-}
-
-void ResourceDispatcherHostImpl::SetDelegate(
- ResourceDispatcherHostDelegate* delegate) {
- delegate_ = delegate;
-}
-
-void ResourceDispatcherHostImpl::SetAllowCrossOriginAuthPrompt(bool value) {
- allow_cross_origin_auth_prompt_ = value;
-}
-
-void ResourceDispatcherHostImpl::AddResourceContext(ResourceContext* context) {
- active_resource_contexts_.insert(context);
-}
-
-void ResourceDispatcherHostImpl::RemoveResourceContext(
- ResourceContext* context) {
- CHECK(ContainsKey(active_resource_contexts_, context));
- active_resource_contexts_.erase(context);
-}
-
-void ResourceDispatcherHostImpl::CancelRequestsForContext(
- ResourceContext* context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(context);
-
- CHECK(ContainsKey(active_resource_contexts_, context));
-
- // Note that request cancellation has side effects. Therefore, we gather all
- // the requests to cancel first, and then we start cancelling. We assert at
- // the end that there are no more to cancel since the context is about to go
- // away.
- typedef std::vector<linked_ptr<ResourceLoader> > LoaderList;
- LoaderList loaders_to_cancel;
-
- for (LoaderMap::iterator i = pending_loaders_.begin();
- i != pending_loaders_.end();) {
- if (i->second->GetRequestInfo()->GetContext() == context) {
- loaders_to_cancel.push_back(i->second);
- pending_loaders_.erase(i++);
- } else {
- ++i;
- }
- }
-
- for (BlockedLoadersMap::iterator i = blocked_loaders_map_.begin();
- i != blocked_loaders_map_.end();) {
- BlockedLoadersList* loaders = i->second;
- if (loaders->empty()) {
- // This can happen if BlockRequestsForRoute() has been called for a route,
- // but we haven't blocked any matching requests yet.
- ++i;
- continue;
- }
- ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo();
- if (info->GetContext() == context) {
- blocked_loaders_map_.erase(i++);
- for (BlockedLoadersList::const_iterator it = loaders->begin();
- it != loaders->end(); ++it) {
- linked_ptr<ResourceLoader> loader = *it;
- info = loader->GetRequestInfo();
- // We make the assumption that all requests on the list have the same
- // ResourceContext.
- DCHECK_EQ(context, info->GetContext());
- IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
- info->GetChildID());
- loaders_to_cancel.push_back(loader);
- }
- delete loaders;
- } else {
- ++i;
- }
- }
-
-#ifndef NDEBUG
- for (LoaderList::iterator i = loaders_to_cancel.begin();
- i != loaders_to_cancel.end(); ++i) {
- // There is no strict requirement that this be the case, but currently
- // downloads and transferred requests are the only requests that aren't
- // cancelled when the associated processes go away. It may be OK for this
- // invariant to change in the future, but if this assertion fires without
- // the invariant changing, then it's indicative of a leak.
- DCHECK((*i)->GetRequestInfo()->is_download() || (*i)->is_transferring());
- }
-#endif
-
- loaders_to_cancel.clear();
-
- // Validate that no more requests for this context were added.
- for (LoaderMap::const_iterator i = pending_loaders_.begin();
- i != pending_loaders_.end(); ++i) {
- // http://crbug.com/90971
- CHECK_NE(i->second->GetRequestInfo()->GetContext(), context);
- }
-
- for (BlockedLoadersMap::const_iterator i = blocked_loaders_map_.begin();
- i != blocked_loaders_map_.end(); ++i) {
- BlockedLoadersList* loaders = i->second;
- if (!loaders->empty()) {
- ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo();
- // http://crbug.com/90971
- CHECK_NE(info->GetContext(), context);
- }
- }
-}
-
-net::Error ResourceDispatcherHostImpl::BeginDownload(
- scoped_ptr<net::URLRequest> request,
- bool is_content_initiated,
- ResourceContext* context,
- int child_id,
- int route_id,
- bool prefer_cache,
- scoped_ptr<DownloadSaveInfo> save_info,
- const DownloadStartedCallback& started_callback) {
- if (is_shutdown_)
- return CallbackAndReturn(started_callback, net::ERR_INSUFFICIENT_RESOURCES);
-
- const GURL& url = request->original_url();
-
- // http://crbug.com/90971
- char url_buf[128];
- base::strlcpy(url_buf, url.spec().c_str(), arraysize(url_buf));
- base::debug::Alias(url_buf);
- CHECK(ContainsKey(active_resource_contexts_, context));
-
- request->set_referrer(MaybeStripReferrer(GURL(request->referrer())).spec());
- int extra_load_flags = net::LOAD_IS_DOWNLOAD;
- if (prefer_cache) {
- // If there is upload data attached, only retrieve from cache because there
- // is no current mechanism to prompt the user for their consent for a
- // re-post. For GETs, try to retrieve data from the cache and skip
- // validating the entry if present.
- if (request->get_upload() != NULL)
- extra_load_flags |= net::LOAD_ONLY_FROM_CACHE;
- else
- extra_load_flags |= net::LOAD_PREFERRING_CACHE;
- } else {
- extra_load_flags |= net::LOAD_DISABLE_CACHE;
- }
- request->set_load_flags(request->load_flags() | extra_load_flags);
- // Check if the renderer is permitted to request the requested URL.
- if (!ChildProcessSecurityPolicyImpl::GetInstance()->
- CanRequestURL(child_id, url)) {
- VLOG(1) << "Denied unauthorized download request for "
- << url.possibly_invalid_spec();
- return CallbackAndReturn(started_callback, net::ERR_ACCESS_DENIED);
- }
-
- request_id_--;
-
- const net::URLRequestContext* request_context = context->GetRequestContext();
- if (!request_context->job_factory()->IsHandledURL(url)) {
- VLOG(1) << "Download request for unsupported protocol: "
- << url.possibly_invalid_spec();
- return CallbackAndReturn(started_callback, net::ERR_ACCESS_DENIED);
- }
-
- ResourceRequestInfoImpl* extra_info =
- CreateRequestInfo(child_id, route_id, true, context);
- extra_info->AssociateWithRequest(request.get()); // Request takes ownership.
-
- // From this point forward, the |DownloadResourceHandler| is responsible for
- // |started_callback|.
- scoped_ptr<ResourceHandler> handler(
- CreateResourceHandlerForDownload(request.get(), is_content_initiated,
- save_info.Pass(), started_callback));
-
- BeginRequestInternal(request.Pass(), handler.Pass());
-
- return net::OK;
-}
-
-void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest(
- net::URLRequest* request) {
- ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request);
- if (info) {
- ResourceLoader* loader = GetLoader(info->GetGlobalRequestID());
- if (loader)
- loader->ClearLoginDelegate();
- }
-}
-
-void ResourceDispatcherHostImpl::Shutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(&ResourceDispatcherHostImpl::OnShutdown,
- base::Unretained(this)));
-}
-
-scoped_ptr<ResourceHandler>
-ResourceDispatcherHostImpl::CreateResourceHandlerForDownload(
- net::URLRequest* request,
- bool is_content_initiated,
- scoped_ptr<DownloadSaveInfo> save_info,
- const DownloadResourceHandler::OnStartedCallback& started_cb) {
- scoped_ptr<ResourceHandler> handler(
- new DownloadResourceHandler(request, started_cb, save_info.Pass()));
- if (delegate_) {
- const ResourceRequestInfo* request_info(
- ResourceRequestInfo::ForRequest(request));
-
- ScopedVector<ResourceThrottle> throttles;
- delegate_->DownloadStarting(
- request, request_info->GetContext(), request_info->GetChildID(),
- request_info->GetRouteID(), request_info->GetRequestID(),
- is_content_initiated, &throttles);
- if (!throttles.empty()) {
- handler.reset(
- new ThrottlingResourceHandler(
- handler.Pass(), request_info->GetChildID(),
- request_info->GetRequestID(), throttles.Pass()));
- }
- }
- return handler.Pass();
-}
-
-void ResourceDispatcherHostImpl::ClearSSLClientAuthHandlerForRequest(
- net::URLRequest* request) {
- ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request);
- if (info) {
- ResourceLoader* loader = GetLoader(info->GetGlobalRequestID());
- if (loader)
- loader->ClearSSLClientAuthHandler();
- }
-}
-
-ResourceDispatcherHostLoginDelegate*
-ResourceDispatcherHostImpl::CreateLoginDelegate(
- ResourceLoader* loader,
- net::AuthChallengeInfo* auth_info) {
- if (!delegate_)
- return NULL;
-
- return delegate_->CreateLoginDelegate(auth_info, loader->request());
-}
-
-bool ResourceDispatcherHostImpl::AcceptAuthRequest(
- ResourceLoader* loader,
- net::AuthChallengeInfo* auth_info) {
- if (delegate_ && !delegate_->AcceptAuthRequest(loader->request(), auth_info))
- return false;
-
- // Prevent third-party content from prompting for login, unless it is
- // a proxy that is trying to authenticate. This is often the foundation
- // of a scam to extract credentials for another domain from the user.
- if (!auth_info->is_proxy) {
- HttpAuthResourceType resource_type =
- HttpAuthResourceTypeOf(loader->request());
- UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthResource",
- resource_type,
- HTTP_AUTH_RESOURCE_LAST);
-
- if (resource_type == HTTP_AUTH_RESOURCE_BLOCKED_CROSS)
- return false;
- }
-
- return true;
-}
-
-bool ResourceDispatcherHostImpl::AcceptSSLClientCertificateRequest(
- ResourceLoader* loader,
- net::SSLCertRequestInfo* cert_info) {
- if (delegate_ && !delegate_->AcceptSSLClientCertificateRequest(
- loader->request(), cert_info)) {
- return false;
- }
-
- return true;
-}
-
-bool ResourceDispatcherHostImpl::HandleExternalProtocol(ResourceLoader* loader,
- const GURL& url) {
- if (!delegate_)
- return false;
-
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
-
- if (!ResourceType::IsFrame(info->GetResourceType()))
- return false;
-
- const net::URLRequestJobFactory* job_factory =
- info->GetContext()->GetRequestContext()->job_factory();
- if (job_factory->IsHandledURL(url))
- return false;
-
- return delegate_->HandleExternalProtocol(url, info->GetChildID(),
- info->GetRouteID());
-}
-
-void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) {
- // Make sure we have the load state monitor running
- if (!update_load_states_timer_->IsRunning()) {
- update_load_states_timer_->Start(FROM_HERE,
- TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
- this, &ResourceDispatcherHostImpl::UpdateLoadStates);
- }
-}
-
-void ResourceDispatcherHostImpl::DidReceiveRedirect(ResourceLoader* loader,
- const GURL& new_url) {
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
-
- int render_process_id, render_view_id;
- if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id))
- return;
-
- // Notify the observers on the UI thread.
- scoped_ptr<ResourceRedirectDetails> detail(new ResourceRedirectDetails(
- loader->request(),
- GetCertID(loader->request(), info->GetChildID()),
- new_url));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &NotifyOnUI<ResourceRedirectDetails>,
- static_cast<int>(NOTIFICATION_RESOURCE_RECEIVED_REDIRECT),
- render_process_id, render_view_id, base::Passed(&detail)));
-}
-
-void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) {
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
-
- int render_process_id, render_view_id;
- if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id))
- return;
-
- // Notify the observers on the UI thread.
- scoped_ptr<ResourceRequestDetails> detail(new ResourceRequestDetails(
- loader->request(),
- GetCertID(loader->request(), info->GetChildID())));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &NotifyOnUI<ResourceRequestDetails>,
- static_cast<int>(NOTIFICATION_RESOURCE_RESPONSE_STARTED),
- render_process_id, render_view_id, base::Passed(&detail)));
-}
-
-void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
- ResourceRequestInfo* info = loader->GetRequestInfo();
-
- // Record final result of all resource loads.
- if (info->GetResourceType() == ResourceType::MAIN_FRAME) {
- // This enumeration has "3" appended to its name to distinguish it from
- // older versions.
- UMA_HISTOGRAM_CUSTOM_ENUMERATION(
- "Net.ErrorCodesForMainFrame3",
- -loader->request()->status().error(),
- base::CustomHistogram::ArrayToCustomRanges(
- kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
-
- if (loader->request()->url().SchemeIsSecure() &&
- loader->request()->url().host() == "www.google.com") {
- UMA_HISTOGRAM_CUSTOM_ENUMERATION(
- "Net.ErrorCodesForHTTPSGoogleMainFrame2",
- -loader->request()->status().error(),
- base::CustomHistogram::ArrayToCustomRanges(
- kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
- }
- } else {
- // This enumeration has "2" appended to distinguish it from older versions.
- UMA_HISTOGRAM_CUSTOM_ENUMERATION(
- "Net.ErrorCodesForSubresources2",
- -loader->request()->status().error(),
- base::CustomHistogram::ArrayToCustomRanges(
- kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
- }
-
- // Destroy the ResourceLoader.
- RemovePendingRequest(info->GetChildID(), info->GetRequestID());
-}
-
-// static
-bool ResourceDispatcherHostImpl::RenderViewForRequest(
- const net::URLRequest* request,
- int* render_process_id,
- int* render_view_id) {
- const ResourceRequestInfoImpl* info =
- ResourceRequestInfoImpl::ForRequest(request);
- if (!info) {
- *render_process_id = -1;
- *render_view_id = -1;
- return false;
- }
-
- return info->GetAssociatedRenderView(render_process_id, render_view_id);
-}
-
-void ResourceDispatcherHostImpl::OnShutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- is_shutdown_ = true;
- pending_loaders_.clear();
-
- // 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_.reset();
-
- // 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_loaders_map_, as it modifies it.
- std::set<ProcessRouteIDs> ids;
- for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin();
- iter != blocked_loaders_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 ResourceDispatcherHostImpl::OnMessageReceived(
- const IPC::Message& message,
- ResourceMessageFilter* filter,
- bool* message_was_ok) {
- filter_ = filter;
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(ResourceDispatcherHostImpl, message, *message_was_ok)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_RequestResource, OnRequestResource)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ResourceHostMsg_SyncLoad, OnSyncLoad)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_ReleaseDownloadedFile,
- OnReleaseDownloadedFile)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_DataReceived_ACK, OnDataReceivedACK)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_DataDownloaded_ACK, OnDataDownloadedACK)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_UploadProgress_ACK, OnUploadProgressACK)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_CancelRequest, OnCancelRequest)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_FollowRedirect, OnFollowRedirect)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SwapOut_ACK, OnSwapOutACK)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache,
- OnDidLoadResourceFromMemoryCache)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP_EX()
-
- if (message.type() == ViewHostMsg_DidLoadResourceFromMemoryCache::ID) {
- // We just needed to peek at this message. We still want it to reach its
- // normal destination.
- handled = false;
- }
-
- filter_ = NULL;
- return handled;
-}
-
-void ResourceDispatcherHostImpl::OnRequestResource(
- const IPC::Message& message,
- int request_id,
- const ResourceHostMsg_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 WebContentsImpl 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 ResourceDispatcherHostImpl::OnSyncLoad(
- int request_id,
- const ResourceHostMsg_Request& request_data,
- IPC::Message* sync_result) {
- BeginRequest(request_id, request_data, sync_result,
- sync_result->routing_id());
-}
-
-void ResourceDispatcherHostImpl::BeginRequest(
- int request_id,
- const ResourceHostMsg_Request& request_data,
- IPC::Message* sync_result, // only valid for sync
- int route_id) {
- ProcessType process_type = filter_->process_type();
- int child_id = filter_->child_id();
-
- // If we crash here, figure out what URL the renderer was requesting.
- // http://crbug.com/91398
- char url_buf[128];
- base::strlcpy(url_buf, request_data.url.spec().c_str(), arraysize(url_buf));
- base::debug::Alias(url_buf);
-
- // If the request that's coming in is being transferred from another process,
- // we want to reuse and resume the old loader rather than start a new one.
- linked_ptr<ResourceLoader> deferred_loader;
- {
- LoaderMap::iterator it = pending_loaders_.find(
- GlobalRequestID(request_data.transferred_request_child_id,
- request_data.transferred_request_request_id));
- if (it != pending_loaders_.end()) {
- if (it->second->is_transferring()) {
- deferred_loader = it->second;
- pending_loaders_.erase(it);
- } else {
- RecordAction(UserMetricsAction("BadMessageTerminate_RDH"));
- filter_->BadMessageReceived();
- return;
- }
- }
- }
-
- ResourceContext* resource_context = filter_->resource_context();
- // http://crbug.com/90971
- CHECK(ContainsKey(active_resource_contexts_, resource_context));
-
- if (is_shutdown_ ||
- !ShouldServiceRequest(process_type, child_id, request_data)) {
- AbortRequestBeforeItStarts(filter_, sync_result, route_id, request_id);
- return;
- }
-
- const Referrer referrer(MaybeStripReferrer(request_data.referrer),
- request_data.referrer_policy);
-
- // Allow the observer to block/handle the request.
- if (delegate_ && !delegate_->ShouldBeginRequest(child_id,
- route_id,
- request_data.method,
- request_data.url,
- request_data.resource_type,
- resource_context,
- referrer)) {
- AbortRequestBeforeItStarts(filter_, sync_result, route_id, request_id);
- return;
- }
-
- int load_flags =
- BuildLoadFlagsForRequest(request_data, child_id, sync_result != NULL);
-
- // Construct the request.
- scoped_ptr<net::URLRequest> new_request;
- net::URLRequest* request;
- if (deferred_loader.get()) {
- request = deferred_loader->request();
-
- // Give the ResourceLoader (or any of the ResourceHandlers held by it) a
- // chance to reset some state before we complete the transfer.
- deferred_loader->WillCompleteTransfer();
- } else {
- net::URLRequestContext* context =
- filter_->GetURLRequestContext(request_data.resource_type);
- new_request.reset(context->CreateRequest(request_data.url, NULL));
- request = new_request.get();
-
- request->set_method(request_data.method);
- request->set_first_party_for_cookies(request_data.first_party_for_cookies);
- request->set_referrer(referrer.url.spec());
- webkit_glue::ConfigureURLRequestForReferrerPolicy(request,
- referrer.policy);
- net::HttpRequestHeaders headers;
- headers.AddHeadersFromString(request_data.headers);
- request->SetExtraRequestHeaders(headers);
- }
-
- // TODO(darin): Do we really need all of these URLRequest setters in the
- // transferred navigation case?
-
- request->set_load_flags(load_flags);
-
- request->set_priority(DetermineRequestPriority(request_data.resource_type));
-
- // Resolve elements from request_body and prepare upload data.
- if (request_data.request_body) {
- request->set_upload(
- request_data.request_body->ResolveElementsAndCreateUploadData(
- filter_->blob_storage_context()->controller()));
- }
-
- bool allow_download = request_data.allow_download &&
- ResourceType::IsFrame(request_data.resource_type);
-
- // Make extra info and read footer (contains request ID).
- ResourceRequestInfoImpl* extra_info =
- new ResourceRequestInfoImpl(
- process_type,
- child_id,
- route_id,
- request_data.origin_pid,
- request_id,
- request_data.is_main_frame,
- request_data.frame_id,
- request_data.parent_is_main_frame,
- request_data.parent_frame_id,
- request_data.resource_type,
- request_data.transition_type,
- false, // is download
- allow_download,
- request_data.has_user_gesture,
- request_data.referrer_policy,
- resource_context);
- extra_info->AssociateWithRequest(request); // Request takes ownership.
-
- if (request->url().SchemeIs(chrome::kBlobScheme)) {
- // Hang on to a reference to ensure the blob is not released prior
- // to the job being started.
- extra_info->set_requested_blob_data(
- filter_->blob_storage_context()->controller()->
- GetBlobDataFromUrl(request->url()));
- }
-
- // Have the appcache associate its extra info with the request.
- appcache::AppCacheInterceptor::SetExtraRequestInfo(
- request, filter_->appcache_service(), child_id,
- request_data.appcache_host_id, request_data.resource_type);
-
- // Construct the IPC resource handler.
- scoped_ptr<ResourceHandler> handler;
- if (sync_result) {
- handler.reset(new SyncResourceHandler(
- filter_, request, sync_result, this));
- } else {
- handler.reset(new AsyncResourceHandler(
- filter_, route_id, request, this));
- }
-
- // The RedirectToFileResourceHandler depends on being next in the chain.
- if (request_data.download_to_file) {
- handler.reset(
- new RedirectToFileResourceHandler(handler.Pass(), child_id, this));
- }
-
- // 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 == PROCESS_TYPE_RENDERER &&
- 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.reset(new CrossSiteResourceHandler(handler.Pass(), child_id,
- route_id, request));
- }
-
- // Insert a buffered event handler before the actual one.
- handler.reset(
- new BufferedResourceHandler(handler.Pass(), this, request));
-
- ScopedVector<ResourceThrottle> throttles;
- if (delegate_) {
- bool is_continuation_of_transferred_request =
- (deferred_loader.get() != NULL);
-
- delegate_->RequestBeginning(request,
- resource_context,
- filter_->appcache_service(),
- request_data.resource_type,
- child_id,
- route_id,
- is_continuation_of_transferred_request,
- &throttles);
- }
-
- if (request_data.resource_type == ResourceType::MAIN_FRAME) {
- throttles.insert(
- throttles.begin(),
- new TransferNavigationResourceThrottle(request));
- }
-
- if (!throttles.empty()) {
- handler.reset(
- new ThrottlingResourceHandler(handler.Pass(), child_id, request_id,
- throttles.Pass()));
- }
-
- if (deferred_loader.get()) {
- pending_loaders_[extra_info->GetGlobalRequestID()] = deferred_loader;
- deferred_loader->CompleteTransfer(handler.Pass());
- } else {
- BeginRequestInternal(new_request.Pass(), handler.Pass());
- }
-}
-
-void ResourceDispatcherHostImpl::OnReleaseDownloadedFile(int request_id) {
- UnregisterDownloadedTempFile(filter_->child_id(), request_id);
-}
-
-void ResourceDispatcherHostImpl::OnDataReceivedACK(int request_id) {
- ResourceLoader* loader = GetLoader(filter_->child_id(), request_id);
- if (!loader)
- return;
-
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- if (info->async_handler())
- info->async_handler()->OnDataReceivedACK();
-}
-
-void ResourceDispatcherHostImpl::OnDataDownloadedACK(int request_id) {
- // TODO(michaeln): maybe throttle DataDownloaded messages
-}
-
-void ResourceDispatcherHostImpl::RegisterDownloadedTempFile(
- int child_id, int request_id, ShareableFileReference* reference) {
- registered_temp_files_[child_id][request_id] = reference;
- ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
- child_id, reference->path());
-
- // When the temp file is deleted, revoke permissions that the renderer has
- // to that file. This covers an edge case where the file is deleted and then
- // the same name is re-used for some other purpose, we don't want the old
- // renderer to still have access to it.
- //
- // We do this when the file is deleted because the renderer can take a blob
- // reference to the temp file that outlives the url loaded that it was
- // loaded with to keep the file (and permissions) alive.
- reference->AddFinalReleaseCallback(
- base::Bind(&RemoveDownloadFileFromChildSecurityPolicy,
- child_id));
-}
-
-void ResourceDispatcherHostImpl::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;
-
- map.erase(found);
-
- // Note that we don't remove the security bits here. This will be done
- // when all file refs are deleted (see RegisterDownloadedTempFile).
-}
-
-bool ResourceDispatcherHostImpl::Send(IPC::Message* message) {
- delete message;
- return false;
-}
-
-void ResourceDispatcherHostImpl::OnUploadProgressACK(int request_id) {
- ResourceLoader* loader = GetLoader(filter_->child_id(), request_id);
- if (loader)
- loader->OnUploadProgressACK();
-}
-
-void ResourceDispatcherHostImpl::OnCancelRequest(int request_id) {
- CancelRequest(filter_->child_id(), request_id, true);
-}
-
-void ResourceDispatcherHostImpl::OnFollowRedirect(
- int request_id,
- bool has_new_first_party_for_cookies,
- const GURL& new_first_party_for_cookies) {
- ResourceLoader* loader = GetLoader(filter_->child_id(), request_id);
- if (!loader) {
- DVLOG(1) << "OnFollowRedirect for invalid request";
- return;
- }
-
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- if (info->async_handler()) {
- info->async_handler()->OnFollowRedirect(
- has_new_first_party_for_cookies,
- new_first_party_for_cookies);
- }
-}
-
-ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
- int child_id,
- int route_id,
- bool download,
- ResourceContext* context) {
- return new ResourceRequestInfoImpl(
- PROCESS_TYPE_RENDERER,
- child_id,
- route_id,
- 0,
- request_id_,
- false, // is_main_frame
- -1, // frame_id
- false, // parent_is_main_frame
- -1, // parent_frame_id
- ResourceType::SUB_RESOURCE,
- PAGE_TRANSITION_LINK,
- download, // is_download
- download, // allow_download
- false, // has_user_gesture
- WebKit::WebReferrerPolicyDefault,
- context);
-}
-
-
-void ResourceDispatcherHostImpl::OnSwapOutACK(
- const ViewMsg_SwapOut_Params& params) {
- HandleSwapOutACK(params, false);
-}
-
-void ResourceDispatcherHostImpl::OnSimulateSwapOutACK(
- const ViewMsg_SwapOut_Params& params) {
- // Call the real implementation with true, which means that we timed out.
- HandleSwapOutACK(params, true);
-}
-
-void ResourceDispatcherHostImpl::HandleSwapOutACK(
- const ViewMsg_SwapOut_Params& params, bool timed_out) {
- // Closes for cross-site transitions are handled such that the cross-site
- // transition continues.
- ResourceLoader* loader = GetLoader(params.new_render_process_host_id,
- params.new_request_id);
- if (loader) {
- // The response we were meant to resume could have already been canceled.
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- if (info->cross_site_handler())
- info->cross_site_handler()->ResumeResponse();
- }
-
- // Update the RenderViewHost's internal state after the ACK.
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&OnSwapOutACKHelper,
- params.closing_process_id,
- params.closing_route_id,
- timed_out));
-}
-
-void ResourceDispatcherHostImpl::OnDidLoadResourceFromMemoryCache(
- const GURL& url,
- const std::string& security_info,
- const std::string& http_method,
- const std::string& mime_type,
- ResourceType::Type resource_type) {
- if (!url.is_valid() || !(url.SchemeIs("http") || url.SchemeIs("https")))
- return;
-
- filter_->GetURLRequestContext(resource_type)->http_transaction_factory()->
- GetCache()->OnExternalCacheHit(url, http_method);
-}
-
-// This function is only used for saving feature.
-void ResourceDispatcherHostImpl::BeginSaveFile(
- const GURL& url,
- const Referrer& referrer,
- int child_id,
- int route_id,
- ResourceContext* context) {
- if (is_shutdown_)
- return;
-
- // http://crbug.com/90971
- char url_buf[128];
- base::strlcpy(url_buf, url.spec().c_str(), arraysize(url_buf));
- base::debug::Alias(url_buf);
- CHECK(ContainsKey(active_resource_contexts_, context));
-
- scoped_ptr<ResourceHandler> handler(
- new SaveFileResourceHandler(child_id,
- route_id,
- url,
- save_file_manager_.get()));
- request_id_--;
-
- const net::URLRequestContext* request_context = context->GetRequestContext();
- bool known_proto =
- request_context->job_factory()->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;
- }
-
- scoped_ptr<net::URLRequest> request(
- request_context->CreateRequest(url, NULL));
- request->set_method("GET");
- request->set_referrer(MaybeStripReferrer(referrer.url).spec());
- webkit_glue::ConfigureURLRequestForReferrerPolicy(request.get(),
- referrer.policy);
- // 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);
-
- // Since we're just saving some resources we need, disallow downloading.
- ResourceRequestInfoImpl* extra_info =
- CreateRequestInfo(child_id, route_id, false, context);
- extra_info->AssociateWithRequest(request.get()); // Request takes ownership.
-
- BeginRequestInternal(request.Pass(), handler.Pass());
-}
-
-void ResourceDispatcherHostImpl::MarkAsTransferredNavigation(
- const GlobalRequestID& id) {
- GetLoader(id)->MarkAsTransferring();
-}
-
-int ResourceDispatcherHostImpl::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 ResourceDispatcherHostImpl::CancelRequestsForProcess(int child_id) {
- CancelRequestsForRoute(child_id, -1 /* cancel all */);
- registered_temp_files_.erase(child_id);
-}
-
-void ResourceDispatcherHostImpl::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 (LoaderMap::const_iterator i = pending_loaders_.begin();
- i != pending_loaders_.end(); ++i) {
- if (i->first.child_id != child_id)
- continue;
-
- ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
-
- GlobalRequestID id(child_id, i->first.request_id);
- DCHECK(id == i->first);
-
- // Don't cancel navigations that are transferring to another process,
- // since they belong to another process now.
- if (!info->is_download() && !IsTransferredNavigation(id) &&
- (route_id == -1 || route_id == info->GetRouteID())) {
- matching_requests.push_back(id);
- }
- }
-
- // Remove matches.
- for (size_t i = 0; i < matching_requests.size(); ++i) {
- LoaderMap::iterator iter = pending_loaders_.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_loaders_.end())
- RemovePendingLoader(iter);
- }
-
- // Now deal with blocked requests if any.
- if (route_id != -1) {
- if (blocked_loaders_map_.find(ProcessRouteIDs(child_id, route_id)) !=
- blocked_loaders_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_loaders_map_, as it modifies it.
- std::set<int> route_ids;
- for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin();
- iter != blocked_loaders_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 ResourceDispatcherHostImpl::RemovePendingRequest(int child_id,
- int request_id) {
- LoaderMap::iterator i = pending_loaders_.find(
- GlobalRequestID(child_id, request_id));
- if (i == pending_loaders_.end()) {
- NOTREACHED() << "Trying to remove a request that's not here";
- return;
- }
- RemovePendingLoader(i);
-}
-
-void ResourceDispatcherHostImpl::RemovePendingLoader(
- const LoaderMap::iterator& iter) {
- ResourceRequestInfoImpl* info = iter->second->GetRequestInfo();
-
- // Remove the memory credit that we added when pushing the request onto
- // the pending list.
- IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
- info->GetChildID());
-
- pending_loaders_.erase(iter);
-
- // If we have no more pending requests, then stop the load state monitor
- if (pending_loaders_.empty() && update_load_states_timer_.get())
- update_load_states_timer_->Stop();
-}
-
-void ResourceDispatcherHostImpl::CancelRequest(int child_id,
- int request_id,
- bool from_renderer) {
- if (from_renderer) {
- // When the old renderer dies, it sends a message to us to cancel its
- // requests.
- if (IsTransferredNavigation(GlobalRequestID(child_id, request_id)))
- return;
- }
-
- ResourceLoader* loader = GetLoader(child_id, request_id);
- if (!loader) {
- // 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.
- DVLOG(1) << "Canceling a request that wasn't found";
- return;
- }
-
- loader->CancelRequest(from_renderer);
-}
-
-int ResourceDispatcherHostImpl::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(child_id);
- else
- outstanding_requests_memory_cost_map_[child_id] = new_cost;
-
- return new_cost;
-}
-
-// static
-int ResourceDispatcherHostImpl::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();
-
- // Note that this expression will typically be dominated by:
- // |kAvgBytesPerOutstandingRequest|.
- return kAvgBytesPerOutstandingRequest + strings_cost;
-}
-
-void ResourceDispatcherHostImpl::BeginRequestInternal(
- scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceHandler> handler) {
- DCHECK(!request->is_pending());
- ResourceRequestInfoImpl* info =
- ResourceRequestInfoImpl::ForRequest(request.get());
-
- if ((TimeTicks::Now() - last_user_gesture_time_) <
- TimeDelta::FromMilliseconds(kUserGestureWindowMs)) {
- request->set_load_flags(
- request->load_flags() | net::LOAD_MAYBE_USER_GESTURE);
- }
-
- // Add the memory estimate that starting this request will consume.
- info->set_memory_cost(CalculateApproximateMemoryCost(request.get()));
- int memory_cost = IncrementOutstandingRequestsMemoryCost(info->memory_cost(),
- info->GetChildID());
-
- // 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 "CancelWithError()" as a way of setting the net::URLRequest's
- // status -- it has no effect beyond this, since the request hasn't started.
- request->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
-
- if (!handler->OnResponseCompleted(info->GetRequestID(), request->status(),
- std::string())) {
- // TODO(darin): The handler is not ready for us to kill the request. Oops!
- NOTREACHED();
- }
-
- IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
- info->GetChildID());
-
- // A ResourceHandler must not outlive its associated URLRequest.
- handler.reset();
- return;
- }
-
- linked_ptr<ResourceLoader> loader(
- new ResourceLoader(request.Pass(), handler.Pass(), this));
-
- ProcessRouteIDs pair_id(info->GetChildID(), info->GetRouteID());
- BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.find(pair_id);
- if (iter != blocked_loaders_map_.end()) {
- // The request should be blocked.
- iter->second->push_back(loader);
- return;
- }
-
- StartLoading(info, loader);
-}
-
-void ResourceDispatcherHostImpl::StartLoading(
- ResourceRequestInfoImpl* info,
- const linked_ptr<ResourceLoader>& loader) {
- pending_loaders_[info->GetGlobalRequestID()] = loader;
-
- loader->StartRequest();
-}
-
-void ResourceDispatcherHostImpl::OnUserGesture(WebContentsImpl* contents) {
- last_user_gesture_time_ = TimeTicks::Now();
-}
-
-net::URLRequest* ResourceDispatcherHostImpl::GetURLRequest(
- const GlobalRequestID& id) {
- ResourceLoader* loader = GetLoader(id);
- if (!loader)
- return NULL;
-
- return loader->request();
-}
-
-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.
-//
-const net::LoadStateWithParam& MoreInterestingLoadState(
- const net::LoadStateWithParam& a, const net::LoadStateWithParam& b) {
- return (a.state < b.state) ? b : a;
-}
-
-// Carries information about a load state change.
-struct LoadInfo {
- GURL url;
- net::LoadStateWithParam 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 marshal calls to LoadStateChanged from the IO to UI threads. We do
-// them all as a single callback to avoid spamming the UI thread.
-void LoadInfoUpdateCallback(const LoadInfoMap& info_map) {
- LoadInfoMap::const_iterator i;
- for (i = info_map.begin(); i != info_map.end(); ++i) {
- RenderViewHostImpl* view =
- RenderViewHostImpl::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);
- }
-}
-
-} // namespace
-
-void ResourceDispatcherHostImpl::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;
-
- LoaderMap::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_loaders_.begin(); i != pending_loaders_.end(); ++i) {
- net::URLRequest* request = i->second->request();
- ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
- uint64 upload_size = request->GetUploadProgress().size();
- if (request->GetLoadState().state != net::LOAD_STATE_SENDING_REQUEST)
- upload_size = 0;
- std::pair<int, int> key(info->GetChildID(), info->GetRouteID());
- if (upload_size && largest_upload_size[key] < upload_size)
- largest_upload_size[key] = upload_size;
- }
-
- for (i = pending_loaders_.begin(); i != pending_loaders_.end(); ++i) {
- net::URLRequest* request = i->second->request();
- ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
- net::LoadStateWithParam load_state = request->GetLoadState();
- net::UploadProgress progress = request->GetUploadProgress();
-
- // We also poll for upload progress on this timer and send upload
- // progress ipc messages to the plugin process.
- i->second->ReportUploadProgress();
-
- std::pair<int, int> key(info->GetChildID(), info->GetRouteID());
-
- // 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() &&
- progress.size() < largest_upload_size[key])
- continue;
-
- net::LoadStateWithParam to_insert = load_state;
- LoadInfoMap::iterator existing = info_map.find(key);
- if (existing != info_map.end()) {
- to_insert =
- MoreInterestingLoadState(existing->second.load_state, load_state);
- if (to_insert.state == existing->second.load_state.state)
- continue;
- }
- LoadInfo& load_info = info_map[key];
- load_info.url = request->url();
- load_info.load_state = to_insert;
- load_info.upload_size = progress.size();
- load_info.upload_position = progress.position();
- }
-
- if (info_map.empty())
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&LoadInfoUpdateCallback, info_map));
-}
-
-void ResourceDispatcherHostImpl::BlockRequestsForRoute(int child_id,
- int route_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ProcessRouteIDs key(child_id, route_id);
- DCHECK(blocked_loaders_map_.find(key) == blocked_loaders_map_.end()) <<
- "BlockRequestsForRoute called multiple time for the same RVH";
- blocked_loaders_map_[key] = new BlockedLoadersList();
-}
-
-void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute(int child_id,
- int route_id) {
- ProcessBlockedRequestsForRoute(child_id, route_id, false);
-}
-
-void ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute(int child_id,
- int route_id) {
- ProcessBlockedRequestsForRoute(child_id, route_id, true);
-}
-
-void ResourceDispatcherHostImpl::ProcessBlockedRequestsForRoute(
- int child_id,
- int route_id,
- bool cancel_requests) {
- BlockedLoadersMap::iterator iter = blocked_loaders_map_.find(
- std::pair<int, int>(child_id, route_id));
- if (iter == blocked_loaders_map_.end()) {
- // It's possible to reach here if the renderer crashed while an interstitial
- // page was showing.
- return;
- }
-
- BlockedLoadersList* loaders = iter->second;
-
- // Removing the vector from the map unblocks any subsequent requests.
- blocked_loaders_map_.erase(iter);
-
- for (BlockedLoadersList::iterator loaders_iter = loaders->begin();
- loaders_iter != loaders->end(); ++loaders_iter) {
- linked_ptr<ResourceLoader> loader = *loaders_iter;
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- if (cancel_requests) {
- IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
- info->GetChildID());
- } else {
- StartLoading(info, loader);
- }
- }
-
- delete loaders;
-}
-
-ResourceDispatcherHostImpl::HttpAuthResourceType
-ResourceDispatcherHostImpl::HttpAuthResourceTypeOf(net::URLRequest* request) {
- // Use the same critera as for cookies to determine the sub-resource type
- // that is requesting to be authenticated.
- if (!request->first_party_for_cookies().is_valid())
- return HTTP_AUTH_RESOURCE_TOP;
-
- if (net::RegistryControlledDomainService::SameDomainOrHost(
- request->first_party_for_cookies(), request->url()))
- return HTTP_AUTH_RESOURCE_SAME_DOMAIN;
-
- if (allow_cross_origin_auth_prompt())
- return HTTP_AUTH_RESOURCE_ALLOWED_CROSS;
-
- return HTTP_AUTH_RESOURCE_BLOCKED_CROSS;
-}
-
-bool ResourceDispatcherHostImpl::allow_cross_origin_auth_prompt() {
- return allow_cross_origin_auth_prompt_;
-}
-
-bool ResourceDispatcherHostImpl::IsTransferredNavigation(
- const GlobalRequestID& id) const {
- ResourceLoader* loader = GetLoader(id);
- return loader ? loader->is_transferring() : false;
-}
-
-ResourceLoader* ResourceDispatcherHostImpl::GetLoader(
- const GlobalRequestID& id) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- LoaderMap::const_iterator i = pending_loaders_.find(id);
- if (i == pending_loaders_.end())
- return NULL;
-
- return i->second.get();
-}
-
-ResourceLoader* ResourceDispatcherHostImpl::GetLoader(int child_id,
- int request_id) const {
- return GetLoader(GlobalRequestID(child_id, request_id));
-}
-
-} // namespace content

Powered by Google App Engine
This is Rietveld 408576698