Stop placing std::isfinite and std::signbit inside the global scope
[WebKit.git] / Source / WebCore / loader / cache / CachedResource.cpp
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 "CachedResource.h"
26
27 #include "MemoryCache.h"
28 #include "CachedMetadata.h"
29 #include "CachedResourceClient.h"
30 #include "CachedResourceClientWalker.h"
31 #include "CachedResourceHandle.h"
32 #include "CachedResourceLoader.h"
33 #include "CrossOriginAccessControl.h"
34 #include "Document.h"
35 #include "DocumentLoader.h"
36 #include "FrameLoaderClient.h"
37 #include "InspectorInstrumentation.h"
38 #include "KURL.h"
39 #include "LoaderStrategy.h"
40 #include "Logging.h"
41 #include "PlatformStrategies.h"
42 #include "PurgeableBuffer.h"
43 #include "ResourceBuffer.h"
44 #include "ResourceHandle.h"
45 #include "ResourceLoadScheduler.h"
46 #include "SecurityOrigin.h"
47 #include "SecurityPolicy.h"
48 #include "SubresourceLoader.h"
49 #include "WebCoreMemoryInstrumentation.h"
50 #include <wtf/CurrentTime.h>
51 #include <wtf/MathExtras.h>
52 #include <wtf/MemoryInstrumentationHashCountedSet.h>
53 #include <wtf/MemoryInstrumentationHashSet.h>
54 #include <wtf/MemoryObjectInfo.h>
55 #include <wtf/RefCountedLeakCounter.h>
56 #include <wtf/StdLibExtras.h>
57 #include <wtf/text/CString.h>
58 #include <wtf/Vector.h>
59
60 namespace WTF {
61
62 template<> struct SequenceMemoryInstrumentationTraits<WebCore::CachedResourceClient*> {
63     template <typename I> static void reportMemoryUsage(I, I, MemoryClassInfo&) { }
64 };
65
66 }
67
68 using namespace WTF;
69
70 namespace WebCore {
71
72 // These response headers are not copied from a revalidated response to the
73 // cached response headers. For compatibility, this list is based on Chromium's
74 // net/http/http_response_headers.cc.
75 const char* const headersToIgnoreAfterRevalidation[] = {
76     "allow",
77     "connection",
78     "etag",
79     "expires",
80     "keep-alive",
81     "last-modified"
82     "proxy-authenticate",
83     "proxy-connection",
84     "trailer",
85     "transfer-encoding",
86     "upgrade",
87     "www-authenticate",
88     "x-frame-options",
89     "x-xss-protection",
90 };
91
92 // Some header prefixes mean "Don't copy this header from a 304 response.".
93 // Rather than listing all the relevant headers, we can consolidate them into
94 // this list, also grabbed from Chromium's net/http/http_response_headers.cc.
95 const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
96     "content-",
97     "x-content-",
98     "x-webkit-"
99 };
100
101 static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& header)
102 {
103     for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation); i++) {
104         if (header == headersToIgnoreAfterRevalidation[i])
105             return false;
106     }
107     for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
108         if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i]))
109             return false;
110     }
111     return true;
112 }
113
114 static ResourceLoadPriority defaultPriorityForResourceType(CachedResource::Type type)
115 {
116     switch (type) {
117     case CachedResource::MainResource:
118         return ResourceLoadPriorityVeryHigh;
119     case CachedResource::CSSStyleSheet:
120         return ResourceLoadPriorityHigh;
121     case CachedResource::Script:
122     case CachedResource::FontResource:
123     case CachedResource::RawResource:
124         return ResourceLoadPriorityMedium;
125     case CachedResource::ImageResource:
126         return ResourceLoadPriorityLow;
127 #if ENABLE(XSLT)
128     case CachedResource::XSLStyleSheet:
129         return ResourceLoadPriorityHigh;
130 #endif
131 #if ENABLE(SVG)
132     case CachedResource::SVGDocumentResource:
133         return ResourceLoadPriorityLow;
134 #endif
135 #if ENABLE(LINK_PREFETCH)
136     case CachedResource::LinkPrefetch:
137         return ResourceLoadPriorityVeryLow;
138     case CachedResource::LinkSubresource:
139         return ResourceLoadPriorityVeryLow;
140 #endif
141 #if ENABLE(VIDEO_TRACK)
142     case CachedResource::TextTrackResource:
143         return ResourceLoadPriorityLow;
144 #endif
145 #if ENABLE(CSS_SHADERS)
146     case CachedResource::ShaderResource:
147         return ResourceLoadPriorityMedium;
148 #endif
149     }
150     ASSERT_NOT_REACHED();
151     return ResourceLoadPriorityLow;
152 }
153
154 #if PLATFORM(CHROMIUM) || PLATFORM(BLACKBERRY)
155 static ResourceRequest::TargetType cachedResourceTypeToTargetType(CachedResource::Type type)
156 {
157     switch (type) {
158     case CachedResource::MainResource:
159         return ResourceRequest::TargetIsMainFrame;
160     case CachedResource::CSSStyleSheet:
161 #if ENABLE(XSLT)
162     case CachedResource::XSLStyleSheet:
163 #endif
164         return ResourceRequest::TargetIsStyleSheet;
165     case CachedResource::Script: 
166         return ResourceRequest::TargetIsScript;
167     case CachedResource::FontResource:
168         return ResourceRequest::TargetIsFontResource;
169     case CachedResource::ImageResource:
170         return ResourceRequest::TargetIsImage;
171 #if ENABLE(CSS_SHADERS)
172     case CachedResource::ShaderResource:
173 #endif
174     case CachedResource::RawResource:
175         return ResourceRequest::TargetIsSubresource;    
176 #if ENABLE(LINK_PREFETCH)
177     case CachedResource::LinkPrefetch:
178         return ResourceRequest::TargetIsPrefetch;
179     case CachedResource::LinkSubresource:
180         return ResourceRequest::TargetIsSubresource;
181 #endif
182 #if ENABLE(VIDEO_TRACK)
183     case CachedResource::TextTrackResource:
184         return ResourceRequest::TargetIsTextTrack;
185 #endif
186 #if ENABLE(SVG)
187     case CachedResource::SVGDocumentResource:
188         return ResourceRequest::TargetIsImage;
189 #endif
190     }
191     ASSERT_NOT_REACHED();
192     return ResourceRequest::TargetIsSubresource;
193 }
194 #endif
195
196 DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("CachedResource"));
197
198 CachedResource::CachedResource(const ResourceRequest& request, Type type)
199     : m_resourceRequest(request)
200     , m_loadPriority(defaultPriorityForResourceType(type))
201     , m_responseTimestamp(currentTime())
202     , m_decodedDataDeletionTimer(this, &CachedResource::decodedDataDeletionTimerFired)
203     , m_lastDecodedAccessTime(0)
204     , m_loadFinishTime(0)
205     , m_encodedSize(0)
206     , m_decodedSize(0)
207     , m_accessCount(0)
208     , m_handleCount(0)
209     , m_preloadCount(0)
210     , m_preloadResult(PreloadNotReferenced)
211     , m_inLiveDecodedResourcesList(false)
212     , m_requestedFromNetworkingLayer(false)
213     , m_inCache(false)
214     , m_loading(false)
215     , m_switchingClientsToRevalidatedResource(false)
216     , m_type(type)
217     , m_status(Pending)
218 #ifndef NDEBUG
219     , m_deleted(false)
220     , m_lruIndex(0)
221 #endif
222     , m_nextInAllResourcesList(0)
223     , m_prevInAllResourcesList(0)
224     , m_nextInLiveResourcesList(0)
225     , m_prevInLiveResourcesList(0)
226     , m_owningCachedResourceLoader(0)
227     , m_resourceToRevalidate(0)
228     , m_proxyResource(0)
229 {
230     ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests careless updates of the enum.
231 #ifndef NDEBUG
232     cachedResourceLeakCounter.increment();
233 #endif
234
235     if (!m_resourceRequest.url().hasFragmentIdentifier())
236         return;
237     KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
238     if (urlForCache.hasFragmentIdentifier())
239         return;
240     m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier();
241     m_resourceRequest.setURL(urlForCache);
242 }
243
244 CachedResource::~CachedResource()
245 {
246     ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() checks this.
247     ASSERT(canDelete());
248     ASSERT(!inCache());
249     ASSERT(!m_deleted);
250     ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
251
252 #ifndef NDEBUG
253     m_deleted = true;
254     cachedResourceLeakCounter.decrement();
255 #endif
256
257     if (m_owningCachedResourceLoader)
258         m_owningCachedResourceLoader->removeCachedResource(this);
259 }
260
261 void CachedResource::failBeforeStarting()
262 {
263     // FIXME: What if resources in other frames were waiting for this revalidation?
264     LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
265     if (m_resourceToRevalidate) 
266         memoryCache()->revalidationFailed(this); 
267     error(CachedResource::LoadError);
268 }
269
270 void CachedResource::addAdditionalRequestHeaders(CachedResourceLoader* cachedResourceLoader)
271 {
272     // Note: We skip the Content-Security-Policy check here because we check
273     // the Content-Security-Policy at the CachedResourceLoader layer so we can
274     // handle different resource types differently.
275
276     FrameLoader* frameLoader = cachedResourceLoader->frame()->loader();
277     String outgoingReferrer;
278     String outgoingOrigin;
279     if (m_resourceRequest.httpReferrer().isNull()) {
280         outgoingReferrer = frameLoader->outgoingReferrer();
281         outgoingOrigin = frameLoader->outgoingOrigin();
282     } else {
283         outgoingReferrer = m_resourceRequest.httpReferrer();
284         outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
285     }
286
287     outgoingReferrer = SecurityPolicy::generateReferrerHeader(cachedResourceLoader->document()->referrerPolicy(), m_resourceRequest.url(), outgoingReferrer);
288     if (outgoingReferrer.isEmpty())
289         m_resourceRequest.clearHTTPReferrer();
290     else if (!m_resourceRequest.httpReferrer())
291         m_resourceRequest.setHTTPReferrer(outgoingReferrer);
292     FrameLoader::addHTTPOriginIfNeeded(m_resourceRequest, outgoingOrigin);
293
294     frameLoader->addExtraFieldsToSubresourceRequest(m_resourceRequest);
295 }
296
297 void CachedResource::load(CachedResourceLoader* cachedResourceLoader, const ResourceLoaderOptions& options)
298 {
299     if (!cachedResourceLoader->frame()) {
300         failBeforeStarting();
301         return;
302     }
303
304     FrameLoader* frameLoader = cachedResourceLoader->frame()->loader();
305     if (options.securityCheck == DoSecurityCheck && (frameLoader->state() == FrameStateProvisional || !frameLoader->activeDocumentLoader() || frameLoader->activeDocumentLoader()->isStopping())) {
306         failBeforeStarting();
307         return;
308     }
309
310     m_options = options;
311     m_loading = true;
312
313 #if PLATFORM(CHROMIUM) || PLATFORM(BLACKBERRY)
314     if (m_resourceRequest.targetType() == ResourceRequest::TargetIsUnspecified)
315         m_resourceRequest.setTargetType(cachedResourceTypeToTargetType(type()));
316 #endif
317
318     if (!accept().isEmpty())
319         m_resourceRequest.setHTTPAccept(accept());
320
321     if (isCacheValidator()) {
322         CachedResource* resourceToRevalidate = m_resourceToRevalidate;
323         ASSERT(resourceToRevalidate->canUseCacheValidator());
324         ASSERT(resourceToRevalidate->isLoaded());
325         const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified");
326         const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag");
327         if (!lastModified.isEmpty() || !eTag.isEmpty()) {
328             ASSERT(cachedResourceLoader->cachePolicy(type()) != CachePolicyReload);
329             if (cachedResourceLoader->cachePolicy(type()) == CachePolicyRevalidate)
330                 m_resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
331             if (!lastModified.isEmpty())
332                 m_resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
333             if (!eTag.isEmpty())
334                 m_resourceRequest.setHTTPHeaderField("If-None-Match", eTag);
335         }
336     }
337
338 #if ENABLE(LINK_PREFETCH)
339     if (type() == CachedResource::LinkPrefetch || type() == CachedResource::LinkSubresource)
340         m_resourceRequest.setHTTPHeaderField("Purpose", "prefetch");
341 #endif
342     m_resourceRequest.setPriority(loadPriority());
343
344     if (type() != MainResource)
345         addAdditionalRequestHeaders(cachedResourceLoader);
346
347     // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers.
348     // We should look into removing the expectation of that knowledge from the platform network stacks.
349     ResourceRequest request(m_resourceRequest);
350     if (!m_fragmentIdentifierForRequest.isNull()) {
351         KURL url = request.url();
352         url.setFragmentIdentifier(m_fragmentIdentifierForRequest);
353         request.setURL(url);
354         m_fragmentIdentifierForRequest = String();
355     }
356
357 #if USE(PLATFORM_STRATEGIES)
358     m_loader = platformStrategies()->loaderStrategy()->resourceLoadScheduler()->scheduleSubresourceLoad(cachedResourceLoader->frame(), this, request, request.priority(), options);
359 #else
360     m_loader = resourceLoadScheduler()->scheduleSubresourceLoad(cachedResourceLoader->frame(), this, request, request.priority(), options);
361 #endif
362
363     if (!m_loader) {
364         failBeforeStarting();
365         return;
366     }
367
368     m_status = Pending;
369 }
370
371 void CachedResource::checkNotify()
372 {
373     if (isLoading())
374         return;
375
376     CachedResourceClientWalker<CachedResourceClient> w(m_clients);
377     while (CachedResourceClient* c = w.next())
378         c->notifyFinished(this);
379 }
380
381 void CachedResource::data(PassRefPtr<ResourceBuffer>, bool allDataReceived)
382 {
383     if (!allDataReceived)
384         return;
385     
386     setLoading(false);
387     checkNotify();
388 }
389
390 void CachedResource::error(CachedResource::Status status)
391 {
392     setStatus(status);
393     ASSERT(errorOccurred());
394     m_data.clear();
395
396     setLoading(false);
397     checkNotify();
398 }
399
400 void CachedResource::finish()
401 {
402     if (!errorOccurred())
403         m_status = Cached;
404 }
405
406 bool CachedResource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
407 {
408     String errorDescription;
409     return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
410 }
411
412 bool CachedResource::isExpired() const
413 {
414     if (m_response.isNull())
415         return false;
416
417     return currentAge() > freshnessLifetime();
418 }
419     
420 double CachedResource::currentAge() const
421 {
422     // RFC2616 13.2.3
423     // No compensation for latency as that is not terribly important in practice
424     double dateValue = m_response.date();
425     double apparentAge = std::isfinite(dateValue) ? std::max(0., m_responseTimestamp - dateValue) : 0;
426     double ageValue = m_response.age();
427     double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
428     double residentTime = currentTime() - m_responseTimestamp;
429     return correctedReceivedAge + residentTime;
430 }
431     
432 double CachedResource::freshnessLifetime() const
433 {
434     // Cache non-http resources liberally
435     if (!m_response.url().protocolIsInHTTPFamily())
436         return std::numeric_limits<double>::max();
437
438     // RFC2616 13.2.4
439     double maxAgeValue = m_response.cacheControlMaxAge();
440     if (std::isfinite(maxAgeValue))
441         return maxAgeValue;
442     double expiresValue = m_response.expires();
443     double dateValue = m_response.date();
444     double creationTime = std::isfinite(dateValue) ? dateValue : m_responseTimestamp;
445     if (std::isfinite(expiresValue))
446         return expiresValue - creationTime;
447     double lastModifiedValue = m_response.lastModified();
448     if (std::isfinite(lastModifiedValue))
449         return (creationTime - lastModifiedValue) * 0.1;
450     // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
451     return 0;
452 }
453
454 void CachedResource::responseReceived(const ResourceResponse& response)
455 {
456     setResponse(response);
457     m_responseTimestamp = currentTime();
458     String encoding = response.textEncodingName();
459     if (!encoding.isNull())
460         setEncoding(encoding);
461 }
462
463 void CachedResource::setSerializedCachedMetadata(const char* data, size_t size)
464 {
465     // We only expect to receive cached metadata from the platform once.
466     // If this triggers, it indicates an efficiency problem which is most
467     // likely unexpected in code designed to improve performance.
468     ASSERT(!m_cachedMetadata);
469
470     m_cachedMetadata = CachedMetadata::deserialize(data, size);
471 }
472
473 void CachedResource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size)
474 {
475     // Currently, only one type of cached metadata per resource is supported.
476     // If the need arises for multiple types of metadata per resource this could
477     // be enhanced to store types of metadata in a map.
478     ASSERT(!m_cachedMetadata);
479
480     m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
481     ResourceHandle::cacheMetadata(m_response, m_cachedMetadata->serialize());
482 }
483
484 CachedMetadata* CachedResource::cachedMetadata(unsigned dataTypeID) const
485 {
486     if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
487         return 0;
488     return m_cachedMetadata.get();
489 }
490
491 void CachedResource::stopLoading()
492 {
493     ASSERT(m_loader);            
494     m_loader = 0;
495
496     CachedResourceHandle<CachedResource> protect(this);
497
498     // All loads finish with data(allDataReceived = true) or error(), except for
499     // canceled loads, which silently set our request to 0. Be sure to notify our
500     // client in that case, so we don't seem to continue loading forever.
501     if (isLoading()) {
502         setLoading(false);
503         setStatus(LoadError);
504         checkNotify();
505     }
506 }
507
508 void CachedResource::addClient(CachedResourceClient* client)
509 {
510     if (addClientToSet(client))
511         didAddClient(client);
512 }
513
514 void CachedResource::didAddClient(CachedResourceClient* c)
515 {
516     if (m_decodedDataDeletionTimer.isActive())
517         m_decodedDataDeletionTimer.stop();
518
519     if (m_clientsAwaitingCallback.contains(c)) {
520         m_clients.add(c);
521         m_clientsAwaitingCallback.remove(c);
522     }
523     if (!isLoading() && !stillNeedsLoad())
524         c->notifyFinished(this);
525 }
526
527 bool CachedResource::addClientToSet(CachedResourceClient* client)
528 {
529     ASSERT(!isPurgeable());
530
531     if (m_preloadResult == PreloadNotReferenced) {
532         if (isLoaded())
533             m_preloadResult = PreloadReferencedWhileComplete;
534         else if (m_requestedFromNetworkingLayer)
535             m_preloadResult = PreloadReferencedWhileLoading;
536         else
537             m_preloadResult = PreloadReferenced;
538     }
539     if (!hasClients() && inCache())
540         memoryCache()->addToLiveResourcesSize(this);
541
542     if ((m_type == RawResource || m_type == MainResource) && !m_response.isNull() && !m_proxyResource) {
543         // Certain resources (especially XHRs and main resources) do crazy things if an asynchronous load returns
544         // synchronously (e.g., scripts may not have set all the state they need to handle the load).
545         // Therefore, rather than immediately sending callbacks on a cache hit like other CachedResources,
546         // we schedule the callbacks and ensure we never finish synchronously.
547         ASSERT(!m_clientsAwaitingCallback.contains(client));
548         m_clientsAwaitingCallback.add(client, CachedResourceCallback::schedule(this, client));
549         return false;
550     }
551
552     m_clients.add(client);
553     return true;
554 }
555
556 void CachedResource::removeClient(CachedResourceClient* client)
557 {
558     OwnPtr<CachedResourceCallback> callback = m_clientsAwaitingCallback.take(client);
559     if (callback) {
560         ASSERT(!m_clients.contains(client));
561         callback->cancel();
562         callback.clear();
563     } else {
564         ASSERT(m_clients.contains(client));
565         m_clients.remove(client);
566         didRemoveClient(client);
567     }
568
569     bool deleted = deleteIfPossible();
570     if (!deleted && !hasClients()) {
571         if (inCache()) {
572             memoryCache()->removeFromLiveResourcesSize(this);
573             memoryCache()->removeFromLiveDecodedResourcesList(this);
574         }
575         if (!m_switchingClientsToRevalidatedResource)
576             allClientsRemoved();
577         destroyDecodedDataIfNeeded();
578         if (response().cacheControlContainsNoStore()) {
579             // RFC2616 14.9.2:
580             // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
581             // "... History buffers MAY store such responses as part of their normal operation."
582             // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
583             if (url().protocolIs("https"))
584                 memoryCache()->remove(this);
585         } else
586             memoryCache()->prune();
587     }
588     // This object may be dead here.
589 }
590
591 void CachedResource::destroyDecodedDataIfNeeded()
592 {
593     if (!m_decodedSize)
594         return;
595
596     if (double interval = memoryCache()->deadDecodedDataDeletionInterval())
597         m_decodedDataDeletionTimer.startOneShot(interval);
598 }
599
600 void CachedResource::decodedDataDeletionTimerFired(Timer<CachedResource>*)
601 {
602     destroyDecodedData();
603 }
604
605 bool CachedResource::deleteIfPossible()
606 {
607     if (canDelete() && !inCache()) {
608         InspectorInstrumentation::willDestroyCachedResource(this);
609         delete this;
610         return true;
611     }
612     return false;
613 }
614
615 void CachedResource::setDecodedSize(unsigned size)
616 {
617     if (size == m_decodedSize)
618         return;
619
620     int delta = size - m_decodedSize;
621
622     // The object must now be moved to a different queue, since its size has been changed.
623     // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
624     // queue.
625     if (inCache())
626         memoryCache()->removeFromLRUList(this);
627     
628     m_decodedSize = size;
629    
630     if (inCache()) { 
631         // Now insert into the new LRU list.
632         memoryCache()->insertInLRUList(this);
633         
634         // Insert into or remove from the live decoded list if necessary.
635         // When inserting into the LiveDecodedResourcesList it is possible
636         // that the m_lastDecodedAccessTime is still zero or smaller than
637         // the m_lastDecodedAccessTime of the current list head. This is a
638         // violation of the invariant that the list is to be kept sorted
639         // by access time. The weakening of the invariant does not pose
640         // a problem. For more details please see: https://bugs.webkit.org/show_bug.cgi?id=30209
641         if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
642             memoryCache()->insertInLiveDecodedResourcesList(this);
643         else if (!m_decodedSize && m_inLiveDecodedResourcesList)
644             memoryCache()->removeFromLiveDecodedResourcesList(this);
645
646         // Update the cache's size totals.
647         memoryCache()->adjustSize(hasClients(), delta);
648     }
649 }
650
651 void CachedResource::setEncodedSize(unsigned size)
652 {
653     if (size == m_encodedSize)
654         return;
655
656     // The size cannot ever shrink (unless it is being nulled out because of an error).  If it ever does, assert.
657     ASSERT(size == 0 || size >= m_encodedSize);
658     
659     int delta = size - m_encodedSize;
660
661     // The object must now be moved to a different queue, since its size has been changed.
662     // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
663     // queue.
664     if (inCache())
665         memoryCache()->removeFromLRUList(this);
666     
667     m_encodedSize = size;
668    
669     if (inCache()) { 
670         // Now insert into the new LRU list.
671         memoryCache()->insertInLRUList(this);
672         
673         // Update the cache's size totals.
674         memoryCache()->adjustSize(hasClients(), delta);
675     }
676 }
677
678 void CachedResource::didAccessDecodedData(double timeStamp)
679 {
680     m_lastDecodedAccessTime = timeStamp;
681     
682     if (inCache()) {
683         if (m_inLiveDecodedResourcesList) {
684             memoryCache()->removeFromLiveDecodedResourcesList(this);
685             memoryCache()->insertInLiveDecodedResourcesList(this);
686         }
687         memoryCache()->prune();
688     }
689 }
690     
691 void CachedResource::setResourceToRevalidate(CachedResource* resource) 
692
693     ASSERT(resource);
694     ASSERT(!m_resourceToRevalidate);
695     ASSERT(resource != this);
696     ASSERT(m_handlesToRevalidate.isEmpty());
697     ASSERT(resource->type() == type());
698
699     LOG(ResourceLoading, "CachedResource %p setResourceToRevalidate %p", this, resource);
700
701     // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
702     // https://bugs.webkit.org/show_bug.cgi?id=28604.
703     // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in CachedResource::clearResourceToRevalidate.
704     ASSERT(!resource->m_proxyResource);
705
706     resource->m_proxyResource = this;
707     m_resourceToRevalidate = resource;
708 }
709
710 void CachedResource::clearResourceToRevalidate() 
711
712     ASSERT(m_resourceToRevalidate);
713     if (m_switchingClientsToRevalidatedResource)
714         return;
715
716     // 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.
717     if (m_resourceToRevalidate->m_proxyResource == this) {
718         m_resourceToRevalidate->m_proxyResource = 0;
719         m_resourceToRevalidate->deleteIfPossible();
720     }
721     m_handlesToRevalidate.clear();
722     m_resourceToRevalidate = 0;
723     deleteIfPossible();
724 }
725     
726 void CachedResource::switchClientsToRevalidatedResource()
727 {
728     ASSERT(m_resourceToRevalidate);
729     ASSERT(m_resourceToRevalidate->inCache());
730     ASSERT(!inCache());
731
732     LOG(ResourceLoading, "CachedResource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
733
734     m_switchingClientsToRevalidatedResource = true;
735     HashSet<CachedResourceHandleBase*>::iterator end = m_handlesToRevalidate.end();
736     for (HashSet<CachedResourceHandleBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
737         CachedResourceHandleBase* handle = *it;
738         handle->m_resource = m_resourceToRevalidate;
739         m_resourceToRevalidate->registerHandle(handle);
740         --m_handleCount;
741     }
742     ASSERT(!m_handleCount);
743     m_handlesToRevalidate.clear();
744
745     Vector<CachedResourceClient*> clientsToMove;
746     HashCountedSet<CachedResourceClient*>::iterator end2 = m_clients.end();
747     for (HashCountedSet<CachedResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
748         CachedResourceClient* client = it->key;
749         unsigned count = it->value;
750         while (count) {
751             clientsToMove.append(client);
752             --count;
753         }
754     }
755
756     unsigned moveCount = clientsToMove.size();
757     for (unsigned n = 0; n < moveCount; ++n)
758         removeClient(clientsToMove[n]);
759     ASSERT(m_clients.isEmpty());
760
761     for (unsigned n = 0; n < moveCount; ++n)
762         m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
763     for (unsigned n = 0; n < moveCount; ++n) {
764         // Calling didAddClient may do anything, including trying to cancel revalidation.
765         // Assert that it didn't succeed.
766         ASSERT(m_resourceToRevalidate);
767         // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
768         if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
769             m_resourceToRevalidate->didAddClient(clientsToMove[n]);
770     }
771     m_switchingClientsToRevalidatedResource = false;
772 }
773
774 void CachedResource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse)
775 {
776     m_responseTimestamp = currentTime();
777
778     // RFC2616 10.3.5
779     // Update cached headers from the 304 response
780     const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
781     HTTPHeaderMap::const_iterator end = newHeaders.end();
782     for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
783         // Entity headers should not be sent by servers when generating a 304
784         // response; misconfigured servers send them anyway. We shouldn't allow
785         // such headers to update the original request. We'll base this on the
786         // list defined by RFC2616 7.1, with a few additions for extension headers
787         // we care about.
788         if (!shouldUpdateHeaderAfterRevalidation(it->key))
789             continue;
790         m_response.setHTTPHeaderField(it->key, it->value);
791     }
792 }
793
794 void CachedResource::registerHandle(CachedResourceHandleBase* h)
795 {
796     ++m_handleCount;
797     if (m_resourceToRevalidate)
798         m_handlesToRevalidate.add(h);
799 }
800
801 void CachedResource::unregisterHandle(CachedResourceHandleBase* h)
802 {
803     ASSERT(m_handleCount > 0);
804     --m_handleCount;
805
806     if (m_resourceToRevalidate)
807          m_handlesToRevalidate.remove(h);
808
809     if (!m_handleCount)
810         deleteIfPossible();
811 }
812
813 bool CachedResource::canUseCacheValidator() const
814 {
815     if (m_loading || errorOccurred())
816         return false;
817
818     if (m_response.cacheControlContainsNoStore())
819         return false;
820     return m_response.hasCacheValidatorFields();
821 }
822
823 bool CachedResource::mustRevalidateDueToCacheHeaders(CachePolicy cachePolicy) const
824 {    
825     ASSERT(cachePolicy == CachePolicyRevalidate || cachePolicy == CachePolicyCache || cachePolicy == CachePolicyVerify);
826
827     if (cachePolicy == CachePolicyRevalidate)
828         return true;
829
830     if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
831         LOG(ResourceLoading, "CachedResource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
832         return true;
833     }
834
835     if (cachePolicy == CachePolicyCache) {
836         if (m_response.cacheControlContainsMustRevalidate() && isExpired()) {
837             LOG(ResourceLoading, "CachedResource %p mustRevalidate because of cachePolicy == CachePolicyCache and m_response.cacheControlContainsMustRevalidate() && isExpired()\n", this);
838             return true;
839         }
840         return false;
841     }
842
843     // CachePolicyVerify
844     if (isExpired()) {
845         LOG(ResourceLoading, "CachedResource %p mustRevalidate because of isExpired()\n", this);
846         return true;
847     }
848
849     return false;
850 }
851
852 bool CachedResource::isSafeToMakePurgeable() const
853
854     return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
855 }
856
857 bool CachedResource::makePurgeable(bool purgeable) 
858
859     if (purgeable) {
860         ASSERT(isSafeToMakePurgeable());
861
862         if (m_purgeableData) {
863             ASSERT(!m_data);
864             return true;
865         }
866         if (!m_data)
867             return false;
868         
869         // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
870         if (!m_data->hasOneRef())
871             return false;
872
873         m_data->createPurgeableBuffer();
874         if (!m_data->hasPurgeableBuffer())
875             return false;
876
877         m_purgeableData = m_data->releasePurgeableBuffer();
878         m_purgeableData->setPurgePriority(purgePriority());
879         m_purgeableData->makePurgeable(true);
880         m_data.clear();
881         return true;
882     }
883
884     if (!m_purgeableData)
885         return true;
886     ASSERT(!m_data);
887     ASSERT(!hasClients());
888
889     if (!m_purgeableData->makePurgeable(false))
890         return false; 
891
892     m_data = ResourceBuffer::adoptSharedBuffer(SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release()));
893     return true;
894 }
895
896 bool CachedResource::isPurgeable() const
897 {
898     return m_purgeableData && m_purgeableData->isPurgeable();
899 }
900
901 bool CachedResource::wasPurged() const
902 {
903     return m_purgeableData && m_purgeableData->wasPurged();
904 }
905
906 unsigned CachedResource::overheadSize() const
907 {
908     static const int kAverageClientsHashMapSize = 384;
909     return sizeof(CachedResource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
910 }
911
912 void CachedResource::setLoadPriority(ResourceLoadPriority loadPriority)
913 {
914     if (loadPriority == ResourceLoadPriorityUnresolved)
915         loadPriority = defaultPriorityForResourceType(type());
916     if (loadPriority == m_loadPriority)
917         return;
918     m_loadPriority = loadPriority;
919     if (m_loader && m_loader->handle())
920         m_loader->handle()->didChangePriority(loadPriority);
921 }
922
923
924 CachedResource::CachedResourceCallback::CachedResourceCallback(CachedResource* resource, CachedResourceClient* client)
925     : m_resource(resource)
926     , m_client(client)
927     , m_callbackTimer(this, &CachedResourceCallback::timerFired)
928 {
929     m_callbackTimer.startOneShot(0);
930 }
931
932 void CachedResource::CachedResourceCallback::cancel()
933 {
934     if (m_callbackTimer.isActive())
935         m_callbackTimer.stop();
936 }
937
938 void CachedResource::CachedResourceCallback::timerFired(Timer<CachedResourceCallback>*)
939 {
940     m_resource->didAddClient(m_client);
941 }
942
943 void CachedResource::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
944 {
945     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CachedResource);
946     memoryObjectInfo->setName(url().string());
947     info.addMember(m_resourceRequest, "resourceRequest");
948     info.addMember(m_fragmentIdentifierForRequest, "fragmentIdentifierForRequest");
949     info.addMember(m_clients, "clients");
950     info.addMember(m_accept, "accept");
951     info.addMember(m_loader, "loader");
952     info.addMember(m_response, "response");
953     info.addMember(m_data, "data");
954     info.addMember(m_cachedMetadata, "cachedMetadata");
955     info.addMember(m_nextInAllResourcesList, "nextInAllResourcesList");
956     info.addMember(m_prevInAllResourcesList, "prevInAllResourcesList");
957     info.addMember(m_nextInLiveResourcesList, "nextInLiveResourcesList");
958     info.addMember(m_prevInLiveResourcesList, "prevInLiveResourcesList");
959     info.addMember(m_owningCachedResourceLoader, "owningCachedResourceLoader");
960     info.addMember(m_resourceToRevalidate, "resourceToRevalidate");
961     info.addMember(m_proxyResource, "proxyResource");
962     info.addMember(m_handlesToRevalidate, "handlesToRevalidate");
963     info.addMember(m_options, "options");
964     info.addMember(m_decodedDataDeletionTimer, "decodedDataDeletionTimer");
965     info.ignoreMember(m_clientsAwaitingCallback);
966
967     if (m_purgeableData && !m_purgeableData->wasPurged())
968         info.addRawBuffer(m_purgeableData.get(), m_purgeableData->size(), "PurgeableData", "purgeableData");
969 }
970
971 }