• 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 // FIXME(crbug.com/352043): This is temporarily enabled even on RELEASE to diagnose a wild crash.
38 #define ENABLE_RESOURCE_IS_DELETED_CHECK
39 
40 namespace blink {
41 
42 struct FetchInitiatorInfo;
43 class MemoryCache;
44 class CachedMetadata;
45 class ResourceClient;
46 class ResourcePtrBase;
47 class ResourceFetcher;
48 class InspectorResource;
49 class ResourceLoader;
50 class SecurityOrigin;
51 class SharedBuffer;
52 
53 // A resource that is held in the cache. Classes who want to use this object should derive
54 // from ResourceClient, to get the function calls in case the requested data has arrived.
55 // This class also does the actual communication with the loader to obtain the resource from the network.
56 class Resource : public NoBaseWillBeGarbageCollectedFinalized<Resource> {
57     WTF_MAKE_NONCOPYABLE(Resource); WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
58     friend class InspectorResource;
59 
60 public:
61     enum Type {
62         MainResource,
63         Image,
64         CSSStyleSheet,
65         Script,
66         Font,
67         Raw,
68         SVGDocument,
69         XSLStyleSheet,
70         LinkPrefetch,
71         LinkSubresource,
72         TextTrack,
73         ImportResource,
74         Media // Audio or video file requested by a HTML5 media element
75     };
76 
77     enum Status {
78         Unknown, // let cache decide what to do with it
79         Pending, // only partially loaded
80         Cached, // regular case
81         LoadError,
82         DecodeError
83     };
84 
85     enum MetadataCacheType {
86         SendToPlatform, // send cache data to blink::Platform::cacheMetadata
87         CacheLocally // cache only in Resource's member variables
88     };
89 
90     Resource(const ResourceRequest&, Type);
91 #if ENABLE(OILPAN)
92     virtual ~Resource();
93 #else
94 protected:
95     // Only deleteIfPossible should delete this.
96     virtual ~Resource();
97 public:
98 #endif
99     virtual void dispose();
100     virtual void trace(Visitor*);
instanceCount()101     static unsigned instanceCount() { return s_instanceCount; }
102 
103     virtual void load(ResourceFetcher*, const ResourceLoaderOptions&);
104 
setEncoding(const String &)105     virtual void setEncoding(const String&) { }
encoding()106     virtual String encoding() const { return String(); }
107     virtual void appendData(const char*, int);
108     virtual void error(Resource::Status);
109 
setNeedsSynchronousCacheHit(bool needsSynchronousCacheHit)110     void setNeedsSynchronousCacheHit(bool needsSynchronousCacheHit) { m_needsSynchronousCacheHit = needsSynchronousCacheHit; }
111 
setResourceError(const ResourceError & error)112     void setResourceError(const ResourceError& error) { m_error = error; }
resourceError()113     const ResourceError& resourceError() const { return m_error; }
114 
setIdentifier(unsigned long identifier)115     void setIdentifier(unsigned long identifier) { m_identifier = identifier; }
identifier()116     unsigned long identifier() const { return m_identifier; }
117 
shouldIgnoreHTTPStatusCodeErrors()118     virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; }
119 
mutableResourceRequest()120     ResourceRequest& mutableResourceRequest() { return m_resourceRequest; }
resourceRequest()121     const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
122     const ResourceRequest& lastResourceRequest() const;
123 
url()124     const KURL& url() const { return m_resourceRequest.url();}
type()125     Type type() const { return static_cast<Type>(m_type); }
options()126     const ResourceLoaderOptions& options() const { return m_options; }
setOptions(const ResourceLoaderOptions & options)127     void setOptions(const ResourceLoaderOptions& options) { m_options = options; }
128 
129     void didChangePriority(ResourceLoadPriority, int intraPriorityValue);
130 
131     void addClient(ResourceClient*);
132     void removeClient(ResourceClient*);
hasClients()133     bool hasClients() const { return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty(); }
134     bool deleteIfPossible();
135 
136     enum PreloadResult {
137         PreloadNotReferenced,
138         PreloadReferenced,
139         PreloadReferencedWhileLoading,
140         PreloadReferencedWhileComplete
141     };
preloadResult()142     PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); }
143 
144     virtual void didAddClient(ResourceClient*);
didRemoveClient(ResourceClient *)145     virtual void didRemoveClient(ResourceClient*) { }
146     virtual void allClientsRemoved();
147 
count()148     unsigned count() const { return m_clients.size(); }
149 
status()150     Status status() const { return static_cast<Status>(m_status); }
setStatus(Status status)151     void setStatus(Status status) { m_status = status; }
152 
size()153     size_t size() const { return encodedSize() + decodedSize() + overheadSize(); }
encodedSize()154     size_t encodedSize() const { return m_encodedSize; }
decodedSize()155     size_t decodedSize() const { return m_decodedSize; }
156     size_t overheadSize() const;
157 
isLoaded()158     bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet.
159 
isLoading()160     bool isLoading() const { return m_loading; }
setLoading(bool b)161     void setLoading(bool b) { m_loading = b; }
stillNeedsLoad()162     virtual bool stillNeedsLoad() const { return false; }
163 
loader()164     ResourceLoader* loader() const { return m_loader.get(); }
165 
isImage()166     virtual bool isImage() const { return false; }
ignoreForRequestCount()167     bool ignoreForRequestCount() const
168     {
169         return type() == MainResource
170             || type() == LinkPrefetch
171             || type() == LinkSubresource
172             || type() == Media
173             || type() == Raw
174             || type() == TextTrack;
175     }
176 
177     // Computes the status of an object after loading.
178     // Updates the expire date on the cache entry file
179     void finish(double finishTime = 0.0);
180 
181     // FIXME: Remove the stringless variant once all the callsites' error messages are updated.
182     bool passesAccessControlCheck(SecurityOrigin*);
183     bool passesAccessControlCheck(SecurityOrigin*, String& errorDescription);
184 
185     void clearLoader();
186 
resourceBuffer()187     SharedBuffer* resourceBuffer() const { return m_data.get(); }
188     void setResourceBuffer(PassRefPtr<SharedBuffer>);
189 
190     virtual void willSendRequest(ResourceRequest&, const ResourceResponse&);
191 
updateRequest(const ResourceRequest &)192     virtual void updateRequest(const ResourceRequest&) { }
193     virtual void responseReceived(const ResourceResponse&);
setResponse(const ResourceResponse & response)194     void setResponse(const ResourceResponse& response) { m_response = response; }
response()195     const ResourceResponse& response() const { return m_response; }
196 
197     // Sets the serialized metadata retrieved from the platform's cache.
198     void setSerializedCachedMetadata(const char*, size_t);
199 
200     // Caches the given metadata in association with this resource and suggests
201     // that the platform persist it. The dataTypeID is a pseudo-randomly chosen
202     // identifier that is used to distinguish data generated by the caller.
203     void setCachedMetadata(unsigned dataTypeID, const char*, size_t, MetadataCacheType = SendToPlatform);
204 
205     // Reset existing metadata, to allow setting new data.
206     void clearCachedMetadata();
207 
208     // Returns cached metadata of the given type associated with this resource.
209     CachedMetadata* cachedMetadata(unsigned dataTypeID) const;
210 
211     bool hasOneHandle() const;
212     bool canDelete() const;
213 
214     // List of acceptable MIME types separated by ",".
215     // A MIME type may contain a wildcard, e.g. "text/*".
accept()216     AtomicString accept() const { return m_accept; }
setAccept(const AtomicString & accept)217     void setAccept(const AtomicString& accept) { m_accept = accept; }
218 
wasCanceled()219     bool wasCanceled() const { return m_error.isCancellation(); }
errorOccurred()220     bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; }
loadFailedOrCanceled()221     bool loadFailedOrCanceled() { return !m_error.isNull(); }
222 
dataBufferingPolicy()223     DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; }
224     void setDataBufferingPolicy(DataBufferingPolicy);
225 
isUnusedPreload()226     bool isUnusedPreload() const { return isPreloaded() && preloadResult() == PreloadNotReferenced; }
isPreloaded()227     bool isPreloaded() const { return m_preloadCount; }
increasePreloadCount()228     void increasePreloadCount() { ++m_preloadCount; }
decreasePreloadCount()229     void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
230 
231     void registerHandle(ResourcePtrBase* h);
232     void unregisterHandle(ResourcePtrBase* h);
233 
234     bool canReuseRedirectChain();
235     bool mustRevalidateDueToCacheHeaders();
236     bool canUseCacheValidator();
isCacheValidator()237     bool isCacheValidator() const { return m_resourceToRevalidate; }
resourceToRevalidate()238     Resource* resourceToRevalidate() const { return m_resourceToRevalidate; }
239     void setResourceToRevalidate(Resource*);
240     bool hasCacheControlNoStoreHeader();
241 
242     bool isPurgeable() const;
243     bool wasPurged() const;
244     bool lock();
245 
didSendData(unsigned long long,unsigned long long)246     virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
didDownloadData(int)247     virtual void didDownloadData(int) { }
248 
loadFinishTime()249     double loadFinishTime() const { return m_loadFinishTime; }
250 
canReuse(const ResourceRequest &)251     virtual bool canReuse(const ResourceRequest&) const { return true; }
252 
253     // Used by the MemoryCache to reduce the memory consumption of the entry.
254     void prune();
255 
256     static const char* resourceTypeToString(Type, const FetchInitiatorInfo&);
257 
258 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
assertAlive()259     void assertAlive() const { RELEASE_ASSERT(!m_deleted); }
260 #else
assertAlive()261     void assertAlive() const { }
262 #endif
263 
264 protected:
265     virtual void checkNotify();
266     virtual void finishOnePart();
267 
268     // Normal resource pointers will silently switch what Resource* they reference when we
269     // successfully revalidated the resource. We need a way to guarantee that the Resource
270     // that received the 304 response survives long enough to switch everything over to the
271     // revalidatedresource. The normal mechanisms for keeping a Resource alive externally
272     // (ResourcePtrs and ResourceClients registering themselves) don't work in this case, so
273     // have a separate internal protector).
274     class InternalResourcePtr {
275     public:
InternalResourcePtr(Resource * resource)276         explicit InternalResourcePtr(Resource* resource)
277             : m_resource(resource)
278         {
279             m_resource->incrementProtectorCount();
280         }
281 
~InternalResourcePtr()282         ~InternalResourcePtr()
283         {
284             m_resource->decrementProtectorCount();
285             m_resource->deleteIfPossible();
286         }
287     private:
288         Resource* m_resource;
289     };
290 
incrementProtectorCount()291     void incrementProtectorCount() { m_protectorCount++; }
decrementProtectorCount()292     void decrementProtectorCount() { m_protectorCount--; }
293 
294     void setEncodedSize(size_t);
295     void setDecodedSize(size_t);
296     void didAccessDecodedData();
297 
298     virtual void switchClientsToRevalidatedResource();
299     void clearResourceToRevalidate();
300     void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse);
301 
302     void finishPendingClients();
303 
304     HashCountedSet<ResourceClient*> m_clients;
305     HashCountedSet<ResourceClient*> m_clientsAwaitingCallback;
306 
307     class ResourceCallback {
308     public:
309         static ResourceCallback* callbackHandler();
310         void schedule(Resource*);
311         void cancel(Resource*);
312         bool isScheduled(Resource*) const;
313     private:
314         ResourceCallback();
315         void timerFired(Timer<ResourceCallback>*);
316         Timer<ResourceCallback> m_callbackTimer;
317         HashSet<Resource*> m_resourcesWithPendingClients;
318     };
319 
hasClient(ResourceClient * client)320     bool hasClient(ResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); }
321 
322     struct RedirectPair {
323     public:
RedirectPairRedirectPair324         explicit RedirectPair(const ResourceRequest& request, const ResourceResponse& redirectResponse)
325             : m_request(request)
326             , m_redirectResponse(redirectResponse)
327         {
328         }
329 
330         ResourceRequest m_request;
331         ResourceResponse m_redirectResponse;
332     };
redirectChain()333     const Vector<RedirectPair>& redirectChain() const { return m_redirectChain; }
334 
isSafeToUnlock()335     virtual bool isSafeToUnlock() const { return false; }
destroyDecodedDataIfPossible()336     virtual void destroyDecodedDataIfPossible() { }
337 
338     ResourceRequest m_resourceRequest;
339     AtomicString m_accept;
340     RefPtrWillBeMember<ResourceLoader> m_loader;
341     ResourceLoaderOptions m_options;
342 
343     ResourceResponse m_response;
344     double m_responseTimestamp;
345 
346     RefPtr<SharedBuffer> m_data;
347     Timer<Resource> m_cancelTimer;
348 
349 private:
350     bool addClientToSet(ResourceClient*);
351     void cancelTimerFired(Timer<Resource>*);
352 
353     void revalidationSucceeded(const ResourceResponse&);
354     void revalidationFailed();
355 
356     bool unlock();
357 
358     bool hasRightHandleCountApartFromCache(unsigned targetCount) const;
359 
360     void failBeforeStarting();
361 
362     String m_fragmentIdentifierForRequest;
363 
364     RefPtr<CachedMetadata> m_cachedMetadata;
365 
366     ResourceError m_error;
367 
368     double m_loadFinishTime;
369 
370     unsigned long m_identifier;
371 
372     size_t m_encodedSize;
373     size_t m_decodedSize;
374     unsigned m_handleCount;
375     unsigned m_preloadCount;
376     unsigned m_protectorCount;
377 
378     unsigned m_preloadResult : 2; // PreloadResult
379     unsigned m_requestedFromNetworkingLayer : 1;
380 
381     unsigned m_loading : 1;
382 
383     unsigned m_switchingClientsToRevalidatedResource : 1;
384 
385     unsigned m_type : 4; // Type
386     unsigned m_status : 3; // Status
387 
388     unsigned m_wasPurged : 1;
389 
390     unsigned m_needsSynchronousCacheHit : 1;
391 
392 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
393     bool m_deleted;
394 #endif
395 
396     // 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
397     // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved
398     // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this
399     // resources becomes normal resource load.
400     RawPtrWillBeMember<Resource> m_resourceToRevalidate;
401 
402     // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate).
403     RawPtrWillBeMember<Resource> m_proxyResource;
404 
405     // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response.
406     HashSet<ResourcePtrBase*> m_handlesToRevalidate;
407 
408     // Ordered list of all redirects followed while fetching this resource.
409     Vector<RedirectPair> m_redirectChain;
410 
411     static unsigned s_instanceCount;
412 };
413 
414 #if !LOG_DISABLED
415 // Intended to be used in LOG statements.
416 const char* ResourceTypeName(Resource::Type);
417 #endif
418 
419 #define DEFINE_RESOURCE_TYPE_CASTS(typeName) \
420     DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, resource->type() == Resource::typeName, resource.type() == Resource::typeName); \
421     inline typeName##Resource* to##typeName##Resource(const ResourcePtr<Resource>& ptr) { return to##typeName##Resource(ptr.get()); }
422 
423 }
424 
425 #endif
426