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