Home | History | Annotate | Download | only in fetch
      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/fetch/Resource.h"
     26 
     27 #include "core/FetchInitiatorTypeNames.h"
     28 #include "core/fetch/CachedMetadata.h"
     29 #include "core/fetch/CrossOriginAccessControl.h"
     30 #include "core/fetch/MemoryCache.h"
     31 #include "core/fetch/ResourceClient.h"
     32 #include "core/fetch/ResourceClientWalker.h"
     33 #include "core/fetch/ResourceFetcher.h"
     34 #include "core/fetch/ResourceLoader.h"
     35 #include "core/fetch/ResourcePtr.h"
     36 #include "core/inspector/InspectorInstrumentation.h"
     37 #include "platform/Logging.h"
     38 #include "platform/SharedBuffer.h"
     39 #include "platform/TraceEvent.h"
     40 #include "platform/weborigin/KURL.h"
     41 #include "public/platform/Platform.h"
     42 #include "wtf/CurrentTime.h"
     43 #include "wtf/MathExtras.h"
     44 #include "wtf/RefCountedLeakCounter.h"
     45 #include "wtf/StdLibExtras.h"
     46 #include "wtf/Vector.h"
     47 #include "wtf/text/CString.h"
     48 
     49 using namespace WTF;
     50 
     51 namespace blink {
     52 
     53 // These response headers are not copied from a revalidated response to the
     54 // cached response headers. For compatibility, this list is based on Chromium's
     55 // net/http/http_response_headers.cc.
     56 const char* const headersToIgnoreAfterRevalidation[] = {
     57     "allow",
     58     "connection",
     59     "etag",
     60     "expires",
     61     "keep-alive",
     62     "last-modified"
     63     "proxy-authenticate",
     64     "proxy-connection",
     65     "trailer",
     66     "transfer-encoding",
     67     "upgrade",
     68     "www-authenticate",
     69     "x-frame-options",
     70     "x-xss-protection",
     71 };
     72 
     73 // Some header prefixes mean "Don't copy this header from a 304 response.".
     74 // Rather than listing all the relevant headers, we can consolidate them into
     75 // this list, also grabbed from Chromium's net/http/http_response_headers.cc.
     76 const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
     77     "content-",
     78     "x-content-",
     79     "x-webkit-"
     80 };
     81 
     82 static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& header)
     83 {
     84     for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation); i++) {
     85         if (equalIgnoringCase(header, headersToIgnoreAfterRevalidation[i]))
     86             return false;
     87     }
     88     for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
     89         if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i], false))
     90             return false;
     91     }
     92     return true;
     93 }
     94 
     95 DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
     96 unsigned Resource::s_instanceCount = 0;
     97 
     98 Resource::Resource(const ResourceRequest& request, Type type)
     99     : m_resourceRequest(request)
    100     , m_responseTimestamp(currentTime())
    101     , m_cancelTimer(this, &Resource::cancelTimerFired)
    102     , m_loadFinishTime(0)
    103     , m_identifier(0)
    104     , m_encodedSize(0)
    105     , m_decodedSize(0)
    106     , m_handleCount(0)
    107     , m_preloadCount(0)
    108     , m_protectorCount(0)
    109     , m_preloadResult(PreloadNotReferenced)
    110     , m_requestedFromNetworkingLayer(false)
    111     , m_loading(false)
    112     , m_switchingClientsToRevalidatedResource(false)
    113     , m_type(type)
    114     , m_status(Pending)
    115     , m_wasPurged(false)
    116     , m_needsSynchronousCacheHit(false)
    117 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
    118     , m_deleted(false)
    119 #endif
    120     , m_resourceToRevalidate(nullptr)
    121     , m_proxyResource(nullptr)
    122 {
    123     ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests careless updates of the enum.
    124     ++s_instanceCount;
    125 #ifndef NDEBUG
    126     cachedResourceLeakCounter.increment();
    127 #endif
    128     memoryCache()->registerLiveResource(*this);
    129 
    130     if (!m_resourceRequest.url().hasFragmentIdentifier())
    131         return;
    132     KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
    133     if (urlForCache.hasFragmentIdentifier())
    134         return;
    135     m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier();
    136     m_resourceRequest.setURL(urlForCache);
    137 }
    138 
    139 Resource::~Resource()
    140 {
    141     ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() checks this.
    142     ASSERT(canDelete());
    143     RELEASE_ASSERT(!memoryCache()->contains(this));
    144     RELEASE_ASSERT(!ResourceCallback::callbackHandler()->isScheduled(this));
    145     ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
    146     assertAlive();
    147 
    148 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
    149     m_deleted = true;
    150 #endif
    151 #ifndef NDEBUG
    152     cachedResourceLeakCounter.decrement();
    153 #endif
    154     --s_instanceCount;
    155 }
    156 
    157 void Resource::dispose()
    158 {
    159 }
    160 
    161 void Resource::trace(Visitor* visitor)
    162 {
    163     visitor->trace(m_loader);
    164     visitor->trace(m_resourceToRevalidate);
    165     visitor->trace(m_proxyResource);
    166 }
    167 
    168 void Resource::failBeforeStarting()
    169 {
    170     WTF_LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
    171     error(Resource::LoadError);
    172 }
    173 
    174 void Resource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& options)
    175 {
    176     if (!fetcher->frame()) {
    177         failBeforeStarting();
    178         return;
    179     }
    180 
    181     m_options = options;
    182     m_loading = true;
    183 
    184     if (!accept().isEmpty())
    185         m_resourceRequest.setHTTPAccept(accept());
    186 
    187     // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers.
    188     // We should look into removing the expectation of that knowledge from the platform network stacks.
    189     ResourceRequest request(m_resourceRequest);
    190     if (!m_fragmentIdentifierForRequest.isNull()) {
    191         KURL url = request.url();
    192         url.setFragmentIdentifier(m_fragmentIdentifierForRequest);
    193         request.setURL(url);
    194         m_fragmentIdentifierForRequest = String();
    195     }
    196     m_status = Pending;
    197     if (m_loader) {
    198         RELEASE_ASSERT(m_options.synchronousPolicy == RequestSynchronously);
    199         m_loader->changeToSynchronous();
    200         return;
    201     }
    202     m_loader = ResourceLoader::create(fetcher, this, request, options);
    203     m_loader->start();
    204 }
    205 
    206 void Resource::checkNotify()
    207 {
    208     if (isLoading())
    209         return;
    210 
    211     ResourceClientWalker<ResourceClient> w(m_clients);
    212     while (ResourceClient* c = w.next())
    213         c->notifyFinished(this);
    214 }
    215 
    216 void Resource::appendData(const char* data, int length)
    217 {
    218     TRACE_EVENT0("blink", "Resource::appendData");
    219     ASSERT(!m_resourceToRevalidate);
    220     ASSERT(!errorOccurred());
    221     if (m_options.dataBufferingPolicy == DoNotBufferData)
    222         return;
    223     if (m_data)
    224         m_data->append(data, length);
    225     else
    226         m_data = SharedBuffer::createPurgeable(data, length);
    227     setEncodedSize(m_data->size());
    228 }
    229 
    230 void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer)
    231 {
    232     ASSERT(!m_resourceToRevalidate);
    233     ASSERT(!errorOccurred());
    234     ASSERT(m_options.dataBufferingPolicy == BufferData);
    235     m_data = resourceBuffer;
    236     setEncodedSize(m_data->size());
    237 }
    238 
    239 void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
    240 {
    241     m_options.dataBufferingPolicy = dataBufferingPolicy;
    242     m_data.clear();
    243     setEncodedSize(0);
    244 }
    245 
    246 void Resource::error(Resource::Status status)
    247 {
    248     if (m_resourceToRevalidate)
    249         revalidationFailed();
    250 
    251     if (!m_error.isNull() && (m_error.isCancellation() || !isPreloaded()))
    252         memoryCache()->remove(this);
    253 
    254     setStatus(status);
    255     ASSERT(errorOccurred());
    256     m_data.clear();
    257 
    258     setLoading(false);
    259     checkNotify();
    260 }
    261 
    262 void Resource::finishOnePart()
    263 {
    264     setLoading(false);
    265     checkNotify();
    266 }
    267 
    268 void Resource::finish(double finishTime)
    269 {
    270     ASSERT(!m_resourceToRevalidate);
    271     ASSERT(!errorOccurred());
    272     m_loadFinishTime = finishTime;
    273     finishOnePart();
    274     if (!errorOccurred())
    275         m_status = Cached;
    276 }
    277 
    278 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
    279 {
    280     String ignoredErrorDescription;
    281     return passesAccessControlCheck(securityOrigin, ignoredErrorDescription);
    282 }
    283 
    284 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
    285 {
    286     return blink::passesAccessControlCheck(m_response, resourceRequest().allowStoredCredentials() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
    287 }
    288 
    289 static double currentAge(const ResourceResponse& response, double responseTimestamp)
    290 {
    291     // RFC2616 13.2.3
    292     // No compensation for latency as that is not terribly important in practice
    293     double dateValue = response.date();
    294     double apparentAge = std::isfinite(dateValue) ? std::max(0., responseTimestamp - dateValue) : 0;
    295     double ageValue = response.age();
    296     double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
    297     double residentTime = currentTime() - responseTimestamp;
    298     return correctedReceivedAge + residentTime;
    299 }
    300 
    301 static double freshnessLifetime(ResourceResponse& response, double responseTimestamp)
    302 {
    303 #if !OS(ANDROID)
    304     // On desktop, local files should be reloaded in case they change.
    305     if (response.url().isLocalFile())
    306         return 0;
    307 #endif
    308 
    309     // Cache other non-http / non-filesystem resources liberally.
    310     if (!response.url().protocolIsInHTTPFamily()
    311         && !response.url().protocolIs("filesystem"))
    312         return std::numeric_limits<double>::max();
    313 
    314     // RFC2616 13.2.4
    315     double maxAgeValue = response.cacheControlMaxAge();
    316     if (std::isfinite(maxAgeValue))
    317         return maxAgeValue;
    318     double expiresValue = response.expires();
    319     double dateValue = response.date();
    320     double creationTime = std::isfinite(dateValue) ? dateValue : responseTimestamp;
    321     if (std::isfinite(expiresValue))
    322         return expiresValue - creationTime;
    323     double lastModifiedValue = response.lastModified();
    324     if (std::isfinite(lastModifiedValue))
    325         return (creationTime - lastModifiedValue) * 0.1;
    326     // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
    327     return 0;
    328 }
    329 
    330 static bool canUseResponse(ResourceResponse& response, double responseTimestamp)
    331 {
    332     if (response.isNull())
    333         return false;
    334 
    335     // FIXME: Why isn't must-revalidate considered a reason we can't use the response?
    336     if (response.cacheControlContainsNoCache() || response.cacheControlContainsNoStore())
    337         return false;
    338 
    339     if (response.httpStatusCode() == 303)  {
    340         // Must not be cached.
    341         return false;
    342     }
    343 
    344     if (response.httpStatusCode() == 302 || response.httpStatusCode() == 307) {
    345         // Default to not cacheable unless explicitly allowed.
    346         bool hasMaxAge = std::isfinite(response.cacheControlMaxAge());
    347         bool hasExpires = std::isfinite(response.expires());
    348         // TODO: consider catching Cache-Control "private" and "public" here.
    349         if (!hasMaxAge && !hasExpires)
    350             return false;
    351     }
    352 
    353     return currentAge(response, responseTimestamp) <= freshnessLifetime(response, responseTimestamp);
    354 }
    355 
    356 const ResourceRequest& Resource::lastResourceRequest() const
    357 {
    358     if (!m_redirectChain.size())
    359         return m_resourceRequest;
    360     return m_redirectChain.last().m_request;
    361 }
    362 
    363 void Resource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
    364 {
    365     m_redirectChain.append(RedirectPair(request, response));
    366     m_requestedFromNetworkingLayer = true;
    367 }
    368 
    369 bool Resource::unlock()
    370 {
    371     if (!m_data)
    372         return false;
    373 
    374     if (!m_data->isLocked())
    375         return true;
    376 
    377     if (!memoryCache()->contains(this) || hasClients() || m_handleCount > 1 || m_proxyResource || m_resourceToRevalidate || !m_loadFinishTime || !isSafeToUnlock())
    378         return false;
    379 
    380     m_data->unlock();
    381     return true;
    382 }
    383 
    384 bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const
    385 {
    386     return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0);
    387 }
    388 
    389 void Resource::responseReceived(const ResourceResponse& response)
    390 {
    391     setResponse(response);
    392     m_responseTimestamp = currentTime();
    393     String encoding = response.textEncodingName();
    394     if (!encoding.isNull())
    395         setEncoding(encoding);
    396 
    397     if (!m_resourceToRevalidate)
    398         return;
    399     if (response.httpStatusCode() == 304)
    400         revalidationSucceeded(response);
    401     else
    402         revalidationFailed();
    403 }
    404 
    405 void Resource::setSerializedCachedMetadata(const char* data, size_t size)
    406 {
    407     // We only expect to receive cached metadata from the platform once.
    408     // If this triggers, it indicates an efficiency problem which is most
    409     // likely unexpected in code designed to improve performance.
    410     ASSERT(!m_cachedMetadata);
    411     ASSERT(!m_resourceToRevalidate);
    412 
    413     m_cachedMetadata = CachedMetadata::deserialize(data, size);
    414 }
    415 
    416 void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size, MetadataCacheType cacheType)
    417 {
    418     // Currently, only one type of cached metadata per resource is supported.
    419     // If the need arises for multiple types of metadata per resource this could
    420     // be enhanced to store types of metadata in a map.
    421     ASSERT(!m_cachedMetadata);
    422 
    423     m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
    424 
    425     if (cacheType == SendToPlatform) {
    426         const Vector<char>& serializedData = m_cachedMetadata->serialize();
    427         blink::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
    428     }
    429 }
    430 
    431 void Resource::clearCachedMetadata()
    432 {
    433     m_cachedMetadata.clear();
    434 }
    435 
    436 bool Resource::canDelete() const
    437 {
    438     return !hasClients() && !m_loader && !m_preloadCount && hasRightHandleCountApartFromCache(0)
    439         && !m_protectorCount && !m_resourceToRevalidate && !m_proxyResource;
    440 }
    441 
    442 bool Resource::hasOneHandle() const
    443 {
    444     return hasRightHandleCountApartFromCache(1);
    445 }
    446 
    447 CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
    448 {
    449     if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
    450         return 0;
    451     return m_cachedMetadata.get();
    452 }
    453 
    454 void Resource::clearLoader()
    455 {
    456     m_loader = nullptr;
    457 }
    458 
    459 void Resource::addClient(ResourceClient* client)
    460 {
    461     if (addClientToSet(client))
    462         didAddClient(client);
    463 }
    464 
    465 void Resource::didAddClient(ResourceClient* c)
    466 {
    467     if (!isLoading() && !stillNeedsLoad())
    468         c->notifyFinished(this);
    469 }
    470 
    471 static bool shouldSendCachedDataSynchronouslyForType(Resource::Type type)
    472 {
    473     // Some resources types default to return data synchronously.
    474     // For most of these, it's because there are layout tests that
    475     // expect data to return synchronously in case of cache hit. In
    476     // the case of fonts, there was a performance regression.
    477     // FIXME: Get to the point where we don't need to special-case sync/async
    478     // behavior for different resource types.
    479     if (type == Resource::Image)
    480         return true;
    481     if (type == Resource::CSSStyleSheet)
    482         return true;
    483     if (type == Resource::Script)
    484         return true;
    485     if (type == Resource::Font)
    486         return true;
    487     return false;
    488 }
    489 
    490 bool Resource::addClientToSet(ResourceClient* client)
    491 {
    492     ASSERT(!isPurgeable());
    493 
    494     if (m_preloadResult == PreloadNotReferenced) {
    495         if (isLoaded())
    496             m_preloadResult = PreloadReferencedWhileComplete;
    497         else if (m_requestedFromNetworkingLayer)
    498             m_preloadResult = PreloadReferencedWhileLoading;
    499         else
    500             m_preloadResult = PreloadReferenced;
    501     }
    502     if (!hasClients())
    503         memoryCache()->makeLive(this);
    504 
    505     // If we have existing data to send to the new client and the resource type supprts it, send it asynchronously.
    506     if (!m_response.isNull() && !m_proxyResource && !shouldSendCachedDataSynchronouslyForType(type()) && !m_needsSynchronousCacheHit) {
    507         m_clientsAwaitingCallback.add(client);
    508         ResourceCallback::callbackHandler()->schedule(this);
    509         return false;
    510     }
    511 
    512     m_clients.add(client);
    513     return true;
    514 }
    515 
    516 void Resource::removeClient(ResourceClient* client)
    517 {
    518     if (m_clientsAwaitingCallback.contains(client)) {
    519         ASSERT(!m_clients.contains(client));
    520         m_clientsAwaitingCallback.remove(client);
    521     } else {
    522         ASSERT(m_clients.contains(client));
    523         m_clients.remove(client);
    524         didRemoveClient(client);
    525     }
    526 
    527     if (m_clientsAwaitingCallback.isEmpty())
    528         ResourceCallback::callbackHandler()->cancel(this);
    529 
    530     bool deleted = deleteIfPossible();
    531     if (!deleted && !hasClients()) {
    532         memoryCache()->makeDead(this);
    533         if (!m_switchingClientsToRevalidatedResource)
    534             allClientsRemoved();
    535 
    536         // RFC2616 14.9.2:
    537         // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
    538         // "... History buffers MAY store such responses as part of their normal operation."
    539         // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
    540         if (hasCacheControlNoStoreHeader() && url().protocolIs("https")) {
    541             memoryCache()->remove(this);
    542             memoryCache()->prune();
    543         } else {
    544             memoryCache()->prune(this);
    545         }
    546     }
    547     // This object may be dead here.
    548 }
    549 
    550 void Resource::allClientsRemoved()
    551 {
    552     if (!m_loader)
    553         return;
    554     if (m_type == MainResource || m_type == Raw)
    555         cancelTimerFired(&m_cancelTimer);
    556     else if (!m_cancelTimer.isActive())
    557         m_cancelTimer.startOneShot(0, FROM_HERE);
    558 
    559     unlock();
    560 }
    561 
    562 void Resource::cancelTimerFired(Timer<Resource>* timer)
    563 {
    564     ASSERT_UNUSED(timer, timer == &m_cancelTimer);
    565     if (hasClients() || !m_loader)
    566         return;
    567     ResourcePtr<Resource> protect(this);
    568     m_loader->cancelIfNotFinishing();
    569     if (m_status != Cached)
    570         memoryCache()->remove(this);
    571 }
    572 
    573 bool Resource::deleteIfPossible()
    574 {
    575     if (canDelete() && !memoryCache()->contains(this)) {
    576         InspectorInstrumentation::willDestroyResource(this);
    577         dispose();
    578         memoryCache()->unregisterLiveResource(*this);
    579 #if !ENABLE(OILPAN)
    580         delete this;
    581 #endif
    582         return true;
    583     }
    584     return false;
    585 }
    586 
    587 void Resource::setDecodedSize(size_t decodedSize)
    588 {
    589     if (decodedSize == m_decodedSize)
    590         return;
    591     size_t oldSize = size();
    592     m_decodedSize = decodedSize;
    593     memoryCache()->update(this, oldSize, size());
    594     memoryCache()->updateDecodedResource(this, UpdateForPropertyChange);
    595 }
    596 
    597 void Resource::setEncodedSize(size_t encodedSize)
    598 {
    599     if (encodedSize == m_encodedSize)
    600         return;
    601     size_t oldSize = size();
    602     m_encodedSize = encodedSize;
    603     memoryCache()->update(this, oldSize, size());
    604 }
    605 
    606 void Resource::didAccessDecodedData()
    607 {
    608     memoryCache()->updateDecodedResource(this, UpdateForAccess);
    609     memoryCache()->prune();
    610 }
    611 
    612 void Resource::finishPendingClients()
    613 {
    614     // We're going to notify clients one by one. It is simple if the client does nothing.
    615     // However there are a couple other things that can happen.
    616     //
    617     // 1. Clients can be added during the loop. Make sure they are not processed.
    618     // 2. Clients can be removed during the loop. Make sure they are always available to be
    619     //    removed. Also don't call removed clients or add them back.
    620 
    621     // Handle case (1) by saving a list of clients to notify. A separate list also ensure
    622     // a client is either in m_clients or m_clientsAwaitingCallback.
    623     Vector<ResourceClient*> clientsToNotify;
    624     copyToVector(m_clientsAwaitingCallback, clientsToNotify);
    625 
    626     for (size_t i = 0; i < clientsToNotify.size(); ++i) {
    627         ResourceClient* client = clientsToNotify[i];
    628 
    629         // Handle case (2) to skip removed clients.
    630         if (!m_clientsAwaitingCallback.remove(client))
    631             continue;
    632         m_clients.add(client);
    633         didAddClient(client);
    634     }
    635 
    636     // It is still possible for the above loop to finish a new client synchronously.
    637     // If there's no client waiting we should deschedule.
    638     bool scheduled = ResourceCallback::callbackHandler()->isScheduled(this);
    639     if (scheduled && m_clientsAwaitingCallback.isEmpty())
    640         ResourceCallback::callbackHandler()->cancel(this);
    641 
    642     // Prevent the case when there are clients waiting but no callback scheduled.
    643     ASSERT(m_clientsAwaitingCallback.isEmpty() || scheduled);
    644 }
    645 
    646 void Resource::prune()
    647 {
    648     destroyDecodedDataIfPossible();
    649     unlock();
    650 }
    651 
    652 void Resource::setResourceToRevalidate(Resource* resource)
    653 {
    654     ASSERT(resource);
    655     ASSERT(!m_resourceToRevalidate);
    656     ASSERT(resource != this);
    657     ASSERT(m_handlesToRevalidate.isEmpty());
    658     ASSERT(resource->type() == type());
    659 
    660     WTF_LOG(ResourceLoading, "Resource %p setResourceToRevalidate %p", this, resource);
    661 
    662     // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
    663     // https://bugs.webkit.org/show_bug.cgi?id=28604.
    664     // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in Resource::clearResourceToRevalidate.
    665     ASSERT(!resource->m_proxyResource);
    666 
    667     resource->m_proxyResource = this;
    668     m_resourceToRevalidate = resource;
    669 }
    670 
    671 void Resource::clearResourceToRevalidate()
    672 {
    673     ASSERT(m_resourceToRevalidate);
    674     if (m_switchingClientsToRevalidatedResource)
    675         return;
    676 
    677     // 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.
    678     if (m_resourceToRevalidate->m_proxyResource == this) {
    679         m_resourceToRevalidate->m_proxyResource = nullptr;
    680         m_resourceToRevalidate->deleteIfPossible();
    681     }
    682     m_handlesToRevalidate.clear();
    683     m_resourceToRevalidate = nullptr;
    684     deleteIfPossible();
    685 }
    686 
    687 void Resource::switchClientsToRevalidatedResource()
    688 {
    689     ASSERT(m_resourceToRevalidate);
    690     ASSERT(memoryCache()->contains(m_resourceToRevalidate));
    691     ASSERT(!memoryCache()->contains(this));
    692 
    693     WTF_LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate.get());
    694 
    695     m_resourceToRevalidate->m_identifier = m_identifier;
    696 
    697     m_switchingClientsToRevalidatedResource = true;
    698     HashSet<ResourcePtrBase*>::iterator end = m_handlesToRevalidate.end();
    699     for (HashSet<ResourcePtrBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
    700         ResourcePtrBase* handle = *it;
    701         handle->m_resource = m_resourceToRevalidate;
    702         m_resourceToRevalidate->registerHandle(handle);
    703         --m_handleCount;
    704     }
    705     ASSERT(!m_handleCount);
    706     m_handlesToRevalidate.clear();
    707 
    708     Vector<ResourceClient*> clientsToMove;
    709     HashCountedSet<ResourceClient*>::iterator end2 = m_clients.end();
    710     for (HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
    711         ResourceClient* client = it->key;
    712         unsigned count = it->value;
    713         while (count) {
    714             clientsToMove.append(client);
    715             --count;
    716         }
    717     }
    718 
    719     unsigned moveCount = clientsToMove.size();
    720     for (unsigned n = 0; n < moveCount; ++n)
    721         removeClient(clientsToMove[n]);
    722     ASSERT(m_clients.isEmpty());
    723 
    724     for (unsigned n = 0; n < moveCount; ++n)
    725         m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
    726     for (unsigned n = 0; n < moveCount; ++n) {
    727         // Calling didAddClient may do anything, including trying to cancel revalidation.
    728         // Assert that it didn't succeed.
    729         ASSERT(m_resourceToRevalidate);
    730         // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
    731         if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
    732             m_resourceToRevalidate->didAddClient(clientsToMove[n]);
    733     }
    734     m_switchingClientsToRevalidatedResource = false;
    735 }
    736 
    737 void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse)
    738 {
    739     m_responseTimestamp = currentTime();
    740 
    741     // RFC2616 10.3.5
    742     // Update cached headers from the 304 response
    743     const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
    744     HTTPHeaderMap::const_iterator end = newHeaders.end();
    745     for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
    746         // Entity headers should not be sent by servers when generating a 304
    747         // response; misconfigured servers send them anyway. We shouldn't allow
    748         // such headers to update the original request. We'll base this on the
    749         // list defined by RFC2616 7.1, with a few additions for extension headers
    750         // we care about.
    751         if (!shouldUpdateHeaderAfterRevalidation(it->key))
    752             continue;
    753         m_response.setHTTPHeaderField(it->key, it->value);
    754     }
    755 }
    756 
    757 void Resource::revalidationSucceeded(const ResourceResponse& response)
    758 {
    759     ASSERT(m_resourceToRevalidate);
    760     ASSERT(!memoryCache()->contains(m_resourceToRevalidate));
    761     ASSERT(m_resourceToRevalidate->isLoaded());
    762 
    763     // Calling evict() can potentially delete revalidatingResource, which we use
    764     // below. This mustn't be the case since revalidation means it is loaded
    765     // and so canDelete() is false.
    766     ASSERT(!canDelete());
    767 
    768     m_resourceToRevalidate->updateResponseAfterRevalidation(response);
    769     memoryCache()->replace(m_resourceToRevalidate, this);
    770 
    771     switchClientsToRevalidatedResource();
    772     assertAlive();
    773     // clearResourceToRevalidate deletes this.
    774     clearResourceToRevalidate();
    775 }
    776 
    777 void Resource::revalidationFailed()
    778 {
    779     ASSERT(WTF::isMainThread());
    780     WTF_LOG(ResourceLoading, "Revalidation failed for %p", this);
    781     ASSERT(resourceToRevalidate());
    782     clearResourceToRevalidate();
    783 }
    784 
    785 void Resource::registerHandle(ResourcePtrBase* h)
    786 {
    787     assertAlive();
    788     ++m_handleCount;
    789     if (m_resourceToRevalidate)
    790         m_handlesToRevalidate.add(h);
    791 }
    792 
    793 void Resource::unregisterHandle(ResourcePtrBase* h)
    794 {
    795     assertAlive();
    796     ASSERT(m_handleCount > 0);
    797     --m_handleCount;
    798 
    799     if (m_resourceToRevalidate)
    800         m_handlesToRevalidate.remove(h);
    801 
    802     if (!m_handleCount) {
    803         if (deleteIfPossible())
    804             return;
    805         unlock();
    806     } else if (m_handleCount == 1 && memoryCache()->contains(this)) {
    807         unlock();
    808         if (!hasClients())
    809             memoryCache()->prune(this);
    810     }
    811 }
    812 
    813 bool Resource::canReuseRedirectChain()
    814 {
    815     for (size_t i = 0; i < m_redirectChain.size(); ++i) {
    816         if (!canUseResponse(m_redirectChain[i].m_redirectResponse, m_responseTimestamp))
    817             return false;
    818         if (m_redirectChain[i].m_request.cacheControlContainsNoCache() || m_redirectChain[i].m_request.cacheControlContainsNoStore())
    819             return false;
    820     }
    821     return true;
    822 }
    823 
    824 bool Resource::hasCacheControlNoStoreHeader()
    825 {
    826     return m_response.cacheControlContainsNoStore() || m_resourceRequest.cacheControlContainsNoStore();
    827 }
    828 
    829 bool Resource::mustRevalidateDueToCacheHeaders()
    830 {
    831     return !canUseResponse(m_response, m_responseTimestamp) || m_resourceRequest.cacheControlContainsNoCache() || m_resourceRequest.cacheControlContainsNoStore();
    832 }
    833 
    834 bool Resource::canUseCacheValidator()
    835 {
    836     if (m_loading || errorOccurred())
    837         return false;
    838 
    839     if (hasCacheControlNoStoreHeader())
    840         return false;
    841     return m_response.hasCacheValidatorFields() || m_resourceRequest.hasCacheValidatorFields();
    842 }
    843 
    844 bool Resource::isPurgeable() const
    845 {
    846     return m_data && !m_data->isLocked();
    847 }
    848 
    849 bool Resource::wasPurged() const
    850 {
    851     return m_wasPurged;
    852 }
    853 
    854 bool Resource::lock()
    855 {
    856     if (!m_data)
    857         return true;
    858     if (m_data->isLocked())
    859         return true;
    860 
    861     ASSERT(!hasClients());
    862 
    863     if (!m_data->lock()) {
    864         m_wasPurged = true;
    865         return false;
    866     }
    867     return true;
    868 }
    869 
    870 size_t Resource::overheadSize() const
    871 {
    872     static const int kAverageClientsHashMapSize = 384;
    873     return sizeof(Resource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
    874 }
    875 
    876 void Resource::didChangePriority(ResourceLoadPriority loadPriority, int intraPriorityValue)
    877 {
    878     if (m_loader)
    879         m_loader->didChangePriority(loadPriority, intraPriorityValue);
    880 }
    881 
    882 Resource::ResourceCallback* Resource::ResourceCallback::callbackHandler()
    883 {
    884     DEFINE_STATIC_LOCAL(ResourceCallback, callbackHandler, ());
    885     return &callbackHandler;
    886 }
    887 
    888 Resource::ResourceCallback::ResourceCallback()
    889     : m_callbackTimer(this, &ResourceCallback::timerFired)
    890 {
    891 }
    892 
    893 void Resource::ResourceCallback::schedule(Resource* resource)
    894 {
    895     if (!m_callbackTimer.isActive())
    896         m_callbackTimer.startOneShot(0, FROM_HERE);
    897     resource->assertAlive();
    898     m_resourcesWithPendingClients.add(resource);
    899 }
    900 
    901 void Resource::ResourceCallback::cancel(Resource* resource)
    902 {
    903     resource->assertAlive();
    904     m_resourcesWithPendingClients.remove(resource);
    905     if (m_callbackTimer.isActive() && m_resourcesWithPendingClients.isEmpty())
    906         m_callbackTimer.stop();
    907 }
    908 
    909 bool Resource::ResourceCallback::isScheduled(Resource* resource) const
    910 {
    911     return m_resourcesWithPendingClients.contains(resource);
    912 }
    913 
    914 void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
    915 {
    916     HashSet<Resource*>::iterator end = m_resourcesWithPendingClients.end();
    917     Vector<ResourcePtr<Resource> > resources;
    918     for (HashSet<Resource*>::iterator it = m_resourcesWithPendingClients.begin(); it != end; ++it)
    919         resources.append(*it);
    920     m_resourcesWithPendingClients.clear();
    921 
    922     for (size_t i = 0; i < resources.size(); i++) {
    923         resources[i]->assertAlive();
    924         resources[i]->finishPendingClients();
    925         resources[i]->assertAlive();
    926     }
    927 
    928     for (size_t i = 0; i < resources.size(); i++)
    929         resources[i]->assertAlive();
    930 }
    931 
    932 static const char* initatorTypeNameToString(const AtomicString& initiatorTypeName)
    933 {
    934     if (initiatorTypeName == FetchInitiatorTypeNames::css)
    935         return "CSS resource";
    936     if (initiatorTypeName == FetchInitiatorTypeNames::document)
    937         return "Document";
    938     if (initiatorTypeName == FetchInitiatorTypeNames::icon)
    939         return "Icon";
    940     if (initiatorTypeName == FetchInitiatorTypeNames::internal)
    941         return "Internal resource";
    942     if (initiatorTypeName == FetchInitiatorTypeNames::link)
    943         return "Link element resource";
    944     if (initiatorTypeName == FetchInitiatorTypeNames::processinginstruction)
    945         return "Processing instruction";
    946     if (initiatorTypeName == FetchInitiatorTypeNames::texttrack)
    947         return "Text track";
    948     if (initiatorTypeName == FetchInitiatorTypeNames::xml)
    949         return "XML resource";
    950     if (initiatorTypeName == FetchInitiatorTypeNames::xmlhttprequest)
    951         return "XMLHttpRequest";
    952 
    953     return "Resource";
    954 }
    955 
    956 const char* Resource::resourceTypeToString(Type type, const FetchInitiatorInfo& initiatorInfo)
    957 {
    958     switch (type) {
    959     case Resource::MainResource:
    960         return "Main resource";
    961     case Resource::Image:
    962         return "Image";
    963     case Resource::CSSStyleSheet:
    964         return "CSS stylesheet";
    965     case Resource::Script:
    966         return "Script";
    967     case Resource::Font:
    968         return "Font";
    969     case Resource::Raw:
    970         return initatorTypeNameToString(initiatorInfo.name);
    971     case Resource::SVGDocument:
    972         return "SVG document";
    973     case Resource::XSLStyleSheet:
    974         return "XSL stylesheet";
    975     case Resource::LinkPrefetch:
    976         return "Link prefetch resource";
    977     case Resource::LinkSubresource:
    978         return "Link subresource";
    979     case Resource::TextTrack:
    980         return "Text track";
    981     case Resource::ImportResource:
    982         return "Imported resource";
    983     case Resource::Media:
    984         return "Media";
    985     }
    986     ASSERT_NOT_REACHED();
    987     return initatorTypeNameToString(initiatorInfo.name);
    988 }
    989 
    990 #if !LOG_DISABLED
    991 const char* ResourceTypeName(Resource::Type type)
    992 {
    993     switch (type) {
    994     case Resource::MainResource:
    995         return "MainResource";
    996     case Resource::Image:
    997         return "Image";
    998     case Resource::CSSStyleSheet:
    999         return "CSSStyleSheet";
   1000     case Resource::Script:
   1001         return "Script";
   1002     case Resource::Font:
   1003         return "Font";
   1004     case Resource::Raw:
   1005         return "Raw";
   1006     case Resource::SVGDocument:
   1007         return "SVGDocument";
   1008     case Resource::XSLStyleSheet:
   1009         return "XSLStyleSheet";
   1010     case Resource::LinkPrefetch:
   1011         return "LinkPrefetch";
   1012     case Resource::LinkSubresource:
   1013         return "LinkSubresource";
   1014     case Resource::TextTrack:
   1015         return "TextTrack";
   1016     case Resource::ImportResource:
   1017         return "ImportResource";
   1018     case Resource::Media:
   1019         return "Media";
   1020     }
   1021     ASSERT_NOT_REACHED();
   1022     return "Unknown";
   1023 }
   1024 #endif // !LOG_DISABLED
   1025 
   1026 }
   1027