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