summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/fetch/Resource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/fetch/Resource.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/fetch/Resource.cpp516
1 files changed, 299 insertions, 217 deletions
diff --git a/chromium/third_party/WebKit/Source/core/fetch/Resource.cpp b/chromium/third_party/WebKit/Source/core/fetch/Resource.cpp
index 8f56b290ade..0e83923fd91 100644
--- a/chromium/third_party/WebKit/Source/core/fetch/Resource.cpp
+++ b/chromium/third_party/WebKit/Source/core/fetch/Resource.cpp
@@ -24,6 +24,7 @@
#include "config.h"
#include "core/fetch/Resource.h"
+#include "core/FetchInitiatorTypeNames.h"
#include "core/fetch/CachedMetadata.h"
#include "core/fetch/CrossOriginAccessControl.h"
#include "core/fetch/MemoryCache.h"
@@ -34,8 +35,8 @@
#include "core/fetch/ResourcePtr.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "platform/Logging.h"
-#include "platform/PurgeableBuffer.h"
#include "platform/SharedBuffer.h"
+#include "platform/TraceEvent.h"
#include "platform/weborigin/KURL.h"
#include "public/platform/Platform.h"
#include "wtf/CurrentTime.h"
@@ -97,32 +98,24 @@ Resource::Resource(const ResourceRequest& request, Type type)
: m_resourceRequest(request)
, m_responseTimestamp(currentTime())
, m_cancelTimer(this, &Resource::cancelTimerFired)
- , m_lastDecodedAccessTime(0)
, m_loadFinishTime(0)
, m_identifier(0)
, m_encodedSize(0)
, m_decodedSize(0)
- , m_accessCount(0)
, m_handleCount(0)
, m_preloadCount(0)
, m_protectorCount(0)
, m_preloadResult(PreloadNotReferenced)
- , m_cacheLiveResourcePriority(CacheLiveResourcePriorityLow)
- , m_inLiveDecodedResourcesList(false)
, m_requestedFromNetworkingLayer(false)
- , m_inCache(false)
, m_loading(false)
, m_switchingClientsToRevalidatedResource(false)
, m_type(type)
, m_status(Pending)
-#ifndef NDEBUG
+ , m_wasPurged(false)
+ , m_needsSynchronousCacheHit(false)
+#ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
, m_deleted(false)
- , m_lruIndex(0)
#endif
- , m_nextInAllResourcesList(0)
- , m_prevInAllResourcesList(0)
- , m_nextInLiveResourcesList(0)
- , m_prevInLiveResourcesList(0)
, m_resourceToRevalidate(0)
, m_proxyResource(0)
{
@@ -144,12 +137,15 @@ Resource::~Resource()
{
ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() checks this.
ASSERT(canDelete());
- ASSERT(!inCache());
- ASSERT(!m_deleted);
+ RELEASE_ASSERT(!memoryCache()->contains(this));
+ RELEASE_ASSERT(!ResourceCallback::callbackHandler()->isScheduled(this));
ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
+ assertAlive();
-#ifndef NDEBUG
+#ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
m_deleted = true;
+#endif
+#ifndef NDEBUG
cachedResourceLeakCounter.decrement();
#endif
}
@@ -212,7 +208,7 @@ void Resource::appendData(const char* data, int length)
if (m_data)
m_data->append(data, length);
else
- m_data = SharedBuffer::create(data, length);
+ m_data = SharedBuffer::createPurgeable(data, length);
setEncodedSize(m_data->size());
}
@@ -225,6 +221,13 @@ void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer)
setEncodedSize(m_data->size());
}
+void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
+{
+ m_options.dataBufferingPolicy = dataBufferingPolicy;
+ m_data.clear();
+ setEncodedSize(0);
+}
+
void Resource::error(Resource::Status status)
{
if (m_resourceToRevalidate)
@@ -265,57 +268,109 @@ bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
{
- return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
+ return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowStoredCredentials() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
}
-bool Resource::isExpired() const
-{
- if (m_response.isNull())
- return false;
-
- return currentAge() > freshnessLifetime();
-}
-
-double Resource::currentAge() const
+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 = m_response.date();
- double apparentAge = std::isfinite(dateValue) ? std::max(0., m_responseTimestamp - dateValue) : 0;
- double ageValue = m_response.age();
+ 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() - m_responseTimestamp;
+ double residentTime = currentTime() - responseTimestamp;
return correctedReceivedAge + residentTime;
}
-double Resource::freshnessLifetime() const
+static double freshnessLifetime(ResourceResponse& response, double responseTimestamp)
{
#if !OS(ANDROID)
// On desktop, local files should be reloaded in case they change.
- if (m_response.url().isLocalFile())
+ if (response.url().isLocalFile())
return 0;
#endif
- // Cache other non-http resources liberally.
- if (!m_response.url().protocolIsInHTTPFamily())
+ // 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 = m_response.cacheControlMaxAge();
+ double maxAgeValue = response.cacheControlMaxAge();
if (std::isfinite(maxAgeValue))
return maxAgeValue;
- double expiresValue = m_response.expires();
- double dateValue = m_response.date();
- double creationTime = std::isfinite(dateValue) ? dateValue : m_responseTimestamp;
+ double expiresValue = response.expires();
+ double dateValue = response.date();
+ double creationTime = std::isfinite(dateValue) ? dateValue : responseTimestamp;
if (std::isfinite(expiresValue))
return expiresValue - creationTime;
- double lastModifiedValue = m_response.lastModified();
+ 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;
}
+static bool canUseResponse(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()
+{
+ if (!m_redirectChain.size())
+ return m_resourceRequest;
+ return m_redirectChain.last().m_request;
+}
+
+void Resource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
+{
+ m_redirectChain.append(RedirectPair(request, response));
+ m_requestedFromNetworkingLayer = true;
+}
+
+bool Resource::unlock()
+{
+ if (!m_data)
+ return false;
+
+ if (!m_data->isLocked())
+ return true;
+
+ if (!memoryCache()->contains(this) || hasClients() || m_handleCount > 1 || m_proxyResource || m_resourceToRevalidate || !m_loadFinishTime || !isSafeToUnlock())
+ return false;
+
+ m_data->unlock();
+ return true;
+}
+
+bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const
+{
+ return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0);
+}
+
void Resource::responseReceived(const ResourceResponse& response)
{
setResponse(response);
@@ -355,6 +410,17 @@ void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t s
blink::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
}
+bool Resource::canDelete() const
+{
+ return !hasClients() && !m_loader && !m_preloadCount && hasRightHandleCountApartFromCache(0)
+ && !m_protectorCount && !m_resourceToRevalidate && !m_proxyResource;
+}
+
+bool Resource::hasOneHandle() const
+{
+ return hasRightHandleCountApartFromCache(1);
+}
+
CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
{
if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
@@ -362,19 +428,9 @@ CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
return m_cachedMetadata.get();
}
-void Resource::setCacheLiveResourcePriority(CacheLiveResourcePriority priority)
-{
- if (inCache() && m_inLiveDecodedResourcesList && cacheLiveResourcePriority() != static_cast<unsigned>(priority)) {
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- m_cacheLiveResourcePriority = priority;
- memoryCache()->insertInLiveDecodedResourcesList(this);
- memoryCache()->prune();
- }
-}
-
void Resource::clearLoader()
{
- m_loader = 0;
+ m_loader = nullptr;
}
void Resource::addClient(ResourceClient* client)
@@ -420,11 +476,11 @@ bool Resource::addClientToSet(ResourceClient* client)
else
m_preloadResult = PreloadReferenced;
}
- if (!hasClients() && inCache())
- memoryCache()->addToLiveResourcesSize(this);
+ if (!hasClients())
+ memoryCache()->makeLive(this);
// If we have existing data to send to the new client and the resource type supprts it, send it asynchronously.
- if (!m_response.isNull() && !m_proxyResource && !shouldSendCachedDataSynchronouslyForType(type())) {
+ if (!m_response.isNull() && !m_proxyResource && !shouldSendCachedDataSynchronouslyForType(type()) && !m_needsSynchronousCacheHit) {
m_clientsAwaitingCallback.add(client);
ResourceCallback::callbackHandler()->schedule(this);
return false;
@@ -439,29 +495,28 @@ void Resource::removeClient(ResourceClient* client)
if (m_clientsAwaitingCallback.contains(client)) {
ASSERT(!m_clients.contains(client));
m_clientsAwaitingCallback.remove(client);
- if (m_clientsAwaitingCallback.isEmpty())
- ResourceCallback::callbackHandler()->cancel(this);
} else {
ASSERT(m_clients.contains(client));
m_clients.remove(client);
didRemoveClient(client);
}
+ if (m_clientsAwaitingCallback.isEmpty())
+ ResourceCallback::callbackHandler()->cancel(this);
+
bool deleted = deleteIfPossible();
if (!deleted && !hasClients()) {
- if (inCache()) {
- memoryCache()->removeFromLiveResourcesSize(this);
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- }
+ memoryCache()->makeDead(this);
if (!m_switchingClientsToRevalidatedResource)
allClientsRemoved();
- if (response().cacheControlContainsNoStore()) {
- // 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 (url().protocolIs("https"))
- memoryCache()->remove(this);
+
+ // 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);
+ memoryCache()->prune();
} else {
memoryCache()->prune(this);
}
@@ -476,7 +531,9 @@ void Resource::allClientsRemoved()
if (m_type == MainResource || m_type == Raw)
cancelTimerFired(&m_cancelTimer);
else if (!m_cancelTimer.isActive())
- m_cancelTimer.startOneShot(0);
+ m_cancelTimer.startOneShot(0, FROM_HERE);
+
+ unlock();
}
void Resource::cancelTimerFired(Timer<Resource>* timer)
@@ -492,7 +549,7 @@ void Resource::cancelTimerFired(Timer<Resource>* timer)
bool Resource::deleteIfPossible()
{
- if (canDelete() && !inCache()) {
+ if (canDelete() && !memoryCache()->contains(this)) {
InspectorInstrumentation::willDestroyResource(this);
delete this;
return true;
@@ -500,86 +557,69 @@ bool Resource::deleteIfPossible()
return false;
}
-void Resource::setDecodedSize(size_t size)
+void Resource::setDecodedSize(size_t decodedSize)
{
- if (size == m_decodedSize)
+ if (decodedSize == m_decodedSize)
return;
-
- ptrdiff_t delta = size - m_decodedSize;
-
- // The object must now be moved to a different queue, since its size has been changed.
- // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
- // queue.
- if (inCache())
- memoryCache()->removeFromLRUList(this);
-
- m_decodedSize = size;
-
- if (inCache()) {
- // Now insert into the new LRU list.
- memoryCache()->insertInLRUList(this);
-
- // Insert into or remove from the live decoded list if necessary.
- // When inserting into the LiveDecodedResourcesList it is possible
- // that the m_lastDecodedAccessTime is still zero or smaller than
- // the m_lastDecodedAccessTime of the current list head. This is a
- // violation of the invariant that the list is to be kept sorted
- // by access time. The weakening of the invariant does not pose
- // a problem. For more details please see: https://bugs.webkit.org/show_bug.cgi?id=30209
- if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
- memoryCache()->insertInLiveDecodedResourcesList(this);
- else if (!m_decodedSize && m_inLiveDecodedResourcesList)
- memoryCache()->removeFromLiveDecodedResourcesList(this);
-
- // Update the cache's size totals.
- memoryCache()->adjustSize(hasClients(), delta);
- }
+ size_t oldSize = size();
+ m_decodedSize = decodedSize;
+ memoryCache()->update(this, oldSize, size());
+ memoryCache()->updateDecodedResource(this, UpdateForPropertyChange);
}
-void Resource::setEncodedSize(size_t size)
+void Resource::setEncodedSize(size_t encodedSize)
{
- if (size == m_encodedSize)
+ if (encodedSize == m_encodedSize)
return;
-
- ptrdiff_t delta = size - m_encodedSize;
-
- // The object must now be moved to a different queue, since its size has been changed.
- // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
- // queue.
- if (inCache())
- memoryCache()->removeFromLRUList(this);
-
- m_encodedSize = size;
-
- if (inCache()) {
- // Now insert into the new LRU list.
- memoryCache()->insertInLRUList(this);
-
- // Update the cache's size totals.
- memoryCache()->adjustSize(hasClients(), delta);
- }
+ size_t oldSize = size();
+ m_encodedSize = encodedSize;
+ memoryCache()->update(this, oldSize, size());
}
-void Resource::didAccessDecodedData(double timeStamp)
+void Resource::didAccessDecodedData()
{
- m_lastDecodedAccessTime = timeStamp;
- if (inCache()) {
- if (m_inLiveDecodedResourcesList) {
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- memoryCache()->insertInLiveDecodedResourcesList(this);
- }
- memoryCache()->prune();
- }
+ memoryCache()->updateDecodedResource(this, UpdateForAccess);
+ memoryCache()->prune();
}
void Resource::finishPendingClients()
{
- while (!m_clientsAwaitingCallback.isEmpty()) {
- ResourceClient* client = m_clientsAwaitingCallback.begin()->key;
- m_clientsAwaitingCallback.remove(client);
+ // 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.
+ Vector<ResourceClient*> clientsToNotify;
+ copyToVector(m_clientsAwaitingCallback, clientsToNotify);
+
+ for (size_t i = 0; i < clientsToNotify.size(); ++i) {
+ ResourceClient* client = clientsToNotify[i];
+
+ // Handle case (2) to skip removed clients.
+ if (!m_clientsAwaitingCallback.remove(client))
+ continue;
m_clients.add(client);
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.
+ ASSERT(m_clientsAwaitingCallback.isEmpty() || scheduled);
+}
+
+void Resource::prune()
+{
+ destroyDecodedDataIfPossible();
+ unlock();
}
void Resource::setResourceToRevalidate(Resource* resource)
@@ -620,8 +660,8 @@ void Resource::clearResourceToRevalidate()
void Resource::switchClientsToRevalidatedResource()
{
ASSERT(m_resourceToRevalidate);
- ASSERT(m_resourceToRevalidate->inCache());
- ASSERT(!inCache());
+ ASSERT(memoryCache()->contains(m_resourceToRevalidate));
+ ASSERT(!memoryCache()->contains(this));
WTF_LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
@@ -690,9 +730,8 @@ void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatin
void Resource::revalidationSucceeded(const ResourceResponse& response)
{
ASSERT(m_resourceToRevalidate);
- ASSERT(!m_resourceToRevalidate->inCache());
+ ASSERT(!memoryCache()->contains(m_resourceToRevalidate));
ASSERT(m_resourceToRevalidate->isLoaded());
- ASSERT(inCache());
// Calling evict() can potentially delete revalidatingResource, which we use
// below. This mustn't be the case since revalidation means it is loaded
@@ -703,7 +742,7 @@ void Resource::revalidationSucceeded(const ResourceResponse& response)
memoryCache()->replace(m_resourceToRevalidate, this);
switchClientsToRevalidatedResource();
- ASSERT(!m_deleted);
+ assertAlive();
// clearResourceToRevalidate deletes this.
clearResourceToRevalidate();
}
@@ -716,24 +755,9 @@ void Resource::revalidationFailed()
clearResourceToRevalidate();
}
-void Resource::updateForAccess()
-{
- ASSERT(inCache());
-
- // Need to make sure to remove before we increase the access count, since
- // the queue will possibly change.
- memoryCache()->removeFromLRUList(this);
-
- // If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
- if (!m_accessCount)
- memoryCache()->adjustSize(hasClients(), size());
-
- m_accessCount++;
- memoryCache()->insertInLRUList(this);
-}
-
void Resource::registerHandle(ResourcePtrBase* h)
{
+ assertAlive();
++m_handleCount;
if (m_resourceToRevalidate)
m_handlesToRevalidate.add(h);
@@ -741,105 +765,91 @@ void Resource::registerHandle(ResourcePtrBase* h)
void Resource::unregisterHandle(ResourcePtrBase* h)
{
+ assertAlive();
ASSERT(m_handleCount > 0);
--m_handleCount;
if (m_resourceToRevalidate)
m_handlesToRevalidate.remove(h);
- if (!m_handleCount)
- deleteIfPossible();
+ if (!m_handleCount) {
+ if (deleteIfPossible())
+ return;
+ unlock();
+ } else if (m_handleCount == 1 && memoryCache()->contains(this)) {
+ unlock();
+ if (!hasClients())
+ memoryCache()->prune(this);
+ }
}
-bool Resource::canUseCacheValidator() const
+bool Resource::canReuseRedirectChain()
{
- if (m_loading || errorOccurred())
- return false;
-
- if (m_response.cacheControlContainsNoStore())
- return false;
- return m_response.hasCacheValidatorFields();
+ for (size_t i = 0; i < m_redirectChain.size(); ++i) {
+ if (!canUseResponse(m_redirectChain[i].m_redirectResponse, m_responseTimestamp))
+ return false;
+ if (m_redirectChain[i].m_request.cacheControlContainsNoCache() || m_redirectChain[i].m_request.cacheControlContainsNoStore())
+ return false;
+ }
+ return true;
}
-bool Resource::mustRevalidateDueToCacheHeaders() const
+bool Resource::hasCacheControlNoStoreHeader()
{
- if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
- WTF_LOG(ResourceLoading, "Resource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
- return true;
- }
-
- if (isExpired()) {
- WTF_LOG(ResourceLoading, "Resource %p mustRevalidate because of isExpired()\n", this);
- return true;
- }
-
- return false;
+ return m_response.cacheControlContainsNoStore() || m_resourceRequest.cacheControlContainsNoStore();
}
-bool Resource::isSafeToMakePurgeable() const
+bool Resource::mustRevalidateDueToCacheHeaders()
{
- return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
+ return !canUseResponse(m_response, m_responseTimestamp) || m_resourceRequest.cacheControlContainsNoCache() || m_resourceRequest.cacheControlContainsNoStore();
}
-bool Resource::makePurgeable(bool purgeable)
+bool Resource::canUseCacheValidator()
{
- if (purgeable) {
- ASSERT(isSafeToMakePurgeable());
+ if (m_loading || errorOccurred())
+ return false;
- if (m_purgeableData) {
- ASSERT(!m_data);
- return true;
- }
- if (!m_data)
- return false;
+ if (hasCacheControlNoStoreHeader())
+ return false;
+ return m_response.hasCacheValidatorFields() || m_resourceRequest.hasCacheValidatorFields();
+}
- // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
- if (!m_data->hasOneRef())
- return false;
+bool Resource::isPurgeable() const
+{
+ return m_data && !m_data->isLocked();
+}
- m_data->createPurgeableBuffer();
- if (!m_data->hasPurgeableBuffer())
- return false;
+bool Resource::wasPurged() const
+{
+ return m_wasPurged;
+}
- m_purgeableData = m_data->releasePurgeableBuffer();
- m_purgeableData->unlock();
- m_data.clear();
+bool Resource::lock()
+{
+ if (!m_data)
return true;
- }
-
- if (!m_purgeableData)
+ if (m_data->isLocked())
return true;
- ASSERT(!m_data);
ASSERT(!hasClients());
- if (!m_purgeableData->lock())
+ if (!m_data->lock()) {
+ m_wasPurged = true;
return false;
-
- m_data = SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release());
+ }
return true;
}
-bool Resource::isPurgeable() const
-{
- return m_purgeableData && m_purgeableData->isPurgeable();
-}
-
-bool Resource::wasPurged() const
-{
- return m_purgeableData && m_purgeableData->wasPurged();
-}
-
size_t Resource::overheadSize() const
{
static const int kAverageClientsHashMapSize = 384;
return sizeof(Resource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
}
-void Resource::didChangePriority(ResourceLoadPriority loadPriority)
+void Resource::didChangePriority(ResourceLoadPriority loadPriority, int intraPriorityValue)
{
if (m_loader)
- m_loader->didChangePriority(loadPriority);
+ m_loader->didChangePriority(loadPriority, intraPriorityValue);
}
Resource::ResourceCallback* Resource::ResourceCallback::callbackHandler()
@@ -856,17 +866,24 @@ Resource::ResourceCallback::ResourceCallback()
void Resource::ResourceCallback::schedule(Resource* resource)
{
if (!m_callbackTimer.isActive())
- m_callbackTimer.startOneShot(0);
+ m_callbackTimer.startOneShot(0, FROM_HERE);
+ resource->assertAlive();
m_resourcesWithPendingClients.add(resource);
}
void Resource::ResourceCallback::cancel(Resource* resource)
{
+ resource->assertAlive();
m_resourcesWithPendingClients.remove(resource);
if (m_callbackTimer.isActive() && m_resourcesWithPendingClients.isEmpty())
m_callbackTimer.stop();
}
+bool Resource::ResourceCallback::isScheduled(Resource* resource) const
+{
+ return m_resourcesWithPendingClients.contains(resource);
+}
+
void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
{
HashSet<Resource*>::iterator end = m_resourcesWithPendingClients.end();
@@ -874,8 +891,73 @@ void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
for (HashSet<Resource*>::iterator it = m_resourcesWithPendingClients.begin(); it != end; ++it)
resources.append(*it);
m_resourcesWithPendingClients.clear();
- for (size_t i = 0; i < resources.size(); i++)
+
+ for (size_t i = 0; i < resources.size(); i++) {
+ resources[i]->assertAlive();
resources[i]->finishPendingClients();
+ resources[i]->assertAlive();
+ }
+
+ for (size_t i = 0; i < resources.size(); i++)
+ resources[i]->assertAlive();
+}
+
+static const char* initatorTypeNameToString(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";
+
+ return "Resource";
+}
+
+const char* Resource::resourceTypeToString(Type type, const FetchInitiatorInfo& initiatorInfo)
+{
+ 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 initatorTypeNameToString(initiatorInfo.name);
+ case Resource::SVGDocument:
+ return "SVG document";
+ case Resource::XSLStyleSheet:
+ return "XSL stylesheet";
+ case Resource::LinkPrefetch:
+ return "Link prefetch resource";
+ case Resource::LinkSubresource:
+ return "Link subresource";
+ case Resource::TextTrack:
+ return "Text track";
+ case Resource::ImportResource:
+ return "Imported resource";
+ case Resource::Media:
+ return "Media";
+ }
+ ASSERT_NOT_REACHED();
+ return initatorTypeNameToString(initiatorInfo.name);
}
#if !LOG_DISABLED
@@ -904,10 +986,10 @@ const char* ResourceTypeName(Resource::Type type)
return "LinkSubresource";
case Resource::TextTrack:
return "TextTrack";
- case Resource::Shader:
- return "Shader";
case Resource::ImportResource:
return "ImportResource";
+ case Resource::Media:
+ return "Media";
}
ASSERT_NOT_REACHED();
return "Unknown";