- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / Resource.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 "core/fetch/Resource.h"
26
27 #include "core/fetch/CachedMetadata.h"
28 #include "core/fetch/CrossOriginAccessControl.h"
29 #include "core/fetch/MemoryCache.h"
30 #include "core/fetch/ResourceClient.h"
31 #include "core/fetch/ResourceClientWalker.h"
32 #include "core/fetch/ResourceFetcher.h"
33 #include "core/fetch/ResourceLoader.h"
34 #include "core/fetch/ResourcePtr.h"
35 #include "core/inspector/InspectorInstrumentation.h"
36 #include "platform/Logging.h"
37 #include "platform/PurgeableBuffer.h"
38 #include "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
48 using namespace WTF;
49
50 namespace 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.
55 const 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.
75 const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
76     "content-",
77     "x-content-",
78     "x-webkit-"
79 };
80
81 static 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
94 DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Resource"));
95
96 Resource::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
142 Resource::~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
156 void Resource::failBeforeStarting()
157 {
158     LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
159     error(Resource::LoadError);
160 }
161
162 void 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     m_status = Pending;
185     if (m_loader) {
186         RELEASE_ASSERT(m_options.synchronousPolicy == RequestSynchronously);
187         m_loader->changeToSynchronous();
188         return;
189     }
190     m_loader = ResourceLoader::create(fetcher, this, request, options);
191     m_loader->start();
192 }
193
194 void Resource::checkNotify()
195 {
196     if (isLoading())
197         return;
198
199     ResourceClientWalker<ResourceClient> w(m_clients);
200     while (ResourceClient* c = w.next())
201         c->notifyFinished(this);
202 }
203
204 void Resource::appendData(const char* data, int length)
205 {
206     TRACE_EVENT0("webkit", "Resource::appendData");
207     ASSERT(!m_resourceToRevalidate);
208     ASSERT(!errorOccurred());
209     if (m_options.dataBufferingPolicy == DoNotBufferData)
210         return;
211     if (m_data)
212         m_data->append(data, length);
213     else
214         m_data = SharedBuffer::create(data, length);
215     setEncodedSize(m_data->size());
216 }
217
218 void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer)
219 {
220     ASSERT(!m_resourceToRevalidate);
221     ASSERT(!errorOccurred());
222     ASSERT(m_options.dataBufferingPolicy == BufferData);
223     m_data = resourceBuffer;
224     setEncodedSize(m_data->size());
225 }
226
227 void Resource::error(Resource::Status status)
228 {
229     if (m_resourceToRevalidate)
230         revalidationFailed();
231
232     if (!m_error.isNull() && (m_error.isCancellation() || !isPreloaded()))
233         memoryCache()->remove(this);
234
235     setStatus(status);
236     ASSERT(errorOccurred());
237     m_data.clear();
238
239     setLoading(false);
240     checkNotify();
241 }
242
243 void Resource::finishOnePart()
244 {
245     setLoading(false);
246     checkNotify();
247 }
248
249 void Resource::finish(double finishTime)
250 {
251     ASSERT(!m_resourceToRevalidate);
252     ASSERT(!errorOccurred());
253     m_loadFinishTime = finishTime;
254     finishOnePart();
255     if (!errorOccurred())
256         m_status = Cached;
257 }
258
259 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
260 {
261     String ignoredErrorDescription;
262     return passesAccessControlCheck(securityOrigin, ignoredErrorDescription);
263 }
264
265 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin, String& errorDescription)
266 {
267     return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
268 }
269
270 bool Resource::isExpired() const
271 {
272     if (m_response.isNull())
273         return false;
274
275     return currentAge() > freshnessLifetime();
276 }
277
278 double Resource::currentAge() const
279 {
280     // RFC2616 13.2.3
281     // No compensation for latency as that is not terribly important in practice
282     double dateValue = m_response.date();
283     double apparentAge = std::isfinite(dateValue) ? std::max(0., m_responseTimestamp - dateValue) : 0;
284     double ageValue = m_response.age();
285     double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
286     double residentTime = currentTime() - m_responseTimestamp;
287     return correctedReceivedAge + residentTime;
288 }
289
290 double Resource::freshnessLifetime() const
291 {
292 #if !OS(ANDROID)
293     // On desktop, local files should be reloaded in case they change.
294     if (m_response.url().isLocalFile())
295         return 0;
296 #endif
297
298     // Cache other non-http resources liberally.
299     if (!m_response.url().protocolIsInHTTPFamily())
300         return std::numeric_limits<double>::max();
301
302     // RFC2616 13.2.4
303     double maxAgeValue = m_response.cacheControlMaxAge();
304     if (std::isfinite(maxAgeValue))
305         return maxAgeValue;
306     double expiresValue = m_response.expires();
307     double dateValue = m_response.date();
308     double creationTime = std::isfinite(dateValue) ? dateValue : m_responseTimestamp;
309     if (std::isfinite(expiresValue))
310         return expiresValue - creationTime;
311     double lastModifiedValue = m_response.lastModified();
312     if (std::isfinite(lastModifiedValue))
313         return (creationTime - lastModifiedValue) * 0.1;
314     // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
315     return 0;
316 }
317
318 void Resource::responseReceived(const ResourceResponse& response)
319 {
320     setResponse(response);
321     m_responseTimestamp = currentTime();
322     String encoding = response.textEncodingName();
323     if (!encoding.isNull())
324         setEncoding(encoding);
325
326     if (!m_resourceToRevalidate)
327         return;
328     if (response.httpStatusCode() == 304)
329         revalidationSucceeded(response);
330     else
331         revalidationFailed();
332 }
333
334 void Resource::setSerializedCachedMetadata(const char* data, size_t size)
335 {
336     // We only expect to receive cached metadata from the platform once.
337     // If this triggers, it indicates an efficiency problem which is most
338     // likely unexpected in code designed to improve performance.
339     ASSERT(!m_cachedMetadata);
340     ASSERT(!m_resourceToRevalidate);
341
342     m_cachedMetadata = CachedMetadata::deserialize(data, size);
343 }
344
345 void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size)
346 {
347     // Currently, only one type of cached metadata per resource is supported.
348     // If the need arises for multiple types of metadata per resource this could
349     // be enhanced to store types of metadata in a map.
350     ASSERT(!m_cachedMetadata);
351
352     m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
353     const Vector<char>& serializedData = m_cachedMetadata->serialize();
354     WebKit::Platform::current()->cacheMetadata(m_response.url(), m_response.responseTime(), serializedData.data(), serializedData.size());
355 }
356
357 CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const
358 {
359     if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
360         return 0;
361     return m_cachedMetadata.get();
362 }
363
364 void Resource::setCacheLiveResourcePriority(CacheLiveResourcePriority priority)
365 {
366     if (inCache() && m_inLiveDecodedResourcesList && m_cacheLiveResourcePriority != priority) {
367         memoryCache()->removeFromLiveDecodedResourcesList(this);
368         m_cacheLiveResourcePriority = priority;
369         memoryCache()->insertInLiveDecodedResourcesList(this);
370         memoryCache()->prune();
371     }
372 }
373
374 void Resource::clearLoader()
375 {
376     m_loader = 0;
377 }
378
379 void Resource::addClient(ResourceClient* client)
380 {
381     if (addClientToSet(client))
382         didAddClient(client);
383 }
384
385 void Resource::didAddClient(ResourceClient* c)
386 {
387     if (!isLoading() && !stillNeedsLoad())
388         c->notifyFinished(this);
389 }
390
391 static bool shouldSendCachedDataSynchronouslyForType(Resource::Type type)
392 {
393     // Some resources types default to return data synchronously.
394     // For most of these, it's because there are layout tests that
395     // expect data to return synchronously in case of cache hit. In
396     // the case of fonts, there was a performance regression.
397     // FIXME: Get to the point where we don't need to special-case sync/async
398     // behavior for different resource types.
399     if (type == Resource::Image)
400         return true;
401     if (type == Resource::CSSStyleSheet)
402         return true;
403     if (type == Resource::Script)
404         return true;
405     if (type == Resource::Font)
406         return true;
407     return false;
408 }
409
410 bool Resource::addClientToSet(ResourceClient* client)
411 {
412     ASSERT(!isPurgeable());
413
414     if (m_preloadResult == PreloadNotReferenced) {
415         if (isLoaded())
416             m_preloadResult = PreloadReferencedWhileComplete;
417         else if (m_requestedFromNetworkingLayer)
418             m_preloadResult = PreloadReferencedWhileLoading;
419         else
420             m_preloadResult = PreloadReferenced;
421     }
422     if (!hasClients() && inCache())
423         memoryCache()->addToLiveResourcesSize(this);
424
425     // If we have existing data to send to the new client and the resource type supprts it, send it asynchronously.
426     if (!m_response.isNull() && !m_proxyResource && !shouldSendCachedDataSynchronouslyForType(type())) {
427         m_clientsAwaitingCallback.add(client);
428         ResourceCallback::callbackHandler()->schedule(this);
429         return false;
430     }
431
432     m_clients.add(client);
433     return true;
434 }
435
436 void Resource::removeClient(ResourceClient* client)
437 {
438     if (m_clientsAwaitingCallback.contains(client)) {
439         ASSERT(!m_clients.contains(client));
440         m_clientsAwaitingCallback.remove(client);
441         if (m_clientsAwaitingCallback.isEmpty())
442             ResourceCallback::callbackHandler()->cancel(this);
443     } else {
444         ASSERT(m_clients.contains(client));
445         m_clients.remove(client);
446         didRemoveClient(client);
447     }
448
449     bool deleted = deleteIfPossible();
450     if (!deleted && !hasClients()) {
451         if (inCache()) {
452             memoryCache()->removeFromLiveResourcesSize(this);
453             memoryCache()->removeFromLiveDecodedResourcesList(this);
454         }
455         if (!m_switchingClientsToRevalidatedResource)
456             allClientsRemoved();
457         if (response().cacheControlContainsNoStore()) {
458             // RFC2616 14.9.2:
459             // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
460             // "... History buffers MAY store such responses as part of their normal operation."
461             // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
462             if (url().protocolIs("https"))
463                 memoryCache()->remove(this);
464         } else {
465             memoryCache()->prune(this);
466         }
467     }
468     // This object may be dead here.
469 }
470
471 void Resource::allClientsRemoved()
472 {
473     if (!m_loader)
474         return;
475     if (m_type == MainResource || m_type == Raw)
476         cancelTimerFired(&m_cancelTimer);
477     else if (!m_cancelTimer.isActive())
478         m_cancelTimer.startOneShot(0);
479 }
480
481 void Resource::cancelTimerFired(Timer<Resource>* timer)
482 {
483     ASSERT_UNUSED(timer, timer == &m_cancelTimer);
484     if (hasClients() || !m_loader)
485         return;
486     ResourcePtr<Resource> protect(this);
487     m_loader->cancelIfNotFinishing();
488     if (m_status != Cached)
489         memoryCache()->remove(this);
490 }
491
492 bool Resource::deleteIfPossible()
493 {
494     if (canDelete() && !inCache()) {
495         InspectorInstrumentation::willDestroyResource(this);
496         delete this;
497         return true;
498     }
499     return false;
500 }
501
502 void Resource::setDecodedSize(unsigned size)
503 {
504     if (size == m_decodedSize)
505         return;
506
507     int delta = size - m_decodedSize;
508
509     // The object must now be moved to a different queue, since its size has been changed.
510     // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
511     // queue.
512     if (inCache())
513         memoryCache()->removeFromLRUList(this);
514
515     m_decodedSize = size;
516
517     if (inCache()) {
518         // Now insert into the new LRU list.
519         memoryCache()->insertInLRUList(this);
520
521         // Insert into or remove from the live decoded list if necessary.
522         // When inserting into the LiveDecodedResourcesList it is possible
523         // that the m_lastDecodedAccessTime is still zero or smaller than
524         // the m_lastDecodedAccessTime of the current list head. This is a
525         // violation of the invariant that the list is to be kept sorted
526         // by access time. The weakening of the invariant does not pose
527         // a problem. For more details please see: https://bugs.webkit.org/show_bug.cgi?id=30209
528         if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
529             memoryCache()->insertInLiveDecodedResourcesList(this);
530         else if (!m_decodedSize && m_inLiveDecodedResourcesList)
531             memoryCache()->removeFromLiveDecodedResourcesList(this);
532
533         // Update the cache's size totals.
534         memoryCache()->adjustSize(hasClients(), delta);
535     }
536 }
537
538 void Resource::setEncodedSize(unsigned size)
539 {
540     if (size == m_encodedSize)
541         return;
542
543     int delta = size - m_encodedSize;
544
545     // The object must now be moved to a different queue, since its size has been changed.
546     // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
547     // queue.
548     if (inCache())
549         memoryCache()->removeFromLRUList(this);
550
551     m_encodedSize = size;
552
553     if (inCache()) {
554         // Now insert into the new LRU list.
555         memoryCache()->insertInLRUList(this);
556
557         // Update the cache's size totals.
558         memoryCache()->adjustSize(hasClients(), delta);
559     }
560 }
561
562 void Resource::didAccessDecodedData(double timeStamp)
563 {
564     m_lastDecodedAccessTime = timeStamp;
565     if (inCache()) {
566         if (m_inLiveDecodedResourcesList) {
567             memoryCache()->removeFromLiveDecodedResourcesList(this);
568             memoryCache()->insertInLiveDecodedResourcesList(this);
569         }
570         memoryCache()->prune();
571     }
572 }
573
574 void Resource::finishPendingClients()
575 {
576     while (!m_clientsAwaitingCallback.isEmpty()) {
577         ResourceClient* client = m_clientsAwaitingCallback.begin()->key;
578         m_clientsAwaitingCallback.remove(client);
579         m_clients.add(client);
580         didAddClient(client);
581     }
582 }
583
584 void Resource::setResourceToRevalidate(Resource* resource)
585 {
586     ASSERT(resource);
587     ASSERT(!m_resourceToRevalidate);
588     ASSERT(resource != this);
589     ASSERT(m_handlesToRevalidate.isEmpty());
590     ASSERT(resource->type() == type());
591
592     LOG(ResourceLoading, "Resource %p setResourceToRevalidate %p", this, resource);
593
594     // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
595     // https://bugs.webkit.org/show_bug.cgi?id=28604.
596     // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in Resource::clearResourceToRevalidate.
597     ASSERT(!resource->m_proxyResource);
598
599     resource->m_proxyResource = this;
600     m_resourceToRevalidate = resource;
601 }
602
603 void Resource::clearResourceToRevalidate()
604 {
605     ASSERT(m_resourceToRevalidate);
606     if (m_switchingClientsToRevalidatedResource)
607         return;
608
609     // 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.
610     if (m_resourceToRevalidate->m_proxyResource == this) {
611         m_resourceToRevalidate->m_proxyResource = 0;
612         m_resourceToRevalidate->deleteIfPossible();
613     }
614     m_handlesToRevalidate.clear();
615     m_resourceToRevalidate = 0;
616     deleteIfPossible();
617 }
618
619 void Resource::switchClientsToRevalidatedResource()
620 {
621     ASSERT(m_resourceToRevalidate);
622     ASSERT(m_resourceToRevalidate->inCache());
623     ASSERT(!inCache());
624
625     LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
626
627     m_resourceToRevalidate->m_identifier = m_identifier;
628
629     m_switchingClientsToRevalidatedResource = true;
630     HashSet<ResourcePtrBase*>::iterator end = m_handlesToRevalidate.end();
631     for (HashSet<ResourcePtrBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
632         ResourcePtrBase* handle = *it;
633         handle->m_resource = m_resourceToRevalidate;
634         m_resourceToRevalidate->registerHandle(handle);
635         --m_handleCount;
636     }
637     ASSERT(!m_handleCount);
638     m_handlesToRevalidate.clear();
639
640     Vector<ResourceClient*> clientsToMove;
641     HashCountedSet<ResourceClient*>::iterator end2 = m_clients.end();
642     for (HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
643         ResourceClient* client = it->key;
644         unsigned count = it->value;
645         while (count) {
646             clientsToMove.append(client);
647             --count;
648         }
649     }
650
651     unsigned moveCount = clientsToMove.size();
652     for (unsigned n = 0; n < moveCount; ++n)
653         removeClient(clientsToMove[n]);
654     ASSERT(m_clients.isEmpty());
655
656     for (unsigned n = 0; n < moveCount; ++n)
657         m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
658     for (unsigned n = 0; n < moveCount; ++n) {
659         // Calling didAddClient may do anything, including trying to cancel revalidation.
660         // Assert that it didn't succeed.
661         ASSERT(m_resourceToRevalidate);
662         // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
663         if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
664             m_resourceToRevalidate->didAddClient(clientsToMove[n]);
665     }
666     m_switchingClientsToRevalidatedResource = false;
667 }
668
669 void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse)
670 {
671     m_responseTimestamp = currentTime();
672
673     // RFC2616 10.3.5
674     // Update cached headers from the 304 response
675     const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
676     HTTPHeaderMap::const_iterator end = newHeaders.end();
677     for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
678         // Entity headers should not be sent by servers when generating a 304
679         // response; misconfigured servers send them anyway. We shouldn't allow
680         // such headers to update the original request. We'll base this on the
681         // list defined by RFC2616 7.1, with a few additions for extension headers
682         // we care about.
683         if (!shouldUpdateHeaderAfterRevalidation(it->key))
684             continue;
685         m_response.setHTTPHeaderField(it->key, it->value);
686     }
687 }
688
689 void Resource::revalidationSucceeded(const ResourceResponse& response)
690 {
691     ASSERT(m_resourceToRevalidate);
692     ASSERT(!m_resourceToRevalidate->inCache());
693     ASSERT(m_resourceToRevalidate->isLoaded());
694     ASSERT(inCache());
695
696     // Calling evict() can potentially delete revalidatingResource, which we use
697     // below. This mustn't be the case since revalidation means it is loaded
698     // and so canDelete() is false.
699     ASSERT(!canDelete());
700
701     m_resourceToRevalidate->updateResponseAfterRevalidation(response);
702     memoryCache()->replace(m_resourceToRevalidate, this);
703
704     switchClientsToRevalidatedResource();
705     ASSERT(!m_deleted);
706     // clearResourceToRevalidate deletes this.
707     clearResourceToRevalidate();
708 }
709
710 void Resource::revalidationFailed()
711 {
712     ASSERT(WTF::isMainThread());
713     LOG(ResourceLoading, "Revalidation failed for %p", this);
714     ASSERT(resourceToRevalidate());
715     clearResourceToRevalidate();
716 }
717
718 void Resource::updateForAccess()
719 {
720     ASSERT(inCache());
721
722     // Need to make sure to remove before we increase the access count, since
723     // the queue will possibly change.
724     memoryCache()->removeFromLRUList(this);
725
726     // If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
727     if (!m_accessCount)
728         memoryCache()->adjustSize(hasClients(), size());
729
730     m_accessCount++;
731     memoryCache()->insertInLRUList(this);
732 }
733
734 void Resource::registerHandle(ResourcePtrBase* h)
735 {
736     ++m_handleCount;
737     if (m_resourceToRevalidate)
738         m_handlesToRevalidate.add(h);
739 }
740
741 void Resource::unregisterHandle(ResourcePtrBase* h)
742 {
743     ASSERT(m_handleCount > 0);
744     --m_handleCount;
745
746     if (m_resourceToRevalidate)
747         m_handlesToRevalidate.remove(h);
748
749     if (!m_handleCount)
750         deleteIfPossible();
751 }
752
753 bool Resource::canUseCacheValidator() const
754 {
755     if (m_loading || errorOccurred())
756         return false;
757
758     if (m_response.cacheControlContainsNoStore())
759         return false;
760     return m_response.hasCacheValidatorFields();
761 }
762
763 bool Resource::mustRevalidateDueToCacheHeaders(CachePolicy cachePolicy) const
764 {
765     ASSERT(cachePolicy == CachePolicyRevalidate || cachePolicy == CachePolicyCache || cachePolicy == CachePolicyVerify);
766
767     if (cachePolicy == CachePolicyRevalidate)
768         return true;
769
770     if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
771         LOG(ResourceLoading, "Resource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
772         return true;
773     }
774
775     if (cachePolicy == CachePolicyCache) {
776         if (m_response.cacheControlContainsMustRevalidate() && isExpired()) {
777             LOG(ResourceLoading, "Resource %p mustRevalidate because of cachePolicy == CachePolicyCache and m_response.cacheControlContainsMustRevalidate() && isExpired()\n", this);
778             return true;
779         }
780         return false;
781     }
782
783     // CachePolicyVerify
784     if (isExpired()) {
785         LOG(ResourceLoading, "Resource %p mustRevalidate because of isExpired()\n", this);
786         return true;
787     }
788
789     return false;
790 }
791
792 bool Resource::isSafeToMakePurgeable() const
793 {
794     return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
795 }
796
797 bool Resource::makePurgeable(bool purgeable)
798 {
799     if (purgeable) {
800         ASSERT(isSafeToMakePurgeable());
801
802         if (m_purgeableData) {
803             ASSERT(!m_data);
804             return true;
805         }
806         if (!m_data)
807             return false;
808
809         // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
810         if (!m_data->hasOneRef())
811             return false;
812
813         m_data->createPurgeableBuffer();
814         if (!m_data->hasPurgeableBuffer())
815             return false;
816
817         m_purgeableData = m_data->releasePurgeableBuffer();
818         m_purgeableData->unlock();
819         m_data.clear();
820         return true;
821     }
822
823     if (!m_purgeableData)
824         return true;
825
826     ASSERT(!m_data);
827     ASSERT(!hasClients());
828
829     if (!m_purgeableData->lock())
830         return false;
831
832     m_data = SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release());
833     return true;
834 }
835
836 bool Resource::isPurgeable() const
837 {
838     return m_purgeableData && m_purgeableData->isPurgeable();
839 }
840
841 bool Resource::wasPurged() const
842 {
843     return m_purgeableData && m_purgeableData->wasPurged();
844 }
845
846 unsigned Resource::overheadSize() const
847 {
848     static const int kAverageClientsHashMapSize = 384;
849     return sizeof(Resource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
850 }
851
852 void Resource::didChangePriority(ResourceLoadPriority loadPriority)
853 {
854     if (m_loader)
855         m_loader->didChangePriority(loadPriority);
856 }
857
858 Resource::ResourceCallback* Resource::ResourceCallback::callbackHandler()
859 {
860     DEFINE_STATIC_LOCAL(ResourceCallback, callbackHandler, ());
861     return &callbackHandler;
862 }
863
864 Resource::ResourceCallback::ResourceCallback()
865     : m_callbackTimer(this, &ResourceCallback::timerFired)
866 {
867 }
868
869 void Resource::ResourceCallback::schedule(Resource* resource)
870 {
871     if (!m_callbackTimer.isActive())
872         m_callbackTimer.startOneShot(0);
873     m_resourcesWithPendingClients.add(resource);
874 }
875
876 void Resource::ResourceCallback::cancel(Resource* resource)
877 {
878     m_resourcesWithPendingClients.remove(resource);
879     if (m_callbackTimer.isActive() && m_resourcesWithPendingClients.isEmpty())
880         m_callbackTimer.stop();
881 }
882
883 void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
884 {
885     HashSet<Resource*>::iterator end = m_resourcesWithPendingClients.end();
886     Vector<ResourcePtr<Resource> > resources;
887     for (HashSet<Resource*>::iterator it = m_resourcesWithPendingClients.begin(); it != end; ++it)
888         resources.append(*it);
889     m_resourcesWithPendingClients.clear();
890     for (size_t i = 0; i < resources.size(); i++)
891         resources[i]->finishPendingClients();
892 }
893
894 #if !LOG_DISABLED
895 const char* ResourceTypeName(Resource::Type type)
896 {
897     switch (type) {
898     case Resource::MainResource:
899         return "MainResource";
900     case Resource::Image:
901         return "Image";
902     case Resource::CSSStyleSheet:
903         return "CSSStyleSheet";
904     case Resource::Script:
905         return "Script";
906     case Resource::Font:
907         return "Font";
908     case Resource::Raw:
909         return "Raw";
910     case Resource::SVGDocument:
911         return "SVGDocument";
912     case Resource::XSLStyleSheet:
913         return "XSLStyleSheet";
914     case Resource::LinkPrefetch:
915         return "LinkPrefetch";
916     case Resource::LinkSubresource:
917         return "LinkSubresource";
918     case Resource::TextTrack:
919         return "TextTrack";
920     case Resource::Shader:
921         return "Shader";
922     case Resource::ImportResource:
923         return "ImportResource";
924     }
925     ASSERT_NOT_REACHED();
926     return "Unknown";
927 }
928 #endif // !LOG_DISABLED
929
930 }