1 /* 2 Copyright (C) 1998 Lars Knoll (knoll (at) mpi-hd.mpg.de) 3 Copyright (C) 2001 Dirk Mueller <mueller (at) kde.org> 4 Copyright (C) 2006 Samuel Weinig (sam.weinig (at) 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/loader/ResourceLoaderOptions.h" 27 #include "core/loader/cache/CachePolicy.h" 28 #include "core/platform/Timer.h" 29 #include "core/platform/network/ResourceError.h" 30 #include "core/platform/network/ResourceLoadPriority.h" 31 #include "core/platform/network/ResourceRequest.h" 32 #include "core/platform/network/ResourceResponse.h" 33 #include "wtf/HashCountedSet.h" 34 #include "wtf/HashSet.h" 35 #include "wtf/OwnPtr.h" 36 #include "wtf/text/WTFString.h" 37 38 namespace WebCore { 39 40 class MemoryCache; 41 class CachedMetadata; 42 class ResourceClient; 43 class ResourcePtrBase; 44 class ResourceFetcher; 45 class InspectorResource; 46 class PurgeableBuffer; 47 class ResourceLoader; 48 class SecurityOrigin; 49 class SharedBuffer; 50 51 // A resource that is held in the cache. Classes who want to use this object should derive 52 // from ResourceClient, to get the function calls in case the requested data has arrived. 53 // This class also does the actual communication with the loader to obtain the resource from the network. 54 class Resource { 55 WTF_MAKE_NONCOPYABLE(Resource); WTF_MAKE_FAST_ALLOCATED; 56 friend class MemoryCache; 57 friend class InspectorResource; 58 59 public: 60 enum Type { 61 MainResource, 62 Image, 63 CSSStyleSheet, 64 Script, 65 Font, 66 Raw, 67 SVGDocument, 68 XSLStyleSheet, 69 LinkPrefetch, 70 LinkSubresource, 71 TextTrack, 72 Shader, 73 ImportResource 74 }; 75 76 enum Status { 77 Unknown, // let cache decide what to do with it 78 Pending, // only partially loaded 79 Cached, // regular case 80 LoadError, 81 DecodeError 82 }; 83 84 Resource(const ResourceRequest&, Type); 85 virtual ~Resource(); 86 87 // Determines the order in which CachedResources are evicted 88 // from the decoded resources cache. 89 enum CacheLiveResourcePriority { 90 CacheLiveResourcePriorityLow = 0, 91 CacheLiveResourcePriorityHigh 92 }; 93 94 virtual void load(ResourceFetcher*, const ResourceLoaderOptions&); 95 96 virtual void setEncoding(const String&) { } 97 virtual String encoding() const { return String(); } 98 virtual void appendData(const char*, int); 99 virtual void error(Resource::Status); 100 101 void setResourceError(const ResourceError& error) { m_error = error; } 102 const ResourceError& resourceError() const { return m_error; } 103 104 void setIdentifier(unsigned long identifier) { m_identifier = identifier; } 105 unsigned long identifier() const { return m_identifier; } 106 107 virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; } 108 109 ResourceRequest& resourceRequest() { return m_resourceRequest; } 110 const KURL& url() const { return m_resourceRequest.url();} 111 Type type() const { return static_cast<Type>(m_type); } 112 const ResourceLoaderOptions& options() const { return m_options; } 113 114 void didChangePriority(ResourceLoadPriority); 115 116 void addClient(ResourceClient*); 117 void removeClient(ResourceClient*); 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 }; 127 PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); } 128 129 virtual void didAddClient(ResourceClient*); 130 virtual void didRemoveClient(ResourceClient*) { } 131 virtual void allClientsRemoved(); 132 133 unsigned count() const { return m_clients.size(); } 134 135 Status status() const { return static_cast<Status>(m_status); } 136 void setStatus(Status status) { m_status = status; } 137 138 unsigned size() const { return encodedSize() + decodedSize() + overheadSize(); } 139 unsigned encodedSize() const { return m_encodedSize; } 140 unsigned decodedSize() const { return m_decodedSize; } 141 unsigned overheadSize() const; 142 143 bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet. 144 145 bool isLoading() const { return m_loading; } 146 void setLoading(bool b) { m_loading = b; } 147 virtual bool stillNeedsLoad() const { return false; } 148 149 ResourceLoader* loader() { return m_loader.get(); } 150 151 virtual bool isImage() const { return false; } 152 bool ignoreForRequestCount() const 153 { 154 return type() == MainResource 155 || type() == LinkPrefetch 156 || type() == LinkSubresource 157 || type() == Raw; 158 } 159 160 void updateForAccess(); 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. 175 void setInCache(bool inCache) { m_inCache = inCache; } 176 bool inCache() const { return m_inCache; } 177 178 void setCacheLiveResourcePriority(CacheLiveResourcePriority); 179 unsigned cacheLiveResourcePriority() const { return m_cacheLiveResourcePriority; } 180 bool inLiveDecodedResourcesList() { return m_inLiveDecodedResourcesList; } 181 182 void clearLoader(); 183 184 SharedBuffer* resourceBuffer() const { ASSERT(!m_purgeableData); return m_data.get(); } 185 186 virtual void willSendRequest(ResourceRequest&, const ResourceResponse&) { m_requestedFromNetworkingLayer = true; } 187 virtual void responseReceived(const ResourceResponse&); 188 void setResponse(const ResourceResponse& response) { m_response = response; } 189 const ResourceResponse& response() const { return m_response; } 190 191 // Sets the serialized metadata retrieved from the platform's cache. 192 void setSerializedCachedMetadata(const char*, size_t); 193 194 // Caches the given metadata in association with this resource and suggests 195 // that the platform persist it. The dataTypeID is a pseudo-randomly chosen 196 // identifier that is used to distinguish data generated by the caller. 197 void setCachedMetadata(unsigned dataTypeID, const char*, size_t); 198 199 // Returns cached metadata of the given type associated with this resource. 200 CachedMetadata* cachedMetadata(unsigned dataTypeID) const; 201 202 bool canDelete() const { return !hasClients() && !m_loader && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_proxyResource; } 203 bool hasOneHandle() const { return m_handleCount == 1; } 204 205 bool isExpired() const; 206 207 // List of acceptable MIME types separated by ",". 208 // A MIME type may contain a wildcard, e.g. "text/*". 209 AtomicString accept() const { return m_accept; } 210 void setAccept(const AtomicString& accept) { m_accept = accept; } 211 212 bool wasCanceled() const { return m_error.isCancellation(); } 213 bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; } 214 bool loadFailedOrCanceled() { return !m_error.isNull(); } 215 216 bool shouldSendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; } 217 DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; } 218 219 virtual void destroyDecodedData() { } 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(ResourcePtrBase* h); 226 void unregisterHandle(ResourcePtrBase* h); 227 228 bool canUseCacheValidator() const; 229 bool mustRevalidateDueToCacheHeaders(CachePolicy) const; 230 bool isCacheValidator() const { return m_resourceToRevalidate; } 231 Resource* resourceToRevalidate() const { return m_resourceToRevalidate; } 232 void setResourceToRevalidate(Resource*); 233 234 bool isPurgeable() const; 235 bool wasPurged() const; 236 237 // This is used by the archive machinery to get at a purged resource without 238 // triggering a load. We should make it protected again if we can find a 239 // better way to handle the archive case. 240 bool makePurgeable(bool purgeable); 241 242 virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { } 243 virtual void didDownloadData(int) { } 244 245 double loadFinishTime() const { return m_loadFinishTime; } 246 247 virtual bool canReuse(const ResourceRequest&) const { return true; } 248 249 protected: 250 virtual void checkNotify(); 251 virtual void finishOnePart(); 252 253 void setEncodedSize(unsigned); 254 void setDecodedSize(unsigned); 255 void didAccessDecodedData(double timeStamp); 256 257 bool isSafeToMakePurgeable() const; 258 259 virtual void switchClientsToRevalidatedResource(); 260 void clearResourceToRevalidate(); 261 void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse); 262 263 HashCountedSet<ResourceClient*> m_clients; 264 265 class ResourceCallback { 266 public: 267 static PassOwnPtr<ResourceCallback> schedule(Resource* resource, ResourceClient* client) { return adoptPtr(new ResourceCallback(resource, client)); } 268 void cancel(); 269 private: 270 ResourceCallback(Resource*, ResourceClient*); 271 void timerFired(Timer<ResourceCallback>*); 272 273 Resource* m_resource; 274 ResourceClient* m_client; 275 Timer<ResourceCallback> m_callbackTimer; 276 }; 277 HashMap<ResourceClient*, OwnPtr<ResourceCallback> > m_clientsAwaitingCallback; 278 279 bool hasClient(ResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); } 280 281 ResourceRequest m_resourceRequest; 282 AtomicString m_accept; 283 RefPtr<ResourceLoader> m_loader; 284 ResourceLoaderOptions m_options; 285 286 ResourceResponse m_response; 287 double m_responseTimestamp; 288 289 RefPtr<SharedBuffer> m_data; 290 OwnPtr<PurgeableBuffer> m_purgeableData; 291 Timer<Resource> m_cancelTimer; 292 293 private: 294 bool addClientToSet(ResourceClient*); 295 void cancelTimerFired(Timer<Resource>*); 296 297 void revalidationSucceeded(const ResourceResponse&); 298 void revalidationFailed(); 299 300 double currentAge() const; 301 double freshnessLifetime() const; 302 303 void failBeforeStarting(); 304 305 String m_fragmentIdentifierForRequest; 306 307 RefPtr<CachedMetadata> m_cachedMetadata; 308 309 ResourceError m_error; 310 311 double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache 312 double m_loadFinishTime; 313 314 unsigned long m_identifier; 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 unsigned m_cacheLiveResourcePriority : 2; // CacheLiveResourcePriority 324 unsigned m_inLiveDecodedResourcesList : 1; 325 unsigned m_requestedFromNetworkingLayer : 1; 326 327 unsigned m_inCache : 1; 328 unsigned m_loading : 1; 329 330 unsigned 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 Resource* m_nextInAllResourcesList; 341 Resource* m_prevInAllResourcesList; 342 343 Resource* m_nextInLiveResourcesList; 344 Resource* m_prevInLiveResourcesList; 345 346 // 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 347 // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved 348 // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this 349 // resources becomes normal resource load. 350 Resource* m_resourceToRevalidate; 351 352 // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate). 353 Resource* m_proxyResource; 354 355 // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response. 356 HashSet<ResourcePtrBase*> m_handlesToRevalidate; 357 }; 358 359 } 360 361 #endif 362