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/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
49using namespace WTF;
50
51namespace 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.
56const 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.
76const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
77    "content-",
78    "x-content-",
79    "x-webkit-"
80};
81
82static 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
95DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
96unsigned Resource::s_instanceCount = 0;
97
98Resource::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
139Resource::~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
157void Resource::dispose()
158{
159}
160
161void Resource::trace(Visitor* visitor)
162{
163    visitor->trace(m_loader);
164    visitor->trace(m_resourceToRevalidate);
165    visitor->trace(m_proxyResource);
166}
167
168void Resource::failBeforeStarting()
169{
170    WTF_LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
171    error(Resource::LoadError);
172}
173
174void 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
206void 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
216void 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
230void 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
239void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
240{
241    m_options.dataBufferingPolicy = dataBufferingPolicy;
242    m_data.clear();
243    setEncodedSize(0);
244}
245
246void 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
262void Resource::finishOnePart()
263{
264    setLoading(false);
265    checkNotify();
266}
267
268void 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
278bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
279{
280    String ignoredErrorDescription;
281    return passesAccessControlCheck(securityOrigin, ignoredErrorDescription);
282}
283
284bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
285{
286    return blink::passesAccessControlCheck(m_response, resourceRequest().allowStoredCredentials() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
287}
288
289static 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
301static 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
330static 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
356const ResourceRequest& Resource::lastResourceRequest() const
357{
358    if (!m_redirectChain.size())
359        return m_resourceRequest;
360    return m_redirectChain.last().m_request;
361}
362
363void Resource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
364{
365    m_redirectChain.append(RedirectPair(request, response));
366    m_requestedFromNetworkingLayer = true;
367}
368
369bool 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
384bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const
385{
386    return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0);
387}
388
389void 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
405void 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
416void 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
431void Resource::clearCachedMetadata()
432{
433    m_cachedMetadata.clear();
434}
435
436bool Resource::canDelete() const
437{
438    return !hasClients() && !m_loader && !m_preloadCount && hasRightHandleCountApartFromCache(0)
439        && !m_protectorCount && !m_resourceToRevalidate && !m_proxyResource;
440}
441
442bool Resource::hasOneHandle() const
443{
444    return hasRightHandleCountApartFromCache(1);
445}
446
447CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
448{
449    if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
450        return 0;
451    return m_cachedMetadata.get();
452}
453
454void Resource::clearLoader()
455{
456    m_loader = nullptr;
457}
458
459void Resource::addClient(ResourceClient* client)
460{
461    if (addClientToSet(client))
462        didAddClient(client);
463}
464
465void Resource::didAddClient(ResourceClient* c)
466{
467    if (!isLoading() && !stillNeedsLoad())
468        c->notifyFinished(this);
469}
470
471static 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
490bool 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
516void 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
550void 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
562void 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
573bool 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
587void 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
597void 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
606void Resource::didAccessDecodedData()
607{
608    memoryCache()->updateDecodedResource(this, UpdateForAccess);
609    memoryCache()->prune();
610}
611
612void 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
646void Resource::prune()
647{
648    destroyDecodedDataIfPossible();
649    unlock();
650}
651
652void 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
671void 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
687void 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
737void 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
757void 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
777void Resource::revalidationFailed()
778{
779    ASSERT(WTF::isMainThread());
780    WTF_LOG(ResourceLoading, "Revalidation failed for %p", this);
781    ASSERT(resourceToRevalidate());
782    clearResourceToRevalidate();
783}
784
785void Resource::registerHandle(ResourcePtrBase* h)
786{
787    assertAlive();
788    ++m_handleCount;
789    if (m_resourceToRevalidate)
790        m_handlesToRevalidate.add(h);
791}
792
793void 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
813bool 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
824bool Resource::hasCacheControlNoStoreHeader()
825{
826    return m_response.cacheControlContainsNoStore() || m_resourceRequest.cacheControlContainsNoStore();
827}
828
829bool Resource::mustRevalidateDueToCacheHeaders()
830{
831    return !canUseResponse(m_response, m_responseTimestamp) || m_resourceRequest.cacheControlContainsNoCache() || m_resourceRequest.cacheControlContainsNoStore();
832}
833
834bool 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
844bool Resource::isPurgeable() const
845{
846    return m_data && !m_data->isLocked();
847}
848
849bool Resource::wasPurged() const
850{
851    return m_wasPurged;
852}
853
854bool 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
870size_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
876void Resource::didChangePriority(ResourceLoadPriority loadPriority, int intraPriorityValue)
877{
878    if (m_loader)
879        m_loader->didChangePriority(loadPriority, intraPriorityValue);
880}
881
882Resource::ResourceCallback* Resource::ResourceCallback::callbackHandler()
883{
884    DEFINE_STATIC_LOCAL(ResourceCallback, callbackHandler, ());
885    return &callbackHandler;
886}
887
888Resource::ResourceCallback::ResourceCallback()
889    : m_callbackTimer(this, &ResourceCallback::timerFired)
890{
891}
892
893void 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
901void 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
909bool Resource::ResourceCallback::isScheduled(Resource* resource) const
910{
911    return m_resourcesWithPendingClients.contains(resource);
912}
913
914void 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
932static 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
956const 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
991const 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