#include "config.h"
#include "core/fetch/Resource.h"
-#include "FetchInitiatorTypeNames.h"
+#include "core/FetchInitiatorTypeNames.h"
#include "core/fetch/CachedMetadata.h"
#include "core/fetch/CrossOriginAccessControl.h"
#include "core/fetch/MemoryCache.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "platform/Logging.h"
#include "platform/SharedBuffer.h"
+#include "platform/TraceEvent.h"
#include "platform/weborigin/KURL.h"
#include "public/platform/Platform.h"
#include "wtf/CurrentTime.h"
using namespace WTF;
-namespace WebCore {
+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
}
DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
+unsigned Resource::s_instanceCount = 0;
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_handleCount(0)
, m_preloadCount(0)
, m_protectorCount(0)
+ , m_cacheIdentifier(MemoryCache::defaultCacheIdentifier())
, m_preloadResult(PreloadNotReferenced)
- , m_cacheLiveResourcePriority(CacheLiveResourcePriorityLow)
, m_requestedFromNetworkingLayer(false)
, m_loading(false)
, m_switchingClientsToRevalidatedResource(false)
#ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
, m_deleted(false)
#endif
- , m_resourceToRevalidate(0)
- , m_proxyResource(0)
+ , m_resourceToRevalidate(nullptr)
+ , m_proxyResource(nullptr)
{
ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests careless updates of the enum.
+ ++s_instanceCount;
#ifndef NDEBUG
cachedResourceLeakCounter.increment();
#endif
+ memoryCache()->registerLiveResource(*this);
if (!m_resourceRequest.url().hasFragmentIdentifier())
return;
ASSERT(canDelete());
RELEASE_ASSERT(!memoryCache()->contains(this));
RELEASE_ASSERT(!ResourceCallback::callbackHandler()->isScheduled(this));
- ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
assertAlive();
#ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
#ifndef NDEBUG
cachedResourceLeakCounter.decrement();
#endif
+ --s_instanceCount;
+}
+
+void Resource::dispose()
+{
+}
+
+void Resource::trace(Visitor* visitor)
+{
+ visitor->trace(m_loader);
+ visitor->trace(m_resourceToRevalidate);
+ visitor->trace(m_proxyResource);
}
void Resource::failBeforeStarting()
c->notifyFinished(this);
}
-void Resource::appendData(const char* data, int length)
+void Resource::appendData(const char* data, unsigned length)
{
- TRACE_EVENT0("webkit", "Resource::appendData");
+ TRACE_EVENT0("blink", "Resource::appendData");
ASSERT(!m_resourceToRevalidate);
ASSERT(!errorOccurred());
if (m_options.dataBufferingPolicy == DoNotBufferData)
checkNotify();
}
-void Resource::finish(double finishTime)
+void Resource::finish()
{
ASSERT(!m_resourceToRevalidate);
ASSERT(!errorOccurred());
- m_loadFinishTime = finishTime;
finishOnePart();
if (!errorOccurred())
m_status = Cached;
bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
{
- return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowStoredCredentials() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
+ return blink::passesAccessControlCheck(m_response, resourceRequest().allowStoredCredentials() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
}
static double currentAge(const ResourceResponse& response, double responseTimestamp)
return correctedReceivedAge + residentTime;
}
-static double freshnessLifetime(const ResourceResponse& response, double responseTimestamp)
+static double freshnessLifetime(ResourceResponse& response, double responseTimestamp)
{
#if !OS(ANDROID)
// On desktop, local files should be reloaded in case they change.
return 0;
}
-static bool canUseResponse(const ResourceResponse& response, double responseTimestamp)
+static bool canUseResponse(ResourceResponse& response, double responseTimestamp)
{
if (response.isNull())
return false;
return currentAge(response, responseTimestamp) <= freshnessLifetime(response, responseTimestamp);
}
-const ResourceRequest& Resource::lastResourceRequest()
+const ResourceRequest& Resource::lastResourceRequest() const
{
if (!m_redirectChain.size())
return m_resourceRequest;
return m_redirectChain.last().m_request;
}
-void Resource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
+void Resource::willFollowRedirect(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
{
- m_redirectChain.append(RedirectPair(request, response));
+ m_redirectChain.append(RedirectPair(newRequest, redirectResponse));
m_requestedFromNetworkingLayer = true;
}
return true;
}
-void Resource::responseReceived(const ResourceResponse& response)
+bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const
+{
+ return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0);
+}
+
+void Resource::responseReceived(const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle>)
{
setResponse(response);
m_responseTimestamp = currentTime();
m_cachedMetadata = CachedMetadata::deserialize(data, size);
}
-void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size)
+void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size, MetadataCacheType 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
ASSERT(!m_cachedMetadata);
m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
- const Vector<char>& serializedData = m_cachedMetadata->serialize();
- blink::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
+
+ if (cacheType == SendToPlatform) {
+ const Vector<char>& serializedData = m_cachedMetadata->serialize();
+ blink::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
+ }
}
-CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
+void Resource::clearCachedMetadata()
{
- if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
- return 0;
- return m_cachedMetadata.get();
+ m_cachedMetadata.clear();
}
-void Resource::setCacheLiveResourcePriority(CacheLiveResourcePriority priority)
+bool Resource::canDelete() const
{
- if (memoryCache()->contains(this) && memoryCache()->isInLiveDecodedResourcesList(this) && cacheLiveResourcePriority() != static_cast<unsigned>(priority)) {
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- m_cacheLiveResourcePriority = priority;
- memoryCache()->insertInLiveDecodedResourcesList(this);
- memoryCache()->prune();
- }
+ 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)
+ return nullptr;
+ return m_cachedMetadata.get();
}
void Resource::clearLoader()
else
m_preloadResult = PreloadReferenced;
}
- if (!hasClients() && memoryCache()->contains(this))
- 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()) && !m_needsSynchronousCacheHit) {
bool deleted = deleteIfPossible();
if (!deleted && !hasClients()) {
- if (memoryCache()->contains(this)) {
- memoryCache()->removeFromLiveResourcesSize(this);
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- }
+ memoryCache()->makeDead(this);
if (!m_switchingClientsToRevalidatedResource)
allClientsRemoved();
// "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 (response().cacheControlContainsNoStore() && url().protocolIs("https")) {
+ if (hasCacheControlNoStoreHeader() && url().protocolIs("https")) {
memoryCache()->remove(this);
memoryCache()->prune();
} else {
{
if (canDelete() && !memoryCache()->contains(this)) {
InspectorInstrumentation::willDestroyResource(this);
+ dispose();
+ memoryCache()->unregisterLiveResource(*this);
+#if !ENABLE(OILPAN)
delete this;
+#endif
return true;
}
return false;
return;
size_t oldSize = size();
m_decodedSize = decodedSize;
-
- if (memoryCache()->contains(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 && !memoryCache()->isInLiveDecodedResourcesList(this) && hasClients())
- memoryCache()->insertInLiveDecodedResourcesList(this);
- else if (!m_decodedSize && memoryCache()->isInLiveDecodedResourcesList(this))
- memoryCache()->removeFromLiveDecodedResourcesList(this);
-
- // Update the cache's size totals.
- memoryCache()->update(this, oldSize, size());
- }
+ memoryCache()->update(this, oldSize, size());
+ memoryCache()->updateDecodedResource(this, UpdateForPropertyChange);
}
void Resource::setEncodedSize(size_t encodedSize)
return;
size_t oldSize = size();
m_encodedSize = encodedSize;
- if (memoryCache()->contains(this))
- memoryCache()->update(this, oldSize, size());
+ memoryCache()->update(this, oldSize, size());
}
-void Resource::didAccessDecodedData(double timeStamp)
+void Resource::didAccessDecodedData()
{
- m_lastDecodedAccessTime = timeStamp;
- if (memoryCache()->contains(this)) {
- if (memoryCache()->isInLiveDecodedResourcesList(this)) {
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- memoryCache()->insertInLiveDecodedResourcesList(this);
- }
- memoryCache()->prune();
- }
+ memoryCache()->updateDecodedResource(this, UpdateForAccess);
+ memoryCache()->prune();
}
void Resource::finishPendingClients()
Vector<ResourceClient*> clientsToNotify;
copyToVector(m_clientsAwaitingCallback, clientsToNotify);
- for (size_t i = 0; i < clientsToNotify.size(); ++i) {
- ResourceClient* client = clientsToNotify[i];
-
+ for (const auto& client : clientsToNotify) {
// Handle case (2) to skip removed clients.
if (!m_clientsAwaitingCallback.remove(client))
continue;
// A resource may start revalidation before this method has been called, so check that this resource is still the proxy resource before clearing it out.
if (m_resourceToRevalidate->m_proxyResource == this) {
- m_resourceToRevalidate->m_proxyResource = 0;
+ m_resourceToRevalidate->m_proxyResource = nullptr;
m_resourceToRevalidate->deleteIfPossible();
}
m_handlesToRevalidate.clear();
- m_resourceToRevalidate = 0;
+ m_resourceToRevalidate = nullptr;
deleteIfPossible();
}
ASSERT(memoryCache()->contains(m_resourceToRevalidate));
ASSERT(!memoryCache()->contains(this));
- WTF_LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
+ WTF_LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate.get());
m_resourceToRevalidate->m_identifier = m_identifier;
m_switchingClientsToRevalidatedResource = true;
- HashSet<ResourcePtrBase*>::iterator end = m_handlesToRevalidate.end();
- for (HashSet<ResourcePtrBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
- ResourcePtrBase* handle = *it;
+ for (ResourcePtrBase* handle : m_handlesToRevalidate) {
handle->m_resource = m_resourceToRevalidate;
m_resourceToRevalidate->registerHandle(handle);
--m_handleCount;
m_handlesToRevalidate.clear();
Vector<ResourceClient*> clientsToMove;
- HashCountedSet<ResourceClient*>::iterator end2 = m_clients.end();
- for (HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
- ResourceClient* client = it->key;
- unsigned count = it->value;
- while (count) {
- clientsToMove.append(client);
- --count;
- }
+ for (const auto& clientHashEntry : m_clients) {
+ unsigned count = clientHashEntry.value;
+ while (count--)
+ clientsToMove.append(clientHashEntry.key);
}
unsigned moveCount = clientsToMove.size();
// RFC2616 10.3.5
// Update cached headers from the 304 response
const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
- HTTPHeaderMap::const_iterator end = newHeaders.end();
- for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
+ 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(it->key))
+ if (!shouldUpdateHeaderAfterRevalidation(header.key))
continue;
- m_response.setHTTPHeaderField(it->key, it->value);
+ m_response.setHTTPHeaderField(header.key, header.value);
}
}
ASSERT(m_resourceToRevalidate);
ASSERT(!memoryCache()->contains(m_resourceToRevalidate));
ASSERT(m_resourceToRevalidate->isLoaded());
- ASSERT(memoryCache()->contains(this));
// Calling evict() can potentially delete revalidatingResource, which we use
// below. This mustn't be the case since revalidation means it is loaded
unlock();
} else if (m_handleCount == 1 && memoryCache()->contains(this)) {
unlock();
+ if (!hasClients())
+ memoryCache()->prune(this);
}
}
-bool Resource::canReuseRedirectChain() const
+bool Resource::canReuseRedirectChain()
{
- for (size_t i = 0; i < m_redirectChain.size(); ++i) {
- if (!canUseResponse(m_redirectChain[i].m_redirectResponse, m_responseTimestamp))
+ 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::mustRevalidateDueToCacheHeaders() const
+bool Resource::hasCacheControlNoStoreHeader()
+{
+ return m_response.cacheControlContainsNoStore() || m_resourceRequest.cacheControlContainsNoStore();
+}
+
+bool Resource::mustRevalidateDueToCacheHeaders()
{
- return !canUseResponse(m_response, m_responseTimestamp);
+ return !canUseResponse(m_response, m_responseTimestamp) || m_resourceRequest.cacheControlContainsNoCache() || m_resourceRequest.cacheControlContainsNoStore();
}
-bool Resource::canUseCacheValidator() const
+bool Resource::canUseCacheValidator()
{
if (m_loading || errorOccurred())
return false;
- if (m_response.cacheControlContainsNoStore())
+ if (hasCacheControlNoStoreHeader())
return false;
- return m_response.hasCacheValidatorFields();
+ return m_response.hasCacheValidatorFields() || m_resourceRequest.hasCacheValidatorFields();
}
bool Resource::isPurgeable() const
void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
{
- HashSet<Resource*>::iterator end = m_resourcesWithPendingClients.end();
- Vector<ResourcePtr<Resource> > resources;
- for (HashSet<Resource*>::iterator it = m_resourcesWithPendingClients.begin(); it != end; ++it)
- resources.append(*it);
+ Vector<ResourcePtr<Resource>> resources;
+ for (Resource* resource : m_resourcesWithPendingClients)
+ resources.append(resource);
m_resourcesWithPendingClients.clear();
- for (size_t i = 0; i < resources.size(); i++) {
- resources[i]->assertAlive();
- resources[i]->finishPendingClients();
- resources[i]->assertAlive();
+ for (const auto& resource : resources) {
+ resource->assertAlive();
+ resource->finishPendingClients();
+ resource->assertAlive();
}
- for (size_t i = 0; i < resources.size(); i++)
- resources[i]->assertAlive();
+ for (const auto& resource : resources)
+ resource->assertAlive();
}
static const char* initatorTypeNameToString(const AtomicString& initiatorTypeName)
return "Link subresource";
case Resource::TextTrack:
return "Text track";
- case Resource::Shader:
- return "Shader";
case Resource::ImportResource:
return "Imported resource";
+ case Resource::Media:
+ return "Media";
}
ASSERT_NOT_REACHED();
return initatorTypeNameToString(initiatorInfo.name);
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";