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