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

Unified Diff: third_party/WebKit/Source/core/fetch/Resource.cpp

Issue 2584423002: Loading: move core/fetch to platform/loader/fetch (Closed)
Patch Set: another try Created 3 years, 11 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: third_party/WebKit/Source/core/fetch/Resource.cpp
diff --git a/third_party/WebKit/Source/core/fetch/Resource.cpp b/third_party/WebKit/Source/core/fetch/Resource.cpp
deleted file mode 100644
index b6888617ab69c500f3b07ab110fa389ffe8bde51..0000000000000000000000000000000000000000
--- a/third_party/WebKit/Source/core/fetch/Resource.cpp
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
- 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) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All
- rights reserved.
-
- 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.
-*/
-
-#include "core/fetch/Resource.h"
-
-#include "core/fetch/CachedMetadata.h"
-#include "core/fetch/CrossOriginAccessControl.h"
-#include "core/fetch/FetchInitiatorTypeNames.h"
-#include "core/fetch/FetchRequest.h"
-#include "core/fetch/IntegrityMetadata.h"
-#include "core/fetch/MemoryCache.h"
-#include "core/fetch/ResourceClient.h"
-#include "core/fetch/ResourceClientWalker.h"
-#include "core/fetch/ResourceLoader.h"
-#include "platform/Histogram.h"
-#include "platform/InstanceCounters.h"
-#include "platform/RuntimeEnabledFeatures.h"
-#include "platform/SharedBuffer.h"
-#include "platform/WebTaskRunner.h"
-#include "platform/instrumentation/tracing/TraceEvent.h"
-#include "platform/network/HTTPParsers.h"
-#include "platform/weborigin/KURL.h"
-#include "public/platform/Platform.h"
-#include "public/platform/WebCachePolicy.h"
-#include "public/platform/WebScheduler.h"
-#include "public/platform/WebSecurityOrigin.h"
-#include "wtf/CurrentTime.h"
-#include "wtf/MathExtras.h"
-#include "wtf/StdLibExtras.h"
-#include "wtf/Vector.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/StringBuilder.h"
-#include <algorithm>
-#include <cassert>
-#include <memory>
-#include <stdint.h>
-
-namespace blink {
-
-// These response headers are not copied from a revalidated response to the
-// cached response headers. For compatibility, this list is based on Chromium's
-// net/http/http_response_headers.cc.
-const char* const headersToIgnoreAfterRevalidation[] = {
- "allow",
- "connection",
- "etag",
- "expires",
- "keep-alive",
- "last-modified",
- "proxy-authenticate",
- "proxy-connection",
- "trailer",
- "transfer-encoding",
- "upgrade",
- "www-authenticate",
- "x-frame-options",
- "x-xss-protection",
-};
-
-// Some header prefixes mean "Don't copy this header from a 304 response.".
-// Rather than listing all the relevant headers, we can consolidate them into
-// this list, also grabbed from Chromium's net/http/http_response_headers.cc.
-const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
- "content-", "x-content-", "x-webkit-"};
-
-static inline bool shouldUpdateHeaderAfterRevalidation(
- const AtomicString& header) {
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation);
- i++) {
- if (equalIgnoringCase(header, headersToIgnoreAfterRevalidation[i]))
- return false;
- }
- for (size_t i = 0;
- i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
- if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i],
- TextCaseASCIIInsensitive))
- return false;
- }
- return true;
-}
-
-class Resource::CachedMetadataHandlerImpl : public CachedMetadataHandler {
- public:
- static Resource::CachedMetadataHandlerImpl* create(Resource* resource) {
- return new CachedMetadataHandlerImpl(resource);
- }
- ~CachedMetadataHandlerImpl() override {}
- DECLARE_VIRTUAL_TRACE();
- void setCachedMetadata(uint32_t, const char*, size_t, CacheType) override;
- void clearCachedMetadata(CacheType) override;
- PassRefPtr<CachedMetadata> cachedMetadata(uint32_t) const override;
- String encoding() const override;
- // Sets the serialized metadata retrieved from the platform's cache.
- void setSerializedCachedMetadata(const char*, size_t);
-
- protected:
- explicit CachedMetadataHandlerImpl(Resource*);
- virtual void sendToPlatform();
- const ResourceResponse& response() const { return m_resource->response(); }
-
- RefPtr<CachedMetadata> m_cachedMetadata;
-
- private:
- Member<Resource> m_resource;
-};
-
-Resource::CachedMetadataHandlerImpl::CachedMetadataHandlerImpl(
- Resource* resource)
- : m_resource(resource) {}
-
-DEFINE_TRACE(Resource::CachedMetadataHandlerImpl) {
- visitor->trace(m_resource);
- CachedMetadataHandler::trace(visitor);
-}
-
-void Resource::CachedMetadataHandlerImpl::setCachedMetadata(
- uint32_t dataTypeID,
- const char* data,
- size_t size,
- CachedMetadataHandler::CacheType cacheType) {
- // Currently, only one type of cached metadata per resource is supported. If
- // the need arises for multiple types of metadata per resource this could be
- // enhanced to store types of metadata in a map.
- DCHECK(!m_cachedMetadata);
- m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
- if (cacheType == CachedMetadataHandler::SendToPlatform)
- sendToPlatform();
-}
-
-void Resource::CachedMetadataHandlerImpl::clearCachedMetadata(
- CachedMetadataHandler::CacheType cacheType) {
- m_cachedMetadata.clear();
- if (cacheType == CachedMetadataHandler::SendToPlatform)
- sendToPlatform();
-}
-
-PassRefPtr<CachedMetadata> Resource::CachedMetadataHandlerImpl::cachedMetadata(
- uint32_t dataTypeID) const {
- if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
- return nullptr;
- return m_cachedMetadata.get();
-}
-
-String Resource::CachedMetadataHandlerImpl::encoding() const {
- return m_resource->encoding();
-}
-
-void Resource::CachedMetadataHandlerImpl::setSerializedCachedMetadata(
- const char* data,
- size_t size) {
- // We only expect to receive cached metadata from the platform once. If this
- // triggers, it indicates an efficiency problem which is most likely
- // unexpected in code designed to improve performance.
- DCHECK(!m_cachedMetadata);
- m_cachedMetadata = CachedMetadata::createFromSerializedData(data, size);
-}
-
-void Resource::CachedMetadataHandlerImpl::sendToPlatform() {
- if (m_cachedMetadata) {
- const Vector<char>& serializedData = m_cachedMetadata->serializedData();
- Platform::current()->cacheMetadata(
- response().url(), response().responseTime(), serializedData.data(),
- serializedData.size());
- } else {
- Platform::current()->cacheMetadata(response().url(),
- response().responseTime(), nullptr, 0);
- }
-}
-
-class Resource::ServiceWorkerResponseCachedMetadataHandler
- : public Resource::CachedMetadataHandlerImpl {
- public:
- static Resource::CachedMetadataHandlerImpl* create(
- Resource* resource,
- SecurityOrigin* securityOrigin) {
- return new ServiceWorkerResponseCachedMetadataHandler(resource,
- securityOrigin);
- }
- ~ServiceWorkerResponseCachedMetadataHandler() override {}
- DECLARE_VIRTUAL_TRACE();
-
- protected:
- void sendToPlatform() override;
-
- private:
- explicit ServiceWorkerResponseCachedMetadataHandler(Resource*,
- SecurityOrigin*);
- String m_cacheStorageCacheName;
- RefPtr<SecurityOrigin> m_securityOrigin;
-};
-
-Resource::ServiceWorkerResponseCachedMetadataHandler::
- ServiceWorkerResponseCachedMetadataHandler(Resource* resource,
- SecurityOrigin* securityOrigin)
- : CachedMetadataHandlerImpl(resource), m_securityOrigin(securityOrigin) {}
-
-DEFINE_TRACE(Resource::ServiceWorkerResponseCachedMetadataHandler) {
- CachedMetadataHandlerImpl::trace(visitor);
-}
-
-void Resource::ServiceWorkerResponseCachedMetadataHandler::sendToPlatform() {
- // We don't support sending the metadata to the platform when the response was
- // directly fetched via a ServiceWorker (eg:
- // FetchEvent.respondWith(fetch(FetchEvent.request))) to prevent an attacker's
- // Service Worker from poisoning the metadata cache of HTTPCache.
- if (response().cacheStorageCacheName().isNull())
- return;
-
- if (m_cachedMetadata) {
- const Vector<char>& serializedData = m_cachedMetadata->serializedData();
- Platform::current()->cacheMetadataInCacheStorage(
- response().url(), response().responseTime(), serializedData.data(),
- serializedData.size(), WebSecurityOrigin(m_securityOrigin),
- response().cacheStorageCacheName());
- } else {
- Platform::current()->cacheMetadataInCacheStorage(
- response().url(), response().responseTime(), nullptr, 0,
- WebSecurityOrigin(m_securityOrigin),
- response().cacheStorageCacheName());
- }
-}
-
-// This class cannot be on-heap because the first callbackHandler() call
-// instantiates the singleton object while we can call it in the
-// pre-finalization step.
-class Resource::ResourceCallback final {
- public:
- static ResourceCallback& callbackHandler();
- void schedule(Resource*);
- void cancel(Resource*);
- bool isScheduled(Resource*) const;
-
- private:
- ResourceCallback();
-
- void runTask();
- TaskHandle m_taskHandle;
- HashSet<Persistent<Resource>> m_resourcesWithPendingClients;
-};
-
-Resource::ResourceCallback& Resource::ResourceCallback::callbackHandler() {
- DEFINE_STATIC_LOCAL(ResourceCallback, callbackHandler, ());
- return callbackHandler;
-}
-
-Resource::ResourceCallback::ResourceCallback() {}
-
-void Resource::ResourceCallback::schedule(Resource* resource) {
- if (!m_taskHandle.isActive()) {
- // WTF::unretained(this) is safe because a posted task is canceled when
- // |m_taskHandle| is destroyed on the dtor of this ResourceCallback.
- m_taskHandle =
- Platform::current()
- ->currentThread()
- ->scheduler()
- ->loadingTaskRunner()
- ->postCancellableTask(
- BLINK_FROM_HERE,
- WTF::bind(&ResourceCallback::runTask, WTF::unretained(this)));
- }
- m_resourcesWithPendingClients.add(resource);
-}
-
-void Resource::ResourceCallback::cancel(Resource* resource) {
- m_resourcesWithPendingClients.remove(resource);
- if (m_taskHandle.isActive() && m_resourcesWithPendingClients.isEmpty())
- m_taskHandle.cancel();
-}
-
-bool Resource::ResourceCallback::isScheduled(Resource* resource) const {
- return m_resourcesWithPendingClients.contains(resource);
-}
-
-void Resource::ResourceCallback::runTask() {
- HeapVector<Member<Resource>> resources;
- for (const Member<Resource>& resource : m_resourcesWithPendingClients)
- resources.push_back(resource.get());
- m_resourcesWithPendingClients.clear();
-
- for (const auto& resource : resources)
- resource->finishPendingClients();
-}
-
-constexpr Resource::Status Resource::NotStarted;
-constexpr Resource::Status Resource::Pending;
-constexpr Resource::Status Resource::Cached;
-constexpr Resource::Status Resource::LoadError;
-constexpr Resource::Status Resource::DecodeError;
-
-Resource::Resource(const ResourceRequest& request,
- Type type,
- const ResourceLoaderOptions& options)
- : m_loadFinishTime(0),
- m_identifier(0),
- m_encodedSize(0),
- m_encodedSizeMemoryUsage(0),
- m_decodedSize(0),
- m_overheadSize(calculateOverheadSize()),
- m_preloadCount(0),
- m_preloadDiscoveryTime(0.0),
- m_cacheIdentifier(MemoryCache::defaultCacheIdentifier()),
- m_preloadResult(PreloadNotReferenced),
- m_type(type),
- m_status(NotStarted),
- m_needsSynchronousCacheHit(false),
- m_linkPreload(false),
- m_isRevalidating(false),
- m_isAlive(false),
- m_isAddRemoveClientProhibited(false),
- m_integrityDisposition(ResourceIntegrityDisposition::NotChecked),
- m_options(options),
- m_responseTimestamp(currentTime()),
- m_cancelTimer(Platform::current()->mainThread()->getWebTaskRunner(),
- this,
- &Resource::cancelTimerFired),
- m_resourceRequest(request) {
- InstanceCounters::incrementCounter(InstanceCounters::ResourceCounter);
-
- // Currently we support the metadata caching only for HTTP family.
- if (resourceRequest().url().protocolIsInHTTPFamily())
- m_cacheHandler = CachedMetadataHandlerImpl::create(this);
- MemoryCoordinator::instance().registerClient(this);
-}
-
-Resource::~Resource() {
- InstanceCounters::decrementCounter(InstanceCounters::ResourceCounter);
-}
-
-DEFINE_TRACE(Resource) {
- visitor->trace(m_loader);
- visitor->trace(m_cacheHandler);
- visitor->trace(m_clients);
- visitor->trace(m_clientsAwaitingCallback);
- visitor->trace(m_finishedClients);
- MemoryCoordinatorClient::trace(visitor);
-}
-
-void Resource::setLoader(ResourceLoader* loader) {
- CHECK(!m_loader);
- DCHECK(stillNeedsLoad());
- m_loader = loader;
- m_status = Pending;
-}
-
-void Resource::checkNotify() {
- if (isLoading())
- return;
-
- ResourceClientWalker<ResourceClient> w(m_clients);
- while (ResourceClient* c = w.next()) {
- markClientFinished(c);
- c->notifyFinished(this);
- }
-}
-
-void Resource::markClientFinished(ResourceClient* client) {
- if (m_clients.contains(client)) {
- m_finishedClients.add(client);
- m_clients.remove(client);
- }
-}
-
-void Resource::appendData(const char* data, size_t length) {
- TRACE_EVENT0("blink", "Resource::appendData");
- DCHECK(!m_isRevalidating);
- DCHECK(!errorOccurred());
- if (m_options.dataBufferingPolicy == DoNotBufferData)
- return;
- if (m_data)
- m_data->append(data, length);
- else
- m_data = SharedBuffer::create(data, length);
- setEncodedSize(m_data->size());
-}
-
-void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer) {
- DCHECK(!m_isRevalidating);
- DCHECK(!errorOccurred());
- DCHECK_EQ(m_options.dataBufferingPolicy, BufferData);
- m_data = resourceBuffer;
- setEncodedSize(m_data->size());
-}
-
-void Resource::clearData() {
- m_data.clear();
- m_encodedSizeMemoryUsage = 0;
-}
-
-void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy) {
- m_options.dataBufferingPolicy = dataBufferingPolicy;
- clearData();
- setEncodedSize(0);
-}
-
-void Resource::error(const ResourceError& error) {
- DCHECK(!error.isNull());
- m_error = error;
- m_isRevalidating = false;
-
- if (m_error.isCancellation() || !isPreloaded())
- memoryCache()->remove(this);
-
- if (!errorOccurred())
- setStatus(LoadError);
- DCHECK(errorOccurred());
- clearData();
- m_loader = nullptr;
- checkNotify();
-}
-
-void Resource::finish(double loadFinishTime) {
- DCHECK(!m_isRevalidating);
- m_loadFinishTime = loadFinishTime;
- if (!errorOccurred())
- m_status = Cached;
- m_loader = nullptr;
- checkNotify();
-}
-
-AtomicString Resource::httpContentType() const {
- return extractMIMETypeFromMediaType(
- response().httpHeaderField(HTTPNames::Content_Type).lower());
-}
-
-bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin) const {
- StoredCredentials storedCredentials =
- lastResourceRequest().allowStoredCredentials()
- ? AllowStoredCredentials
- : DoNotAllowStoredCredentials;
- CrossOriginAccessControl::AccessStatus status =
- CrossOriginAccessControl::checkAccess(response(), storedCredentials,
- securityOrigin);
-
- return status == CrossOriginAccessControl::kAccessAllowed;
-}
-
-bool Resource::isEligibleForIntegrityCheck(
- SecurityOrigin* securityOrigin) const {
- return securityOrigin->canRequest(resourceRequest().url()) ||
- passesAccessControlCheck(securityOrigin);
-}
-
-void Resource::setIntegrityDisposition(
- ResourceIntegrityDisposition disposition) {
- DCHECK_NE(disposition, ResourceIntegrityDisposition::NotChecked);
- DCHECK(m_type == Resource::Script || m_type == Resource::CSSStyleSheet);
- m_integrityDisposition = disposition;
-}
-
-bool Resource::mustRefetchDueToIntegrityMetadata(
- const FetchRequest& request) const {
- if (request.integrityMetadata().isEmpty())
- return false;
-
- return !IntegrityMetadata::setsEqual(m_integrityMetadata,
- request.integrityMetadata());
-}
-
-static double currentAge(const ResourceResponse& response,
- double responseTimestamp) {
- // RFC2616 13.2.3
- // No compensation for latency as that is not terribly important in practice
- double dateValue = response.date();
- double apparentAge = std::isfinite(dateValue)
- ? std::max(0., responseTimestamp - dateValue)
- : 0;
- double ageValue = response.age();
- double correctedReceivedAge =
- std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
- double residentTime = currentTime() - responseTimestamp;
- return correctedReceivedAge + residentTime;
-}
-
-double Resource::currentAge() const {
- return blink::currentAge(response(), m_responseTimestamp);
-}
-
-static double freshnessLifetime(const ResourceResponse& response,
- double responseTimestamp) {
-#if !OS(ANDROID)
- // On desktop, local files should be reloaded in case they change.
- if (response.url().isLocalFile())
- return 0;
-#endif
-
- // Cache other non-http / non-filesystem resources liberally.
- if (!response.url().protocolIsInHTTPFamily() &&
- !response.url().protocolIs("filesystem"))
- return std::numeric_limits<double>::max();
-
- // RFC2616 13.2.4
- double maxAgeValue = response.cacheControlMaxAge();
- if (std::isfinite(maxAgeValue))
- return maxAgeValue;
- double expiresValue = response.expires();
- double dateValue = response.date();
- double creationTime =
- std::isfinite(dateValue) ? dateValue : responseTimestamp;
- if (std::isfinite(expiresValue))
- return expiresValue - creationTime;
- double lastModifiedValue = response.lastModified();
- if (std::isfinite(lastModifiedValue))
- return (creationTime - lastModifiedValue) * 0.1;
- // If no cache headers are present, the specification leaves the decision to
- // the UA. Other browsers seem to opt for 0.
- return 0;
-}
-
-double Resource::freshnessLifetime() const {
- return blink::freshnessLifetime(response(), m_responseTimestamp);
-}
-
-double Resource::stalenessLifetime() const {
- return response().cacheControlStaleWhileRevalidate();
-}
-
-static bool canUseResponse(const ResourceResponse& response,
- double responseTimestamp) {
- if (response.isNull())
- return false;
-
- // FIXME: Why isn't must-revalidate considered a reason we can't use the
- // response?
- if (response.cacheControlContainsNoCache() ||
- response.cacheControlContainsNoStore())
- return false;
-
- if (response.httpStatusCode() == 303) {
- // Must not be cached.
- return false;
- }
-
- if (response.httpStatusCode() == 302 || response.httpStatusCode() == 307) {
- // Default to not cacheable unless explicitly allowed.
- bool hasMaxAge = std::isfinite(response.cacheControlMaxAge());
- bool hasExpires = std::isfinite(response.expires());
- // TODO: consider catching Cache-Control "private" and "public" here.
- if (!hasMaxAge && !hasExpires)
- return false;
- }
-
- return currentAge(response, responseTimestamp) <=
- freshnessLifetime(response, responseTimestamp);
-}
-
-const ResourceRequest& Resource::lastResourceRequest() const {
- if (!m_redirectChain.size())
- return resourceRequest();
- return m_redirectChain.back().m_request;
-}
-
-void Resource::setRevalidatingRequest(const ResourceRequest& request) {
- SECURITY_CHECK(m_redirectChain.isEmpty());
- DCHECK(!request.isNull());
- CHECK(!m_isRevalidationStartForbidden);
- m_isRevalidating = true;
- m_resourceRequest = request;
- m_status = NotStarted;
-}
-
-bool Resource::willFollowRedirect(const ResourceRequest& newRequest,
- const ResourceResponse& redirectResponse) {
- if (m_isRevalidating)
- revalidationFailed();
- m_redirectChain.push_back(RedirectPair(newRequest, redirectResponse));
- return true;
-}
-
-void Resource::setResponse(const ResourceResponse& response) {
- m_response = response;
- if (this->response().wasFetchedViaServiceWorker()) {
- m_cacheHandler = ServiceWorkerResponseCachedMetadataHandler::create(
- this, m_fetcherSecurityOrigin.get());
- }
-}
-
-void Resource::responseReceived(const ResourceResponse& response,
- std::unique_ptr<WebDataConsumerHandle>) {
- m_responseTimestamp = currentTime();
- if (m_preloadDiscoveryTime) {
- int timeSinceDiscovery = static_cast<int>(
- 1000 * (monotonicallyIncreasingTime() - m_preloadDiscoveryTime));
- DEFINE_STATIC_LOCAL(CustomCountHistogram,
- preloadDiscoveryToFirstByteHistogram,
- ("PreloadScanner.TTFB", 0, 10000, 50));
- preloadDiscoveryToFirstByteHistogram.count(timeSinceDiscovery);
- }
-
- if (m_isRevalidating) {
- if (response.httpStatusCode() == 304) {
- revalidationSucceeded(response);
- return;
- }
- revalidationFailed();
- }
- setResponse(response);
- String encoding = response.textEncodingName();
- if (!encoding.isNull())
- setEncoding(encoding);
-}
-
-void Resource::setSerializedCachedMetadata(const char* data, size_t size) {
- DCHECK(!m_isRevalidating);
- DCHECK(!response().isNull());
- if (m_cacheHandler)
- m_cacheHandler->setSerializedCachedMetadata(data, size);
-}
-
-CachedMetadataHandler* Resource::cacheHandler() {
- return m_cacheHandler.get();
-}
-
-String Resource::reasonNotDeletable() const {
- StringBuilder builder;
- if (hasClientsOrObservers()) {
- builder.append("hasClients(");
- builder.appendNumber(m_clients.size());
- if (!m_clientsAwaitingCallback.isEmpty()) {
- builder.append(", AwaitingCallback=");
- builder.appendNumber(m_clientsAwaitingCallback.size());
- }
- if (!m_finishedClients.isEmpty()) {
- builder.append(", Finished=");
- builder.appendNumber(m_finishedClients.size());
- }
- builder.append(')');
- }
- if (m_loader) {
- if (!builder.isEmpty())
- builder.append(' ');
- builder.append("m_loader");
- }
- if (m_preloadCount) {
- if (!builder.isEmpty())
- builder.append(' ');
- builder.append("m_preloadCount(");
- builder.appendNumber(m_preloadCount);
- builder.append(')');
- }
- if (memoryCache()->contains(this)) {
- if (!builder.isEmpty())
- builder.append(' ');
- builder.append("in_memory_cache");
- }
- return builder.toString();
-}
-
-void Resource::didAddClient(ResourceClient* c) {
- if (isLoaded()) {
- c->notifyFinished(this);
- if (m_clients.contains(c)) {
- m_finishedClients.add(c);
- m_clients.remove(c);
- }
- }
-}
-
-static bool typeNeedsSynchronousCacheHit(Resource::Type type) {
- // Some resources types default to return data synchronously. For most of
- // these, it's because there are layout tests that expect data to return
- // synchronously in case of cache hit. In the case of fonts, there was a
- // performance regression.
- // FIXME: Get to the point where we don't need to special-case sync/async
- // behavior for different resource types.
- if (type == Resource::Image)
- return true;
- if (type == Resource::CSSStyleSheet)
- return true;
- if (type == Resource::Script)
- return true;
- if (type == Resource::Font)
- return true;
- return false;
-}
-
-void Resource::willAddClientOrObserver(PreloadReferencePolicy policy) {
- if (policy == MarkAsReferenced && m_preloadResult == PreloadNotReferenced) {
- if (isLoaded())
- m_preloadResult = PreloadReferencedWhileComplete;
- else if (isLoading())
- m_preloadResult = PreloadReferencedWhileLoading;
- else
- m_preloadResult = PreloadReferenced;
-
- if (m_preloadDiscoveryTime) {
- int timeSinceDiscovery = static_cast<int>(
- 1000 * (monotonicallyIncreasingTime() - m_preloadDiscoveryTime));
- DEFINE_STATIC_LOCAL(CustomCountHistogram, preloadDiscoveryHistogram,
- ("PreloadScanner.ReferenceTime", 0, 10000, 50));
- preloadDiscoveryHistogram.count(timeSinceDiscovery);
- }
- }
- if (!hasClientsOrObservers()) {
- m_isAlive = true;
- }
-}
-
-void Resource::addClient(ResourceClient* client,
- PreloadReferencePolicy policy) {
- CHECK(!m_isAddRemoveClientProhibited);
-
- willAddClientOrObserver(policy);
-
- if (m_isRevalidating) {
- m_clients.add(client);
- return;
- }
-
- // If an error has occurred or we have existing data to send to the new client
- // and the resource type supprts it, send it asynchronously.
- if ((errorOccurred() || !response().isNull()) &&
- !typeNeedsSynchronousCacheHit(getType()) && !m_needsSynchronousCacheHit) {
- m_clientsAwaitingCallback.add(client);
- ResourceCallback::callbackHandler().schedule(this);
- return;
- }
-
- m_clients.add(client);
- didAddClient(client);
- return;
-}
-
-void Resource::removeClient(ResourceClient* client) {
- CHECK(!m_isAddRemoveClientProhibited);
-
- // This code may be called in a pre-finalizer, where weak members in the
- // HashCountedSet are already swept out.
-
- if (m_finishedClients.contains(client))
- m_finishedClients.remove(client);
- else if (m_clientsAwaitingCallback.contains(client))
- m_clientsAwaitingCallback.remove(client);
- else
- m_clients.remove(client);
-
- if (m_clientsAwaitingCallback.isEmpty())
- ResourceCallback::callbackHandler().cancel(this);
-
- didRemoveClientOrObserver();
-}
-
-void Resource::didRemoveClientOrObserver() {
- if (!hasClientsOrObservers() && m_isAlive) {
- m_isAlive = false;
- allClientsAndObserversRemoved();
-
- // RFC2616 14.9.2:
- // "no-store: ... MUST make a best-effort attempt to remove the information
- // from volatile storage as promptly as possible"
- // "... History buffers MAY store such responses as part of their normal
- // operation."
- // We allow non-secure content to be reused in history, but we do not allow
- // secure content to be reused.
- if (hasCacheControlNoStoreHeader() && url().protocolIs("https"))
- memoryCache()->remove(this);
- }
-}
-
-void Resource::allClientsAndObserversRemoved() {
- if (!m_loader)
- return;
- if (!m_cancelTimer.isActive())
- m_cancelTimer.startOneShot(0, BLINK_FROM_HERE);
-}
-
-void Resource::cancelTimerFired(TimerBase* timer) {
- DCHECK_EQ(timer, &m_cancelTimer);
- if (!hasClientsOrObservers() && m_loader)
- m_loader->cancel();
-}
-
-void Resource::setDecodedSize(size_t decodedSize) {
- if (decodedSize == m_decodedSize)
- return;
- size_t oldSize = size();
- m_decodedSize = decodedSize;
- memoryCache()->update(this, oldSize, size());
-}
-
-void Resource::setEncodedSize(size_t encodedSize) {
- if (encodedSize == m_encodedSize && encodedSize == m_encodedSizeMemoryUsage)
- return;
- size_t oldSize = size();
- m_encodedSize = encodedSize;
- m_encodedSizeMemoryUsage = encodedSize;
- memoryCache()->update(this, oldSize, size());
-}
-
-void Resource::finishPendingClients() {
- // We're going to notify clients one by one. It is simple if the client does
- // nothing. However there are a couple other things that can happen.
- //
- // 1. Clients can be added during the loop. Make sure they are not processed.
- // 2. Clients can be removed during the loop. Make sure they are always
- // available to be removed. Also don't call removed clients or add them
- // back.
- //
- // Handle case (1) by saving a list of clients to notify. A separate list also
- // ensure a client is either in m_clients or m_clientsAwaitingCallback.
- HeapVector<Member<ResourceClient>> clientsToNotify;
- copyToVector(m_clientsAwaitingCallback, clientsToNotify);
-
- for (const auto& client : clientsToNotify) {
- // Handle case (2) to skip removed clients.
- if (!m_clientsAwaitingCallback.remove(client))
- continue;
- m_clients.add(client);
-
- // When revalidation starts after waiting clients are scheduled and
- // before they are added here. In such cases, we just add the clients
- // to |m_clients| without didAddClient(), as in Resource::addClient().
- if (!m_isRevalidating)
- didAddClient(client);
- }
-
- // It is still possible for the above loop to finish a new client
- // synchronously. If there's no client waiting we should deschedule.
- bool scheduled = ResourceCallback::callbackHandler().isScheduled(this);
- if (scheduled && m_clientsAwaitingCallback.isEmpty())
- ResourceCallback::callbackHandler().cancel(this);
-
- // Prevent the case when there are clients waiting but no callback scheduled.
- DCHECK(m_clientsAwaitingCallback.isEmpty() || scheduled);
-}
-
-void Resource::prune() {
- destroyDecodedDataIfPossible();
-}
-
-void Resource::onMemoryStateChange(MemoryState state) {
- if (state != MemoryState::SUSPENDED)
- return;
- prune();
- if (!m_cacheHandler)
- return;
- m_cacheHandler->clearCachedMetadata(CachedMetadataHandler::CacheLocally);
-}
-
-void Resource::onMemoryDump(WebMemoryDumpLevelOfDetail levelOfDetail,
- WebProcessMemoryDump* memoryDump) const {
- static const size_t kMaxURLReportLength = 128;
- static const int kMaxResourceClientToShowInMemoryInfra = 10;
-
- const String dumpName = getMemoryDumpName();
- WebMemoryAllocatorDump* dump =
- memoryDump->createMemoryAllocatorDump(dumpName);
- dump->addScalar("encoded_size", "bytes", m_encodedSizeMemoryUsage);
- if (hasClientsOrObservers())
- dump->addScalar("live_size", "bytes", m_encodedSizeMemoryUsage);
- else
- dump->addScalar("dead_size", "bytes", m_encodedSizeMemoryUsage);
-
- if (m_data)
- m_data->onMemoryDump(dumpName, memoryDump);
-
- if (levelOfDetail == WebMemoryDumpLevelOfDetail::Detailed) {
- String urlToReport = url().getString();
- if (urlToReport.length() > kMaxURLReportLength) {
- urlToReport.truncate(kMaxURLReportLength);
- urlToReport = urlToReport + "...";
- }
- dump->addString("url", "", urlToReport);
-
- dump->addString("reason_not_deletable", "", reasonNotDeletable());
-
- Vector<String> clientNames;
- ResourceClientWalker<ResourceClient> walker(m_clients);
- while (ResourceClient* client = walker.next())
- clientNames.push_back(client->debugName());
- ResourceClientWalker<ResourceClient> walker2(m_clientsAwaitingCallback);
- while (ResourceClient* client = walker2.next())
- clientNames.push_back("(awaiting) " + client->debugName());
- ResourceClientWalker<ResourceClient> walker3(m_finishedClients);
- while (ResourceClient* client = walker3.next())
- clientNames.push_back("(finished) " + client->debugName());
- std::sort(clientNames.begin(), clientNames.end(),
- WTF::codePointCompareLessThan);
-
- StringBuilder builder;
- for (size_t i = 0;
- i < clientNames.size() && i < kMaxResourceClientToShowInMemoryInfra;
- ++i) {
- if (i > 0)
- builder.append(" / ");
- builder.append(clientNames[i]);
- }
- if (clientNames.size() > kMaxResourceClientToShowInMemoryInfra) {
- builder.append(" / and ");
- builder.appendNumber(clientNames.size() -
- kMaxResourceClientToShowInMemoryInfra);
- builder.append(" more");
- }
- dump->addString("ResourceClient", "", builder.toString());
- }
-
- const String overheadName = dumpName + "/metadata";
- WebMemoryAllocatorDump* overheadDump =
- memoryDump->createMemoryAllocatorDump(overheadName);
- overheadDump->addScalar("size", "bytes", overheadSize());
- memoryDump->addSuballocation(
- overheadDump->guid(), String(WTF::Partitions::kAllocatedObjectPoolName));
-}
-
-String Resource::getMemoryDumpName() const {
- return String::format(
- "web_cache/%s_resources/%ld",
- resourceTypeToString(getType(), options().initiatorInfo.name),
- m_identifier);
-}
-
-void Resource::setCachePolicyBypassingCache() {
- m_resourceRequest.setCachePolicy(WebCachePolicy::BypassingCache);
-}
-
-void Resource::setPreviewsStateNoTransform() {
- m_resourceRequest.setPreviewsState(WebURLRequest::PreviewsNoTransform);
-}
-
-void Resource::clearRangeRequestHeader() {
- m_resourceRequest.clearHTTPHeaderField("range");
-}
-
-void Resource::revalidationSucceeded(
- const ResourceResponse& validatingResponse) {
- SECURITY_CHECK(m_redirectChain.isEmpty());
- SECURITY_CHECK(equalIgnoringFragmentIdentifier(validatingResponse.url(),
- response().url()));
- m_response.setResourceLoadTiming(validatingResponse.resourceLoadTiming());
-
- // RFC2616 10.3.5
- // Update cached headers from the 304 response
- const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
- for (const auto& header : newHeaders) {
- // Entity headers should not be sent by servers when generating a 304
- // response; misconfigured servers send them anyway. We shouldn't allow such
- // headers to update the original request. We'll base this on the list
- // defined by RFC2616 7.1, with a few additions for extension headers we
- // care about.
- if (!shouldUpdateHeaderAfterRevalidation(header.key))
- continue;
- m_response.setHTTPHeaderField(header.key, header.value);
- }
-
- m_isRevalidating = false;
-}
-
-void Resource::revalidationFailed() {
- SECURITY_CHECK(m_redirectChain.isEmpty());
- clearData();
- m_cacheHandler.clear();
- destroyDecodedDataForFailedRevalidation();
- m_isRevalidating = false;
-}
-
-bool Resource::canReuseRedirectChain() const {
- for (auto& redirect : m_redirectChain) {
- if (!canUseResponse(redirect.m_redirectResponse, m_responseTimestamp))
- return false;
- if (redirect.m_request.cacheControlContainsNoCache() ||
- redirect.m_request.cacheControlContainsNoStore())
- return false;
- }
- return true;
-}
-
-bool Resource::hasCacheControlNoStoreHeader() const {
- return response().cacheControlContainsNoStore() ||
- resourceRequest().cacheControlContainsNoStore();
-}
-
-bool Resource::hasVaryHeader() const {
- return !response().httpHeaderField(HTTPNames::Vary).isNull();
-}
-
-bool Resource::mustRevalidateDueToCacheHeaders() const {
- return !canUseResponse(response(), m_responseTimestamp) ||
- resourceRequest().cacheControlContainsNoCache() ||
- resourceRequest().cacheControlContainsNoStore();
-}
-
-bool Resource::canUseCacheValidator() const {
- if (isLoading() || errorOccurred())
- return false;
-
- if (hasCacheControlNoStoreHeader())
- return false;
-
- // Do not revalidate Resource with redirects. https://crbug.com/613971
- if (!redirectChain().isEmpty())
- return false;
-
- return response().hasCacheValidatorFields() ||
- resourceRequest().hasCacheValidatorFields();
-}
-
-size_t Resource::calculateOverheadSize() const {
- static const int kAverageClientsHashMapSize = 384;
- return sizeof(Resource) + response().memoryUsage() +
- kAverageClientsHashMapSize +
- resourceRequest().url().getString().length() * 2;
-}
-
-void Resource::didChangePriority(ResourceLoadPriority loadPriority,
- int intraPriorityValue) {
- m_resourceRequest.setPriority(loadPriority, intraPriorityValue);
- if (m_loader)
- m_loader->didChangePriority(loadPriority, intraPriorityValue);
-}
-
-// TODO(toyoshim): Consider to generate automatically. https://crbug.com/675515.
-static const char* initiatorTypeNameToString(
- const AtomicString& initiatorTypeName) {
- if (initiatorTypeName == FetchInitiatorTypeNames::css)
- return "CSS resource";
- if (initiatorTypeName == FetchInitiatorTypeNames::document)
- return "Document";
- if (initiatorTypeName == FetchInitiatorTypeNames::icon)
- return "Icon";
- if (initiatorTypeName == FetchInitiatorTypeNames::internal)
- return "Internal resource";
- if (initiatorTypeName == FetchInitiatorTypeNames::link)
- return "Link element resource";
- if (initiatorTypeName == FetchInitiatorTypeNames::processinginstruction)
- return "Processing instruction";
- if (initiatorTypeName == FetchInitiatorTypeNames::texttrack)
- return "Text track";
- if (initiatorTypeName == FetchInitiatorTypeNames::xml)
- return "XML resource";
- if (initiatorTypeName == FetchInitiatorTypeNames::xmlhttprequest)
- return "XMLHttpRequest";
-
- static_assert(
- FetchInitiatorTypeNames::FetchInitiatorTypeNamesCount == 12,
- "New FetchInitiatorTypeNames should be handled correctly here.");
-
- return "Resource";
-}
-
-const char* Resource::resourceTypeToString(
- Type type,
- const AtomicString& fetchInitiatorName) {
- switch (type) {
- case Resource::MainResource:
- return "Main resource";
- case Resource::Image:
- return "Image";
- case Resource::CSSStyleSheet:
- return "CSS stylesheet";
- case Resource::Script:
- return "Script";
- case Resource::Font:
- return "Font";
- case Resource::Raw:
- return initiatorTypeNameToString(fetchInitiatorName);
- case Resource::SVGDocument:
- return "SVG document";
- case Resource::XSLStyleSheet:
- return "XSL stylesheet";
- case Resource::LinkPrefetch:
- return "Link prefetch resource";
- case Resource::TextTrack:
- return "Text track";
- case Resource::ImportResource:
- return "Imported resource";
- case Resource::Media:
- return "Media";
- case Resource::Manifest:
- return "Manifest";
- case Resource::Mock:
- return "Mock";
- }
- NOTREACHED();
- return initiatorTypeNameToString(fetchInitiatorName);
-}
-
-bool Resource::shouldBlockLoadEvent() const {
- return !m_linkPreload && isLoadEventBlockingResourceType();
-}
-
-bool Resource::isLoadEventBlockingResourceType() const {
- switch (m_type) {
- case Resource::MainResource:
- case Resource::Image:
- case Resource::CSSStyleSheet:
- case Resource::Script:
- case Resource::Font:
- case Resource::SVGDocument:
- case Resource::XSLStyleSheet:
- case Resource::ImportResource:
- return true;
- case Resource::Raw:
- case Resource::LinkPrefetch:
- case Resource::TextTrack:
- case Resource::Media:
- case Resource::Manifest:
- case Resource::Mock:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
-} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/fetch/Resource.h ('k') | third_party/WebKit/Source/core/fetch/ResourceClient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698