blob: b6733bbb5e5a4f4519c6f4cff58ce1b89447579b [file] [log] [blame]
/*
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/MemoryCoordinator.h"
#include "platform/SharedBuffer.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 "platform/scheduler/CancellableTaskFactory.h"
#include "platform/web_process_memory_dump.h"
#include "public/platform/WebDataConsumerHandle.h"
#include "wtf/Allocator.h"
#include "wtf/HashCountedSet.h"
#include "wtf/HashSet.h"
#include "wtf/text/WTFString.h"
#include <memory>
namespace blink {
struct FetchInitiatorInfo;
class CachedMetadata;
class FetchRequest;
class ResourceClient;
class ResourceTimingInfo;
class ResourceLoader;
class SecurityOrigin;
// 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 GarbageCollectedFinalized<Resource>,
public MemoryCoordinatorClient {
USING_GARBAGE_COLLECTED_MIXIN(Resource);
WTF_MAKE_NONCOPYABLE(Resource);
public:
// |Type| enum values are used in UMAs, so do not change the values of
// existing |Type|. When adding a new |Type|, append it at the end and update
// |kLastResourceType|.
enum Type {
MainResource,
Image,
CSSStyleSheet,
Script,
Font,
Raw,
SVGDocument,
XSLStyleSheet,
LinkPrefetch,
TextTrack,
ImportResource,
Media, // Audio or video file requested by a HTML5 media element
Manifest
};
static const int kLastResourceType = Manifest + 1;
enum Status {
NotStarted,
Pending, // load in progress
Cached, // load completed successfully
LoadError,
DecodeError
};
// Whether a resource client for a preload should mark the preload as
// referenced.
enum PreloadReferencePolicy {
MarkAsReferenced,
DontMarkAsReferenced,
};
// Exposed for testing.
static Resource* create(
const ResourceRequest& request,
Type type,
const ResourceLoaderOptions& options = ResourceLoaderOptions()) {
return new Resource(request, type, options);
}
virtual ~Resource();
DECLARE_VIRTUAL_TRACE();
virtual void setEncoding(const String&) {}
virtual String encoding() const { return String(); }
virtual void appendData(const char*, size_t);
virtual void error(const ResourceError&);
virtual void setCORSFailed() {}
void setNeedsSynchronousCacheHit(bool needsSynchronousCacheHit) {
m_needsSynchronousCacheHit = needsSynchronousCacheHit;
}
void setLinkPreload(bool isLinkPreload) { m_linkPreload = isLinkPreload; }
bool isLinkPreload() const { return m_linkPreload; }
void setPreloadDiscoveryTime(double preloadDiscoveryTime) {
m_preloadDiscoveryTime = preloadDiscoveryTime;
}
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; }
const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
const ResourceRequest& lastResourceRequest() const;
virtual void setRevalidatingRequest(const ResourceRequest&);
void setFetcherSecurityOrigin(SecurityOrigin* origin) {
m_fetcherSecurityOrigin = origin;
}
// This url can have a fragment, but it can match resources that differ by the
// fragment only.
const KURL& url() const { return m_resourceRequest.url(); }
Type getType() const { return static_cast<Type>(m_type); }
const ResourceLoaderOptions& options() const { return m_options; }
ResourceLoaderOptions& mutableOptions() { return m_options; }
void didChangePriority(ResourceLoadPriority, int intraPriorityValue);
virtual ResourcePriority priorityFromObservers() {
return ResourcePriority();
}
// The reference policy indicates that the client should not affect whether
// a preload is considered referenced or not. This allows for "passive"
// resource clients that simply observe the resource.
void addClient(ResourceClient*, PreloadReferencePolicy = MarkAsReferenced);
void removeClient(ResourceClient*);
enum PreloadResult {
PreloadNotReferenced,
PreloadReferenced,
PreloadReferencedWhileLoading,
PreloadReferencedWhileComplete
};
PreloadResult getPreloadResult() const {
return static_cast<PreloadResult>(m_preloadResult);
}
Status getStatus() 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 { return m_overheadSize; }
bool isLoaded() const { return m_status > Pending; }
bool isLoading() const { return m_status == Pending; }
bool stillNeedsLoad() const { return m_status < Pending; }
void setLoader(ResourceLoader*);
ResourceLoader* loader() const { return m_loader.get(); }
virtual bool isImage() const { return false; }
bool shouldBlockLoadEvent() const;
bool isLoadEventBlockingResourceType() const;
// Computes the status of an object after loading. Updates the expire date on
// the cache entry file
virtual void finish(double finishTime);
void finish() { finish(0.0); }
// 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;
virtual PassRefPtr<const SharedBuffer> resourceBuffer() const {
return m_data;
}
void setResourceBuffer(PassRefPtr<SharedBuffer>);
virtual void willFollowRedirect(ResourceRequest&, const ResourceResponse&);
// Called when a redirect response was received but a decision has already
// been made to not follow it.
virtual void willNotFollowRedirect() {}
virtual void responseReceived(const ResourceResponse&,
std::unique_ptr<WebDataConsumerHandle>);
void setResponse(const ResourceResponse&);
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();
AtomicString httpContentType() const;
bool wasCanceled() const { return m_error.isCancellation(); }
bool errorOccurred() const {
return m_status == LoadError || m_status == DecodeError;
}
bool loadFailedOrCanceled() { return !m_error.isNull(); }
DataBufferingPolicy getDataBufferingPolicy() const {
return m_options.dataBufferingPolicy;
}
void setDataBufferingPolicy(DataBufferingPolicy);
// The isPreloaded() flag is using a counter in order to make sure that even
// when multiple ResourceFetchers are preloading the resource, it will remain
// marked as preloaded until *all* of them have used it.
bool isUnusedPreload() const {
return isPreloaded() && getPreloadResult() == PreloadNotReferenced;
}
bool isPreloaded() const { return m_preloadCount; }
void increasePreloadCount() { ++m_preloadCount; }
void decreasePreloadCount() {
DCHECK(m_preloadCount);
--m_preloadCount;
}
bool canReuseRedirectChain();
bool mustRevalidateDueToCacheHeaders();
bool canUseCacheValidator();
bool isCacheValidator() const { return m_isRevalidating; }
bool hasCacheControlNoStoreHeader() const;
bool hasVaryHeader() const;
virtual bool mustRefetchDueToIntegrityMetadata(
const FetchRequest& request) const {
return false;
}
double currentAge() const;
double freshnessLifetime();
double stalenessLifetime();
bool isAlive() const { return m_isAlive; }
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; }
void addToEncodedBodyLength(int value) {
m_response.addToEncodedBodyLength(value);
}
void addToDecodedBodyLength(int value) {
m_response.addToDecodedBodyLength(value);
}
virtual bool canReuse(const ResourceRequest&) const { return true; }
// Used by the MemoryCache to reduce the memory consumption of the entry.
void prune();
virtual void onMemoryDump(WebMemoryDumpLevelOfDetail,
WebProcessMemoryDump*) const;
static const char* resourceTypeToString(Type, const FetchInitiatorInfo&);
protected:
Resource(const ResourceRequest&, Type, const ResourceLoaderOptions&);
virtual void checkNotify();
enum class MarkFinishedOption { ShouldMarkFinished, DoNotMarkFinished };
void notifyClientsInternal(MarkFinishedOption);
void markClientFinished(ResourceClient*);
virtual bool hasClientsOrObservers() const {
return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty() ||
!m_finishedClients.isEmpty();
}
virtual void destroyDecodedDataForFailedRevalidation() {}
void setEncodedSize(size_t);
void setDecodedSize(size_t);
void didAccessDecodedData();
void finishPendingClients();
virtual void didAddClient(ResourceClient*);
void willAddClientOrObserver(PreloadReferencePolicy);
// |this| object may be dead after didRemoveClientOrObserver().
void didRemoveClientOrObserver();
virtual void allClientsAndObserversRemoved();
bool hasClient(ResourceClient* client) {
return m_clients.contains(client) ||
m_clientsAwaitingCallback.contains(client) ||
m_finishedClients.contains(client);
}
struct RedirectPair {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
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 void destroyDecodedDataIfPossible() {}
// Returns the memory dump name used for tracing. See Resource::onMemoryDump.
String getMemoryDumpName() const;
const HeapHashCountedSet<WeakMember<ResourceClient>>& clients() const {
return m_clients;
}
DataBufferingPolicy dataBufferingPolicy() const {
return m_options.dataBufferingPolicy;
}
void setCachePolicyBypassingCache();
void setLoFiStateOff();
SharedBuffer* data() const { return m_data.get(); }
void clearData() { m_data.clear(); }
private:
class ResourceCallback;
class CachedMetadataHandlerImpl;
class ServiceWorkerResponseCachedMetadataHandler;
void cancelTimerFired(TimerBase*);
void revalidationSucceeded(const ResourceResponse&);
void revalidationFailed();
size_t calculateOverheadSize() const;
String reasonNotDeletable() const;
// MemoryCoordinatorClient overrides:
void prepareToSuspend() override;
Member<CachedMetadataHandlerImpl> m_cacheHandler;
RefPtr<SecurityOrigin> m_fetcherSecurityOrigin;
ResourceError m_error;
double m_loadFinishTime;
unsigned long m_identifier;
size_t m_encodedSize;
size_t m_decodedSize;
// Resource::calculateOverheadSize() is affected by changes in
// |m_resourceRequest.url()|, but |m_overheadSize| is not updated after
// initial |m_resourceRequest| is given, to reduce MemoryCache manipulation
// and thus potential bugs. crbug.com/594644
const size_t m_overheadSize;
unsigned m_preloadCount;
double m_preloadDiscoveryTime;
String m_cacheIdentifier;
unsigned m_preloadResult : 2; // PreloadResult
unsigned m_type : 4; // Type
unsigned m_status : 3; // Status
unsigned m_needsSynchronousCacheHit : 1;
unsigned m_linkPreload : 1;
bool m_isRevalidating : 1;
bool m_isAlive : 1;
// Ordered list of all redirects followed while fetching this resource.
Vector<RedirectPair> m_redirectChain;
HeapHashCountedSet<WeakMember<ResourceClient>> m_clients;
HeapHashCountedSet<WeakMember<ResourceClient>> m_clientsAwaitingCallback;
HeapHashCountedSet<WeakMember<ResourceClient>> m_finishedClients;
ResourceLoaderOptions m_options;
double m_responseTimestamp;
Timer<Resource> m_cancelTimer;
ResourceRequest m_resourceRequest;
Member<ResourceLoader> m_loader;
ResourceResponse m_response;
RefPtr<SharedBuffer> m_data;
};
class ResourceFactory {
STACK_ALLOCATED();
public:
virtual Resource* create(const ResourceRequest&,
const ResourceLoaderOptions&,
const String&) const = 0;
Resource::Type type() const { return m_type; }
protected:
explicit ResourceFactory(Resource::Type type) : m_type(type) {}
Resource::Type m_type;
};
#define DEFINE_RESOURCE_TYPE_CASTS(typeName) \
DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, \
resource->getType() == Resource::typeName, \
resource.getType() == Resource::typeName);
} // namespace blink
#endif