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