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