1/*
2    Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3    Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4    Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5    Copyright (C) 2006 Samuel Weinig (sam.weinig@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
48using namespace WTF;
49
50namespace 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.
55const 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.
75const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
76    "content-",
77    "x-content-",
78    "x-webkit-"
79};
80
81static 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
94DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
95
96Resource::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
142Resource::~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
156void Resource::failBeforeStarting()
157{
158    LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
159    error(Resource::LoadError);
160}
161
162void 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
193void 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
203void 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
216void 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
232void Resource::finishOnePart()
233{
234    setLoading(false);
235    checkNotify();
236}
237
238void 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
248bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
249{
250    String ignoredErrorDescription;
251    return passesAccessControlCheck(securityOrigin, ignoredErrorDescription);
252}
253
254bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
255{
256    return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
257}
258
259bool Resource::isExpired() const
260{
261    if (m_response.isNull())
262        return false;
263
264    return currentAge() > freshnessLifetime();
265}
266
267double 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
279double 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
301void 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
317void 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
328void 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
340CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
341{
342    if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
343        return 0;
344    return m_cachedMetadata.get();
345}
346
347void 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
357void Resource::clearLoader()
358{
359    m_loader = 0;
360}
361
362void Resource::addClient(ResourceClient* client)
363{
364    if (addClientToSet(client))
365        didAddClient(client);
366}
367
368void 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
378bool 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
407void 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
442void 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
452void 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
463bool Resource::deleteIfPossible()
464{
465    if (canDelete() && !inCache()) {
466        InspectorInstrumentation::willDestroyResource(this);
467        delete this;
468        return true;
469    }
470    return false;
471}
472
473void 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
509void 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
533void 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
545void 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
564void 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
580void 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
630void 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
650void 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
671void Resource::revalidationFailed()
672{
673    ASSERT(WTF::isMainThread());
674    LOG(ResourceLoading, "Revalidation failed for %p", this);
675    ASSERT(resourceToRevalidate());
676    clearResourceToRevalidate();
677}
678
679void 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
695void Resource::registerHandle(ResourcePtrBase* h)
696{
697    ++m_handleCount;
698    if (m_resourceToRevalidate)
699        m_handlesToRevalidate.add(h);
700}
701
702void 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
714bool 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
724bool 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
753bool Resource::isSafeToMakePurgeable() const
754{
755    return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
756}
757
758bool 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
797bool Resource::isPurgeable() const
798{
799    return m_purgeableData && m_purgeableData->isPurgeable();
800}
801
802bool Resource::wasPurged() const
803{
804    return m_purgeableData && m_purgeableData->wasPurged();
805}
806
807unsigned 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
813void Resource::didChangePriority(ResourceLoadPriority loadPriority)
814{
815    if (m_loader)
816        m_loader->didChangePriority(loadPriority);
817}
818
819Resource::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
827void Resource::ResourceCallback::cancel()
828{
829    if (m_callbackTimer.isActive())
830        m_callbackTimer.stop();
831}
832
833void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
834{
835    m_resource->didAddClient(m_client);
836}
837
838}
839
840