summaryrefslogtreecommitdiff
path: root/Source/WebCore/loader/cache/CachedResourceLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/loader/cache/CachedResourceLoader.cpp')
-rw-r--r--Source/WebCore/loader/cache/CachedResourceLoader.cpp1162
1 files changed, 756 insertions, 406 deletions
diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
index bd38fe823..baf827eb7 100644
--- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp
+++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
@@ -2,7 +2,7 @@
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ Copyright (C) 2004-2016 Apple Inc. All rights reserved.
Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
This library is free software; you can redistribute it and/or
@@ -28,18 +28,22 @@
#include "CachedResourceLoader.h"
#include "CachedCSSStyleSheet.h"
-#include "CachedSVGDocument.h"
#include "CachedFont.h"
#include "CachedImage.h"
#include "CachedRawResource.h"
#include "CachedResourceRequest.h"
+#include "CachedSVGDocument.h"
+#include "CachedSVGFont.h"
#include "CachedScript.h"
#include "CachedXSLStyleSheet.h"
#include "Chrome.h"
#include "ChromeClient.h"
-#include "Console.h"
+#include "ContentExtensionError.h"
+#include "ContentExtensionRule.h"
#include "ContentSecurityPolicy.h"
#include "DOMWindow.h"
+#include "DiagnosticLoggingClient.h"
+#include "DiagnosticLoggingKeys.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Frame.h"
@@ -48,16 +52,26 @@
#include "HTMLElement.h"
#include "HTMLFrameOwnerElement.h"
#include "LoaderStrategy.h"
+#include "LocalizedStrings.h"
#include "Logging.h"
+#include "MainFrame.h"
#include "MemoryCache.h"
#include "Page.h"
#include "PingLoader.h"
#include "PlatformStrategies.h"
#include "RenderElement.h"
-#include "ResourceLoadScheduler.h"
+#include "ResourceLoadInfo.h"
+#include "ResourceTiming.h"
+#include "RuntimeEnabledFeatures.h"
#include "ScriptController.h"
#include "SecurityOrigin.h"
+#include "SecurityPolicy.h"
+#include "SessionID.h"
#include "Settings.h"
+#include "StyleSheetContents.h"
+#include "SubresourceLoader.h"
+#include "UserContentController.h"
+#include "UserStyleSheet.h"
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
@@ -65,56 +79,57 @@
#include "CachedTextTrack.h"
#endif
-#if ENABLE(RESOURCE_TIMING)
-#include "Performance.h"
-#endif
-
#define PRELOAD_DEBUG 0
+#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - CachedResourceLoader::" fmt, this, ##__VA_ARGS__)
+
namespace WebCore {
-static CachedResource* createResource(CachedResource::Type type, ResourceRequest& request, const String& charset)
+static CachedResource* createResource(CachedResource::Type type, CachedResourceRequest&& request, SessionID sessionID)
{
switch (type) {
case CachedResource::ImageResource:
- return new CachedImage(request);
+ return new CachedImage(WTFMove(request), sessionID);
case CachedResource::CSSStyleSheet:
- return new CachedCSSStyleSheet(request, charset);
+ return new CachedCSSStyleSheet(WTFMove(request), sessionID);
case CachedResource::Script:
- return new CachedScript(request, charset);
-#if ENABLE(SVG)
+ return new CachedScript(WTFMove(request), sessionID);
case CachedResource::SVGDocumentResource:
- return new CachedSVGDocument(request);
+ return new CachedSVGDocument(WTFMove(request), sessionID);
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+ return new CachedSVGFont(WTFMove(request), sessionID);
#endif
case CachedResource::FontResource:
- return new CachedFont(request);
+ return new CachedFont(WTFMove(request), sessionID);
+ case CachedResource::MediaResource:
case CachedResource::RawResource:
case CachedResource::MainResource:
- return new CachedRawResource(request, type);
+ return new CachedRawResource(WTFMove(request), type, sessionID);
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
- return new CachedXSLStyleSheet(request);
+ return new CachedXSLStyleSheet(WTFMove(request), sessionID);
#endif
#if ENABLE(LINK_PREFETCH)
case CachedResource::LinkPrefetch:
- return new CachedResource(request, CachedResource::LinkPrefetch);
+ return new CachedResource(WTFMove(request), CachedResource::LinkPrefetch, sessionID);
case CachedResource::LinkSubresource:
- return new CachedResource(request, CachedResource::LinkSubresource);
+ return new CachedResource(WTFMove(request), CachedResource::LinkSubresource, sessionID);
#endif
#if ENABLE(VIDEO_TRACK)
case CachedResource::TextTrackResource:
- return new CachedTextTrack(request);
+ return new CachedTextTrack(WTFMove(request), sessionID);
#endif
}
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
CachedResourceLoader::CachedResourceLoader(DocumentLoader* documentLoader)
- : m_document(0)
+ : m_document(nullptr)
, m_documentLoader(documentLoader)
, m_requestCount(0)
- , m_garbageCollectDocumentResourcesTimer(this, &CachedResourceLoader::garbageCollectDocumentResourcesTimerFired)
+ , m_garbageCollectDocumentResourcesTimer(*this, &CachedResourceLoader::garbageCollectDocumentResources)
, m_autoLoadImages(true)
, m_imagesEnabled(true)
, m_allowStaleResources(false)
@@ -123,157 +138,233 @@ CachedResourceLoader::CachedResourceLoader(DocumentLoader* documentLoader)
CachedResourceLoader::~CachedResourceLoader()
{
- m_documentLoader = 0;
- m_document = 0;
+ m_documentLoader = nullptr;
+ m_document = nullptr;
- clearPreloads();
- DocumentResourceMap::iterator end = m_documentResources.end();
- for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it)
- it->value->setOwningCachedResourceLoader(0);
+ clearPreloads(ClearPreloadsMode::ClearAllPreloads);
+ for (auto& resource : m_documentResources.values())
+ resource->setOwningCachedResourceLoader(nullptr);
// Make sure no requests still point to this CachedResourceLoader
ASSERT(m_requestCount == 0);
}
-CachedResource* CachedResourceLoader::cachedResource(const String& resourceURL) const
+CachedResource* CachedResourceLoader::cachedResource(const String& resourceURL) const
{
- URL url = m_document->completeURL(resourceURL);
- return cachedResource(url);
+ ASSERT(!resourceURL.isNull());
+ return cachedResource(MemoryCache::removeFragmentIdentifierIfNeeded(m_document->completeURL(resourceURL)));
}
-CachedResource* CachedResourceLoader::cachedResource(const URL& resourceURL) const
+CachedResource* CachedResourceLoader::cachedResource(const URL& url) const
{
- URL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
- return m_documentResources.get(url).get();
+ ASSERT(!MemoryCache::shouldRemoveFragmentIdentifier(url));
+ return m_documentResources.get(url).get();
}
Frame* CachedResourceLoader::frame() const
{
- return m_documentLoader ? m_documentLoader->frame() : 0;
+ return m_documentLoader ? m_documentLoader->frame() : nullptr;
+}
+
+SessionID CachedResourceLoader::sessionID() const
+{
+ SessionID sessionID = SessionID::defaultSessionID();
+
+ if (Frame* f = frame())
+ sessionID = f->page()->sessionID();
+
+ return sessionID;
}
-CachedResourceHandle<CachedImage> CachedResourceLoader::requestImage(CachedResourceRequest& request)
+CachedResourceHandle<CachedImage> CachedResourceLoader::requestImage(CachedResourceRequest&& request)
{
- if (Frame* f = frame()) {
- if (f->loader().pageDismissalEventBeingDispatched() != FrameLoader::NoDismissal) {
+ if (Frame* frame = this->frame()) {
+ if (frame->loader().pageDismissalEventBeingDispatched() != FrameLoader::PageDismissalType::None) {
+ if (Document* document = frame->document())
+ request.upgradeInsecureRequestIfNeeded(*document);
URL requestURL = request.resourceRequest().url();
- if (requestURL.isValid() && canRequest(CachedResource::ImageResource, requestURL, request.options(), request.forPreload()))
- PingLoader::loadImage(f, requestURL);
- return 0;
+ if (requestURL.isValid() && canRequest(CachedResource::ImageResource, requestURL, request, ForPreload::No))
+ PingLoader::loadImage(*frame, requestURL);
+ return nullptr;
}
}
- request.setDefer(clientDefersImage(request.resourceRequest().url()) ? CachedResourceRequest::DeferredByClient : CachedResourceRequest::NoDefer);
- return static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, request).get());
+
+ auto defer = clientDefersImage(request.resourceRequest().url()) ? DeferOption::DeferredByClient : DeferOption::NoDefer;
+ return downcast<CachedImage>(requestResource(CachedResource::ImageResource, WTFMove(request), ForPreload::No, defer).get());
}
-CachedResourceHandle<CachedFont> CachedResourceLoader::requestFont(CachedResourceRequest& request)
+CachedResourceHandle<CachedFont> CachedResourceLoader::requestFont(CachedResourceRequest&& request, bool isSVG)
{
- return static_cast<CachedFont*>(requestResource(CachedResource::FontResource, request).get());
+#if ENABLE(SVG_FONTS)
+ if (isSVG)
+ return downcast<CachedSVGFont>(requestResource(CachedResource::SVGFontResource, WTFMove(request)).get());
+#else
+ UNUSED_PARAM(isSVG);
+#endif
+ return downcast<CachedFont>(requestResource(CachedResource::FontResource, WTFMove(request)).get());
}
#if ENABLE(VIDEO_TRACK)
-CachedResourceHandle<CachedTextTrack> CachedResourceLoader::requestTextTrack(CachedResourceRequest& request)
+CachedResourceHandle<CachedTextTrack> CachedResourceLoader::requestTextTrack(CachedResourceRequest&& request)
{
- return static_cast<CachedTextTrack*>(requestResource(CachedResource::TextTrackResource, request).get());
+ return downcast<CachedTextTrack>(requestResource(CachedResource::TextTrackResource, WTFMove(request)).get());
}
#endif
-CachedResourceHandle<CachedCSSStyleSheet> CachedResourceLoader::requestCSSStyleSheet(CachedResourceRequest& request)
+CachedResourceHandle<CachedCSSStyleSheet> CachedResourceLoader::requestCSSStyleSheet(CachedResourceRequest&& request)
{
- return static_cast<CachedCSSStyleSheet*>(requestResource(CachedResource::CSSStyleSheet, request).get());
+ return downcast<CachedCSSStyleSheet>(requestResource(CachedResource::CSSStyleSheet, WTFMove(request)).get());
}
-CachedResourceHandle<CachedCSSStyleSheet> CachedResourceLoader::requestUserCSSStyleSheet(CachedResourceRequest& request)
+CachedResourceHandle<CachedCSSStyleSheet> CachedResourceLoader::requestUserCSSStyleSheet(CachedResourceRequest&& request)
{
- URL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
-
-#if ENABLE(CACHE_PARTITIONING)
- request.mutableResourceRequest().setCachePartition(document()->topOrigin()->cachePartition());
-#endif
-
- if (CachedResource* existing = memoryCache()->resourceForRequest(request.resourceRequest())) {
- if (existing->type() == CachedResource::CSSStyleSheet)
- return static_cast<CachedCSSStyleSheet*>(existing);
- memoryCache()->remove(existing);
+ ASSERT(document());
+ request.setDomainForCachePartition(*document());
+
+ auto& memoryCache = MemoryCache::singleton();
+ if (request.allowsCaching()) {
+ if (CachedResource* existing = memoryCache.resourceForRequest(request.resourceRequest(), sessionID())) {
+ if (is<CachedCSSStyleSheet>(*existing))
+ return downcast<CachedCSSStyleSheet>(existing);
+ memoryCache.remove(*existing);
+ }
}
- if (url.string() != request.resourceRequest().url())
- request.mutableResourceRequest().setURL(url);
- CachedResourceHandle<CachedCSSStyleSheet> userSheet = new CachedCSSStyleSheet(request.resourceRequest(), request.charset());
+ request.removeFragmentIdentifierIfNeeded();
+
+ CachedResourceHandle<CachedCSSStyleSheet> userSheet = new CachedCSSStyleSheet(WTFMove(request), sessionID());
- memoryCache()->add(userSheet.get());
+ if (userSheet->allowsCaching())
+ memoryCache.add(*userSheet);
// FIXME: loadResource calls setOwningCachedResourceLoader() if the resource couldn't be added to cache. Does this function need to call it, too?
- userSheet->load(this, ResourceLoaderOptions(DoNotSendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForAllCredentials, SkipSecurityCheck, UseDefaultOriginRestrictionsForType));
-
+ userSheet->load(*this);
return userSheet;
}
-CachedResourceHandle<CachedScript> CachedResourceLoader::requestScript(CachedResourceRequest& request)
+CachedResourceHandle<CachedScript> CachedResourceLoader::requestScript(CachedResourceRequest&& request)
{
- return static_cast<CachedScript*>(requestResource(CachedResource::Script, request).get());
+ return downcast<CachedScript>(requestResource(CachedResource::Script, WTFMove(request)).get());
}
#if ENABLE(XSLT)
-CachedResourceHandle<CachedXSLStyleSheet> CachedResourceLoader::requestXSLStyleSheet(CachedResourceRequest& request)
+CachedResourceHandle<CachedXSLStyleSheet> CachedResourceLoader::requestXSLStyleSheet(CachedResourceRequest&& request)
{
- return static_cast<CachedXSLStyleSheet*>(requestResource(CachedResource::XSLStyleSheet, request).get());
+ return downcast<CachedXSLStyleSheet>(requestResource(CachedResource::XSLStyleSheet, WTFMove(request)).get());
}
#endif
-#if ENABLE(SVG)
-CachedResourceHandle<CachedSVGDocument> CachedResourceLoader::requestSVGDocument(CachedResourceRequest& request)
+CachedResourceHandle<CachedSVGDocument> CachedResourceLoader::requestSVGDocument(CachedResourceRequest&& request)
{
- return static_cast<CachedSVGDocument*>(requestResource(CachedResource::SVGDocumentResource, request).get());
+ return downcast<CachedSVGDocument>(requestResource(CachedResource::SVGDocumentResource, WTFMove(request)).get());
}
-#endif
#if ENABLE(LINK_PREFETCH)
-CachedResourceHandle<CachedResource> CachedResourceLoader::requestLinkResource(CachedResource::Type type, CachedResourceRequest& request)
+CachedResourceHandle<CachedResource> CachedResourceLoader::requestLinkResource(CachedResource::Type type, CachedResourceRequest&& request)
{
ASSERT(frame());
ASSERT(type == CachedResource::LinkPrefetch || type == CachedResource::LinkSubresource);
- return requestResource(type, request);
+ return requestResource(type, WTFMove(request));
}
#endif
-CachedResourceHandle<CachedRawResource> CachedResourceLoader::requestRawResource(CachedResourceRequest& request)
+CachedResourceHandle<CachedRawResource> CachedResourceLoader::requestMedia(CachedResourceRequest&& request)
{
- return static_cast<CachedRawResource*>(requestResource(CachedResource::RawResource, request).get());
+ return downcast<CachedRawResource>(requestResource(CachedResource::MediaResource, WTFMove(request)).get());
}
-CachedResourceHandle<CachedRawResource> CachedResourceLoader::requestMainResource(CachedResourceRequest& request)
+CachedResourceHandle<CachedRawResource> CachedResourceLoader::requestRawResource(CachedResourceRequest&& request)
{
- return static_cast<CachedRawResource*>(requestResource(CachedResource::MainResource, request).get());
+ return downcast<CachedRawResource>(requestResource(CachedResource::RawResource, WTFMove(request)).get());
+}
+
+CachedResourceHandle<CachedRawResource> CachedResourceLoader::requestMainResource(CachedResourceRequest&& request)
+{
+ return downcast<CachedRawResource>(requestResource(CachedResource::MainResource, WTFMove(request)).get());
+}
+
+static MixedContentChecker::ContentType contentTypeFromResourceType(CachedResource::Type type)
+{
+ switch (type) {
+ // https://w3c.github.io/webappsec-mixed-content/#category-optionally-blockable
+ // Editor's Draft, 11 February 2016
+ // 3.1. Optionally-blockable Content
+ case CachedResource::ImageResource:
+ case CachedResource::MediaResource:
+ return MixedContentChecker::ContentType::ActiveCanWarn;
+
+ case CachedResource::CSSStyleSheet:
+ case CachedResource::Script:
+ case CachedResource::FontResource:
+ return MixedContentChecker::ContentType::Active;
+
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+ return MixedContentChecker::ContentType::Active;
+#endif
+
+ case CachedResource::RawResource:
+ case CachedResource::SVGDocumentResource:
+ return MixedContentChecker::ContentType::Active;
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+ return MixedContentChecker::ContentType::Active;
+#endif
+
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ case CachedResource::LinkSubresource:
+ return MixedContentChecker::ContentType::Active;
+#endif
+
+#if ENABLE(VIDEO_TRACK)
+ case CachedResource::TextTrackResource:
+ return MixedContentChecker::ContentType::Active;
+#endif
+ default:
+ ASSERT_NOT_REACHED();
+ return MixedContentChecker::ContentType::Active;
+ }
}
bool CachedResourceLoader::checkInsecureContent(CachedResource::Type type, const URL& url) const
{
+ if (!canRequestInContentDispositionAttachmentSandbox(type, url))
+ return false;
+
switch (type) {
case CachedResource::Script:
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
#endif
-#if ENABLE(SVG)
case CachedResource::SVGDocumentResource:
-#endif
case CachedResource::CSSStyleSheet:
// These resource can inject script into the current document (Script,
// XSL) or exfiltrate the content of the current document (CSS).
- if (Frame* f = frame())
- if (!f->loader().mixedContentChecker().canRunInsecureContent(m_document->securityOrigin(), url))
+ if (Frame* frame = this->frame()) {
+ if (!frame->loader().mixedContentChecker().canRunInsecureContent(m_document->securityOrigin(), url))
return false;
+ Frame& top = frame->tree().top();
+ if (&top != frame && !top.loader().mixedContentChecker().canRunInsecureContent(top.document()->securityOrigin(), url))
+ return false;
+ }
break;
#if ENABLE(VIDEO_TRACK)
case CachedResource::TextTrackResource:
#endif
+ case CachedResource::MediaResource:
case CachedResource::RawResource:
case CachedResource::ImageResource:
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
case CachedResource::FontResource: {
// These resources can corrupt only the frame's pixels.
- if (Frame* f = frame()) {
- Frame& topFrame = f->tree().top();
- if (!topFrame.loader().mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), url))
+ if (Frame* frame = this->frame()) {
+ if (!frame->loader().mixedContentChecker().canDisplayInsecureContent(m_document->securityOrigin(), contentTypeFromResourceType(type), url, MixedContentChecker::AlwaysDisplayInNonStrictMode::Yes))
+ return false;
+ Frame& topFrame = frame->tree().top();
+ if (!topFrame.loader().mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), contentTypeFromResourceType(type), url))
return false;
}
break;
@@ -289,306 +380,602 @@ bool CachedResourceLoader::checkInsecureContent(CachedResource::Type type, const
return true;
}
-bool CachedResourceLoader::canRequest(CachedResource::Type type, const URL& url, const ResourceLoaderOptions& options, bool forPreload)
+bool CachedResourceLoader::allowedByContentSecurityPolicy(CachedResource::Type type, const URL& url, const ResourceLoaderOptions& options, ContentSecurityPolicy::RedirectResponseReceived redirectResponseReceived) const
{
- if (document() && !document()->securityOrigin()->canDisplay(url)) {
- if (!forPreload)
- FrameLoader::reportLocalLoadFailed(frame(), url.stringCenterEllipsizedToLength());
- LOG(ResourceLoading, "CachedResourceLoader::requestResource URL was not allowed by SecurityOrigin::canDisplay");
- return 0;
- }
-
- // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
- bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy());
+ if (options.contentSecurityPolicyImposition == ContentSecurityPolicyImposition::SkipPolicyCheck)
+ return true;
- // Some types of resources can be loaded only from the same origin. Other
- // types of resources, like Images, Scripts, and CSS, can be loaded from
- // any URL.
- switch (type) {
- case CachedResource::MainResource:
- case CachedResource::ImageResource:
- case CachedResource::CSSStyleSheet:
- case CachedResource::Script:
- case CachedResource::FontResource:
- case CachedResource::RawResource:
-#if ENABLE(LINK_PREFETCH)
- case CachedResource::LinkPrefetch:
- case CachedResource::LinkSubresource:
-#endif
-#if ENABLE(VIDEO_TRACK)
- case CachedResource::TextTrackResource:
-#endif
- if (options.requestOriginPolicy == RestrictToSameOrigin && !m_document->securityOrigin()->canRequest(url)) {
- printAccessDeniedMessage(url);
- return false;
- }
- break;
-#if ENABLE(SVG)
- case CachedResource::SVGDocumentResource:
-#endif
-#if ENABLE(XSLT)
- case CachedResource::XSLStyleSheet:
- if (!m_document->securityOrigin()->canRequest(url)) {
- printAccessDeniedMessage(url);
- return false;
- }
-#endif
- break;
- }
+ ASSERT(m_document);
+ ASSERT(m_document->contentSecurityPolicy());
switch (type) {
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
- if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
- return false;
- break;
#endif
case CachedResource::Script:
- if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
+ if (!m_document->contentSecurityPolicy()->allowScriptFromSource(url, redirectResponseReceived))
return false;
-
- if (frame()) {
- if (!frame()->loader().client().allowScriptFromSource(frame()->settings().isScriptEnabled(), url))
- return false;
- }
break;
case CachedResource::CSSStyleSheet:
- if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
+ if (!m_document->contentSecurityPolicy()->allowStyleFromSource(url, redirectResponseReceived))
return false;
break;
-#if ENABLE(SVG)
case CachedResource::SVGDocumentResource:
-#endif
case CachedResource::ImageResource:
- if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
- return false;
- break;
- case CachedResource::FontResource: {
- if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
+ if (!m_document->contentSecurityPolicy()->allowImageFromSource(url, redirectResponseReceived))
return false;
break;
- }
- case CachedResource::MainResource:
- case CachedResource::RawResource:
-#if ENABLE(LINK_PREFETCH)
- case CachedResource::LinkPrefetch:
- case CachedResource::LinkSubresource:
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
#endif
+ case CachedResource::FontResource:
+ if (!m_document->contentSecurityPolicy()->allowFontFromSource(url, redirectResponseReceived))
+ return false;
break;
+ case CachedResource::MediaResource:
#if ENABLE(VIDEO_TRACK)
case CachedResource::TextTrackResource:
- if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
+#endif
+ if (!m_document->contentSecurityPolicy()->allowMediaFromSource(url, redirectResponseReceived))
return false;
break;
-#endif
+ case CachedResource::RawResource:
+ return true;
+ default:
+ ASSERT_NOT_REACHED();
}
+ return true;
+}
+
+static inline bool isSameOriginDataURL(const URL& url, const ResourceLoaderOptions& options)
+{
+ // FIXME: Remove same-origin data URL flag since it was removed from fetch spec (https://github.com/whatwg/fetch/issues/381).
+ return url.protocolIsData() && options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set;
+}
+
+bool CachedResourceLoader::canRequest(CachedResource::Type type, const URL& url, const CachedResourceRequest& request, ForPreload forPreload)
+{
+ auto& options = request.options();
+
+ if (document() && !document()->securityOrigin().canDisplay(url)) {
+ if (forPreload == ForPreload::No)
+ FrameLoader::reportLocalLoadFailed(frame(), url.stringCenterEllipsizedToLength());
+ LOG(ResourceLoading, "CachedResourceLoader::requestResource URL was not allowed by SecurityOrigin::canDisplay");
+ return false;
+ }
+
+ if (options.mode == FetchOptions::Mode::SameOrigin && !m_document->securityOrigin().canRequest(url) && !isSameOriginDataURL(url, options)) {
+ printAccessDeniedMessage(url);
+ return false;
+ }
+
+ if (!allowedByContentSecurityPolicy(type, url, options, ContentSecurityPolicy::RedirectResponseReceived::No))
+ return false;
+
// SVG Images have unique security rules that prevent all subresource requests except for data urls.
if (type != CachedResource::MainResource && frame() && frame()->page()) {
if (frame()->page()->chrome().client().isSVGImageChromeClient() && !url.protocolIsData())
return false;
}
- // Last of all, check for insecure content. We do this last so that when
- // folks block insecure content with a CSP policy, they don't get a warning.
+ // Last of all, check for insecure content. We do this last so that when folks block insecure content with a CSP policy, they don't get a warning.
// They'll still get a warning in the console about CSP blocking the load.
- // FIXME: Should we consider forPreload here?
+ // FIXME: Should we consider whether the request is for preload here?
+ if (!checkInsecureContent(type, url))
+ return false;
+
+ return true;
+}
+
+// FIXME: Should we find a way to know whether the redirection is for a preload request like we do for CachedResourceLoader::canRequest?
+bool CachedResourceLoader::canRequestAfterRedirection(CachedResource::Type type, const URL& url, const ResourceLoaderOptions& options) const
+{
+ if (document() && !document()->securityOrigin().canDisplay(url)) {
+ FrameLoader::reportLocalLoadFailed(frame(), url.stringCenterEllipsizedToLength());
+ LOG(ResourceLoading, "CachedResourceLoader::requestResource URL was not allowed by SecurityOrigin::canDisplay");
+ return false;
+ }
+
+ // FIXME: According to https://fetch.spec.whatwg.org/#http-redirect-fetch, we should check that the URL is HTTP(s) except if in navigation mode.
+ // But we currently allow at least data URLs to be loaded.
+
+ if (options.mode == FetchOptions::Mode::SameOrigin && !m_document->securityOrigin().canRequest(url)) {
+ printAccessDeniedMessage(url);
+ return false;
+ }
+
+ if (!allowedByContentSecurityPolicy(type, url, options, ContentSecurityPolicy::RedirectResponseReceived::Yes))
+ return false;
+
+ // Last of all, check for insecure content. We do this last so that when folks block insecure content with a CSP policy, they don't get a warning.
+ // They'll still get a warning in the console about CSP blocking the load.
if (!checkInsecureContent(type, url))
return false;
return true;
}
-bool CachedResourceLoader::shouldContinueAfterNotifyingLoadedFromMemoryCache(CachedResource* resource)
+bool CachedResourceLoader::updateRequestAfterRedirection(CachedResource::Type type, ResourceRequest& request, const ResourceLoaderOptions& options)
+{
+ ASSERT(m_documentLoader);
+ if (auto* document = m_documentLoader->cachedResourceLoader().document())
+ upgradeInsecureResourceRequestIfNeeded(request, *document);
+
+ // FIXME: We might want to align the checks done here with the ones done in CachedResourceLoader::requestResource, content extensions blocking in particular.
+
+ return canRequestAfterRedirection(type, request.url(), options);
+}
+
+bool CachedResourceLoader::canRequestInContentDispositionAttachmentSandbox(CachedResource::Type type, const URL& url) const
+{
+ Document* document;
+
+ // FIXME: Do we want to expand this to all resource types that the mixed content checker would consider active content?
+ switch (type) {
+ case CachedResource::MainResource:
+ if (auto ownerElement = frame() ? frame()->ownerElement() : nullptr) {
+ document = &ownerElement->document();
+ break;
+ }
+ return true;
+ case CachedResource::CSSStyleSheet:
+ document = m_document;
+ break;
+ default:
+ return true;
+ }
+
+ if (!document->shouldEnforceContentDispositionAttachmentSandbox() || document->securityOrigin().canRequest(url))
+ return true;
+
+ String message = "Unsafe attempt to load URL " + url.stringCenterEllipsizedToLength() + " from document with Content-Disposition: attachment at URL " + document->url().stringCenterEllipsizedToLength() + ".";
+ document->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
+ return false;
+}
+
+bool CachedResourceLoader::shouldContinueAfterNotifyingLoadedFromMemoryCache(const CachedResourceRequest& request, CachedResource* resource)
{
if (!resource || !frame() || resource->status() != CachedResource::Cached)
return true;
- ResourceRequest newRequest;
+ ResourceRequest newRequest = ResourceRequest(resource->url());
+ newRequest.setInitiatorIdentifier(request.resourceRequest().initiatorIdentifier());
+ if (request.resourceRequest().hiddenFromInspector())
+ newRequest.setHiddenFromInspector(true);
frame()->loader().loadedResourceFromMemoryCache(resource, newRequest);
-
+
// FIXME <http://webkit.org/b/113251>: If the delegate modifies the request's
// URL, it is no longer appropriate to use this CachedResource.
return !newRequest.isNull();
}
-CachedResourceHandle<CachedResource> CachedResourceLoader::requestResource(CachedResource::Type type, CachedResourceRequest& request)
+bool CachedResourceLoader::shouldUpdateCachedResourceWithCurrentRequest(const CachedResource& resource, const CachedResourceRequest& request)
+{
+ // WebKit is not supporting CORS for fonts (https://bugs.webkit.org/show_bug.cgi?id=86817), no need to update the resource before reusing it.
+ if (resource.type() == CachedResource::Type::FontResource)
+ return false;
+
+#if ENABLE(SVG_FONTS)
+ if (resource.type() == CachedResource::Type::SVGFontResource)
+ return false;
+#endif
+
+#if ENABLE(XSLT)
+ // Load is same-origin, we do not check for CORS.
+ if (resource.type() == CachedResource::XSLStyleSheet)
+ return false;
+#endif
+
+ // FIXME: We should enable resource reuse for these resource types
+ switch (resource.type()) {
+ case CachedResource::SVGDocumentResource:
+ return false;
+ case CachedResource::MainResource:
+ return false;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return false;
+ case CachedResource::LinkSubresource:
+ return false;
+#endif
+ default:
+ break;
+ }
+
+ if (resource.options().mode != request.options().mode || !originsMatch(request.origin(), resource.origin()))
+ return true;
+
+ if (resource.options().redirect != request.options().redirect && resource.hasRedirections())
+ return true;
+
+ return false;
+}
+
+static inline bool isResourceSuitableForDirectReuse(const CachedResource& resource, const CachedResourceRequest& request)
+{
+ // FIXME: For being loaded requests, the response tainting may not be correctly computed if the fetch mode is not the same.
+ // Even if the fetch mode is the same, we are not sure that the resource can be reused (Vary: Origin header for instance).
+ // We should find a way to improve this.
+ if (resource.status() != CachedResource::Cached)
+ return false;
+
+ // If the cached resource has not followed redirections, it is incomplete and we should not use it.
+ // Let's make sure the memory cache has no such resource.
+ ASSERT(resource.response().type() != ResourceResponse::Type::Opaqueredirect);
+
+ // We could support redirect modes other than Follow in case of a redirected resource.
+ // This case is rare and is not worth optimizing currently.
+ if (request.options().redirect != FetchOptions::Redirect::Follow && resource.hasRedirections())
+ return false;
+
+ // FIXME: Implement reuse of cached raw resources.
+ if (resource.type() == CachedResource::Type::RawResource || resource.type() == CachedResource::Type::MediaResource)
+ return false;
+
+ return true;
+}
+
+CachedResourceHandle<CachedResource> CachedResourceLoader::updateCachedResourceWithCurrentRequest(const CachedResource& resource, CachedResourceRequest&& request)
+{
+ if (!isResourceSuitableForDirectReuse(resource, request)) {
+ request.setCachingPolicy(CachingPolicy::DisallowCaching);
+ return loadResource(resource.type(), WTFMove(request));
+ }
+
+ auto resourceHandle = createResource(resource.type(), WTFMove(request), sessionID());
+ resourceHandle->loadFrom(resource);
+ return resourceHandle;
+}
+
+static inline void logMemoryCacheResourceRequest(Frame* frame, const String& key, const String& description)
{
+ if (!frame || !frame->page())
+ return;
+ frame->page()->diagnosticLoggingClient().logDiagnosticMessage(key, description, ShouldSample::Yes);
+}
+
+void CachedResourceLoader::prepareFetch(CachedResource::Type type, CachedResourceRequest& request)
+{
+ // Implementing step 1 to 7 of https://fetch.spec.whatwg.org/#fetching
+
+ if (!request.origin() && document())
+ request.setOrigin(document()->securityOrigin());
+
+ request.setAcceptHeaderIfNone(type);
+
+ // Accept-Language value is handled in underlying port-specific code.
+ // FIXME: Decide whether to support client hints
+}
+
+void CachedResourceLoader::updateHTTPRequestHeaders(CachedResource::Type type, CachedResourceRequest& request)
+{
+ // Implementing steps 7 to 12 of https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
+
+ // FIXME: We should reconcile handling of MainResource with other resources.
+ if (type != CachedResource::Type::MainResource) {
+ // In some cases we may try to load resources in frameless documents. Such loads always fail.
+ // FIXME: We shouldn't need to do the check on frame.
+ if (auto* frame = this->frame())
+ request.updateReferrerOriginAndUserAgentHeaders(frame->loader(), document() ? document()->referrerPolicy() : ReferrerPolicy::Default);
+ }
+
+ request.updateAccordingCacheMode();
+}
+
+CachedResourceHandle<CachedResource> CachedResourceLoader::requestResource(CachedResource::Type type, CachedResourceRequest&& request, ForPreload forPreload, DeferOption defer)
+{
+ if (Document* document = this->document())
+ request.upgradeInsecureRequestIfNeeded(*document);
+
URL url = request.resourceRequest().url();
-
- LOG(ResourceLoading, "CachedResourceLoader::requestResource '%s', charset '%s', priority=%d, forPreload=%u", url.stringCenterEllipsizedToLength().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload());
-
- // If only the fragment identifiers differ, it is the same resource.
- url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
- if (!url.isValid())
- return 0;
+ LOG(ResourceLoading, "CachedResourceLoader::requestResource '%s', charset '%s', priority=%d, forPreload=%u", url.stringCenterEllipsizedToLength().latin1().data(), request.charset().latin1().data(), request.priority() ? static_cast<int>(request.priority().value()) : -1, forPreload == ForPreload::Yes);
- if (!canRequest(type, url, request.options(), request.forPreload()))
- return 0;
+ if (!url.isValid()) {
+ RELEASE_LOG_IF_ALLOWED("requestResource: URL is invalid (frame = %p)", frame());
+ return nullptr;
+ }
- if (Frame* f = frame())
- f->loader().client().dispatchWillRequestResource(&request);
+ prepareFetch(type, request);
+
+ // We are passing url as well as request, as request url may contain a fragment identifier.
+ if (!canRequest(type, url, request, forPreload)) {
+ RELEASE_LOG_IF_ALLOWED("requestResource: Not allowed to request resource (frame = %p)", frame());
+ return nullptr;
+ }
- if (memoryCache()->disabled()) {
+#if ENABLE(CONTENT_EXTENSIONS)
+ if (frame() && frame()->mainFrame().page() && m_documentLoader) {
+ const auto& resourceRequest = request.resourceRequest();
+ auto blockedStatus = frame()->mainFrame().page()->userContentProvider().processContentExtensionRulesForLoad(resourceRequest.url(), toResourceType(type), *m_documentLoader);
+ request.applyBlockedStatus(blockedStatus);
+ if (blockedStatus.blockedLoad) {
+ RELEASE_LOG_IF_ALLOWED("requestResource: Resource blocked by content blocker (frame = %p)", frame());
+ if (type == CachedResource::Type::MainResource) {
+ auto resource = createResource(type, WTFMove(request), sessionID());
+ ASSERT(resource);
+ resource->error(CachedResource::Status::LoadError);
+ resource->setResourceError(ResourceError(ContentExtensions::WebKitContentBlockerDomain, 0, resourceRequest.url(), WEB_UI_STRING("The URL was blocked by a content blocker", "WebKitErrorBlockedByContentBlocker description")));
+ return resource;
+ }
+ return nullptr;
+ }
+ if (blockedStatus.madeHTTPS
+ && type == CachedResource::Type::MainResource
+ && m_documentLoader->isLoadingMainResource()) {
+ // This is to make sure the correct 'new' URL shows in the location bar.
+ m_documentLoader->frameLoader()->client().dispatchDidChangeProvisionalURL();
+ }
+ url = request.resourceRequest().url(); // The content extension could have changed it from http to https.
+ url = MemoryCache::removeFragmentIdentifierIfNeeded(url); // Might need to remove fragment identifier again.
+ }
+#endif
+
+#if ENABLE(WEB_TIMING)
+ LoadTiming loadTiming;
+ loadTiming.markStartTimeAndFetchStart();
+ InitiatorContext initiatorContext = request.options().initiatorContext;
+#endif
+
+ if (request.resourceRequest().url().protocolIsInHTTPFamily())
+ updateHTTPRequestHeaders(type, request);
+
+ auto& memoryCache = MemoryCache::singleton();
+ if (request.allowsCaching() && memoryCache.disabled()) {
DocumentResourceMap::iterator it = m_documentResources.find(url.string());
if (it != m_documentResources.end()) {
- it->value->setOwningCachedResourceLoader(0);
+ it->value->setOwningCachedResourceLoader(nullptr);
m_documentResources.remove(it);
}
}
// See if we can use an existing resource from the cache.
CachedResourceHandle<CachedResource> resource;
-#if ENABLE(CACHE_PARTITIONING)
if (document())
- request.mutableResourceRequest().setCachePartition(document()->topOrigin()->cachePartition());
-#endif
+ request.setDomainForCachePartition(*document());
+
+ if (request.allowsCaching())
+ resource = memoryCache.resourceForRequest(request.resourceRequest(), sessionID());
+
+ if (resource && request.isLinkPreload() && !resource->isLinkPreload())
+ resource->setLinkPreload();
- resource = memoryCache()->resourceForRequest(request.resourceRequest());
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::memoryCacheUsageKey(), resource ? DiagnosticLoggingKeys::inMemoryCacheKey() : DiagnosticLoggingKeys::notInMemoryCacheKey());
- const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer());
+ RevalidationPolicy policy = determineRevalidationPolicy(type, request, resource.get(), forPreload, defer);
switch (policy) {
case Reload:
- memoryCache()->remove(resource.get());
+ memoryCache.remove(*resource);
FALLTHROUGH;
case Load:
- resource = loadResource(type, request, request.charset());
+ if (resource)
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::memoryCacheEntryDecisionKey(), DiagnosticLoggingKeys::unusedKey());
+ resource = loadResource(type, WTFMove(request));
break;
case Revalidate:
- resource = revalidateResource(request, resource.get());
+ if (resource)
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::memoryCacheEntryDecisionKey(), DiagnosticLoggingKeys::revalidatingKey());
+ resource = revalidateResource(WTFMove(request), *resource);
break;
case Use:
- if (!shouldContinueAfterNotifyingLoadedFromMemoryCache(resource.get()))
- return 0;
- memoryCache()->resourceAccessed(resource.get());
+ ASSERT(resource);
+ if (shouldUpdateCachedResourceWithCurrentRequest(*resource, request)) {
+ resource = updateCachedResourceWithCurrentRequest(*resource, WTFMove(request));
+ if (resource->status() != CachedResource::Status::Cached)
+ policy = Load;
+ } else {
+ if (!shouldContinueAfterNotifyingLoadedFromMemoryCache(request, resource.get()))
+ return nullptr;
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::memoryCacheEntryDecisionKey(), DiagnosticLoggingKeys::usedKey());
+ memoryCache.resourceAccessed(*resource);
+#if ENABLE(WEB_TIMING)
+ loadTiming.setResponseEnd(MonotonicTime::now());
+
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()) {
+ ResourceTiming resourceTiming = ResourceTiming::fromCache(url, request.initiatorName(), loadTiming);
+ if (initiatorContext == InitiatorContext::Worker) {
+ ASSERT(is<CachedRawResource>(resource.get()));
+ downcast<CachedRawResource>(resource.get())->finishedTimingForWorkerLoad(WTFMove(resourceTiming));
+ } else if (document()) {
+ ASSERT(initiatorContext == InitiatorContext::Document);
+ m_resourceTimingInfo.storeResourceTimingInitiatorInformation(resource, request.initiatorName(), frame());
+ m_resourceTimingInfo.addResourceTiming(*resource.get(), *document(), WTFMove(resourceTiming));
+ }
+ }
+#endif
+ if (forPreload == ForPreload::No)
+ resource->setLoadPriority(request.priority());
+ }
break;
}
if (!resource)
- return 0;
+ return nullptr;
- if (!request.forPreload() || policy != Use)
- resource->setLoadPriority(request.priority());
+ if (forPreload == ForPreload::No && resource->loader() && resource->resourceRequest().ignoreForRequestCount()) {
+ resource->resourceRequest().setIgnoreForRequestCount(false);
+ incrementRequestCount(*resource);
+ }
- if ((policy != Use || resource->stillNeedsLoad()) && CachedResourceRequest::NoDefer == request.defer()) {
- resource->load(this, request.options());
+ if ((policy != Use || resource->stillNeedsLoad()) && defer == DeferOption::NoDefer) {
+ resource->load(*this);
// We don't support immediate loads, but we do support immediate failure.
if (resource->errorOccurred()) {
- if (resource->inCache())
- memoryCache()->remove(resource.get());
- return 0;
+ if (resource->allowsCaching() && resource->inCache())
+ memoryCache.remove(*resource);
+ return nullptr;
}
}
- if (!request.resourceRequest().url().protocolIsData())
- m_validatedURLs.add(request.resourceRequest().url());
+ if (document() && !document()->loadEventFinished() && !resource->resourceRequest().url().protocolIsData())
+ m_validatedURLs.add(resource->resourceRequest().url());
ASSERT(resource->url() == url.string());
m_documentResources.set(resource->url(), resource);
return resource;
}
-CachedResourceHandle<CachedResource> CachedResourceLoader::revalidateResource(const CachedResourceRequest& request, CachedResource* resource)
+void CachedResourceLoader::documentDidFinishLoadEvent()
{
- ASSERT(resource);
- ASSERT(resource->inCache());
- ASSERT(!memoryCache()->disabled());
- ASSERT(resource->canUseCacheValidator());
- ASSERT(!resource->resourceToRevalidate());
-
- // Copy the URL out of the resource to be revalidated in case it gets deleted by the remove() call below.
- String url = resource->url();
- CachedResourceHandle<CachedResource> newResource = createResource(resource->type(), resource->resourceRequest(), resource->encoding());
-
- LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
- newResource->setResourceToRevalidate(resource);
-
- memoryCache()->remove(resource);
- memoryCache()->add(newResource.get());
-#if ENABLE(RESOURCE_TIMING)
- storeResourceTimingInitiatorInformation(resource, request);
-#else
- UNUSED_PARAM(request);
+ m_validatedURLs.clear();
+}
+
+CachedResourceHandle<CachedResource> CachedResourceLoader::revalidateResource(CachedResourceRequest&& request, CachedResource& resource)
+{
+ ASSERT(resource.inCache());
+ auto& memoryCache = MemoryCache::singleton();
+ ASSERT(!memoryCache.disabled());
+ ASSERT(resource.canUseCacheValidator());
+ ASSERT(!resource.resourceToRevalidate());
+ ASSERT(resource.sessionID() == sessionID());
+ ASSERT(resource.allowsCaching());
+
+ CachedResourceHandle<CachedResource> newResource = createResource(resource.type(), WTFMove(request), resource.sessionID());
+
+ LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), &resource);
+ newResource->setResourceToRevalidate(&resource);
+
+ memoryCache.remove(resource);
+ memoryCache.add(*newResource);
+#if ENABLE(WEB_TIMING)
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
+ m_resourceTimingInfo.storeResourceTimingInitiatorInformation(newResource, newResource->initiatorName(), frame());
#endif
return newResource;
}
-CachedResourceHandle<CachedResource> CachedResourceLoader::loadResource(CachedResource::Type type, CachedResourceRequest& request, const String& charset)
+CachedResourceHandle<CachedResource> CachedResourceLoader::loadResource(CachedResource::Type type, CachedResourceRequest&& request)
{
- ASSERT(!memoryCache()->resourceForRequest(request.resourceRequest()));
+ auto& memoryCache = MemoryCache::singleton();
+ ASSERT(!request.allowsCaching() || !memoryCache.resourceForRequest(request.resourceRequest(), sessionID())
+ || request.resourceRequest().cachePolicy() == DoNotUseAnyCache || request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData || request.resourceRequest().cachePolicy() == RefreshAnyCacheData);
LOG(ResourceLoading, "Loading CachedResource for '%s'.", request.resourceRequest().url().stringCenterEllipsizedToLength().latin1().data());
- CachedResourceHandle<CachedResource> resource = createResource(type, request.mutableResourceRequest(), charset);
+ CachedResourceHandle<CachedResource> resource = createResource(type, WTFMove(request), sessionID());
- if (!memoryCache()->add(resource.get()))
+ if (resource->allowsCaching() && !memoryCache.add(*resource))
resource->setOwningCachedResourceLoader(this);
-#if ENABLE(RESOURCE_TIMING)
- storeResourceTimingInitiatorInformation(resource, request);
+#if ENABLE(WEB_TIMING)
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
+ m_resourceTimingInfo.storeResourceTimingInitiatorInformation(resource, resource->initiatorName(), frame());
#endif
return resource;
}
-#if ENABLE(RESOURCE_TIMING)
-void CachedResourceLoader::storeResourceTimingInitiatorInformation(const CachedResourceHandle<CachedResource>& resource, const CachedResourceRequest& request)
+static void logRevalidation(const String& reason, DiagnosticLoggingClient& logClient)
{
- if (resource->type() == CachedResource::MainResource) {
- // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
- if (frame()->ownerElement() && m_documentLoader->frameLoader()->stateMachine()->committingFirstRealLoad()) {
- InitiatorInfo info = { frame()->ownerElement()->localName(), monotonicallyIncreasingTime() };
- m_initiatorMap.add(resource.get(), info);
- }
- } else {
- InitiatorInfo info = { request.initiatorName(), monotonicallyIncreasingTime() };
- m_initiatorMap.add(resource.get(), info);
+ logClient.logDiagnosticMessage(DiagnosticLoggingKeys::cachedResourceRevalidationReasonKey(), reason, ShouldSample::Yes);
+}
+
+static void logResourceRevalidationDecision(CachedResource::RevalidationDecision reason, const Frame* frame)
+{
+ if (!frame || !frame->page())
+ return;
+ auto& logClient = frame->page()->diagnosticLoggingClient();
+ switch (reason) {
+ case CachedResource::RevalidationDecision::No:
+ break;
+ case CachedResource::RevalidationDecision::YesDueToExpired:
+ logRevalidation(DiagnosticLoggingKeys::isExpiredKey(), logClient);
+ break;
+ case CachedResource::RevalidationDecision::YesDueToNoStore:
+ logRevalidation(DiagnosticLoggingKeys::noStoreKey(), logClient);
+ break;
+ case CachedResource::RevalidationDecision::YesDueToNoCache:
+ logRevalidation(DiagnosticLoggingKeys::noCacheKey(), logClient);
+ break;
+ case CachedResource::RevalidationDecision::YesDueToCachePolicy:
+ logRevalidation(DiagnosticLoggingKeys::reloadKey(), logClient);
+ break;
}
}
-#endif // ENABLE(RESOURCE_TIMING)
-CachedResourceLoader::RevalidationPolicy CachedResourceLoader::determineRevalidationPolicy(CachedResource::Type type, ResourceRequest& request, bool forPreload, CachedResource* existingResource, CachedResourceRequest::DeferOption defer) const
+CachedResourceLoader::RevalidationPolicy CachedResourceLoader::determineRevalidationPolicy(CachedResource::Type type, CachedResourceRequest& cachedResourceRequest, CachedResource* existingResource, ForPreload forPreload, DeferOption defer) const
{
+ auto& request = cachedResourceRequest.resourceRequest();
+
if (!existingResource)
return Load;
+ if (request.cachePolicy() == DoNotUseAnyCache || request.cachePolicy() == ReloadIgnoringCacheData)
+ return Load;
+
+ if (request.cachePolicy() == RefreshAnyCacheData)
+ return Reload;
+
// We already have a preload going for this URL.
- if (forPreload && existingResource->isPreloaded())
+ if (forPreload == ForPreload::Yes && existingResource->isPreloaded())
return Use;
// If the same URL has been loaded as a different type, we need to reload.
if (existingResource->type() != type) {
LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to type mismatch.");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonTypeMismatchKey());
return Reload;
}
- if (!existingResource->canReuse(request))
+ if (!existingResource->varyHeaderValuesMatch(request))
return Reload;
+ auto* textDecoder = existingResource->textResourceDecoder();
+ if (textDecoder && !textDecoder->hasEqualEncodingForCharset(cachedResourceRequest.charset()))
+ return Reload;
+
+ // FIXME: We should use the same cache policy for all resource types. The raw resource policy is overly strict
+ // while the normal subresource policy is too loose.
+ if (existingResource->isMainOrMediaOrRawResource() && frame()) {
+ bool strictPolicyDisabled = frame()->loader().isStrictRawResourceValidationPolicyDisabledForTesting();
+ bool canReuseRawResource = strictPolicyDisabled || downcast<CachedRawResource>(*existingResource).canReuse(request);
+ if (!canReuseRawResource)
+ return Reload;
+ }
+
// Conditional requests should have failed canReuse check.
ASSERT(!request.isConditional());
- // Do not load from cache if images are not enabled. The load for this image will be blocked
- // in CachedImage::load.
- if (CachedResourceRequest::DeferredByClient == defer)
+ // Do not load from cache if images are not enabled. The load for this image will be blocked in CachedImage::load.
+ if (defer == DeferOption::DeferredByClient)
return Reload;
-
- // Don't reload resources while pasting.
- if (m_allowStaleResources)
+
+ // Don't reload resources while pasting or if cache mode allows stale resources.
+ if (m_allowStaleResources || cachedResourceRequest.options().cache == FetchOptions::Cache::ForceCache || cachedResourceRequest.options().cache == FetchOptions::Cache::OnlyIfCached)
return Use;
-
- // Alwaus use preloads.
+
+ ASSERT(cachedResourceRequest.options().cache == FetchOptions::Cache::Default || cachedResourceRequest.options().cache == FetchOptions::Cache::NoCache);
+
+ // Always use preloads.
if (existingResource->isPreloaded())
return Use;
-
- // CachePolicyHistoryBuffer uses the cache no matter what.
- if (cachePolicy(type) == CachePolicyHistoryBuffer)
+
+ // We can find resources that are being validated from cache only when validation is just successfully completing.
+ if (existingResource->validationCompleting())
return Use;
+ ASSERT(!existingResource->validationInProgress());
+
+ // Validate the redirect chain.
+ bool cachePolicyIsHistoryBuffer = cachePolicy(type) == CachePolicyHistoryBuffer;
+ if (!existingResource->redirectChainAllowsReuse(cachePolicyIsHistoryBuffer ? ReuseExpiredRedirection : DoNotReuseExpiredRedirection)) {
+ LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to not cached or expired redirections.");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonRedirectChainKey());
+ return Reload;
+ }
+
+ // CachePolicyHistoryBuffer uses the cache except if this is a main resource with "cache-control: no-store".
+ if (cachePolicyIsHistoryBuffer) {
+ // FIXME: Ignoring "cache-control: no-cache" for sub-resources on history navigation but not the main
+ // resource is inconsistent. We should probably harmonize this.
+ if (!existingResource->response().cacheControlContainsNoStore() || type != CachedResource::MainResource)
+ return Use;
+ }
// Don't reuse resources with Cache-control: no-store.
if (existingResource->response().cacheControlContainsNoStore()) {
LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to Cache-control: no-store.");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonNoStoreKey());
return Reload;
}
@@ -600,6 +987,7 @@ CachedResourceLoader::RevalidationPolicy CachedResourceLoader::determineRevalida
// client's requests are made without CORS and some with.
if (existingResource->resourceRequest().allowCookies() != request.allowCookies()) {
LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to difference in credentials settings.");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonCredentialSettingsKey());
return Reload;
}
@@ -610,27 +998,40 @@ CachedResourceLoader::RevalidationPolicy CachedResourceLoader::determineRevalida
// CachePolicyReload always reloads
if (cachePolicy(type) == CachePolicyReload) {
LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to CachePolicyReload.");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonReloadKey());
return Reload;
}
// We'll try to reload the resource if it failed last time.
if (existingResource->errorOccurred()) {
LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicye reloading due to resource being in the error state");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonErrorKey());
return Reload;
}
-
- // For resources that are not yet loaded we ignore the cache policy.
- if (existingResource->isLoading())
+
+ if (existingResource->isLoading()) {
+ // Do not use cached main resources that are still loading because sharing
+ // loading CachedResources in this case causes issues with regards to cancellation.
+ // If one of the DocumentLoader clients decides to cancel the load, then the load
+ // would be cancelled for all other DocumentLoaders as well.
+ if (type == CachedResource::Type::MainResource)
+ return Reload;
+ // For cached subresources that are still loading we ignore the cache policy.
return Use;
+ }
+
+ auto revalidationDecision = existingResource->makeRevalidationDecision(cachePolicy(type));
+ logResourceRevalidationDecision(revalidationDecision, frame());
// Check if the cache headers requires us to revalidate (cache expiration for example).
- if (existingResource->mustRevalidateDueToCacheHeaders(cachePolicy(type))) {
+ if (revalidationDecision != CachedResource::RevalidationDecision::No) {
// See if the resource has usable ETag or Last-modified headers.
if (existingResource->canUseCacheValidator())
return Revalidate;
// No, must reload.
- LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to missing cache validators.");
+ LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to missing cache validators.");
+ logMemoryCacheResourceRequest(frame(), DiagnosticLoggingKeys::inMemoryCacheKey(), DiagnosticLoggingKeys::unusedReasonMustRevalidateNoValidatorKey());
return Reload;
}
@@ -651,7 +1052,7 @@ void CachedResourceLoader::printAccessDeniedMessage(const URL& url) const
else
message = "Unsafe attempt to load URL " + url.stringCenterEllipsizedToLength() + " from frame with URL " + m_document->url().stringCenterEllipsizedToLength() + ". Domains, protocols and ports must match.\n";
- frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
+ frame()->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
}
void CachedResourceLoader::setAutoLoadImages(bool enable)
@@ -680,72 +1081,72 @@ void CachedResourceLoader::setImagesEnabled(bool enable)
reloadImagesIfNotDeferred();
}
-bool CachedResourceLoader::clientDefersImage(const URL& url) const
+bool CachedResourceLoader::clientDefersImage(const URL&) const
+{
+ return !m_imagesEnabled;
+}
+
+bool CachedResourceLoader::shouldPerformImageLoad(const URL& url) const
{
- return frame() && !frame()->loader().client().allowImage(m_imagesEnabled, url);
+ return m_autoLoadImages || url.protocolIsData();
}
bool CachedResourceLoader::shouldDeferImageLoad(const URL& url) const
{
- return clientDefersImage(url) || !m_autoLoadImages;
+ return clientDefersImage(url) || !shouldPerformImageLoad(url);
}
void CachedResourceLoader::reloadImagesIfNotDeferred()
{
- DocumentResourceMap::iterator end = m_documentResources.end();
- for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
- CachedResource* resource = it->value.get();
- if (resource->type() == CachedResource::ImageResource && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
- const_cast<CachedResource*>(resource)->load(this, defaultCachedResourceOptions());
+ for (auto& resource : m_documentResources.values()) {
+ if (is<CachedImage>(*resource) && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
+ downcast<CachedImage>(*resource).load(*this);
}
}
CachePolicy CachedResourceLoader::cachePolicy(CachedResource::Type type) const
{
- if (!frame())
+ Frame* frame = this->frame();
+ if (!frame)
return CachePolicyVerify;
if (type != CachedResource::MainResource)
- return frame()->loader().subresourceCachePolicy();
-
- if (frame()->loader().loadType() == FrameLoadTypeReloadFromOrigin || frame()->loader().loadType() == FrameLoadTypeReload)
+ return frame->loader().subresourceCachePolicy();
+
+ if (Page* page = frame->page()) {
+ if (page->isResourceCachingDisabled())
+ return CachePolicyReload;
+ }
+
+ switch (frame->loader().loadType()) {
+ case FrameLoadType::ReloadFromOrigin:
+ case FrameLoadType::Reload:
return CachePolicyReload;
- return CachePolicyVerify;
+ case FrameLoadType::Back:
+ case FrameLoadType::Forward:
+ case FrameLoadType::IndexedBackForward:
+ // Do not revalidate cached main resource on back/forward navigation.
+ return CachePolicyHistoryBuffer;
+ default:
+ return CachePolicyVerify;
+ }
}
-void CachedResourceLoader::removeCachedResource(CachedResource* resource) const
+void CachedResourceLoader::removeCachedResource(CachedResource& resource)
{
#ifndef NDEBUG
- DocumentResourceMap::iterator it = m_documentResources.find(resource->url());
+ DocumentResourceMap::iterator it = m_documentResources.find(resource.url());
if (it != m_documentResources.end())
- ASSERT(it->value.get() == resource);
+ ASSERT(it->value.get() == &resource);
#endif
- m_documentResources.remove(resource->url());
+ m_documentResources.remove(resource.url());
}
-void CachedResourceLoader::loadDone(CachedResource* resource, bool shouldPerformPostLoadActions)
+void CachedResourceLoader::loadDone(bool shouldPerformPostLoadActions)
{
RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
RefPtr<Document> protectDocument(m_document);
-#if ENABLE(RESOURCE_TIMING)
- if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304)) {
- HashMap<CachedResource*, InitiatorInfo>::iterator initiatorIt = m_initiatorMap.find(resource);
- if (initiatorIt != m_initiatorMap.end()) {
- ASSERT(document());
- Document* initiatorDocument = document();
- if (resource->type() == CachedResource::MainResource)
- initiatorDocument = document()->parentDocument();
- ASSERT(initiatorDocument);
- const InitiatorInfo& info = initiatorIt->value;
- initiatorDocument->domWindow()->performance()->addResourceTiming(info.name, initiatorDocument, resource->resourceRequest(), resource->response(), info.startTime, resource->loadFinishTime());
- m_initiatorMap.remove(initiatorIt);
- }
- }
-#else
- UNUSED_PARAM(resource);
-#endif // ENABLE(RESOURCE_TIMING)
-
if (frame())
frame()->loader().loadDone();
@@ -762,111 +1163,65 @@ void CachedResourceLoader::loadDone(CachedResource* resource, bool shouldPerform
// bookkeeping on CachedResources, so instead pseudo-GC them -- when the
// reference count reaches 1, m_documentResources is the only reference, so
// remove it from the map.
-void CachedResourceLoader::garbageCollectDocumentResourcesTimerFired(Timer<CachedResourceLoader>& timer)
-{
- ASSERT_UNUSED(timer, &timer == &m_garbageCollectDocumentResourcesTimer);
- garbageCollectDocumentResources();
-}
-
void CachedResourceLoader::garbageCollectDocumentResources()
{
typedef Vector<String, 10> StringVector;
StringVector resourcesToDelete;
- for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
- if (it->value->hasOneHandle()) {
- resourcesToDelete.append(it->key);
- it->value->setOwningCachedResourceLoader(0);
+ for (auto& resource : m_documentResources) {
+ if (resource.value->hasOneHandle()) {
+ resourcesToDelete.append(resource.key);
+ resource.value->setOwningCachedResourceLoader(nullptr);
}
}
- for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
- m_documentResources.remove(*it);
+ for (auto& resource : resourcesToDelete)
+ m_documentResources.remove(resource);
}
void CachedResourceLoader::performPostLoadActions()
{
- checkForPendingPreloads();
-
- platformStrategies()->loaderStrategy()->resourceLoadScheduler()->servePendingRequests();
+ platformStrategies()->loaderStrategy()->servePendingRequests();
}
-void CachedResourceLoader::incrementRequestCount(const CachedResource* res)
+void CachedResourceLoader::incrementRequestCount(const CachedResource& resource)
{
- if (res->ignoreForRequestCount())
+ if (resource.ignoreForRequestCount())
return;
++m_requestCount;
}
-void CachedResourceLoader::decrementRequestCount(const CachedResource* res)
+void CachedResourceLoader::decrementRequestCount(const CachedResource& resource)
{
- if (res->ignoreForRequestCount())
+ if (resource.ignoreForRequestCount())
return;
--m_requestCount;
ASSERT(m_requestCount > -1);
}
-void CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest& request, const String& charset)
+CachedResourceHandle<CachedResource> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request)
{
- // We always preload resources on iOS. See <https://bugs.webkit.org/show_bug.cgi?id=91276>.
- // FIXME: We should consider adding a setting to toggle aggressive preloading behavior as opposed
- // to making this behavior specific to iOS.
-#if !PLATFORM(IOS)
- bool hasRendering = m_document->body() && m_document->renderView();
- bool canBlockParser = type == CachedResource::Script || type == CachedResource::CSSStyleSheet;
- if (!hasRendering && !canBlockParser) {
- // Don't preload subresources that can't block the parser before we have something to draw.
- // This helps prevent preloads from delaying first display when bandwidth is limited.
- PendingPreload pendingPreload = { type, request, charset };
- m_pendingPreloads.append(pendingPreload);
- return;
- }
-#endif
- requestPreload(type, request, charset);
-}
-
-void CachedResourceLoader::checkForPendingPreloads()
-{
- if (m_pendingPreloads.isEmpty() || !m_document->body() || !m_document->body()->renderer())
- return;
-#if PLATFORM(IOS)
- // We always preload resources on iOS. See <https://bugs.webkit.org/show_bug.cgi?id=91276>.
- // So, we should never have any pending preloads.
- // FIXME: We should look to avoid compiling this code entirely when building for iOS.
- ASSERT_NOT_REACHED();
-#endif
- while (!m_pendingPreloads.isEmpty()) {
- PendingPreload preload = m_pendingPreloads.takeFirst();
- // Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored).
- if (!cachedResource(preload.m_request.resourceRequest().url()))
- requestPreload(preload.m_type, preload.m_request, preload.m_charset);
- }
- m_pendingPreloads.clear();
-}
+ if (request.charset().isEmpty() && (type == CachedResource::Script || type == CachedResource::CSSStyleSheet))
+ request.setCharset(m_document->charset());
-void CachedResourceLoader::requestPreload(CachedResource::Type type, CachedResourceRequest& request, const String& charset)
-{
- String encoding;
- if (type == CachedResource::Script || type == CachedResource::CSSStyleSheet)
- encoding = charset.isEmpty() ? m_document->charset() : charset;
-
- request.setCharset(encoding);
- request.setForPreload(true);
-
- CachedResourceHandle<CachedResource> resource = requestResource(type, request);
+ CachedResourceHandle<CachedResource> resource = requestResource(type, WTFMove(request), ForPreload::Yes);
if (!resource || (m_preloads && m_preloads->contains(resource.get())))
- return;
+ return nullptr;
+ // Fonts need special treatment since just creating the resource doesn't trigger a load.
+ if (type == CachedResource::FontResource)
+ downcast<CachedFont>(resource.get())->beginLoadIfNeeded(*this);
resource->increasePreloadCount();
if (!m_preloads)
- m_preloads = adoptPtr(new ListHashSet<CachedResource*>);
+ m_preloads = std::make_unique<ListHashSet<CachedResource*>>();
m_preloads->add(resource.get());
#if PRELOAD_DEBUG
printf("PRELOADING %s\n", resource->url().latin1().data());
#endif
+ return resource;
}
bool CachedResourceLoader::isPreloaded(const String& urlString) const
@@ -874,24 +1229,15 @@ bool CachedResourceLoader::isPreloaded(const String& urlString) const
const URL& url = m_document->completeURL(urlString);
if (m_preloads) {
- ListHashSet<CachedResource*>::iterator end = m_preloads->end();
- for (ListHashSet<CachedResource*>::iterator it = m_preloads->begin(); it != end; ++it) {
- CachedResource* resource = *it;
+ for (auto& resource : *m_preloads) {
if (resource->url() == url)
return true;
}
}
-
- Deque<PendingPreload>::const_iterator dequeEnd = m_pendingPreloads.end();
- for (Deque<PendingPreload>::const_iterator it = m_pendingPreloads.begin(); it != dequeEnd; ++it) {
- PendingPreload pendingPreload = *it;
- if (pendingPreload.m_request.resourceRequest().url() == url)
- return true;
- }
return false;
}
-void CachedResourceLoader::clearPreloads()
+void CachedResourceLoader::clearPreloads(ClearPreloadsMode mode)
{
#if PRELOAD_DEBUG
printPreloadStats();
@@ -899,20 +1245,21 @@ void CachedResourceLoader::clearPreloads()
if (!m_preloads)
return;
- ListHashSet<CachedResource*>::iterator end = m_preloads->end();
- for (ListHashSet<CachedResource*>::iterator it = m_preloads->begin(); it != end; ++it) {
- CachedResource* res = *it;
- res->decreasePreloadCount();
- bool deleted = res->deleteIfPossible();
- if (!deleted && res->preloadResult() == CachedResource::PreloadNotReferenced)
- memoryCache()->remove(res);
+ std::unique_ptr<ListHashSet<CachedResource*>> remainingLinkPreloads;
+ for (auto* resource : *m_preloads) {
+ ASSERT(resource);
+ if (mode == ClearPreloadsMode::ClearSpeculativePreloads && resource->isLinkPreload()) {
+ if (!remainingLinkPreloads)
+ remainingLinkPreloads = std::make_unique<ListHashSet<CachedResource*>>();
+ remainingLinkPreloads->add(resource);
+ continue;
+ }
+ resource->decreasePreloadCount();
+ bool deleted = resource->deleteIfPossible();
+ if (!deleted && resource->preloadResult() == CachedResource::PreloadNotReferenced)
+ MemoryCache::singleton().remove(*resource);
}
- m_preloads.clear();
-}
-
-void CachedResourceLoader::clearPendingPreloads()
-{
- m_pendingPreloads.clear();
+ m_preloads = WTFMove(remainingLinkPreloads);
}
#if PRELOAD_DEBUG
@@ -924,37 +1271,35 @@ void CachedResourceLoader::printPreloadStats()
unsigned stylesheetMisses = 0;
unsigned images = 0;
unsigned imageMisses = 0;
- ListHashSet<CachedResource*>::iterator end = m_preloads.end();
- for (ListHashSet<CachedResource*>::iterator it = m_preloads.begin(); it != end; ++it) {
- CachedResource* res = *it;
- if (res->preloadResult() == CachedResource::PreloadNotReferenced)
- printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data());
- else if (res->preloadResult() == CachedResource::PreloadReferencedWhileComplete)
- printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data());
- else if (res->preloadResult() == CachedResource::PreloadReferencedWhileLoading)
- printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data());
-
- if (res->type() == CachedResource::Script) {
+ for (auto& resource : m_preloads) {
+ if (resource->preloadResult() == CachedResource::PreloadNotReferenced)
+ printf("!! UNREFERENCED PRELOAD %s\n", resource->url().latin1().data());
+ else if (resource->preloadResult() == CachedResource::PreloadReferencedWhileComplete)
+ printf("HIT COMPLETE PRELOAD %s\n", resource->url().latin1().data());
+ else if (resource->preloadResult() == CachedResource::PreloadReferencedWhileLoading)
+ printf("HIT LOADING PRELOAD %s\n", resource->url().latin1().data());
+
+ if (resource->type() == CachedResource::Script) {
scripts++;
- if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
+ if (resource->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
scriptMisses++;
- } else if (res->type() == CachedResource::CSSStyleSheet) {
+ } else if (resource->type() == CachedResource::CSSStyleSheet) {
stylesheets++;
- if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
+ if (resource->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
stylesheetMisses++;
} else {
images++;
- if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
+ if (resource->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
imageMisses++;
}
-
- if (res->errorOccurred())
- memoryCache()->remove(res);
-
- res->decreasePreloadCount();
+
+ if (resource->errorOccurred() && resource->preloadResult() == CachedResource::PreloadNotReferenced)
+ MemoryCache::singleton().remove(resource);
+
+ resource->decreasePreloadCount();
}
- m_preloads.clear();
-
+ m_preloads = nullptr;
+
if (scripts)
printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
if (stylesheets)
@@ -966,8 +1311,13 @@ void CachedResourceLoader::printPreloadStats()
const ResourceLoaderOptions& CachedResourceLoader::defaultCachedResourceOptions()
{
- static ResourceLoaderOptions options(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForAllCredentials, DoSecurityCheck, UseDefaultOriginRestrictionsForType);
+ static NeverDestroyed<ResourceLoaderOptions> options(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientCredentialPolicy::MayAskClientForCredentials, FetchOptions::Credentials::Include, DoSecurityCheck, FetchOptions::Mode::NoCors, DoNotIncludeCertificateInfo, ContentSecurityPolicyImposition::DoPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching);
return options;
}
+bool CachedResourceLoader::isAlwaysOnLoggingAllowed() const
+{
+ return m_documentLoader ? m_documentLoader->isAlwaysOnLoggingAllowed() : true;
+}
+
}