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 CachedResource_h
24#define CachedResource_h
25
26#include "CachePolicy.h"
27#include "FrameLoaderTypes.h"
28#include "PurgePriority.h"
29#include "ResourceError.h"
30#include "ResourceLoadPriority.h"
31#include "ResourceLoaderOptions.h"
32#include "ResourceRequest.h"
33#include "ResourceResponse.h"
34#include "Timer.h"
35#include <time.h>
36#include <wtf/HashCountedSet.h>
37#include <wtf/HashSet.h>
38#include <wtf/OwnPtr.h>
39#include <wtf/Vector.h>
40#include <wtf/text/WTFString.h>
41
42namespace WebCore {
43
44class MemoryCache;
45class CachedResourceClient;
46class CachedResourceHandleBase;
47class CachedResourceLoader;
48class InspectorResource;
49class PurgeableBuffer;
50class ResourceBuffer;
51class SecurityOrigin;
52class SharedBuffer;
53class SubresourceLoader;
54
55// A resource that is held in the cache. Classes who want to use this object should derive
56// from CachedResourceClient, to get the function calls in case the requested data has arrived.
57// This class also does the actual communication with the loader to obtain the resource from the network.
58class CachedResource {
59    WTF_MAKE_NONCOPYABLE(CachedResource); WTF_MAKE_FAST_ALLOCATED;
60    friend class MemoryCache;
61    friend class InspectorResource;
62
63public:
64    enum Type {
65        MainResource,
66        ImageResource,
67        CSSStyleSheet,
68        Script,
69        FontResource,
70        RawResource
71#if ENABLE(SVG)
72        , SVGDocumentResource
73#endif
74#if ENABLE(XSLT)
75        , XSLStyleSheet
76#endif
77#if ENABLE(LINK_PREFETCH)
78        , LinkPrefetch
79        , LinkSubresource
80#endif
81#if ENABLE(VIDEO_TRACK)
82        , TextTrackResource
83#endif
84#if ENABLE(CSS_SHADERS)
85        , ShaderResource
86#endif
87    };
88
89    enum Status {
90        Unknown,      // let cache decide what to do with it
91        Pending,      // only partially loaded
92        Cached,       // regular case
93        LoadError,
94        DecodeError
95    };
96
97    CachedResource(const ResourceRequest&, Type);
98    virtual ~CachedResource();
99
100    virtual void load(CachedResourceLoader*, const ResourceLoaderOptions&);
101
102    virtual void setEncoding(const String&) { }
103    virtual String encoding() const { return String(); }
104    virtual void addDataBuffer(ResourceBuffer*);
105    virtual void addData(const char* data, unsigned length);
106    virtual void finishLoading(ResourceBuffer*);
107    virtual void error(CachedResource::Status);
108
109    void setResourceError(const ResourceError& error) { m_error = error; }
110    const ResourceError& resourceError() const { return m_error; }
111
112    virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; }
113
114    ResourceRequest& resourceRequest() { return m_resourceRequest; }
115    const KURL& url() const { return m_resourceRequest.url();}
116#if ENABLE(CACHE_PARTITIONING)
117    const String& cachePartition() const { return m_resourceRequest.cachePartition(); }
118#endif
119    Type type() const { return static_cast<Type>(m_type); }
120
121    ResourceLoadPriority loadPriority() const { return m_loadPriority; }
122    void setLoadPriority(ResourceLoadPriority);
123
124    void addClient(CachedResourceClient*);
125    void removeClient(CachedResourceClient*);
126    bool hasClients() const { return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty(); }
127    bool hasClient(CachedResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); }
128    bool deleteIfPossible();
129
130    enum PreloadResult {
131        PreloadNotReferenced,
132        PreloadReferenced,
133        PreloadReferencedWhileLoading,
134        PreloadReferencedWhileComplete
135    };
136    PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); }
137
138    virtual void didAddClient(CachedResourceClient*);
139    virtual void didRemoveClient(CachedResourceClient*) { }
140    virtual void allClientsRemoved() { }
141    void destroyDecodedDataIfNeeded();
142
143    unsigned count() const { return m_clients.size(); }
144
145    Status status() const { return static_cast<Status>(m_status); }
146    void setStatus(Status status) { m_status = status; }
147
148    unsigned size() const { return encodedSize() + decodedSize() + overheadSize(); }
149    unsigned encodedSize() const { return m_encodedSize; }
150    unsigned decodedSize() const { return m_decodedSize; }
151    unsigned overheadSize() const;
152
153    bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet.
154
155    bool isLoading() const { return m_loading; }
156    void setLoading(bool b) { m_loading = b; }
157    virtual bool stillNeedsLoad() const { return false; }
158
159    SubresourceLoader* loader() { return m_loader.get(); }
160
161    virtual bool isImage() const { return false; }
162    bool ignoreForRequestCount() const
163    {
164        return type() == MainResource
165#if ENABLE(LINK_PREFETCH)
166            || type() == LinkPrefetch
167            || type() == LinkSubresource
168#endif
169            || type() == RawResource;
170    }
171
172    unsigned accessCount() const { return m_accessCount; }
173    void increaseAccessCount() { m_accessCount++; }
174
175    // Computes the status of an object after loading.
176    // Updates the expire date on the cache entry file
177    void finish();
178
179    bool passesAccessControlCheck(SecurityOrigin*);
180
181    // Called by the cache if the object has been removed from the cache
182    // while still being referenced. This means the object should delete itself
183    // if the number of clients observing it ever drops to 0.
184    // The resource can be brought back to cache after successful revalidation.
185    void setInCache(bool inCache) { m_inCache = inCache; }
186    bool inCache() const { return m_inCache; }
187
188    bool inLiveDecodedResourcesList() { return m_inLiveDecodedResourcesList; }
189
190    void clearLoader();
191
192    ResourceBuffer* resourceBuffer() const { ASSERT(!m_purgeableData); return m_data.get(); }
193
194    virtual void willSendRequest(ResourceRequest&, const ResourceResponse&) { m_requestedFromNetworkingLayer = true; }
195    virtual void responseReceived(const ResourceResponse&);
196    void setResponse(const ResourceResponse& response) { m_response = response; }
197    const ResourceResponse& response() const { return m_response; }
198
199    bool canDelete() const { return !hasClients() && !m_loader && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_proxyResource; }
200    bool hasOneHandle() const { return m_handleCount == 1; }
201
202    bool isExpired() const;
203
204    // List of acceptable MIME types separated by ",".
205    // A MIME type may contain a wildcard, e.g. "text/*".
206    String accept() const { return m_accept; }
207    void setAccept(const String& accept) { m_accept = accept; }
208
209    void cancelLoad();
210    bool wasCanceled() const { return m_error.isCancellation(); }
211    bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; }
212    bool loadFailedOrCanceled() { return !m_error.isNull(); }
213
214    bool shouldSendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; }
215    DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; }
216
217    virtual void destroyDecodedData() { }
218
219    void setOwningCachedResourceLoader(CachedResourceLoader* cachedResourceLoader) { m_owningCachedResourceLoader = cachedResourceLoader; }
220
221    bool isPreloaded() const { return m_preloadCount; }
222    void increasePreloadCount() { ++m_preloadCount; }
223    void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
224
225    void registerHandle(CachedResourceHandleBase* h);
226    void unregisterHandle(CachedResourceHandleBase* h);
227
228    bool canUseCacheValidator() const;
229    bool mustRevalidateDueToCacheHeaders(CachePolicy) const;
230    bool isCacheValidator() const { return m_resourceToRevalidate; }
231    CachedResource* resourceToRevalidate() const { return m_resourceToRevalidate; }
232
233    bool isPurgeable() const;
234    bool wasPurged() const;
235
236    // This is used by the archive machinery to get at a purged resource without
237    // triggering a load. We should make it protected again if we can find a
238    // better way to handle the archive case.
239    bool makePurgeable(bool purgeable);
240
241    // HTTP revalidation support methods for CachedResourceLoader.
242    void setResourceToRevalidate(CachedResource*);
243    virtual void switchClientsToRevalidatedResource();
244    void clearResourceToRevalidate();
245    void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse);
246
247    virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
248
249    void setLoadFinishTime(double finishTime) { m_loadFinishTime = finishTime; }
250    double loadFinishTime() const { return m_loadFinishTime; }
251
252    virtual bool canReuse(const ResourceRequest&) const { return true; }
253
254#if PLATFORM(MAC)
255    void tryReplaceEncodedData(PassRefPtr<SharedBuffer>);
256#endif
257
258protected:
259    virtual void checkNotify();
260
261    void setEncodedSize(unsigned);
262    void setDecodedSize(unsigned);
263    void didAccessDecodedData(double timeStamp);
264
265    bool isSafeToMakePurgeable() const;
266
267    HashCountedSet<CachedResourceClient*> m_clients;
268
269    class CachedResourceCallback {
270    public:
271        static PassOwnPtr<CachedResourceCallback> schedule(CachedResource* resource, CachedResourceClient* client) { return adoptPtr(new CachedResourceCallback(resource, client)); }
272        void cancel();
273    private:
274        CachedResourceCallback(CachedResource*, CachedResourceClient*);
275        void timerFired(Timer<CachedResourceCallback>*);
276
277        CachedResource* m_resource;
278        CachedResourceClient* m_client;
279        Timer<CachedResourceCallback> m_callbackTimer;
280    };
281    HashMap<CachedResourceClient*, OwnPtr<CachedResourceCallback> > m_clientsAwaitingCallback;
282
283    ResourceRequest m_resourceRequest;
284    String m_accept;
285    RefPtr<SubresourceLoader> m_loader;
286    ResourceLoaderOptions m_options;
287    ResourceLoadPriority m_loadPriority;
288
289    ResourceResponse m_response;
290    double m_responseTimestamp;
291
292    RefPtr<ResourceBuffer> m_data;
293    OwnPtr<PurgeableBuffer> m_purgeableData;
294    Timer<CachedResource> m_decodedDataDeletionTimer;
295
296private:
297    bool addClientToSet(CachedResourceClient*);
298    void decodedDataDeletionTimerFired(Timer<CachedResource>*);
299
300    virtual PurgePriority purgePriority() const { return PurgeDefault; }
301    virtual bool mayTryReplaceEncodedData() const { return false; }
302
303    double currentAge() const;
304    double freshnessLifetime() const;
305
306    void addAdditionalRequestHeaders(CachedResourceLoader*);
307    void failBeforeStarting();
308
309    String m_fragmentIdentifierForRequest;
310
311    ResourceError m_error;
312
313    double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache
314    double m_loadFinishTime;
315
316    unsigned m_encodedSize;
317    unsigned m_decodedSize;
318    unsigned m_accessCount;
319    unsigned m_handleCount;
320    unsigned m_preloadCount;
321
322    unsigned m_preloadResult : 2; // PreloadResult
323
324    bool m_inLiveDecodedResourcesList : 1;
325    bool m_requestedFromNetworkingLayer : 1;
326
327    bool m_inCache : 1;
328    bool m_loading : 1;
329
330    bool m_switchingClientsToRevalidatedResource : 1;
331
332    unsigned m_type : 4; // Type
333    unsigned m_status : 3; // Status
334
335#ifndef NDEBUG
336    bool m_deleted;
337    unsigned m_lruIndex;
338#endif
339
340    CachedResource* m_nextInAllResourcesList;
341    CachedResource* m_prevInAllResourcesList;
342
343    CachedResource* m_nextInLiveResourcesList;
344    CachedResource* m_prevInLiveResourcesList;
345
346    CachedResourceLoader* m_owningCachedResourceLoader; // only non-0 for resources that are not in the cache
347
348    // 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
349    // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved
350    // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this
351    // resources becomes normal resource load.
352    CachedResource* m_resourceToRevalidate;
353
354    // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate).
355    CachedResource* m_proxyResource;
356
357    // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response.
358    HashSet<CachedResourceHandleBase*> m_handlesToRevalidate;
359};
360
361}
362
363#endif
364