• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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.
6 
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.
11 
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.
16 
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.
21 */
22 
23 #ifndef Resource_h
24 #define Resource_h
25 
26 #include "core/fetch/ResourceLoaderOptions.h"
27 #include "platform/Timer.h"
28 #include "platform/network/ResourceError.h"
29 #include "platform/network/ResourceLoadPriority.h"
30 #include "platform/network/ResourceRequest.h"
31 #include "platform/network/ResourceResponse.h"
32 #include "wtf/HashCountedSet.h"
33 #include "wtf/HashSet.h"
34 #include "wtf/OwnPtr.h"
35 #include "wtf/text/WTFString.h"
36 
37 namespace WebCore {
38 
39 class MemoryCache;
40 class CachedMetadata;
41 class ResourceClient;
42 class ResourcePtrBase;
43 class ResourceFetcher;
44 class InspectorResource;
45 class PurgeableBuffer;
46 class ResourceLoader;
47 class SecurityOrigin;
48 class SharedBuffer;
49 
50 // A resource that is held in the cache. Classes who want to use this object should derive
51 // from ResourceClient, to get the function calls in case the requested data has arrived.
52 // This class also does the actual communication with the loader to obtain the resource from the network.
53 class Resource {
54     WTF_MAKE_NONCOPYABLE(Resource); WTF_MAKE_FAST_ALLOCATED;
55     friend class MemoryCache;
56     friend class InspectorResource;
57 
58 public:
59     enum Type {
60         MainResource,
61         Image,
62         CSSStyleSheet,
63         Script,
64         Font,
65         Raw,
66         SVGDocument,
67         XSLStyleSheet,
68         LinkPrefetch,
69         LinkSubresource,
70         TextTrack,
71         Shader,
72         ImportResource
73     };
74 
75     enum Status {
76         Unknown, // let cache decide what to do with it
77         Pending, // only partially loaded
78         Cached, // regular case
79         LoadError,
80         DecodeError
81     };
82 
83     Resource(const ResourceRequest&, Type);
84     virtual ~Resource();
85 
86     // Determines the order in which CachedResources are evicted
87     // from the decoded resources cache.
88     enum CacheLiveResourcePriority {
89         CacheLiveResourcePriorityLow = 0,
90         CacheLiveResourcePriorityHigh
91     };
92 
93     virtual void load(ResourceFetcher*, const ResourceLoaderOptions&);
94 
setEncoding(const String &)95     virtual void setEncoding(const String&) { }
encoding()96     virtual String encoding() const { return String(); }
97     virtual void appendData(const char*, int);
98     virtual void error(Resource::Status);
99 
setResourceError(const ResourceError & error)100     void setResourceError(const ResourceError& error) { m_error = error; }
resourceError()101     const ResourceError& resourceError() const { return m_error; }
102 
setIdentifier(unsigned long identifier)103     void setIdentifier(unsigned long identifier) { m_identifier = identifier; }
identifier()104     unsigned long identifier() const { return m_identifier; }
105 
shouldIgnoreHTTPStatusCodeErrors()106     virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; }
107 
resourceRequest()108     ResourceRequest& resourceRequest() { return m_resourceRequest; }
url()109     const KURL& url() const { return m_resourceRequest.url();}
type()110     Type type() const { return static_cast<Type>(m_type); }
options()111     const ResourceLoaderOptions& options() const { return m_options; }
setOptions(const ResourceLoaderOptions & options)112     void setOptions(const ResourceLoaderOptions& options) { m_options = options; }
113 
114     void didChangePriority(ResourceLoadPriority);
115 
116     void addClient(ResourceClient*);
117     void removeClient(ResourceClient*);
hasClients()118     bool hasClients() const { return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty(); }
119     bool deleteIfPossible();
120 
121     enum PreloadResult {
122         PreloadNotReferenced,
123         PreloadReferenced,
124         PreloadReferencedWhileLoading,
125         PreloadReferencedWhileComplete
126     };
preloadResult()127     PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); }
128 
129     virtual void didAddClient(ResourceClient*);
didRemoveClient(ResourceClient *)130     virtual void didRemoveClient(ResourceClient*) { }
131     virtual void allClientsRemoved();
132 
count()133     unsigned count() const { return m_clients.size(); }
134 
status()135     Status status() const { return static_cast<Status>(m_status); }
setStatus(Status status)136     void setStatus(Status status) { m_status = status; }
137 
size()138     size_t size() const { return encodedSize() + decodedSize() + overheadSize(); }
encodedSize()139     size_t encodedSize() const { return m_encodedSize; }
decodedSize()140     size_t decodedSize() const { return m_decodedSize; }
141     size_t overheadSize() const;
142 
isLoaded()143     bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet.
144 
isLoading()145     bool isLoading() const { return m_loading; }
setLoading(bool b)146     void setLoading(bool b) { m_loading = b; }
stillNeedsLoad()147     virtual bool stillNeedsLoad() const { return false; }
148 
loader()149     ResourceLoader* loader() const { return m_loader.get(); }
150 
isImage()151     virtual bool isImage() const { return false; }
ignoreForRequestCount()152     bool ignoreForRequestCount() const
153     {
154         return type() == MainResource
155             || type() == LinkPrefetch
156             || type() == LinkSubresource
157             || type() == Raw;
158     }
159 
160     void updateForAccess();
accessCount()161     unsigned accessCount() const { return m_accessCount; }
162 
163     // Computes the status of an object after loading.
164     // Updates the expire date on the cache entry file
165     void finish(double finishTime = 0.0);
166 
167     // FIXME: Remove the stringless variant once all the callsites' error messages are updated.
168     bool passesAccessControlCheck(SecurityOrigin*);
169     bool passesAccessControlCheck(SecurityOrigin*, String& errorDescription);
170 
171     // Called by the cache if the object has been removed from the cache
172     // while still being referenced. This means the object should delete itself
173     // if the number of clients observing it ever drops to 0.
174     // The resource can be brought back to cache after successful revalidation.
setInCache(bool inCache)175     void setInCache(bool inCache) { m_inCache = inCache; }
inCache()176     bool inCache() const { return m_inCache; }
177 
178     void setCacheLiveResourcePriority(CacheLiveResourcePriority);
cacheLiveResourcePriority()179     unsigned cacheLiveResourcePriority() const { return m_cacheLiveResourcePriority; }
inLiveDecodedResourcesList()180     bool inLiveDecodedResourcesList() { return m_inLiveDecodedResourcesList; }
181 
182     void clearLoader();
183 
resourceBuffer()184     SharedBuffer* resourceBuffer() const { ASSERT(!m_purgeableData); return m_data.get(); }
185     void setResourceBuffer(PassRefPtr<SharedBuffer>);
186 
willSendRequest(ResourceRequest &,const ResourceResponse &)187     virtual void willSendRequest(ResourceRequest&, const ResourceResponse&) { m_requestedFromNetworkingLayer = true; }
188     virtual void responseReceived(const ResourceResponse&);
setResponse(const ResourceResponse & response)189     void setResponse(const ResourceResponse& response) { m_response = response; }
response()190     const ResourceResponse& response() const { return m_response; }
191 
192     // Sets the serialized metadata retrieved from the platform's cache.
193     void setSerializedCachedMetadata(const char*, size_t);
194 
195     // Caches the given metadata in association with this resource and suggests
196     // that the platform persist it. The dataTypeID is a pseudo-randomly chosen
197     // identifier that is used to distinguish data generated by the caller.
198     void setCachedMetadata(unsigned dataTypeID, const char*, size_t);
199 
200     // Returns cached metadata of the given type associated with this resource.
201     CachedMetadata* cachedMetadata(unsigned dataTypeID) const;
202 
canDelete()203     bool canDelete() const { return !hasClients() && !m_loader && !m_preloadCount && !m_handleCount && !m_protectorCount && !m_resourceToRevalidate && !m_proxyResource; }
hasOneHandle()204     bool hasOneHandle() const { return m_handleCount == 1; }
205 
206     bool isExpired() const;
207 
208     // List of acceptable MIME types separated by ",".
209     // A MIME type may contain a wildcard, e.g. "text/*".
accept()210     AtomicString accept() const { return m_accept; }
setAccept(const AtomicString & accept)211     void setAccept(const AtomicString& accept) { m_accept = accept; }
212 
wasCanceled()213     bool wasCanceled() const { return m_error.isCancellation(); }
errorOccurred()214     bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; }
loadFailedOrCanceled()215     bool loadFailedOrCanceled() { return !m_error.isNull(); }
216 
shouldSendResourceLoadCallbacks()217     bool shouldSendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; }
dataBufferingPolicy()218     DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; }
219 
destroyDecodedData()220     virtual void destroyDecodedData() { }
221 
isPreloaded()222     bool isPreloaded() const { return m_preloadCount; }
increasePreloadCount()223     void increasePreloadCount() { ++m_preloadCount; }
decreasePreloadCount()224     void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
225 
226     void registerHandle(ResourcePtrBase* h);
227     void unregisterHandle(ResourcePtrBase* h);
228 
229     bool canUseCacheValidator() const;
230     bool mustRevalidateDueToCacheHeaders() const;
isCacheValidator()231     bool isCacheValidator() const { return m_resourceToRevalidate; }
resourceToRevalidate()232     Resource* resourceToRevalidate() const { return m_resourceToRevalidate; }
233     void setResourceToRevalidate(Resource*);
234 
235     bool isPurgeable() const;
236     bool wasPurged() const;
237 
238     // This is used by the archive machinery to get at a purged resource without
239     // triggering a load. We should make it protected again if we can find a
240     // better way to handle the archive case.
241     bool makePurgeable(bool purgeable);
242 
didSendData(unsigned long long,unsigned long long)243     virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
didDownloadData(int)244     virtual void didDownloadData(int) { }
245 
loadFinishTime()246     double loadFinishTime() const { return m_loadFinishTime; }
247 
canReuse(const ResourceRequest &)248     virtual bool canReuse(const ResourceRequest&) const { return true; }
249 
250 protected:
251     virtual void checkNotify();
252     virtual void finishOnePart();
253 
254     // Normal resource pointers will silently switch what Resource* they reference when we
255     // successfully revalidated the resource. We need a way to guarantee that the Resource
256     // that received the 304 response survives long enough to switch everything over to the
257     // revalidatedresource. The normal mechanisms for keeping a Resource alive externally
258     // (ResourcePtrs and ResourceClients registering themselves) don't work in this case, so
259     // have a separate internal protector).
260     class InternalResourcePtr {
261     public:
InternalResourcePtr(Resource * resource)262         explicit InternalResourcePtr(Resource* resource)
263             : m_resource(resource)
264         {
265             m_resource->incrementProtectorCount();
266         }
267 
~InternalResourcePtr()268         ~InternalResourcePtr()
269         {
270             m_resource->decrementProtectorCount();
271             m_resource->deleteIfPossible();
272         }
273     private:
274         Resource* m_resource;
275     };
276 
incrementProtectorCount()277     void incrementProtectorCount() { m_protectorCount++; }
decrementProtectorCount()278     void decrementProtectorCount() { m_protectorCount--; }
279 
280     void setEncodedSize(size_t);
281     void setDecodedSize(size_t);
282     void didAccessDecodedData(double timeStamp);
283 
284     bool isSafeToMakePurgeable() const;
285 
286     virtual void switchClientsToRevalidatedResource();
287     void clearResourceToRevalidate();
288     void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse);
289 
290     void finishPendingClients();
291 
292     HashCountedSet<ResourceClient*> m_clients;
293     HashCountedSet<ResourceClient*> m_clientsAwaitingCallback;
294 
295     class ResourceCallback {
296     public:
297         static ResourceCallback* callbackHandler();
298         void schedule(Resource*);
299         void cancel(Resource*);
300     private:
301         ResourceCallback();
302         void timerFired(Timer<ResourceCallback>*);
303         Timer<ResourceCallback> m_callbackTimer;
304         HashSet<Resource*> m_resourcesWithPendingClients;
305     };
306 
hasClient(ResourceClient * client)307     bool hasClient(ResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); }
308 
309     ResourceRequest m_resourceRequest;
310     AtomicString m_accept;
311     RefPtr<ResourceLoader> m_loader;
312     ResourceLoaderOptions m_options;
313 
314     ResourceResponse m_response;
315     double m_responseTimestamp;
316 
317     RefPtr<SharedBuffer> m_data;
318     OwnPtr<PurgeableBuffer> m_purgeableData;
319     Timer<Resource> m_cancelTimer;
320 
321 private:
322     bool addClientToSet(ResourceClient*);
323     void cancelTimerFired(Timer<Resource>*);
324 
325     void revalidationSucceeded(const ResourceResponse&);
326     void revalidationFailed();
327 
328     double currentAge() const;
329     double freshnessLifetime() const;
330 
331     void failBeforeStarting();
332 
333     String m_fragmentIdentifierForRequest;
334 
335     RefPtr<CachedMetadata> m_cachedMetadata;
336 
337     ResourceError m_error;
338 
339     double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache
340     double m_loadFinishTime;
341 
342     unsigned long m_identifier;
343 
344     size_t m_encodedSize;
345     size_t m_decodedSize;
346     unsigned m_accessCount;
347     unsigned m_handleCount;
348     unsigned m_preloadCount;
349     unsigned m_protectorCount;
350 
351     unsigned m_preloadResult : 2; // PreloadResult
352     unsigned m_cacheLiveResourcePriority : 2; // CacheLiveResourcePriority
353     unsigned m_inLiveDecodedResourcesList : 1;
354     unsigned m_requestedFromNetworkingLayer : 1;
355 
356     unsigned m_inCache : 1;
357     unsigned m_loading : 1;
358 
359     unsigned m_switchingClientsToRevalidatedResource : 1;
360 
361     unsigned m_type : 4; // Type
362     unsigned m_status : 3; // Status
363 
364 #ifndef NDEBUG
365     bool m_deleted;
366     unsigned m_lruIndex;
367 #endif
368 
369     Resource* m_nextInAllResourcesList;
370     Resource* m_prevInAllResourcesList;
371 
372     Resource* m_nextInLiveResourcesList;
373     Resource* m_prevInLiveResourcesList;
374 
375     // 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
376     // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved
377     // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this
378     // resources becomes normal resource load.
379     Resource* m_resourceToRevalidate;
380 
381     // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate).
382     Resource* m_proxyResource;
383 
384     // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response.
385     HashSet<ResourcePtrBase*> m_handlesToRevalidate;
386 };
387 
388 #if !LOG_DISABLED
389 // Intended to be used in LOG statements.
390 const char* ResourceTypeName(Resource::Type);
391 #endif
392 
393 #define DEFINE_RESOURCE_TYPE_CASTS(typeName) \
394     DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, resource->type() == Resource::typeName, resource.type() == Resource::typeName); \
395     inline typeName##Resource* to##typeName##Resource(const ResourcePtr<Resource>& ptr) { return to##typeName##Resource(ptr.get()); }
396 
397 }
398 
399 #endif
400