2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
4 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
26 #include "core/CoreExport.h"
27 #include "core/fetch/CachedMetadataHandler.h"
28 #include "core/fetch/ResourceLoaderOptions.h"
29 #include "platform/Timer.h"
30 #include "platform/network/ResourceError.h"
31 #include "platform/network/ResourceLoadPriority.h"
32 #include "platform/network/ResourceRequest.h"
33 #include "platform/network/ResourceResponse.h"
34 #include "public/platform/WebDataConsumerHandle.h"
35 #include "wtf/Allocator.h"
36 #include "wtf/HashCountedSet.h"
37 #include "wtf/HashSet.h"
38 #include "wtf/OwnPtr.h"
39 #include "wtf/text/WTFString.h"
41 // FIXME(crbug.com/352043): This is temporarily enabled even on RELEASE to diagnose a wild crash.
42 #define ENABLE_RESOURCE_IS_DELETED_CHECK
46 struct FetchInitiatorInfo
;
49 class ResourcePtrBase
;
50 class ResourceFetcher
;
51 class ResourceTimingInfo
;
52 class InspectorResource
;
57 // A resource that is held in the cache. Classes who want to use this object should derive
58 // from ResourceClient, to get the function calls in case the requested data has arrived.
59 // This class also does the actual communication with the loader to obtain the resource from the network.
60 class CORE_EXPORT Resource
: public NoBaseWillBeGarbageCollectedFinalized
<Resource
> {
61 WTF_MAKE_NONCOPYABLE(Resource
); WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(Resource
);
62 friend class InspectorResource
;
79 Media
// Audio or video file requested by a HTML5 media element
83 Unknown
, // let cache decide what to do with it
84 Pending
, // only partially loaded
85 Cached
, // regular case
90 // Exposed for testing.
91 Resource(const ResourceRequest
&, Type
);
96 // Only deleteIfPossible should delete this.
100 virtual void dispose();
101 DECLARE_VIRTUAL_TRACE();
103 virtual void load(ResourceFetcher
*, const ResourceLoaderOptions
&);
105 virtual void setEncoding(const String
&) { }
106 virtual String
encoding() const { return String(); }
107 virtual void appendData(const char*, unsigned);
108 virtual void error(Resource::Status
);
109 virtual void setCORSFailed() { }
111 void setNeedsSynchronousCacheHit(bool needsSynchronousCacheHit
) { m_needsSynchronousCacheHit
= needsSynchronousCacheHit
; }
113 void setResourceError(const ResourceError
& error
) { m_error
= error
; }
114 const ResourceError
& resourceError() const { return m_error
; }
116 void setIdentifier(unsigned long identifier
) { m_identifier
= identifier
; }
117 unsigned long identifier() const { return m_identifier
; }
119 virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; }
121 ResourceRequest
& mutableResourceRequest() { return m_resourceRequest
; }
122 const ResourceRequest
& resourceRequest() const { return m_resourceRequest
; }
123 const ResourceRequest
& lastResourceRequest() const;
125 const KURL
& url() const { return m_resourceRequest
.url();}
126 Type
type() const { return static_cast<Type
>(m_type
); }
127 const ResourceLoaderOptions
& options() const { return m_options
; }
128 void setOptions(const ResourceLoaderOptions
& options
) { m_options
= options
; }
130 void didChangePriority(ResourceLoadPriority
, int intraPriorityValue
);
132 void addClient(ResourceClient
*);
133 void removeClient(ResourceClient
*);
134 bool hasClients() const { return !m_clients
.isEmpty() || !m_clientsAwaitingCallback
.isEmpty(); }
135 bool deleteIfPossible();
138 PreloadNotReferenced
,
140 PreloadReferencedWhileLoading
,
141 PreloadReferencedWhileComplete
143 PreloadResult
preloadResult() const { return static_cast<PreloadResult
>(m_preloadResult
); }
145 virtual void didAddClient(ResourceClient
*);
146 virtual void didRemoveClient(ResourceClient
*) { }
147 virtual void allClientsRemoved();
149 unsigned count() const { return m_clients
.size(); }
151 Status
status() const { return static_cast<Status
>(m_status
); }
152 void setStatus(Status status
) { m_status
= status
; }
154 size_t size() const { return encodedSize() + decodedSize() + overheadSize(); }
155 size_t encodedSize() const { return m_encodedSize
; }
156 size_t decodedSize() const { return m_decodedSize
; }
157 size_t overheadSize() const;
159 bool isLoaded() const { return !m_loading
; } // FIXME. Method name is inaccurate. Loading might not have started yet.
161 bool isLoading() const { return m_loading
; }
162 void setLoading(bool b
) { m_loading
= b
; }
163 virtual bool stillNeedsLoad() const { return false; }
165 ResourceLoader
* loader() const { return m_loader
.get(); }
167 virtual bool isImage() const { return false; }
168 bool shouldBlockLoadEvent() const
170 return type() != LinkPrefetch
171 && type() != LinkSubresource
174 && type() != TextTrack
;
177 // Computes the status of an object after loading.
178 // Updates the expire date on the cache entry file
179 void setLoadFinishTime(double finishTime
) { m_loadFinishTime
= finishTime
; }
182 // FIXME: Remove the stringless variant once all the callsites' error messages are updated.
183 bool passesAccessControlCheck(SecurityOrigin
*) const;
184 bool passesAccessControlCheck(SecurityOrigin
*, String
& errorDescription
) const;
186 bool isEligibleForIntegrityCheck(SecurityOrigin
*) const;
190 SharedBuffer
* resourceBuffer() const { return m_data
.get(); }
191 void setResourceBuffer(PassRefPtr
<SharedBuffer
>);
193 virtual void willFollowRedirect(ResourceRequest
&, const ResourceResponse
&);
195 virtual void updateRequest(const ResourceRequest
&) { }
196 virtual void responseReceived(const ResourceResponse
&, PassOwnPtr
<WebDataConsumerHandle
>);
197 void setResponse(const ResourceResponse
& response
) { m_response
= response
; }
198 const ResourceResponse
& response() const { return m_response
; }
200 virtual void reportResourceTimingToClients(const ResourceTimingInfo
&) { }
202 // Sets the serialized metadata retrieved from the platform's cache.
203 virtual void setSerializedCachedMetadata(const char*, size_t);
205 // This may return nullptr when the resource isn't cacheable.
206 CachedMetadataHandler
* cacheHandler();
208 bool hasOneHandle() const;
209 bool canDelete() const;
211 // List of acceptable MIME types separated by ",".
212 // A MIME type may contain a wildcard, e.g. "text/*".
213 AtomicString
accept() const { return m_accept
; }
214 void setAccept(const AtomicString
& accept
) { m_accept
= accept
; }
216 bool wasCanceled() const { return m_error
.isCancellation(); }
217 bool errorOccurred() const { return m_status
== LoadError
|| m_status
== DecodeError
; }
218 bool loadFailedOrCanceled() { return !m_error
.isNull(); }
220 DataBufferingPolicy
dataBufferingPolicy() const { return m_options
.dataBufferingPolicy
; }
221 void setDataBufferingPolicy(DataBufferingPolicy
);
223 bool isUnusedPreload() const { return isPreloaded() && preloadResult() == PreloadNotReferenced
; }
224 bool isPreloaded() const { return m_preloadCount
; }
225 void increasePreloadCount() { ++m_preloadCount
; }
226 void decreasePreloadCount() { ASSERT(m_preloadCount
); --m_preloadCount
; }
228 void registerHandle(ResourcePtrBase
* h
);
229 void unregisterHandle(ResourcePtrBase
* h
);
231 bool canReuseRedirectChain();
232 bool mustRevalidateDueToCacheHeaders();
233 bool canUseCacheValidator();
234 bool isCacheValidator() const { return m_resourceToRevalidate
; }
235 Resource
* resourceToRevalidate() const { return m_resourceToRevalidate
; }
236 void setResourceToRevalidate(Resource
*);
237 bool hasCacheControlNoStoreHeader();
238 bool hasVaryHeader() const;
240 double currentAge() const;
241 double freshnessLifetime();
242 double stalenessLifetime();
244 bool isPurgeable() const;
245 bool wasPurged() const;
248 void setCacheIdentifier(const String
& cacheIdentifier
) { m_cacheIdentifier
= cacheIdentifier
; }
249 String
cacheIdentifier() const { return m_cacheIdentifier
; }
251 virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
252 virtual void didDownloadData(int) { }
254 double loadFinishTime() const { return m_loadFinishTime
; }
256 virtual bool canReuse(const ResourceRequest
&) const { return true; }
258 // Used by the MemoryCache to reduce the memory consumption of the entry.
261 static const char* resourceTypeToString(Type
, const FetchInitiatorInfo
&);
263 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
264 void assertAlive() const { RELEASE_ASSERT(!m_deleted
); }
266 void assertAlive() const { }
270 virtual void checkNotify();
271 virtual void finishOnePart();
273 // Normal resource pointers will silently switch what Resource* they reference when we
274 // successfully revalidated the resource. We need a way to guarantee that the Resource
275 // that received the 304 response survives long enough to switch everything over to the
276 // revalidatedresource. The normal mechanisms for keeping a Resource alive externally
277 // (ResourcePtrs and ResourceClients registering themselves) don't work in this case, so
278 // have a separate internal protector).
279 class InternalResourcePtr
{
281 explicit InternalResourcePtr(Resource
* resource
)
282 : m_resource(resource
)
284 m_resource
->incrementProtectorCount();
287 ~InternalResourcePtr()
289 m_resource
->decrementProtectorCount();
290 m_resource
->deleteIfPossible();
293 Resource
* m_resource
;
296 void incrementProtectorCount() { m_protectorCount
++; }
297 void decrementProtectorCount() { m_protectorCount
--; }
299 void setEncodedSize(size_t);
300 void setDecodedSize(size_t);
301 void didAccessDecodedData();
303 void clearResourceToRevalidate();
304 void updateResponseAfterRevalidation(const ResourceResponse
& validatingResponse
);
306 void finishPendingClients();
308 HashCountedSet
<ResourceClient
*> m_clients
;
309 HashCountedSet
<ResourceClient
*> m_clientsAwaitingCallback
;
311 class ResourceCallback
: public NoBaseWillBeGarbageCollectedFinalized
<ResourceCallback
> {
313 static ResourceCallback
* callbackHandler();
315 void schedule(Resource
*);
316 void cancel(Resource
*);
317 bool isScheduled(Resource
*) const;
320 void timerFired(Timer
<ResourceCallback
>*);
321 Timer
<ResourceCallback
> m_callbackTimer
;
322 WillBeHeapHashSet
<RawPtrWillBeMember
<Resource
>> m_resourcesWithPendingClients
;
325 bool hasClient(ResourceClient
* client
) { return m_clients
.contains(client
) || m_clientsAwaitingCallback
.contains(client
); }
327 struct RedirectPair
{
328 ALLOW_ONLY_INLINE_ALLOCATION();
330 explicit RedirectPair(const ResourceRequest
& request
, const ResourceResponse
& redirectResponse
)
332 , m_redirectResponse(redirectResponse
)
336 ResourceRequest m_request
;
337 ResourceResponse m_redirectResponse
;
339 const Vector
<RedirectPair
>& redirectChain() const { return m_redirectChain
; }
341 virtual bool isSafeToUnlock() const { return false; }
342 virtual void destroyDecodedDataIfPossible() { }
344 ResourceRequest m_resourceRequest
;
345 AtomicString m_accept
;
346 PersistentWillBeMember
<ResourceLoader
> m_loader
;
347 ResourceLoaderOptions m_options
;
349 ResourceResponse m_response
;
350 double m_responseTimestamp
;
352 RefPtr
<SharedBuffer
> m_data
;
353 Timer
<Resource
> m_cancelTimer
;
357 bool addClientToSet(ResourceClient
*);
358 void cancelTimerFired(Timer
<Resource
>*);
360 void switchClientsToRevalidatedResource();
361 void revalidationSucceeded(const ResourceResponse
&);
362 void revalidationFailed();
366 bool hasRightHandleCountApartFromCache(unsigned targetCount
) const;
368 void setCachedMetadata(unsigned dataTypeID
, const char*, size_t, CachedMetadataHandler::CacheType
);
369 void clearCachedMetadata(CachedMetadataHandler::CacheType
);
370 CachedMetadata
* cachedMetadata(unsigned dataTypeID
) const;
372 String m_fragmentIdentifierForRequest
;
374 RefPtr
<CachedMetadata
> m_cachedMetadata
;
375 OwnPtrWillBeMember
<CacheHandler
> m_cacheHandler
;
377 ResourceError m_error
;
379 double m_loadFinishTime
;
381 unsigned long m_identifier
;
383 size_t m_encodedSize
;
384 size_t m_decodedSize
;
385 unsigned m_handleCount
;
386 unsigned m_preloadCount
;
387 unsigned m_protectorCount
;
389 String m_cacheIdentifier
;
391 unsigned m_preloadResult
: 2; // PreloadResult
392 unsigned m_requestedFromNetworkingLayer
: 1;
394 unsigned m_loading
: 1;
396 unsigned m_switchingClientsToRevalidatedResource
: 1;
398 unsigned m_type
: 4; // Type
399 unsigned m_status
: 3; // Status
401 unsigned m_wasPurged
: 1;
403 unsigned m_needsSynchronousCacheHit
: 1;
405 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
409 // If this field is non-null we are using the resource as a proxy for checking whether an existing resource is still up to date
410 // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved
411 // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this
412 // resources becomes normal resource load.
413 RawPtrWillBeMember
<Resource
> m_resourceToRevalidate
;
415 // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate).
416 RawPtrWillBeMember
<Resource
> m_proxyResource
;
418 // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response.
419 HashSet
<ResourcePtrBase
*> m_handlesToRevalidate
;
421 // Ordered list of all redirects followed while fetching this resource.
422 Vector
<RedirectPair
> m_redirectChain
;
425 class ResourceFactory
{
428 virtual Resource
* create(const ResourceRequest
&, const String
&) const = 0;
429 Resource::Type
type() const { return m_type
; }
432 ResourceFactory(Resource::Type type
) : m_type(type
) { }
434 Resource::Type m_type
;
438 // Intended to be used in LOG statements.
439 const char* ResourceTypeName(Resource::Type
);
442 #define DEFINE_RESOURCE_TYPE_CASTS(typeName) \
443 DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, resource->type() == Resource::typeName, resource.type() == Resource::typeName); \
444 inline typeName##Resource* to##typeName##Resource(const ResourcePtr<Resource>& ptr) { return to##typeName##Resource(ptr.get()); }