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