| 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
|
| index ff49288d3c89a16b80c715ef6e3e207f82c5b55a..10388635e8b089ce6ce277b73831191ef67f5cb8 100644
|
| --- a/third_party/WebKit/Source/core/fetch/Resource.cpp
|
| +++ b/third_party/WebKit/Source/core/fetch/Resource.cpp
|
| @@ -41,6 +41,7 @@
|
| #include "public/platform/Platform.h"
|
| #include "public/platform/WebProcessMemoryDump.h"
|
| #include "public/platform/WebScheduler.h"
|
| +#include "public/platform/WebSecurityOrigin.h"
|
| #include "wtf/CurrentTime.h"
|
| #include "wtf/MathExtras.h"
|
| #include "wtf/StdLibExtras.h"
|
| @@ -92,55 +93,138 @@ static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& heade
|
| return true;
|
| }
|
|
|
| -class Resource::CacheHandler : public CachedMetadataHandler {
|
| +class Resource::CachedMetadataHandlerImpl : public CachedMetadataHandler {
|
| public:
|
| - static CacheHandler* create(Resource* resource)
|
| + static Resource::CachedMetadataHandlerImpl* create(Resource* resource)
|
| {
|
| - return new CacheHandler(resource);
|
| + return new CachedMetadataHandlerImpl(resource);
|
| }
|
| - ~CacheHandler() override { }
|
| + ~CachedMetadataHandlerImpl() override {}
|
| DECLARE_VIRTUAL_TRACE();
|
| void setCachedMetadata(unsigned, const char*, size_t, CacheType) override;
|
| void clearCachedMetadata(CacheType) override;
|
| CachedMetadata* cachedMetadata(unsigned) 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:
|
| - explicit CacheHandler(Resource*);
|
| Member<Resource> m_resource;
|
| };
|
|
|
| -Resource::CacheHandler::CacheHandler(Resource* resource)
|
| +Resource::CachedMetadataHandlerImpl::CachedMetadataHandlerImpl(Resource* resource)
|
| : m_resource(resource)
|
| {
|
| }
|
|
|
| -DEFINE_TRACE(Resource::CacheHandler)
|
| +DEFINE_TRACE(Resource::CachedMetadataHandlerImpl)
|
| {
|
| visitor->trace(m_resource);
|
| CachedMetadataHandler::trace(visitor);
|
| }
|
|
|
| -void Resource::CacheHandler::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size, CacheType type)
|
| +void Resource::CachedMetadataHandlerImpl::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size, CachedMetadataHandler::CacheType cacheType)
|
| {
|
| - m_resource->setCachedMetadata(dataTypeID, data, size, type);
|
| + // 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.
|
| + ASSERT(!m_cachedMetadata);
|
| + m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
|
| + if (cacheType == CachedMetadataHandler::SendToPlatform)
|
| + sendToPlatform();
|
| }
|
|
|
| -void Resource::CacheHandler::clearCachedMetadata(CacheType type)
|
| +void Resource::CachedMetadataHandlerImpl::clearCachedMetadata(CachedMetadataHandler::CacheType cacheType)
|
| {
|
| - m_resource->clearCachedMetadata(type);
|
| + m_cachedMetadata.clear();
|
| + if (cacheType == CachedMetadataHandler::SendToPlatform)
|
| + sendToPlatform();
|
| }
|
|
|
| -CachedMetadata* Resource::CacheHandler::cachedMetadata(unsigned dataTypeID) const
|
| +CachedMetadata* Resource::CachedMetadataHandlerImpl::cachedMetadata(unsigned dataTypeID) const
|
| {
|
| - return m_resource->cachedMetadata(dataTypeID);
|
| + if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
|
| + return nullptr;
|
| + return m_cachedMetadata.get();
|
| }
|
|
|
| -String Resource::CacheHandler::encoding() const
|
| +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.
|
| + ASSERT(!m_cachedMetadata);
|
| + m_cachedMetadata = CachedMetadata::deserialize(data, size);
|
| +}
|
| +
|
| +void Resource::CachedMetadataHandlerImpl::sendToPlatform()
|
| +{
|
| + if (m_cachedMetadata) {
|
| + const Vector<char>& serializedData = m_cachedMetadata->serialize();
|
| + 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->serialize();
|
| + 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());
|
| + }
|
| +}
|
| +
|
| class Resource::ResourceCallback final : public GarbageCollectedFinalized<ResourceCallback> {
|
| public:
|
| static ResourceCallback& callbackHandler();
|
| @@ -231,7 +315,7 @@ Resource::Resource(const ResourceRequest& request, Type type, const ResourceLoad
|
|
|
| // Currently we support the metadata caching only for HTTP family.
|
| if (m_resourceRequest.url().protocolIsInHTTPFamily())
|
| - m_cacheHandler = CacheHandler::create(this);
|
| + m_cacheHandler = CachedMetadataHandlerImpl::create(this);
|
| }
|
|
|
| Resource::~Resource()
|
| @@ -265,6 +349,7 @@ void Resource::load(ResourceFetcher* fetcher)
|
| KURL url = request.url();
|
| request.setAllowStoredCredentials(m_options.allowCredentials == AllowStoredCredentials);
|
|
|
| + m_fetcherSecurityOrigin = fetcher->context().getSecurityOrigin();
|
| m_loader = ResourceLoader::create(fetcher, this);
|
| m_loader->start(request);
|
| // If the request reference is null (i.e., a synchronous revalidation will
|
| @@ -474,6 +559,13 @@ void Resource::willFollowRedirect(ResourceRequest& newRequest, const ResourceRes
|
| m_redirectChain.append(RedirectPair(newRequest, redirectResponse));
|
| }
|
|
|
| +void Resource::setResponse(const ResourceResponse& response)
|
| +{
|
| + m_response = response;
|
| + if (m_response.wasFetchedViaServiceWorker())
|
| + m_cacheHandler = ServiceWorkerResponseCachedMetadataHandler::create(this, m_fetcherSecurityOrigin.get());
|
| +}
|
| +
|
| bool Resource::unlock()
|
| {
|
| if (!m_data)
|
| @@ -508,13 +600,10 @@ void Resource::responseReceived(const ResourceResponse& response, PassOwnPtr<Web
|
|
|
| void Resource::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.
|
| - ASSERT(!m_cachedMetadata);
|
| ASSERT(m_revalidatingRequest.isNull());
|
| -
|
| - m_cachedMetadata = CachedMetadata::deserialize(data, size);
|
| + ASSERT(!m_response.isNull());
|
| + if (m_cacheHandler)
|
| + m_cacheHandler->setSerializedCachedMetadata(data, size);
|
| }
|
|
|
| CachedMetadataHandler* Resource::cacheHandler()
|
| @@ -522,33 +611,6 @@ CachedMetadataHandler* Resource::cacheHandler()
|
| return m_cacheHandler.get();
|
| }
|
|
|
| -void Resource::setCachedMetadata(unsigned 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.
|
| - ASSERT(!m_cachedMetadata);
|
| -
|
| - m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
|
| -
|
| - // We don't support sending the metadata to the platform when the response
|
| - // was fetched via a ServiceWorker to prevent an attacker's Service Worker
|
| - // from poisoning the metadata cache.
|
| - // FIXME: Support sending the metadata even if the response was fetched via
|
| - // a ServiceWorker. https://crbug.com/448706
|
| - if (cacheType == CachedMetadataHandler::SendToPlatform && !m_response.wasFetchedViaServiceWorker()) {
|
| - const Vector<char>& serializedData = m_cachedMetadata->serialize();
|
| - Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
|
| - }
|
| -}
|
| -
|
| -void Resource::clearCachedMetadata(CachedMetadataHandler::CacheType cacheType)
|
| -{
|
| - m_cachedMetadata.clear();
|
| -
|
| - if (cacheType == CachedMetadataHandler::SendToPlatform)
|
| - Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), 0, 0);
|
| -}
|
|
|
| String Resource::reasonNotDeletable() const
|
| {
|
| @@ -586,13 +648,6 @@ String Resource::reasonNotDeletable() const
|
| return builder.toString();
|
| }
|
|
|
| -CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
|
| -{
|
| - if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
|
| - return nullptr;
|
| - return m_cachedMetadata.get();
|
| -}
|
| -
|
| void Resource::clearLoader()
|
| {
|
| m_loader = nullptr;
|
| @@ -878,7 +933,7 @@ void Resource::revalidationFailed()
|
| m_revalidatingRequest = ResourceRequest();
|
| m_redirectChain.clear();
|
| m_data.clear();
|
| - m_cachedMetadata.clear();
|
| + m_cacheHandler.clear();
|
| destroyDecodedDataForFailedRevalidation();
|
| }
|
|
|
|
|