Index: third_party/WebKit/Source/platform/loader/fetch/Resource.cpp |
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp |
index 34f21f4f07c7fc31db107c60389302a999569710..25b8de4b956b3ccf6896374304e2e59d53af7c8a 100644 |
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp |
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp |
@@ -36,6 +36,7 @@ |
#include "platform/instrumentation/tracing/TraceEvent.h" |
#include "platform/loader/fetch/CachedMetadata.h" |
#include "platform/loader/fetch/CrossOriginAccessControl.h" |
+#include "platform/loader/fetch/FetchContext.h" |
#include "platform/loader/fetch/FetchInitiatorTypeNames.h" |
#include "platform/loader/fetch/FetchRequest.h" |
#include "platform/loader/fetch/IntegrityMetadata.h" |
@@ -58,6 +59,64 @@ |
namespace blink { |
+namespace { |
+ |
+class StaticResourceCallback final : public Resource::ResourceCallback { |
+ public: |
+ StaticResourceCallback(); |
+ ~StaticResourceCallback() override; |
+ void schedule(Resource*) override; |
+ void cancel(Resource*) override; |
+ bool isScheduled(Resource*) const override; |
+ |
+ private: |
+ void runTask(); |
+ |
+ TaskHandle m_taskHandle; |
+ HashSet<Persistent<Resource>> m_resourcesWithPendingClients; |
+}; |
+ |
+StaticResourceCallback::StaticResourceCallback() {} |
+StaticResourceCallback::~StaticResourceCallback() {} |
+ |
+void StaticResourceCallback::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(&StaticResourceCallback::runTask, |
+ WTF::unretained(this))); |
+ } |
+ m_resourcesWithPendingClients.insert(resource); |
+} |
+ |
+void StaticResourceCallback::cancel(Resource* resource) { |
+ m_resourcesWithPendingClients.erase(resource); |
+ if (m_taskHandle.isActive() && m_resourcesWithPendingClients.isEmpty()) |
+ m_taskHandle.cancel(); |
+} |
+ |
+bool StaticResourceCallback::isScheduled(Resource* resource) const { |
+ return m_resourcesWithPendingClients.contains(resource); |
+} |
+ |
+void StaticResourceCallback::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(); |
+} |
+ |
+} // namespace |
+ |
// 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. |
@@ -241,70 +300,10 @@ void Resource::ServiceWorkerResponseCachedMetadataHandler::sendToPlatform() { |
} |
} |
-// 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.insert(resource); |
-} |
- |
-void Resource::ResourceCallback::cancel(Resource* resource) { |
- m_resourcesWithPendingClients.erase(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(); |
-} |
- |
Resource::Resource(const ResourceRequest& request, |
Type type, |
- const ResourceLoaderOptions& options) |
+ const ResourceLoaderOptions& options, |
+ FetchContext* fetchContext) |
: m_loadFinishTime(0), |
m_identifier(0), |
m_encodedSize(0), |
@@ -325,16 +324,20 @@ Resource::Resource(const ResourceRequest& request, |
m_integrityDisposition(ResourceIntegrityDisposition::NotChecked), |
m_options(options), |
m_responseTimestamp(currentTime()), |
- m_cancelTimer(Platform::current()->mainThread()->getWebTaskRunner(), |
+ m_cancelTimer(fetchContext && fetchContext->timerTaskRunner() |
+ ? fetchContext->timerTaskRunner() |
+ : Platform::current()->mainThread()->getWebTaskRunner(), |
this, |
&Resource::cancelTimerFired), |
+ m_fetchContext(fetchContext), |
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); |
+ if (isMainThread()) |
+ MemoryCoordinator::instance().registerClient(this); |
} |
Resource::~Resource() { |
@@ -343,6 +346,7 @@ Resource::~Resource() { |
DEFINE_TRACE(Resource) { |
visitor->trace(m_loader); |
+ visitor->trace(m_fetchContext); |
visitor->trace(m_cacheHandler); |
visitor->trace(m_clients); |
visitor->trace(m_clientsAwaitingCallback); |
@@ -412,7 +416,7 @@ void Resource::error(const ResourceError& error) { |
m_error = error; |
m_isRevalidating = false; |
- if (m_error.isCancellation() || !isPreloaded()) |
+ if ((m_error.isCancellation() || !isPreloaded()) && isMainThread()) |
memoryCache()->remove(this); |
if (!errorOccurred()) |
@@ -648,7 +652,7 @@ String Resource::reasonNotDeletable() const { |
builder.appendNumber(m_preloadCount); |
builder.append(')'); |
} |
- if (memoryCache()->contains(this)) { |
+ if (isMainThread() && memoryCache()->contains(this)) { |
if (!builder.isEmpty()) |
builder.append(' '); |
builder.append("in_memory_cache"); |
@@ -722,7 +726,7 @@ void Resource::addClient(ResourceClient* client, |
if ((errorOccurred() || !response().isNull()) && |
!typeNeedsSynchronousCacheHit(getType()) && !m_needsSynchronousCacheHit) { |
m_clientsAwaitingCallback.insert(client); |
- ResourceCallback::callbackHandler().schedule(this); |
+ resourceCallback().schedule(this); |
return; |
} |
@@ -745,7 +749,7 @@ void Resource::removeClient(ResourceClient* client) { |
m_clients.erase(client); |
if (m_clientsAwaitingCallback.isEmpty()) |
- ResourceCallback::callbackHandler().cancel(this); |
+ resourceCallback().cancel(this); |
didRemoveClientOrObserver(); |
} |
@@ -762,8 +766,10 @@ void Resource::didRemoveClientOrObserver() { |
// 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")) |
+ if (hasCacheControlNoStoreHeader() && url().protocolIs("https") && |
+ isMainThread()) { |
memoryCache()->remove(this); |
+ } |
} |
} |
@@ -785,7 +791,8 @@ void Resource::setDecodedSize(size_t decodedSize) { |
return; |
size_t oldSize = size(); |
m_decodedSize = decodedSize; |
- memoryCache()->update(this, oldSize, size()); |
+ if (isMainThread()) |
+ memoryCache()->update(this, oldSize, size()); |
} |
void Resource::setEncodedSize(size_t encodedSize) { |
@@ -794,7 +801,8 @@ void Resource::setEncodedSize(size_t encodedSize) { |
size_t oldSize = size(); |
m_encodedSize = encodedSize; |
m_encodedSizeMemoryUsage = encodedSize; |
- memoryCache()->update(this, oldSize, size()); |
+ if (isMainThread()) |
+ memoryCache()->update(this, oldSize, size()); |
} |
void Resource::finishPendingClients() { |
@@ -826,9 +834,9 @@ void Resource::finishPendingClients() { |
// 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); |
+ bool scheduled = resourceCallback().isScheduled(this); |
if (scheduled && m_clientsAwaitingCallback.isEmpty()) |
- ResourceCallback::callbackHandler().cancel(this); |
+ resourceCallback().cancel(this); |
// Prevent the case when there are clients waiting but no callback scheduled. |
DCHECK(m_clientsAwaitingCallback.isEmpty() || scheduled); |
@@ -1125,4 +1133,14 @@ bool Resource::isLoadEventBlockingResourceType() const { |
return false; |
} |
+Resource::ResourceCallback& Resource::resourceCallback() { |
+ if (m_fetchContext && m_fetchContext->resourceCallback()) { |
+ DCHECK(!isMainThread()); |
+ return *m_fetchContext->resourceCallback(); |
+ } |
+ DCHECK(isMainThread()); |
+ DEFINE_STATIC_LOCAL(StaticResourceCallback, callbackHandler, ()); |
+ return callbackHandler; |
+} |
+ |
} // namespace blink |