| /* | 
 |     Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) | 
 |     Copyright (C) 2001 Dirk Mueller <mueller@kde.org> | 
 |     Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) | 
 |     Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. | 
 |  | 
 |     This library is free software; you can redistribute it and/or | 
 |     modify it under the terms of the GNU Library General Public | 
 |     License as published by the Free Software Foundation; either | 
 |     version 2 of the License, or (at your option) any later version. | 
 |  | 
 |     This library is distributed in the hope that it will be useful, | 
 |     but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |     Library General Public License for more details. | 
 |  | 
 |     You should have received a copy of the GNU Library General Public License | 
 |     along with this library; see the file COPYING.LIB.  If not, write to | 
 |     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
 |     Boston, MA 02110-1301, USA. | 
 | */ | 
 |  | 
 | #ifndef Resource_h | 
 | #define Resource_h | 
 |  | 
 | #include "core/CoreExport.h" | 
 | #include "core/fetch/CachedMetadataHandler.h" | 
 | #include "core/fetch/ResourceLoaderOptions.h" | 
 | #include "platform/Timer.h" | 
 | #include "platform/network/ResourceError.h" | 
 | #include "platform/network/ResourceLoadPriority.h" | 
 | #include "platform/network/ResourceRequest.h" | 
 | #include "platform/network/ResourceResponse.h" | 
 | #include "public/platform/WebDataConsumerHandle.h" | 
 | #include "wtf/Allocator.h" | 
 | #include "wtf/HashCountedSet.h" | 
 | #include "wtf/HashSet.h" | 
 | #include "wtf/OwnPtr.h" | 
 | #include "wtf/text/WTFString.h" | 
 |  | 
 | // FIXME(crbug.com/352043): This is temporarily enabled even on RELEASE to diagnose a wild crash. | 
 | #define ENABLE_RESOURCE_IS_DELETED_CHECK | 
 |  | 
 | namespace blink { | 
 |  | 
 | struct FetchInitiatorInfo; | 
 | class CachedMetadata; | 
 | class ResourceClient; | 
 | class ResourcePtrBase; | 
 | class ResourceFetcher; | 
 | class ResourceTimingInfo; | 
 | class InspectorResource; | 
 | class ResourceLoader; | 
 | class SecurityOrigin; | 
 | class SharedBuffer; | 
 |  | 
 | // A resource that is held in the cache. Classes who want to use this object should derive | 
 | // from ResourceClient, to get the function calls in case the requested data has arrived. | 
 | // This class also does the actual communication with the loader to obtain the resource from the network. | 
 | class CORE_EXPORT Resource : public NoBaseWillBeGarbageCollectedFinalized<Resource> { | 
 |     WTF_MAKE_NONCOPYABLE(Resource); WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(Resource); | 
 |     friend class InspectorResource; | 
 |  | 
 | public: | 
 |     enum Type { | 
 |         MainResource, | 
 |         Image, | 
 |         CSSStyleSheet, | 
 |         Script, | 
 |         Font, | 
 |         Raw, | 
 |         SVGDocument, | 
 |         XSLStyleSheet, | 
 |         LinkPrefetch, | 
 |         LinkSubresource, | 
 |         LinkPreload, | 
 |         TextTrack, | 
 |         ImportResource, | 
 |         Media // Audio or video file requested by a HTML5 media element | 
 |     }; | 
 |  | 
 |     enum Status { | 
 |         Unknown, // let cache decide what to do with it | 
 |         Pending, // only partially loaded | 
 |         Cached, // regular case | 
 |         LoadError, | 
 |         DecodeError | 
 |     }; | 
 |  | 
 |     // Exposed for testing. | 
 |     Resource(const ResourceRequest&, Type); | 
 | #if ENABLE(OILPAN) | 
 |     virtual ~Resource(); | 
 | #else | 
 | protected: | 
 |     // Only deleteIfPossible should delete this. | 
 |     virtual ~Resource(); | 
 | public: | 
 | #endif | 
 |     virtual void dispose(); | 
 |     DECLARE_VIRTUAL_TRACE(); | 
 |  | 
 |     virtual void load(ResourceFetcher*, const ResourceLoaderOptions&); | 
 |  | 
 |     virtual void setEncoding(const String&) { } | 
 |     virtual String encoding() const { return String(); } | 
 |     virtual void appendData(const char*, unsigned); | 
 |     virtual void error(Resource::Status); | 
 |     virtual void setCORSFailed() { } | 
 |  | 
 |     void setNeedsSynchronousCacheHit(bool needsSynchronousCacheHit) { m_needsSynchronousCacheHit = needsSynchronousCacheHit; } | 
 |  | 
 |     void setResourceError(const ResourceError& error) { m_error = error; } | 
 |     const ResourceError& resourceError() const { return m_error; } | 
 |  | 
 |     void setIdentifier(unsigned long identifier) { m_identifier = identifier; } | 
 |     unsigned long identifier() const { return m_identifier; } | 
 |  | 
 |     virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; } | 
 |  | 
 |     ResourceRequest& mutableResourceRequest() { return m_resourceRequest; } | 
 |     const ResourceRequest& resourceRequest() const { return m_resourceRequest; } | 
 |     const ResourceRequest& lastResourceRequest() const; | 
 |  | 
 |     const KURL& url() const { return m_resourceRequest.url();} | 
 |     Type type() const { return static_cast<Type>(m_type); } | 
 |     const ResourceLoaderOptions& options() const { return m_options; } | 
 |     void setOptions(const ResourceLoaderOptions& options) { m_options = options; } | 
 |  | 
 |     void didChangePriority(ResourceLoadPriority, int intraPriorityValue); | 
 |  | 
 |     void addClient(ResourceClient*); | 
 |     void removeClient(ResourceClient*); | 
 |     bool hasClients() const { return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty(); } | 
 |     bool deleteIfPossible(); | 
 |  | 
 |     enum PreloadResult { | 
 |         PreloadNotReferenced, | 
 |         PreloadReferenced, | 
 |         PreloadReferencedWhileLoading, | 
 |         PreloadReferencedWhileComplete | 
 |     }; | 
 |     PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); } | 
 |  | 
 |     virtual void didAddClient(ResourceClient*); | 
 |     virtual void didRemoveClient(ResourceClient*) { } | 
 |     virtual void allClientsRemoved(); | 
 |  | 
 |     unsigned count() const { return m_clients.size(); } | 
 |  | 
 |     Status status() const { return static_cast<Status>(m_status); } | 
 |     void setStatus(Status status) { m_status = status; } | 
 |  | 
 |     size_t size() const { return encodedSize() + decodedSize() + overheadSize(); } | 
 |     size_t encodedSize() const { return m_encodedSize; } | 
 |     size_t decodedSize() const { return m_decodedSize; } | 
 |     size_t overheadSize() const; | 
 |  | 
 |     bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet. | 
 |  | 
 |     bool isLoading() const { return m_loading; } | 
 |     void setLoading(bool b) { m_loading = b; } | 
 |     virtual bool stillNeedsLoad() const { return false; } | 
 |  | 
 |     ResourceLoader* loader() const { return m_loader.get(); } | 
 |  | 
 |     virtual bool isImage() const { return false; } | 
 |     bool shouldBlockLoadEvent() const | 
 |     { | 
 |         return type() != LinkPrefetch | 
 |             && type() != LinkSubresource | 
 |             && type() != Media | 
 |             && type() != Raw | 
 |             && type() != TextTrack; | 
 |     } | 
 |  | 
 |     // Computes the status of an object after loading. | 
 |     // Updates the expire date on the cache entry file | 
 |     void setLoadFinishTime(double finishTime) { m_loadFinishTime = finishTime; } | 
 |     void finish(); | 
 |  | 
 |     // FIXME: Remove the stringless variant once all the callsites' error messages are updated. | 
 |     bool passesAccessControlCheck(SecurityOrigin*) const; | 
 |     bool passesAccessControlCheck(SecurityOrigin*, String& errorDescription) const; | 
 |  | 
 |     bool isEligibleForIntegrityCheck(SecurityOrigin*) const; | 
 |  | 
 |     void clearLoader(); | 
 |  | 
 |     SharedBuffer* resourceBuffer() const { return m_data.get(); } | 
 |     void setResourceBuffer(PassRefPtr<SharedBuffer>); | 
 |  | 
 |     virtual void willFollowRedirect(ResourceRequest&, const ResourceResponse&); | 
 |  | 
 |     virtual void updateRequest(const ResourceRequest&) { } | 
 |     virtual void responseReceived(const ResourceResponse&, PassOwnPtr<WebDataConsumerHandle>); | 
 |     void setResponse(const ResourceResponse& response) { m_response = response; } | 
 |     const ResourceResponse& response() const { return m_response; } | 
 |  | 
 |     virtual void reportResourceTimingToClients(const ResourceTimingInfo&) { } | 
 |  | 
 |     // Sets the serialized metadata retrieved from the platform's cache. | 
 |     virtual void setSerializedCachedMetadata(const char*, size_t); | 
 |  | 
 |     // This may return nullptr when the resource isn't cacheable. | 
 |     CachedMetadataHandler* cacheHandler(); | 
 |  | 
 |     bool hasOneHandle() const; | 
 |     bool canDelete() const; | 
 |  | 
 |     // List of acceptable MIME types separated by ",". | 
 |     // A MIME type may contain a wildcard, e.g. "text/*". | 
 |     AtomicString accept() const { return m_accept; } | 
 |     void setAccept(const AtomicString& accept) { m_accept = accept; } | 
 |  | 
 |     bool wasCanceled() const { return m_error.isCancellation(); } | 
 |     bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; } | 
 |     bool loadFailedOrCanceled() { return !m_error.isNull(); } | 
 |  | 
 |     DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; } | 
 |     void setDataBufferingPolicy(DataBufferingPolicy); | 
 |  | 
 |     bool isUnusedPreload() const { return isPreloaded() && preloadResult() == PreloadNotReferenced; } | 
 |     bool isPreloaded() const { return m_preloadCount; } | 
 |     void increasePreloadCount() { ++m_preloadCount; } | 
 |     void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; } | 
 |  | 
 |     void registerHandle(ResourcePtrBase* h); | 
 |     void unregisterHandle(ResourcePtrBase* h); | 
 |  | 
 |     bool canReuseRedirectChain(); | 
 |     bool mustRevalidateDueToCacheHeaders(); | 
 |     bool canUseCacheValidator(); | 
 |     bool isCacheValidator() const { return m_resourceToRevalidate; } | 
 |     Resource* resourceToRevalidate() const { return m_resourceToRevalidate; } | 
 |     void setResourceToRevalidate(Resource*); | 
 |     bool hasCacheControlNoStoreHeader(); | 
 |     bool hasVaryHeader() const; | 
 |  | 
 |     double currentAge() const; | 
 |     double freshnessLifetime(); | 
 |     double stalenessLifetime(); | 
 |  | 
 |     bool isPurgeable() const; | 
 |     bool wasPurged() const; | 
 |     bool lock(); | 
 |  | 
 |     void setCacheIdentifier(const String& cacheIdentifier) { m_cacheIdentifier = cacheIdentifier; } | 
 |     String cacheIdentifier() const { return m_cacheIdentifier; } | 
 |  | 
 |     virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { } | 
 |     virtual void didDownloadData(int) { } | 
 |  | 
 |     double loadFinishTime() const { return m_loadFinishTime; } | 
 |  | 
 |     virtual bool canReuse(const ResourceRequest&) const { return true; } | 
 |  | 
 |     // Used by the MemoryCache to reduce the memory consumption of the entry. | 
 |     void prune(); | 
 |  | 
 |     static const char* resourceTypeToString(Type, const FetchInitiatorInfo&); | 
 |  | 
 | #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK | 
 |     void assertAlive() const { RELEASE_ASSERT(!m_deleted); } | 
 | #else | 
 |     void assertAlive() const { } | 
 | #endif | 
 |  | 
 | protected: | 
 |     virtual void checkNotify(); | 
 |     virtual void finishOnePart(); | 
 |  | 
 |     // Normal resource pointers will silently switch what Resource* they reference when we | 
 |     // successfully revalidated the resource. We need a way to guarantee that the Resource | 
 |     // that received the 304 response survives long enough to switch everything over to the | 
 |     // revalidatedresource. The normal mechanisms for keeping a Resource alive externally | 
 |     // (ResourcePtrs and ResourceClients registering themselves) don't work in this case, so | 
 |     // have a separate internal protector). | 
 |     class InternalResourcePtr { | 
 |     public: | 
 |         explicit InternalResourcePtr(Resource* resource) | 
 |             : m_resource(resource) | 
 |         { | 
 |             m_resource->incrementProtectorCount(); | 
 |         } | 
 |  | 
 |         ~InternalResourcePtr() | 
 |         { | 
 |             m_resource->decrementProtectorCount(); | 
 |             m_resource->deleteIfPossible(); | 
 |         } | 
 |     private: | 
 |         Resource* m_resource; | 
 |     }; | 
 |  | 
 |     void incrementProtectorCount() { m_protectorCount++; } | 
 |     void decrementProtectorCount() { m_protectorCount--; } | 
 |  | 
 |     void setEncodedSize(size_t); | 
 |     void setDecodedSize(size_t); | 
 |     void didAccessDecodedData(); | 
 |  | 
 |     void clearResourceToRevalidate(); | 
 |     void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse); | 
 |  | 
 |     void finishPendingClients(); | 
 |  | 
 |     HashCountedSet<ResourceClient*> m_clients; | 
 |     HashCountedSet<ResourceClient*> m_clientsAwaitingCallback; | 
 |  | 
 |     class ResourceCallback : public NoBaseWillBeGarbageCollectedFinalized<ResourceCallback> { | 
 |     public: | 
 |         static ResourceCallback* callbackHandler(); | 
 |         DECLARE_TRACE(); | 
 |         void schedule(Resource*); | 
 |         void cancel(Resource*); | 
 |         bool isScheduled(Resource*) const; | 
 |     private: | 
 |         ResourceCallback(); | 
 |         void timerFired(Timer<ResourceCallback>*); | 
 |         Timer<ResourceCallback> m_callbackTimer; | 
 |         WillBeHeapHashSet<RawPtrWillBeMember<Resource>> m_resourcesWithPendingClients; | 
 |     }; | 
 |  | 
 |     bool hasClient(ResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); } | 
 |  | 
 |     struct RedirectPair { | 
 |         ALLOW_ONLY_INLINE_ALLOCATION(); | 
 |     public: | 
 |         explicit RedirectPair(const ResourceRequest& request, const ResourceResponse& redirectResponse) | 
 |             : m_request(request) | 
 |             , m_redirectResponse(redirectResponse) | 
 |         { | 
 |         } | 
 |  | 
 |         ResourceRequest m_request; | 
 |         ResourceResponse m_redirectResponse; | 
 |     }; | 
 |     const Vector<RedirectPair>& redirectChain() const { return m_redirectChain; } | 
 |  | 
 |     virtual bool isSafeToUnlock() const { return false; } | 
 |     virtual void destroyDecodedDataIfPossible() { } | 
 |  | 
 |     ResourceRequest m_resourceRequest; | 
 |     AtomicString m_accept; | 
 |     PersistentWillBeMember<ResourceLoader> m_loader; | 
 |     ResourceLoaderOptions m_options; | 
 |  | 
 |     ResourceResponse m_response; | 
 |     double m_responseTimestamp; | 
 |  | 
 |     RefPtr<SharedBuffer> m_data; | 
 |     Timer<Resource> m_cancelTimer; | 
 |  | 
 | private: | 
 |     class CacheHandler; | 
 |     bool addClientToSet(ResourceClient*); | 
 |     void cancelTimerFired(Timer<Resource>*); | 
 |  | 
 |     void switchClientsToRevalidatedResource(); | 
 |     void revalidationSucceeded(const ResourceResponse&); | 
 |     void revalidationFailed(); | 
 |  | 
 |     bool unlock(); | 
 |  | 
 |     bool hasRightHandleCountApartFromCache(unsigned targetCount) const; | 
 |  | 
 |     void setCachedMetadata(unsigned dataTypeID, const char*, size_t, CachedMetadataHandler::CacheType); | 
 |     void clearCachedMetadata(CachedMetadataHandler::CacheType); | 
 |     CachedMetadata* cachedMetadata(unsigned dataTypeID) const; | 
 |  | 
 |     String m_fragmentIdentifierForRequest; | 
 |  | 
 |     RefPtr<CachedMetadata> m_cachedMetadata; | 
 |     OwnPtrWillBeMember<CacheHandler> m_cacheHandler; | 
 |  | 
 |     ResourceError m_error; | 
 |  | 
 |     double m_loadFinishTime; | 
 |  | 
 |     unsigned long m_identifier; | 
 |  | 
 |     size_t m_encodedSize; | 
 |     size_t m_decodedSize; | 
 |     unsigned m_handleCount; | 
 |     unsigned m_preloadCount; | 
 |     unsigned m_protectorCount; | 
 |  | 
 |     String m_cacheIdentifier; | 
 |  | 
 |     unsigned m_preloadResult : 2; // PreloadResult | 
 |     unsigned m_requestedFromNetworkingLayer : 1; | 
 |  | 
 |     unsigned m_loading : 1; | 
 |  | 
 |     unsigned m_switchingClientsToRevalidatedResource : 1; | 
 |  | 
 |     unsigned m_type : 4; // Type | 
 |     unsigned m_status : 3; // Status | 
 |  | 
 |     unsigned m_wasPurged : 1; | 
 |  | 
 |     unsigned m_needsSynchronousCacheHit : 1; | 
 |  | 
 | #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK | 
 |     bool m_deleted; | 
 | #endif | 
 |  | 
 |     // 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 | 
 |     // using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved | 
 |     // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this | 
 |     // resources becomes normal resource load. | 
 |     RawPtrWillBeMember<Resource> m_resourceToRevalidate; | 
 |  | 
 |     // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate). | 
 |     RawPtrWillBeMember<Resource> m_proxyResource; | 
 |  | 
 |     // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response. | 
 |     HashSet<ResourcePtrBase*> m_handlesToRevalidate; | 
 |  | 
 |     // Ordered list of all redirects followed while fetching this resource. | 
 |     Vector<RedirectPair> m_redirectChain; | 
 | }; | 
 |  | 
 | class ResourceFactory { | 
 |     STACK_ALLOCATED(); | 
 | public: | 
 |     virtual Resource* create(const ResourceRequest&, const String&) const = 0; | 
 |     Resource::Type type() const { return m_type; } | 
 |  | 
 | protected: | 
 |     ResourceFactory(Resource::Type type) : m_type(type) { } | 
 |  | 
 |     Resource::Type m_type; | 
 | }; | 
 |  | 
 | #if !LOG_DISABLED | 
 | // Intended to be used in LOG statements. | 
 | const char* ResourceTypeName(Resource::Type); | 
 | #endif | 
 |  | 
 | #define DEFINE_RESOURCE_TYPE_CASTS(typeName) \ | 
 |     DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, resource->type() == Resource::typeName, resource.type() == Resource::typeName); \ | 
 |     inline typeName##Resource* to##typeName##Resource(const ResourcePtr<Resource>& ptr) { return to##typeName##Resource(ptr.get()); } | 
 |  | 
 | } | 
 |  | 
 | #endif |