Home | History | Annotate | Download | only in cache
      1 /*
      2     Copyright (C) 1998 Lars Knoll (knoll (at) mpi-hd.mpg.de)
      3     Copyright (C) 2001 Dirk Mueller (mueller (at) kde.org)
      4     Copyright (C) 2002 Waldo Bastian (bastian (at) kde.org)
      5     Copyright (C) 2006 Samuel Weinig (sam.weinig (at) gmail.com)
      6     Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
      7 
      8     This library is free software; you can redistribute it and/or
      9     modify it under the terms of the GNU Library General Public
     10     License as published by the Free Software Foundation; either
     11     version 2 of the License, or (at your option) any later version.
     12 
     13     This library is distributed in the hope that it will be useful,
     14     but WITHOUT ANY WARRANTY; without even the implied warranty of
     15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16     Library General Public License for more details.
     17 
     18     You should have received a copy of the GNU Library General Public License
     19     along with this library; see the file COPYING.LIB.  If not, write to
     20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21     Boston, MA 02110-1301, USA.
     22 */
     23 
     24 #include "config.h"
     25 #include "core/loader/cache/Resource.h"
     26 
     27 #include "core/inspector/InspectorInstrumentation.h"
     28 #include "core/loader/CachedMetadata.h"
     29 #include "core/loader/CrossOriginAccessControl.h"
     30 #include "core/loader/ResourceLoader.h"
     31 #include "core/loader/cache/MemoryCache.h"
     32 #include "core/loader/cache/ResourceClient.h"
     33 #include "core/loader/cache/ResourceClientWalker.h"
     34 #include "core/loader/cache/ResourceFetcher.h"
     35 #include "core/loader/cache/ResourcePtr.h"
     36 #include "core/platform/Logging.h"
     37 #include "core/platform/PurgeableBuffer.h"
     38 #include "core/platform/SharedBuffer.h"
     39 #include "public/platform/Platform.h"
     40 #include "weborigin/KURL.h"
     41 #include "wtf/CurrentTime.h"
     42 #include "wtf/MathExtras.h"
     43 #include "wtf/RefCountedLeakCounter.h"
     44 #include "wtf/StdLibExtras.h"
     45 #include "wtf/Vector.h"
     46 #include "wtf/text/CString.h"
     47 
     48 using namespace WTF;
     49 
     50 namespace WebCore {
     51 
     52 // These response headers are not copied from a revalidated response to the
     53 // cached response headers. For compatibility, this list is based on Chromium's
     54 // net/http/http_response_headers.cc.
     55 const char* const headersToIgnoreAfterRevalidation[] = {
     56     "allow",
     57     "connection",
     58     "etag",
     59     "expires",
     60     "keep-alive",
     61     "last-modified"
     62     "proxy-authenticate",
     63     "proxy-connection",
     64     "trailer",
     65     "transfer-encoding",
     66     "upgrade",
     67     "www-authenticate",
     68     "x-frame-options",
     69     "x-xss-protection",
     70 };
     71 
     72 // Some header prefixes mean "Don't copy this header from a 304 response.".
     73 // Rather than listing all the relevant headers, we can consolidate them into
     74 // this list, also grabbed from Chromium's net/http/http_response_headers.cc.
     75 const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
     76     "content-",
     77     "x-content-",
     78     "x-webkit-"
     79 };
     80 
     81 static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& header)
     82 {
     83     for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation); i++) {
     84         if (equalIgnoringCase(header, headersToIgnoreAfterRevalidation[i]))
     85             return false;
     86     }
     87     for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
     88         if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i], false))
     89             return false;
     90     }
     91     return true;
     92 }
     93 
     94 DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
     95 
     96 Resource::Resource(const ResourceRequest& request, Type type)
     97     : m_resourceRequest(request)
     98     , m_responseTimestamp(currentTime())
     99     , m_cancelTimer(this, &Resource::cancelTimerFired)
    100     , m_lastDecodedAccessTime(0)
    101     , m_loadFinishTime(0)
    102     , m_identifier(0)
    103     , m_encodedSize(0)
    104     , m_decodedSize(0)
    105     , m_accessCount(0)
    106     , m_handleCount(0)
    107     , m_preloadCount(0)
    108     , m_preloadResult(PreloadNotReferenced)
    109     , m_cacheLiveResourcePriority(CacheLiveResourcePriorityLow)
    110     , m_inLiveDecodedResourcesList(false)
    111     , m_requestedFromNetworkingLayer(false)
    112     , m_inCache(false)
    113     , m_loading(false)
    114     , m_switchingClientsToRevalidatedResource(false)
    115     , m_type(type)
    116     , m_status(Pending)
    117 #ifndef NDEBUG
    118     , m_deleted(false)
    119     , m_lruIndex(0)
    120 #endif
    121     , m_nextInAllResourcesList(0)
    122     , m_prevInAllResourcesList(0)
    123     , m_nextInLiveResourcesList(0)
    124     , m_prevInLiveResourcesList(0)
    125     , m_resourceToRevalidate(0)
    126     , m_proxyResource(0)
    127 {
    128     ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests careless updates of the enum.
    129 #ifndef NDEBUG
    130     cachedResourceLeakCounter.increment();
    131 #endif
    132 
    133     if (!m_resourceRequest.url().hasFragmentIdentifier())
    134         return;
    135     KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
    136     if (urlForCache.hasFragmentIdentifier())
    137         return;
    138     m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier();
    139     m_resourceRequest.setURL(urlForCache);
    140 }
    141 
    142 Resource::~Resource()
    143 {
    144     ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() checks this.
    145     ASSERT(canDelete());
    146     ASSERT(!inCache());
    147     ASSERT(!m_deleted);
    148     ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
    149 
    150 #ifndef NDEBUG
    151     m_deleted = true;
    152     cachedResourceLeakCounter.decrement();
    153 #endif
    154 }
    155 
    156 void Resource::failBeforeStarting()
    157 {
    158     LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
    159     error(Resource::LoadError);
    160 }
    161 
    162 void Resource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& options)
    163 {
    164     if (!fetcher->frame()) {
    165         failBeforeStarting();
    166         return;
    167     }
    168 
    169     m_options = options;
    170     m_loading = true;
    171 
    172     if (!accept().isEmpty())
    173         m_resourceRequest.setHTTPAccept(accept());
    174 
    175     // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers.
    176     // We should look into removing the expectation of that knowledge from the platform network stacks.
    177     ResourceRequest request(m_resourceRequest);
    178     if (!m_fragmentIdentifierForRequest.isNull()) {
    179         KURL url = request.url();
    180         url.setFragmentIdentifier(m_fragmentIdentifierForRequest);
    181         request.setURL(url);
    182         m_fragmentIdentifierForRequest = String();
    183     }
    184 
    185     m_loader = ResourceLoader::create(fetcher, this, request, options);
    186     if (!m_loader) {
    187         failBeforeStarting();
    188         return;
    189     }
    190     m_status = Pending;
    191 }
    192 
    193 void Resource::checkNotify()
    194 {
    195     if (isLoading())
    196         return;
    197 
    198     ResourceClientWalker<ResourceClient> w(m_clients);
    199     while (ResourceClient* c = w.next())
    200         c->notifyFinished(this);
    201 }
    202 
    203 void Resource::appendData(const char* data, int length)
    204 {
    205     ASSERT(!m_resourceToRevalidate);
    206     ASSERT(!errorOccurred());
    207     if (m_options.dataBufferingPolicy == DoNotBufferData)
    208         return;
    209     if (m_data)
    210         m_data->append(data, length);
    211     else
    212         m_data = SharedBuffer::create(data, length);
    213     setEncodedSize(m_data->size());
    214 }
    215 
    216 void Resource::error(Resource::Status status)
    217 {
    218     if (m_resourceToRevalidate)
    219         revalidationFailed();
    220 
    221     if (!m_error.isNull() && (m_error.isCancellation() || !isPreloaded()))
    222         memoryCache()->remove(this);
    223 
    224     setStatus(status);
    225     ASSERT(errorOccurred());
    226     m_data.clear();
    227 
    228     setLoading(false);
    229     checkNotify();
    230 }
    231 
    232 void Resource::finishOnePart()
    233 {
    234     setLoading(false);
    235     checkNotify();
    236 }
    237 
    238 void Resource::finish(double finishTime)
    239 {
    240     ASSERT(!m_resourceToRevalidate);
    241     ASSERT(!errorOccurred());
    242     m_loadFinishTime = finishTime;
    243     finishOnePart();
    244     if (!errorOccurred())
    245         m_status = Cached;
    246 }
    247 
    248 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
    249 {
    250     String ignoredErrorDescription;
    251     return passesAccessControlCheck(securityOrigin, ignoredErrorDescription);
    252 }
    253 
    254 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
    255 {
    256     return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
    257 }
    258 
    259 bool Resource::isExpired() const
    260 {
    261     if (m_response.isNull())
    262         return false;
    263 
    264     return currentAge() > freshnessLifetime();
    265 }
    266 
    267 double Resource::currentAge() const
    268 {
    269     // RFC2616 13.2.3
    270     // No compensation for latency as that is not terribly important in practice
    271     double dateValue = m_response.date();
    272     double apparentAge = std::isfinite(dateValue) ? std::max(0., m_responseTimestamp - dateValue) : 0;
    273     double ageValue = m_response.age();
    274     double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
    275     double residentTime = currentTime() - m_responseTimestamp;
    276     return correctedReceivedAge + residentTime;
    277 }
    278 
    279 double Resource::freshnessLifetime() const
    280 {
    281     // Cache non-http resources liberally
    282     if (!m_response.url().protocolIsInHTTPFamily())
    283         return std::numeric_limits<double>::max();
    284 
    285     // RFC2616 13.2.4
    286     double maxAgeValue = m_response.cacheControlMaxAge();
    287     if (std::isfinite(maxAgeValue))
    288         return maxAgeValue;
    289     double expiresValue = m_response.expires();
    290     double dateValue = m_response.date();
    291     double creationTime = std::isfinite(dateValue) ? dateValue : m_responseTimestamp;
    292     if (std::isfinite(expiresValue))
    293         return expiresValue - creationTime;
    294     double lastModifiedValue = m_response.lastModified();
    295     if (std::isfinite(lastModifiedValue))
    296         return (creationTime - lastModifiedValue) * 0.1;
    297     // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
    298     return 0;
    299 }
    300 
    301 void Resource::responseReceived(const ResourceResponse& response)
    302 {
    303     setResponse(response);
    304     m_responseTimestamp = currentTime();
    305     String encoding = response.textEncodingName();
    306     if (!encoding.isNull())
    307         setEncoding(encoding);
    308 
    309     if (!m_resourceToRevalidate)
    310         return;
    311     if (response.httpStatusCode() == 304)
    312         revalidationSucceeded(response);
    313     else
    314         revalidationFailed();
    315 }
    316 
    317 void Resource::setSerializedCachedMetadata(const char* data, size_t size)
    318 {
    319     // We only expect to receive cached metadata from the platform once.
    320     // If this triggers, it indicates an efficiency problem which is most
    321     // likely unexpected in code designed to improve performance.
    322     ASSERT(!m_cachedMetadata);
    323     ASSERT(!m_resourceToRevalidate);
    324 
    325     m_cachedMetadata = CachedMetadata::deserialize(data, size);
    326 }
    327 
    328 void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size)
    329 {
    330     // Currently, only one type of cached metadata per resource is supported.
    331     // If the need arises for multiple types of metadata per resource this could
    332     // be enhanced to store types of metadata in a map.
    333     ASSERT(!m_cachedMetadata);
    334 
    335     m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
    336     const Vector<char>& serializedData = m_cachedMetadata->serialize();
    337     WebKit::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
    338 }
    339 
    340 CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
    341 {
    342     if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
    343         return 0;
    344     return m_cachedMetadata.get();
    345 }
    346 
    347 void Resource::setCacheLiveResourcePriority(CacheLiveResourcePriority priority)
    348 {
    349     if (inCache() && m_inLiveDecodedResourcesList && m_cacheLiveResourcePriority != priority) {
    350         memoryCache()->removeFromLiveDecodedResourcesList(this);
    351         m_cacheLiveResourcePriority = priority;
    352         memoryCache()->insertInLiveDecodedResourcesList(this);
    353         memoryCache()->prune();
    354     }
    355 }
    356 
    357 void Resource::clearLoader()
    358 {
    359     m_loader = 0;
    360 }
    361 
    362 void Resource::addClient(ResourceClient* client)
    363 {
    364     if (addClientToSet(client))
    365         didAddClient(client);
    366 }
    367 
    368 void Resource::didAddClient(ResourceClient* c)
    369 {
    370     if (m_clientsAwaitingCallback.contains(c)) {
    371         m_clients.add(c);
    372         m_clientsAwaitingCallback.remove(c);
    373     }
    374     if (!isLoading() && !stillNeedsLoad())
    375         c->notifyFinished(this);
    376 }
    377 
    378 bool Resource::addClientToSet(ResourceClient* client)
    379 {
    380     ASSERT(!isPurgeable());
    381 
    382     if (m_preloadResult == PreloadNotReferenced) {
    383         if (isLoaded())
    384             m_preloadResult = PreloadReferencedWhileComplete;
    385         else if (m_requestedFromNetworkingLayer)
    386             m_preloadResult = PreloadReferencedWhileLoading;
    387         else
    388             m_preloadResult = PreloadReferenced;
    389     }
    390     if (!hasClients() && inCache())
    391         memoryCache()->addToLiveResourcesSize(this);
    392 
    393     if ((m_type == Raw || m_type == MainResource) && !m_response.isNull() && !m_proxyResource) {
    394         // Certain resources (especially XHRs and main resources) do crazy things if an asynchronous load returns
    395         // synchronously (e.g., scripts may not have set all the state they need to handle the load).
    396         // Therefore, rather than immediately sending callbacks on a cache hit like other Resources,
    397         // we schedule the callbacks and ensure we never finish synchronously.
    398         ASSERT(!m_clientsAwaitingCallback.contains(client));
    399         m_clientsAwaitingCallback.add(client, ResourceCallback::schedule(this, client));
    400         return false;
    401     }
    402 
    403     m_clients.add(client);
    404     return true;
    405 }
    406 
    407 void Resource::removeClient(ResourceClient* client)
    408 {
    409     OwnPtr<ResourceCallback> callback = m_clientsAwaitingCallback.take(client);
    410     if (callback) {
    411         ASSERT(!m_clients.contains(client));
    412         callback->cancel();
    413         callback.clear();
    414     } else {
    415         ASSERT(m_clients.contains(client));
    416         m_clients.remove(client);
    417         didRemoveClient(client);
    418     }
    419 
    420     bool deleted = deleteIfPossible();
    421     if (!deleted && !hasClients()) {
    422         if (inCache()) {
    423             memoryCache()->removeFromLiveResourcesSize(this);
    424             memoryCache()->removeFromLiveDecodedResourcesList(this);
    425         }
    426         if (!m_switchingClientsToRevalidatedResource)
    427             allClientsRemoved();
    428         if (response().cacheControlContainsNoStore()) {
    429             // RFC2616 14.9.2:
    430             // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
    431             // "... History buffers MAY store such responses as part of their normal operation."
    432             // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
    433             if (url().protocolIs("https"))
    434                 memoryCache()->remove(this);
    435         } else {
    436             memoryCache()->prune();
    437         }
    438     }
    439     // This object may be dead here.
    440 }
    441 
    442 void Resource::allClientsRemoved()
    443 {
    444     if (!m_loader)
    445         return;
    446     if (m_type == MainResource || m_type == Raw)
    447         cancelTimerFired(&m_cancelTimer);
    448     else if (!m_cancelTimer.isActive())
    449         m_cancelTimer.startOneShot(0);
    450 }
    451 
    452 void Resource::cancelTimerFired(Timer<Resource>* timer)
    453 {
    454     ASSERT_UNUSED(timer, timer == &m_cancelTimer);
    455     if (hasClients() || !m_loader)
    456         return;
    457     ResourcePtr<Resource> protect(this);
    458     m_loader->cancelIfNotFinishing();
    459     if (m_status != Cached)
    460         memoryCache()->remove(this);
    461 }
    462 
    463 bool Resource::deleteIfPossible()
    464 {
    465     if (canDelete() && !inCache()) {
    466         InspectorInstrumentation::willDestroyResource(this);
    467         delete this;
    468         return true;
    469     }
    470     return false;
    471 }
    472 
    473 void Resource::setDecodedSize(unsigned size)
    474 {
    475     if (size == m_decodedSize)
    476         return;
    477 
    478     int delta = size - m_decodedSize;
    479 
    480     // The object must now be moved to a different queue, since its size has been changed.
    481     // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
    482     // queue.
    483     if (inCache())
    484         memoryCache()->removeFromLRUList(this);
    485 
    486     m_decodedSize = size;
    487 
    488     if (inCache()) {
    489         // Now insert into the new LRU list.
    490         memoryCache()->insertInLRUList(this);
    491 
    492         // Insert into or remove from the live decoded list if necessary.
    493         // When inserting into the LiveDecodedResourcesList it is possible
    494         // that the m_lastDecodedAccessTime is still zero or smaller than
    495         // the m_lastDecodedAccessTime of the current list head. This is a
    496         // violation of the invariant that the list is to be kept sorted
    497         // by access time. The weakening of the invariant does not pose
    498         // a problem. For more details please see: https://bugs.webkit.org/show_bug.cgi?id=30209
    499         if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
    500             memoryCache()->insertInLiveDecodedResourcesList(this);
    501         else if (!m_decodedSize && m_inLiveDecodedResourcesList)
    502             memoryCache()->removeFromLiveDecodedResourcesList(this);
    503 
    504         // Update the cache's size totals.
    505         memoryCache()->adjustSize(hasClients(), delta);
    506     }
    507 }
    508 
    509 void Resource::setEncodedSize(unsigned size)
    510 {
    511     if (size == m_encodedSize)
    512         return;
    513 
    514     int delta = size - m_encodedSize;
    515 
    516     // The object must now be moved to a different queue, since its size has been changed.
    517     // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
    518     // queue.
    519     if (inCache())
    520         memoryCache()->removeFromLRUList(this);
    521 
    522     m_encodedSize = size;
    523 
    524     if (inCache()) {
    525         // Now insert into the new LRU list.
    526         memoryCache()->insertInLRUList(this);
    527 
    528         // Update the cache's size totals.
    529         memoryCache()->adjustSize(hasClients(), delta);
    530     }
    531 }
    532 
    533 void Resource::didAccessDecodedData(double timeStamp)
    534 {
    535     m_lastDecodedAccessTime = timeStamp;
    536     if (inCache()) {
    537         if (m_inLiveDecodedResourcesList) {
    538             memoryCache()->removeFromLiveDecodedResourcesList(this);
    539             memoryCache()->insertInLiveDecodedResourcesList(this);
    540         }
    541         memoryCache()->prune();
    542     }
    543 }
    544 
    545 void Resource::setResourceToRevalidate(Resource* resource)
    546 {
    547     ASSERT(resource);
    548     ASSERT(!m_resourceToRevalidate);
    549     ASSERT(resource != this);
    550     ASSERT(m_handlesToRevalidate.isEmpty());
    551     ASSERT(resource->type() == type());
    552 
    553     LOG(ResourceLoading, "Resource %p setResourceToRevalidate %p", this, resource);
    554 
    555     // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
    556     // https://bugs.webkit.org/show_bug.cgi?id=28604.
    557     // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in Resource::clearResourceToRevalidate.
    558     ASSERT(!resource->m_proxyResource);
    559 
    560     resource->m_proxyResource = this;
    561     m_resourceToRevalidate = resource;
    562 }
    563 
    564 void Resource::clearResourceToRevalidate()
    565 {
    566     ASSERT(m_resourceToRevalidate);
    567     if (m_switchingClientsToRevalidatedResource)
    568         return;
    569 
    570     // 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.
    571     if (m_resourceToRevalidate->m_proxyResource == this) {
    572         m_resourceToRevalidate->m_proxyResource = 0;
    573         m_resourceToRevalidate->deleteIfPossible();
    574     }
    575     m_handlesToRevalidate.clear();
    576     m_resourceToRevalidate = 0;
    577     deleteIfPossible();
    578 }
    579 
    580 void Resource::switchClientsToRevalidatedResource()
    581 {
    582     ASSERT(m_resourceToRevalidate);
    583     ASSERT(m_resourceToRevalidate->inCache());
    584     ASSERT(!inCache());
    585 
    586     LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
    587 
    588     m_resourceToRevalidate->m_identifier = m_identifier;
    589 
    590     m_switchingClientsToRevalidatedResource = true;
    591     HashSet<ResourcePtrBase*>::iterator end = m_handlesToRevalidate.end();
    592     for (HashSet<ResourcePtrBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
    593         ResourcePtrBase* handle = *it;
    594         handle->m_resource = m_resourceToRevalidate;
    595         m_resourceToRevalidate->registerHandle(handle);
    596         --m_handleCount;
    597     }
    598     ASSERT(!m_handleCount);
    599     m_handlesToRevalidate.clear();
    600 
    601     Vector<ResourceClient*> clientsToMove;
    602     HashCountedSet<ResourceClient*>::iterator end2 = m_clients.end();
    603     for (HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
    604         ResourceClient* client = it->key;
    605         unsigned count = it->value;
    606         while (count) {
    607             clientsToMove.append(client);
    608             --count;
    609         }
    610     }
    611 
    612     unsigned moveCount = clientsToMove.size();
    613     for (unsigned n = 0; n < moveCount; ++n)
    614         removeClient(clientsToMove[n]);
    615     ASSERT(m_clients.isEmpty());
    616 
    617     for (unsigned n = 0; n < moveCount; ++n)
    618         m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
    619     for (unsigned n = 0; n < moveCount; ++n) {
    620         // Calling didAddClient may do anything, including trying to cancel revalidation.
    621         // Assert that it didn't succeed.
    622         ASSERT(m_resourceToRevalidate);
    623         // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
    624         if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
    625             m_resourceToRevalidate->didAddClient(clientsToMove[n]);
    626     }
    627     m_switchingClientsToRevalidatedResource = false;
    628 }
    629 
    630 void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse)
    631 {
    632     m_responseTimestamp = currentTime();
    633 
    634     // RFC2616 10.3.5
    635     // Update cached headers from the 304 response
    636     const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
    637     HTTPHeaderMap::const_iterator end = newHeaders.end();
    638     for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
    639         // Entity headers should not be sent by servers when generating a 304
    640         // response; misconfigured servers send them anyway. We shouldn't allow
    641         // such headers to update the original request. We'll base this on the
    642         // list defined by RFC2616 7.1, with a few additions for extension headers
    643         // we care about.
    644         if (!shouldUpdateHeaderAfterRevalidation(it->key))
    645             continue;
    646         m_response.setHTTPHeaderField(it->key, it->value);
    647     }
    648 }
    649 
    650 void Resource::revalidationSucceeded(const ResourceResponse& response)
    651 {
    652     ASSERT(m_resourceToRevalidate);
    653     ASSERT(!m_resourceToRevalidate->inCache());
    654     ASSERT(m_resourceToRevalidate->isLoaded());
    655     ASSERT(inCache());
    656 
    657     // Calling evict() can potentially delete revalidatingResource, which we use
    658     // below. This mustn't be the case since revalidation means it is loaded
    659     // and so canDelete() is false.
    660     ASSERT(!canDelete());
    661 
    662     m_resourceToRevalidate->updateResponseAfterRevalidation(response);
    663     memoryCache()->replace(m_resourceToRevalidate, this);
    664 
    665     switchClientsToRevalidatedResource();
    666     ASSERT(!m_deleted);
    667     // clearResourceToRevalidate deletes this.
    668     clearResourceToRevalidate();
    669 }
    670 
    671 void Resource::revalidationFailed()
    672 {
    673     ASSERT(WTF::isMainThread());
    674     LOG(ResourceLoading, "Revalidation failed for %p", this);
    675     ASSERT(resourceToRevalidate());
    676     clearResourceToRevalidate();
    677 }
    678 
    679 void Resource::updateForAccess()
    680 {
    681     ASSERT(inCache());
    682 
    683     // Need to make sure to remove before we increase the access count, since
    684     // the queue will possibly change.
    685     memoryCache()->removeFromLRUList(this);
    686 
    687     // If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
    688     if (!m_accessCount)
    689         memoryCache()->adjustSize(hasClients(), size());
    690 
    691     m_accessCount++;
    692     memoryCache()->insertInLRUList(this);
    693 }
    694 
    695 void Resource::registerHandle(ResourcePtrBase* h)
    696 {
    697     ++m_handleCount;
    698     if (m_resourceToRevalidate)
    699         m_handlesToRevalidate.add(h);
    700 }
    701 
    702 void Resource::unregisterHandle(ResourcePtrBase* h)
    703 {
    704     ASSERT(m_handleCount > 0);
    705     --m_handleCount;
    706 
    707     if (m_resourceToRevalidate)
    708         m_handlesToRevalidate.remove(h);
    709 
    710     if (!m_handleCount)
    711         deleteIfPossible();
    712 }
    713 
    714 bool Resource::canUseCacheValidator() const
    715 {
    716     if (m_loading || errorOccurred())
    717         return false;
    718 
    719     if (m_response.cacheControlContainsNoStore())
    720         return false;
    721     return m_response.hasCacheValidatorFields();
    722 }
    723 
    724 bool Resource::mustRevalidateDueToCacheHeaders(CachePolicy cachePolicy) const
    725 {
    726     ASSERT(cachePolicy == CachePolicyRevalidate || cachePolicy == CachePolicyCache || cachePolicy == CachePolicyVerify);
    727 
    728     if (cachePolicy == CachePolicyRevalidate)
    729         return true;
    730 
    731     if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
    732         LOG(ResourceLoading, "Resource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
    733         return true;
    734     }
    735 
    736     if (cachePolicy == CachePolicyCache) {
    737         if (m_response.cacheControlContainsMustRevalidate() && isExpired()) {
    738             LOG(ResourceLoading, "Resource %p mustRevalidate because of cachePolicy == CachePolicyCache and m_response.cacheControlContainsMustRevalidate() && isExpired()\n", this);
    739             return true;
    740         }
    741         return false;
    742     }
    743 
    744     // CachePolicyVerify
    745     if (isExpired()) {
    746         LOG(ResourceLoading, "Resource %p mustRevalidate because of isExpired()\n", this);
    747         return true;
    748     }
    749 
    750     return false;
    751 }
    752 
    753 bool Resource::isSafeToMakePurgeable() const
    754 {
    755     return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
    756 }
    757 
    758 bool Resource::makePurgeable(bool purgeable)
    759 {
    760     if (purgeable) {
    761         ASSERT(isSafeToMakePurgeable());
    762 
    763         if (m_purgeableData) {
    764             ASSERT(!m_data);
    765             return true;
    766         }
    767         if (!m_data)
    768             return false;
    769 
    770         // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
    771         if (!m_data->hasOneRef())
    772             return false;
    773 
    774         m_data->createPurgeableBuffer();
    775         if (!m_data->hasPurgeableBuffer())
    776             return false;
    777 
    778         m_purgeableData = m_data->releasePurgeableBuffer();
    779         m_purgeableData->unlock();
    780         m_data.clear();
    781         return true;
    782     }
    783 
    784     if (!m_purgeableData)
    785         return true;
    786 
    787     ASSERT(!m_data);
    788     ASSERT(!hasClients());
    789 
    790     if (!m_purgeableData->lock())
    791         return false;
    792 
    793     m_data = SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release());
    794     return true;
    795 }
    796 
    797 bool Resource::isPurgeable() const
    798 {
    799     return m_purgeableData && m_purgeableData->isPurgeable();
    800 }
    801 
    802 bool Resource::wasPurged() const
    803 {
    804     return m_purgeableData && m_purgeableData->wasPurged();
    805 }
    806 
    807 unsigned Resource::overheadSize() const
    808 {
    809     static const int kAverageClientsHashMapSize = 384;
    810     return sizeof(Resource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
    811 }
    812 
    813 void Resource::didChangePriority(ResourceLoadPriority loadPriority)
    814 {
    815     if (m_loader)
    816         m_loader->didChangePriority(loadPriority);
    817 }
    818 
    819 Resource::ResourceCallback::ResourceCallback(Resource* resource, ResourceClient* client)
    820     : m_resource(resource)
    821     , m_client(client)
    822     , m_callbackTimer(this, &ResourceCallback::timerFired)
    823 {
    824     m_callbackTimer.startOneShot(0);
    825 }
    826 
    827 void Resource::ResourceCallback::cancel()
    828 {
    829     if (m_callbackTimer.isActive())
    830         m_callbackTimer.stop();
    831 }
    832 
    833 void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
    834 {
    835     m_resource->didAddClient(m_client);
    836 }
    837 
    838 }
    839 
    840