flutter_flutter/engine/core/fetch/ResourceFetcher.cpp
Eric Seidel e0fd75b5ab Make absolute and sort all Sky headers
This caused us to lose our gn check certification. :(

Turns out gn check was just ignoring all the header
paths it didn't understand and so gn check passing
for sky wasn't meaning much.  I tried to straighten
out some of the mess in this CL, but its going to take
several more rounds of massaging before gn check
passes again.  On the bright side (almost) all of
our headers are absolute now.  Turns out my script
(attached to the bug) didn't notice ../ includes
but I'll fix that in the next patch.

R=abarth@chromium.org
BUG=435361

Review URL: https://codereview.chromium.org/746023002
2014-11-20 17:42:05 -08:00

772 lines
28 KiB
C++

/*
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
This class provides all functionality needed for loading images, style sheets and html
pages from the web. It has a memory cache for these objects.
*/
#include "sky/engine/config.h"
#include "sky/engine/core/fetch/ResourceFetcher.h"
#include "gen/sky/core/FetchInitiatorTypeNames.h"
#include "gen/sky/platform/RuntimeEnabledFeatures.h"
#include "sky/engine/bindings/core/v8/ScriptController.h"
#include "sky/engine/core/dom/Document.h"
#include "sky/engine/core/fetch/FetchContext.h"
#include "sky/engine/core/fetch/FontResource.h"
#include "sky/engine/core/fetch/ImageResource.h"
#include "sky/engine/core/fetch/MemoryCache.h"
#include "sky/engine/core/fetch/RawResource.h"
#include "sky/engine/core/fetch/ResourceLoader.h"
#include "sky/engine/core/fetch/ResourceLoaderSet.h"
#include "sky/engine/core/frame/LocalDOMWindow.h"
#include "sky/engine/core/frame/LocalFrame.h"
#include "sky/engine/core/frame/Settings.h"
#include "sky/engine/core/frame/UseCounter.h"
#include "sky/engine/core/html/HTMLElement.h"
#include "sky/engine/core/html/imports/HTMLImportsController.h"
#include "sky/engine/core/inspector/ConsoleMessage.h"
#include "sky/engine/core/loader/FrameLoaderClient.h"
#include "sky/engine/core/loader/UniqueIdentifier.h"
#include "sky/engine/core/page/Page.h"
#include "sky/engine/platform/Logging.h"
#include "sky/engine/platform/SharedBuffer.h"
#include "sky/engine/platform/TraceEvent.h"
#include "sky/engine/platform/weborigin/SecurityPolicy.h"
#include "sky/engine/public/platform/Platform.h"
#include "sky/engine/public/platform/WebURL.h"
#include "sky/engine/public/platform/WebURLRequest.h"
#include "sky/engine/wtf/text/CString.h"
#include "sky/engine/wtf/text/WTFString.h"
using blink::WebURLRequest;
namespace blink {
static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset)
{
switch (type) {
case Resource::Image:
return new ImageResource(request);
case Resource::Font:
return new FontResource(request);
case Resource::MainResource:
case Resource::Raw:
case Resource::Media:
return new RawResource(request, type);
case Resource::LinkPrefetch:
return new Resource(request, Resource::LinkPrefetch);
case Resource::LinkSubresource:
return new Resource(request, Resource::LinkSubresource);
case Resource::ImportResource:
return new RawResource(request, type);
}
ASSERT_NOT_REACHED();
return 0;
}
static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request)
{
if (request.priority() != ResourceLoadPriorityUnresolved)
return request.priority();
switch (type) {
case Resource::MainResource:
return ResourceLoadPriorityVeryHigh;
case Resource::Raw:
case Resource::Font:
case Resource::ImportResource:
return ResourceLoadPriorityMedium;
case Resource::Image:
// We'll default images to VeryLow, and promote whatever is visible. This improves
// speed-index by ~5% on average, ~14% at the 99th percentile.
return ResourceLoadPriorityVeryLow;
case Resource::Media:
return ResourceLoadPriorityLow;
case Resource::LinkPrefetch:
return ResourceLoadPriorityVeryLow;
case Resource::LinkSubresource:
return ResourceLoadPriorityLow;
}
ASSERT_NOT_REACHED();
return ResourceLoadPriorityUnresolved;
}
static WebURLRequest::RequestContext requestContextFromType(const ResourceFetcher* fetcher, Resource::Type type)
{
switch (type) {
case Resource::MainResource:
// FIXME: Change this to a context frame type (once we introduce them): http://fetch.spec.whatwg.org/#concept-request-context-frame-type
return WebURLRequest::RequestContextHyperlink;
case Resource::Font:
return WebURLRequest::RequestContextFont;
case Resource::Image:
return WebURLRequest::RequestContextImage;
case Resource::Raw:
return WebURLRequest::RequestContextSubresource;
case Resource::ImportResource:
return WebURLRequest::RequestContextImport;
case Resource::LinkPrefetch:
return WebURLRequest::RequestContextPrefetch;
case Resource::LinkSubresource:
return WebURLRequest::RequestContextSubresource;
case Resource::Media: // TODO: Split this.
return WebURLRequest::RequestContextVideo;
}
ASSERT_NOT_REACHED();
return WebURLRequest::RequestContextSubresource;
}
ResourceFetcher::ResourceFetcher(Document* document)
: m_document(document)
, m_requestCount(0)
, m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
, m_autoLoadImages(true)
, m_imagesEnabled(true)
, m_allowStaleResources(false)
{
}
ResourceFetcher::~ResourceFetcher()
{
m_document = nullptr;
// Make sure no requests still point to this ResourceFetcher
ASSERT(!m_requestCount);
}
Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
{
KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
return m_documentResources.get(url).get();
}
LocalFrame* ResourceFetcher::frame() const
{
// FIXME(sky): This used to prefer DocumentLoader::frame
// over importsController->master()->frame(), but in our
// world we should always just have one frame.
if (!m_document)
return 0;
if (m_document->importsController())
return m_document->importsController()->master()->frame();
return m_document->frame();
}
FetchContext& ResourceFetcher::context() const
{
if (LocalFrame* frame = this->frame())
return frame->fetchContext();
return FetchContext::nullInstance();
}
ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
{
request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
ResourcePtr<Resource> resource = requestResource(Resource::Image, request);
return resource && resource->type() == Resource::Image ? toImageResource(resource) : 0;
}
ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
{
ASSERT(request.resourceRequest().frameType() == WebURLRequest::FrameTypeNone);
request.mutableResourceRequest().setRequestContext(WebURLRequest::RequestContextFont);
return toFontResource(requestResource(Resource::Font, request));
}
bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, FetchRequest::OriginRestriction originRestriction) const
{
// FIXME(sky): Remove
return true;
}
bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
{
if (!frame())
return false;
return true;
}
bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
{
if (FetchRequest::DeferredByClient == request.defer())
return false;
if (policy != Use)
return true;
return resource->stillNeedsLoad();
}
void ResourceFetcher::requestLoadStarted(Resource* resource, const FetchRequest& request, ResourceLoadStartType type)
{
if (type == ResourceLoadingFromCache)
notifyLoadedFromMemoryCache(resource);
if (request.resourceRequest().url().protocolIsData())
return;
m_validatedURLs.add(request.resourceRequest().url());
}
ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
{
ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
TRACE_EVENT0("blink", "ResourceFetcher::requestResource");
KURL url = request.resourceRequest().url();
WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, type=%s", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), ResourceTypeName(type));
// If only the fragment identifiers differ, it is the same resource.
url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
if (!url.isValid())
return 0;
if (!canRequest(type, url, request.options(), request.originRestriction()))
return 0;
if (LocalFrame* f = frame())
f->loaderClient()->dispatchWillRequestResource(&request);
// See if we can use an existing resource from the cache.
ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
const RevalidationPolicy policy = determineRevalidationPolicy(type, request, resource.get());
switch (policy) {
case Reload:
memoryCache()->remove(resource.get());
// Fall through
case Load:
resource = createResourceForLoading(type, request, request.charset());
break;
case Revalidate:
resource = createResourceForRevalidation(request, resource.get());
break;
case Use:
memoryCache()->updateForAccess(resource.get());
break;
}
if (!resource)
return 0;
if (!resource->hasClients())
m_deadStatsRecorder.update(policy);
if (policy != Use)
resource->setIdentifier(createUniqueIdentifier());
ResourceLoadPriority priority = loadPriority(type, request);
if (priority != resource->resourceRequest().priority()) {
resource->mutableResourceRequest().setPriority(priority);
resource->didChangePriority(priority, 0);
}
if (resourceNeedsLoad(resource.get(), request, policy)) {
if (!shouldLoadNewResource(type)) {
if (memoryCache()->contains(resource.get()))
memoryCache()->remove(resource.get());
return 0;
}
resource->load(this, request.options());
// For asynchronous loads that immediately fail, it's sufficient to return a
// null Resource, as it indicates that something prevented the load from starting.
// If there's a network error, that failure will happen asynchronously. However, if
// a sync load receives a network error, it will have already happened by this point.
// In that case, the requester should have access to the relevant ResourceError, so
// we need to return a non-null Resource.
if (resource->errorOccurred()) {
if (memoryCache()->contains(resource.get()))
memoryCache()->remove(resource.get());
return 0;
}
}
requestLoadStarted(resource.get(), request, policy == Use ? ResourceLoadingFromCache : ResourceLoadingFromNetwork);
ASSERT(resource->url() == url.string());
m_documentResources.set(resource->url(), resource);
return resource;
}
void ResourceFetcher::determineRequestContext(ResourceRequest& request, Resource::Type type)
{
WebURLRequest::RequestContext requestContext = requestContextFromType(this, type);
request.setRequestContext(requestContext);
}
ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
{
if (request.isConditional())
return ReloadIgnoringCacheData;
return UseProtocolCachePolicy;
}
void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
{
if (!frame())
return;
if (request.cachePolicy() == UseProtocolCachePolicy)
request.setCachePolicy(resourceRequestCachePolicy(request, type));
if (request.requestContext() == WebURLRequest::RequestContextUnspecified)
determineRequestContext(request, type);
if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
request.setHTTPHeaderField("Purpose", "prefetch");
context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
}
ResourcePtr<Resource> ResourceFetcher::createResourceForRevalidation(const FetchRequest& request, Resource* resource)
{
ASSERT(resource);
ASSERT(memoryCache()->contains(resource));
ASSERT(resource->isLoaded());
ASSERT(resource->canUseCacheValidator());
ASSERT(!resource->resourceToRevalidate());
ResourceRequest revalidatingRequest(resource->resourceRequest());
revalidatingRequest.clearHTTPReferrer();
addAdditionalRequestHeaders(revalidatingRequest, resource->type());
const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
const AtomicString& eTag = resource->response().httpHeaderField("ETag");
if (!lastModified.isEmpty() || !eTag.isEmpty()) {
ASSERT(context().cachePolicy(document()) != CachePolicyReload);
if (context().cachePolicy(document()) == CachePolicyRevalidate)
revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
}
if (!lastModified.isEmpty())
revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
if (!eTag.isEmpty())
revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
newResource->setResourceToRevalidate(resource);
memoryCache()->remove(resource);
memoryCache()->add(newResource.get());
return newResource;
}
ResourcePtr<Resource> ResourceFetcher::createResourceForLoading(Resource::Type type, FetchRequest& request, const String& charset)
{
ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
ResourcePtr<Resource> resource = createResource(type, request.resourceRequest(), charset);
memoryCache()->add(resource.get());
return resource;
}
ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, const FetchRequest& fetchRequest, Resource* existingResource) const
{
const ResourceRequest& request = fetchRequest.resourceRequest();
if (!existingResource)
return Load;
// If the same URL has been loaded as a different type, we need to reload.
if (existingResource->type() != type) {
WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
return Reload;
}
// Do not load from cache if images are not enabled. The load for this image will be blocked
// in ImageResource::load.
if (FetchRequest::DeferredByClient == fetchRequest.defer())
return Reload;
// Always use data uris.
// FIXME: Extend this to non-images.
if (type == Resource::Image && request.url().protocolIsData())
return Use;
if (!existingResource->canReuse(request))
return Reload;
// Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
if (request.downloadToFile())
return Reload;
// Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
// FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
// of things about how revalidation works that manual headers violate, so punt to Reload instead.
if (request.isConditional())
return Reload;
// Don't reload resources while pasting.
if (m_allowStaleResources)
return Use;
if (!fetchRequest.options().canReuseRequest(existingResource->options()))
return Reload;
// CachePolicyHistoryBuffer uses the cache no matter what.
CachePolicy cachePolicy = context().cachePolicy(document());
if (cachePolicy == CachePolicyHistoryBuffer)
return Use;
// Don't reuse resources with Cache-control: no-store.
if (existingResource->hasCacheControlNoStoreHeader()) {
WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
return Reload;
}
// If credentials were sent with the previous request and won't be
// with this one, or vice versa, re-fetch the resource.
//
// This helps with the case where the server sends back
// "Access-Control-Allow-Origin: *" all the time, but some of the
// client's requests are made without CORS and some with.
if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) {
WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
return Reload;
}
// During the initial load, avoid loading the same resource multiple times for a single document,
// even if the cache policies would tell us to.
// We also group loads of the same resource together.
// Raw resources are exempted, as XHRs fall into this category and may have user-set Cache-Control:
// headers or other factors that require separate requests.
if (type != Resource::Raw) {
if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
return Use;
if (existingResource->isLoading())
return Use;
}
// CachePolicyReload always reloads
if (cachePolicy == CachePolicyReload) {
WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
return Reload;
}
// We'll try to reload the resource if it failed last time.
if (existingResource->errorOccurred()) {
WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
return Reload;
}
// List of available images logic allows images to be re-used without cache validation. We restrict this only to images
// from memory cache which are the same as the version in the current document.
if (type == Resource::Image && existingResource == cachedResource(request.url()))
return Use;
// Check if the cache headers requires us to revalidate (cache expiration for example).
if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()
|| request.cacheControlContainsNoCache()) {
// See if the resource has usable ETag or Last-modified headers.
if (existingResource->canUseCacheValidator())
return Revalidate;
// No, must reload.
WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
return Reload;
}
return Use;
}
void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
{
if (url.isNull())
return;
if (!frame())
return;
String message;
if (!m_document || m_document->url().isNull())
message = "Unsafe attempt to load URL " + url.elidedString() + '.';
else
message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
frame()->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message));
}
void ResourceFetcher::setAutoLoadImages(bool enable)
{
if (enable == m_autoLoadImages)
return;
m_autoLoadImages = enable;
if (!m_autoLoadImages)
return;
reloadImagesIfNotDeferred();
}
void ResourceFetcher::setImagesEnabled(bool enable)
{
if (enable == m_imagesEnabled)
return;
m_imagesEnabled = enable;
if (!m_imagesEnabled)
return;
reloadImagesIfNotDeferred();
}
bool ResourceFetcher::clientDefersImage(const KURL& url) const
{
// FIXME(sky): remove
return false;
}
bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
{
return clientDefersImage(url) || !m_autoLoadImages;
}
void ResourceFetcher::reloadImagesIfNotDeferred()
{
DocumentResourceMap::iterator end = m_documentResources.end();
for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
Resource* resource = it->value.get();
if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
}
}
void ResourceFetcher::didLoadResource(Resource* resource)
{
RefPtr<Document> protectDocument(m_document);
if (m_document)
m_document->checkCompleted();
scheduleDocumentResourcesGC();
}
void ResourceFetcher::scheduleDocumentResourcesGC()
{
if (!m_garbageCollectDocumentResourcesTimer.isActive())
m_garbageCollectDocumentResourcesTimer.startOneShot(0, FROM_HERE);
}
// Garbage collecting m_documentResources is a workaround for the
// ResourcePtrs on the RHS being strong references. Ideally this
// would be a weak map, however ResourcePtrs perform additional
// bookkeeping on Resources, so instead pseudo-GC them -- when the
// reference count reaches 1, m_documentResources is the only reference, so
// remove it from the map.
void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
{
ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
garbageCollectDocumentResources();
}
void ResourceFetcher::garbageCollectDocumentResources()
{
typedef Vector<String, 10> StringVector;
StringVector resourcesToDelete;
for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
if (it->value->hasOneHandle())
resourcesToDelete.append(it->key);
}
m_documentResources.removeAll(resourcesToDelete);
}
void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
{
if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
return;
ResourceRequest request(resource->url());
unsigned long identifier = createUniqueIdentifier();
context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
// FIXME: If willSendRequest changes the request, we don't respect it.
willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
context().sendRemainingDelegateMessages(m_document, identifier, resource->response(), resource->encodedSize());
}
void ResourceFetcher::incrementRequestCount(const Resource* res)
{
if (res->ignoreForRequestCount())
return;
++m_requestCount;
}
void ResourceFetcher::decrementRequestCount(const Resource* res)
{
if (res->ignoreForRequestCount())
return;
--m_requestCount;
ASSERT(m_requestCount > -1);
}
void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
{
TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
context().dispatchDidFinishLoading(m_document, resource->identifier(), finishTime, encodedDataLength);
}
void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority, int intraPriorityValue)
{
TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority, intraPriorityValue);
}
void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
{
TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
context().dispatchDidFail(m_document, resource->identifier(), error);
}
void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
{
context().dispatchWillSendRequest(m_document, identifier, request, redirectResponse, initiatorInfo);
}
void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
{
context().dispatchDidReceiveResponse(m_document, resource->identifier(), response, resource->loader());
}
void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
{
context().dispatchDidReceiveData(m_document, resource->identifier(), data, dataLength, encodedDataLength);
}
void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
{
context().dispatchDidDownloadData(m_document, resource->identifier(), dataLength, encodedDataLength);
}
void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
{
if (!m_multipartLoaders)
m_multipartLoaders = ResourceLoaderSet::create();
m_multipartLoaders->add(loader);
m_loaders->remove(loader);
}
void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
{
if (!m_document)
return;
if (!m_loaders)
m_loaders = ResourceLoaderSet::create();
ASSERT(!m_loaders->contains(loader));
m_loaders->add(loader);
}
void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
{
if (m_loaders && m_loaders->contains(loader))
m_loaders->remove(loader);
if (m_multipartLoaders && m_multipartLoaders->contains(loader))
m_multipartLoaders->remove(loader);
}
void ResourceFetcher::willStartLoadingResource(Resource* resource, ResourceRequest& request)
{
TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource, "url", resource->url().string().ascii().data(), "priority", resource->resourceRequest().priority());
}
void ResourceFetcher::stopFetching()
{
if (m_multipartLoaders)
m_multipartLoaders->cancelAll();
if (m_loaders)
m_loaders->cancelAll();
}
bool ResourceFetcher::isFetching() const
{
return m_loaders && !m_loaders->isEmpty();
}
bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
{
return this == possibleOwner;
}
#if !ENABLE(OILPAN)
void ResourceFetcher::refResourceLoaderHost()
{
ref();
}
void ResourceFetcher::derefResourceLoaderHost()
{
deref();
}
#endif
const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
{
DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (BufferData, AllowStoredCredentials, ClientRequestedCredentials, DocumentContext));
return options;
}
ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
: m_useCount(0)
, m_revalidateCount(0)
, m_loadCount(0)
{
}
ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
{
blink::Platform::current()->histogramCustomCounts(
"WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
blink::Platform::current()->histogramCustomCounts(
"WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
blink::Platform::current()->histogramCustomCounts(
"WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
}
void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
{
switch (policy) {
case Reload:
case Load:
++m_loadCount;
return;
case Revalidate:
++m_revalidateCount;
return;
case Use:
++m_useCount;
return;
}
}
}