summaryrefslogtreecommitdiff
path: root/Source/WebCore/loader
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/loader')
-rw-r--r--Source/WebCore/loader/ContentFilter.cpp301
-rw-r--r--Source/WebCore/loader/ContentFilter.h102
-rw-r--r--Source/WebCore/loader/CookieJar.cpp53
-rw-r--r--Source/WebCore/loader/CookieJar.h27
-rw-r--r--Source/WebCore/loader/CrossOriginAccessControl.cpp136
-rw-r--r--Source/WebCore/loader/CrossOriginAccessControl.h26
-rw-r--r--Source/WebCore/loader/CrossOriginPreflightChecker.cpp167
-rw-r--r--Source/WebCore/loader/CrossOriginPreflightChecker.h (renamed from Source/WebCore/loader/DocumentThreadableLoaderClient.h)45
-rw-r--r--Source/WebCore/loader/CrossOriginPreflightResultCache.cpp64
-rw-r--r--Source/WebCore/loader/CrossOriginPreflightResultCache.h82
-rw-r--r--Source/WebCore/loader/DocumentLoadTiming.h90
-rw-r--r--Source/WebCore/loader/DocumentLoader.cpp1121
-rw-r--r--Source/WebCore/loader/DocumentLoader.h797
-rw-r--r--Source/WebCore/loader/DocumentThreadableLoader.cpp571
-rw-r--r--Source/WebCore/loader/DocumentThreadableLoader.h101
-rw-r--r--Source/WebCore/loader/DocumentWriter.cpp68
-rw-r--r--Source/WebCore/loader/DocumentWriter.h11
-rw-r--r--Source/WebCore/loader/EmptyClients.cpp682
-rw-r--r--Source/WebCore/loader/EmptyClients.h667
-rw-r--r--Source/WebCore/loader/FTPDirectoryParser.cpp6
-rw-r--r--Source/WebCore/loader/FTPDirectoryParser.h9
-rw-r--r--Source/WebCore/loader/FetchOptions.h56
-rw-r--r--Source/WebCore/loader/FormState.cpp12
-rw-r--r--Source/WebCore/loader/FormState.h51
-rw-r--r--Source/WebCore/loader/FormSubmission.cpp144
-rw-r--r--Source/WebCore/loader/FormSubmission.h56
-rw-r--r--Source/WebCore/loader/FrameLoadRequest.cpp12
-rw-r--r--Source/WebCore/loader/FrameLoadRequest.h114
-rw-r--r--Source/WebCore/loader/FrameLoader.cpp1942
-rw-r--r--Source/WebCore/loader/FrameLoader.h188
-rw-r--r--Source/WebCore/loader/FrameLoaderClient.h519
-rw-r--r--Source/WebCore/loader/FrameLoaderStateMachine.h12
-rw-r--r--Source/WebCore/loader/FrameLoaderTypes.h195
-rw-r--r--Source/WebCore/loader/FrameNetworkingContext.h13
-rw-r--r--Source/WebCore/loader/HistoryController.cpp400
-rw-r--r--Source/WebCore/loader/HistoryController.h41
-rw-r--r--Source/WebCore/loader/ImageLoader.cpp199
-rw-r--r--Source/WebCore/loader/ImageLoader.h25
-rw-r--r--Source/WebCore/loader/LinkHeader.cpp365
-rw-r--r--Source/WebCore/loader/LinkHeader.h87
-rw-r--r--Source/WebCore/loader/LinkLoader.cpp202
-rw-r--r--Source/WebCore/loader/LinkLoader.h40
-rw-r--r--Source/WebCore/loader/LinkLoaderClient.h8
-rw-r--r--Source/WebCore/loader/LinkPreloadResourceClients.cpp46
-rw-r--r--Source/WebCore/loader/LinkPreloadResourceClients.h193
-rw-r--r--Source/WebCore/loader/LoadTiming.cpp (renamed from Source/WebCore/loader/DocumentLoadTiming.cpp)81
-rw-r--r--Source/WebCore/loader/LoadTiming.h92
-rw-r--r--Source/WebCore/loader/LoaderStrategy.cpp22
-rw-r--r--Source/WebCore/loader/LoaderStrategy.h43
-rw-r--r--Source/WebCore/loader/MediaResourceLoader.cpp213
-rw-r--r--Source/WebCore/loader/MediaResourceLoader.h93
-rw-r--r--Source/WebCore/loader/MixedContentChecker.cpp67
-rw-r--r--Source/WebCore/loader/MixedContentChecker.h23
-rw-r--r--Source/WebCore/loader/NavigationAction.cpp86
-rw-r--r--Source/WebCore/loader/NavigationAction.h65
-rw-r--r--Source/WebCore/loader/NavigationScheduler.cpp261
-rw-r--r--Source/WebCore/loader/NavigationScheduler.h41
-rw-r--r--Source/WebCore/loader/NetscapePlugInStreamLoader.cpp93
-rw-r--r--Source/WebCore/loader/NetscapePlugInStreamLoader.h40
-rw-r--r--Source/WebCore/loader/PingLoader.cpp155
-rw-r--r--Source/WebCore/loader/PingLoader.h53
-rw-r--r--Source/WebCore/loader/PolicyCallback.cpp20
-rw-r--r--Source/WebCore/loader/PolicyCallback.h20
-rw-r--r--Source/WebCore/loader/PolicyChecker.cpp87
-rw-r--r--Source/WebCore/loader/PolicyChecker.h32
-rw-r--r--Source/WebCore/loader/ProgressTracker.cpp39
-rw-r--r--Source/WebCore/loader/ProgressTracker.h25
-rw-r--r--Source/WebCore/loader/ProgressTrackerClient.h5
-rw-r--r--Source/WebCore/loader/ResourceBuffer.cpp149
-rw-r--r--Source/WebCore/loader/ResourceBuffer.h105
-rw-r--r--Source/WebCore/loader/ResourceLoadInfo.cpp123
-rw-r--r--Source/WebCore/loader/ResourceLoadInfo.h78
-rw-r--r--Source/WebCore/loader/ResourceLoadNotifier.cpp40
-rw-r--r--Source/WebCore/loader/ResourceLoadNotifier.h11
-rw-r--r--Source/WebCore/loader/ResourceLoadObserver.cpp415
-rw-r--r--Source/WebCore/loader/ResourceLoadObserver.h79
-rw-r--r--Source/WebCore/loader/ResourceLoadScheduler.cpp378
-rw-r--r--Source/WebCore/loader/ResourceLoadScheduler.h132
-rw-r--r--Source/WebCore/loader/ResourceLoadStatistics.cpp358
-rw-r--r--Source/WebCore/loader/ResourceLoadStatistics.h92
-rw-r--r--Source/WebCore/loader/ResourceLoadStatisticsStore.cpp196
-rw-r--r--Source/WebCore/loader/ResourceLoadStatisticsStore.h76
-rw-r--r--Source/WebCore/loader/ResourceLoader.cpp424
-rw-r--r--Source/WebCore/loader/ResourceLoader.h184
-rw-r--r--Source/WebCore/loader/ResourceLoaderOptions.h99
-rw-r--r--Source/WebCore/loader/ResourceLoaderTypes.h5
-rw-r--r--Source/WebCore/loader/ResourceTiming.cpp104
-rw-r--r--Source/WebCore/loader/ResourceTiming.h75
-rw-r--r--Source/WebCore/loader/ResourceTimingInformation.cpp110
-rw-r--r--Source/WebCore/loader/ResourceTimingInformation.h59
-rw-r--r--Source/WebCore/loader/SinkDocument.cpp14
-rw-r--r--Source/WebCore/loader/SinkDocument.h18
-rw-r--r--Source/WebCore/loader/SubframeLoader.cpp255
-rw-r--r--Source/WebCore/loader/SubframeLoader.h34
-rw-r--r--Source/WebCore/loader/SubresourceLoader.cpp416
-rw-r--r--Source/WebCore/loader/SubresourceLoader.h97
-rw-r--r--Source/WebCore/loader/SubstituteData.h50
-rw-r--r--Source/WebCore/loader/SubstituteResource.h26
-rw-r--r--Source/WebCore/loader/TextResourceDecoder.cpp27
-rw-r--r--Source/WebCore/loader/TextResourceDecoder.h25
-rw-r--r--Source/WebCore/loader/TextTrackLoader.cpp122
-rw-r--r--Source/WebCore/loader/TextTrackLoader.h52
-rw-r--r--Source/WebCore/loader/ThreadableLoader.cpp68
-rw-r--r--Source/WebCore/loader/ThreadableLoader.h50
-rw-r--r--Source/WebCore/loader/ThreadableLoaderClient.h13
-rw-r--r--Source/WebCore/loader/ThreadableLoaderClientWrapper.h44
-rw-r--r--Source/WebCore/loader/WorkerThreadableLoader.cpp221
-rw-r--r--Source/WebCore/loader/WorkerThreadableLoader.h61
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCache.cpp122
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCache.h64
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp32
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp628
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheGroup.h100
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheHost.cpp315
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheHost.h291
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheResource.cpp12
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheResource.h15
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp517
-rw-r--r--Source/WebCore/loader/appcache/ApplicationCacheStorage.h88
-rw-r--r--Source/WebCore/loader/appcache/DOMApplicationCache.cpp104
-rw-r--r--Source/WebCore/loader/appcache/DOMApplicationCache.h61
-rw-r--r--Source/WebCore/loader/appcache/DOMApplicationCache.idl35
-rw-r--r--Source/WebCore/loader/appcache/ManifestParser.cpp34
-rw-r--r--Source/WebCore/loader/appcache/ManifestParser.h24
-rw-r--r--Source/WebCore/loader/archive/Archive.cpp20
-rw-r--r--Source/WebCore/loader/archive/Archive.h44
-rw-r--r--Source/WebCore/loader/archive/ArchiveFactory.cpp54
-rw-r--r--Source/WebCore/loader/archive/ArchiveFactory.h12
-rw-r--r--Source/WebCore/loader/archive/ArchiveResource.cpp20
-rw-r--r--Source/WebCore/loader/archive/ArchiveResource.h15
-rw-r--r--Source/WebCore/loader/archive/ArchiveResourceCollection.cpp63
-rw-r--r--Source/WebCore/loader/archive/ArchiveResourceCollection.h38
-rw-r--r--Source/WebCore/loader/archive/mhtml/MHTMLArchive.cpp94
-rw-r--r--Source/WebCore/loader/archive/mhtml/MHTMLArchive.h28
-rw-r--r--Source/WebCore/loader/archive/mhtml/MHTMLParser.cpp78
-rw-r--r--Source/WebCore/loader/archive/mhtml/MHTMLParser.h16
-rw-r--r--Source/WebCore/loader/cache/CachePolicy.h26
-rw-r--r--Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp101
-rw-r--r--Source/WebCore/loader/cache/CachedCSSStyleSheet.h68
-rw-r--r--Source/WebCore/loader/cache/CachedFont.cpp155
-rw-r--r--Source/WebCore/loader/cache/CachedFont.h60
-rw-r--r--Source/WebCore/loader/cache/CachedFontClient.h9
-rw-r--r--Source/WebCore/loader/cache/CachedImage.cpp432
-rw-r--r--Source/WebCore/loader/cache/CachedImage.h155
-rw-r--r--Source/WebCore/loader/cache/CachedImageClient.h22
-rw-r--r--Source/WebCore/loader/cache/CachedRawResource.cpp164
-rw-r--r--Source/WebCore/loader/cache/CachedRawResource.h52
-rw-r--r--Source/WebCore/loader/cache/CachedRawResourceClient.h22
-rw-r--r--Source/WebCore/loader/cache/CachedResource.cpp824
-rw-r--r--Source/WebCore/loader/cache/CachedResource.h286
-rw-r--r--Source/WebCore/loader/cache/CachedResourceClient.h20
-rw-r--r--Source/WebCore/loader/cache/CachedResourceClientWalker.h9
-rw-r--r--Source/WebCore/loader/cache/CachedResourceHandle.cpp2
-rw-r--r--Source/WebCore/loader/cache/CachedResourceHandle.h9
-rw-r--r--Source/WebCore/loader/cache/CachedResourceLoader.cpp1162
-rw-r--r--Source/WebCore/loader/cache/CachedResourceLoader.h145
-rw-r--r--Source/WebCore/loader/cache/CachedResourceRequest.cpp247
-rw-r--r--Source/WebCore/loader/cache/CachedResourceRequest.h72
-rw-r--r--Source/WebCore/loader/cache/CachedResourceRequestInitiators.cpp3
-rw-r--r--Source/WebCore/loader/cache/CachedResourceRequestInitiators.h11
-rw-r--r--Source/WebCore/loader/cache/CachedSVGDocument.cpp24
-rw-r--r--Source/WebCore/loader/cache/CachedSVGDocument.h24
-rw-r--r--Source/WebCore/loader/cache/CachedSVGDocumentClient.h13
-rw-r--r--Source/WebCore/loader/cache/CachedSVGDocumentReference.cpp18
-rw-r--r--Source/WebCore/loader/cache/CachedSVGDocumentReference.h13
-rw-r--r--Source/WebCore/loader/cache/CachedSVGFont.cpp142
-rw-r--r--Source/WebCore/loader/cache/CachedSVGFont.h61
-rw-r--r--Source/WebCore/loader/cache/CachedScript.cpp83
-rw-r--r--Source/WebCore/loader/cache/CachedScript.h55
-rw-r--r--Source/WebCore/loader/cache/CachedStyleSheetClient.h7
-rw-r--r--Source/WebCore/loader/cache/CachedTextTrack.cpp30
-rw-r--r--Source/WebCore/loader/cache/CachedTextTrack.h23
-rw-r--r--Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp32
-rw-r--r--Source/WebCore/loader/cache/CachedXSLStyleSheet.h50
-rw-r--r--Source/WebCore/loader/cache/MemoryCache.cpp922
-rw-r--r--Source/WebCore/loader/cache/MemoryCache.h209
-rw-r--r--Source/WebCore/loader/icon/IconController.cpp170
-rw-r--r--Source/WebCore/loader/icon/IconController.h21
-rw-r--r--Source/WebCore/loader/icon/IconDatabase.cpp559
-rw-r--r--Source/WebCore/loader/icon/IconDatabase.h187
-rw-r--r--Source/WebCore/loader/icon/IconDatabaseBase.cpp8
-rw-r--r--Source/WebCore/loader/icon/IconDatabaseBase.h76
-rw-r--r--Source/WebCore/loader/icon/IconDatabaseClient.h8
-rw-r--r--Source/WebCore/loader/icon/IconLoader.cpp84
-rw-r--r--Source/WebCore/loader/icon/IconLoader.h21
-rw-r--r--Source/WebCore/loader/icon/IconRecord.cpp8
-rw-r--r--Source/WebCore/loader/icon/IconRecord.h15
-rw-r--r--Source/WebCore/loader/icon/PageURLRecord.cpp16
-rw-r--r--Source/WebCore/loader/icon/PageURLRecord.h16
-rw-r--r--Source/WebCore/loader/soup/CachedRawResourceSoup.cpp9
-rw-r--r--Source/WebCore/loader/soup/SubresourceLoaderSoup.cpp5
191 files changed, 15445 insertions, 11031 deletions
diff --git a/Source/WebCore/loader/ContentFilter.cpp b/Source/WebCore/loader/ContentFilter.cpp
new file mode 100644
index 000000000..6f2e50376
--- /dev/null
+++ b/Source/WebCore/loader/ContentFilter.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ContentFilter.h"
+
+#if ENABLE(CONTENT_FILTERING)
+
+#include "CachedRawResource.h"
+#include "ContentFilterUnblockHandler.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "Logging.h"
+#include "NetworkExtensionContentFilter.h"
+#include "ParentalControlsContentFilter.h"
+#include "ScriptController.h"
+#include "SharedBuffer.h"
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Ref.h>
+#include <wtf/SetForScope.h>
+#include <wtf/Vector.h>
+
+#if !LOG_DISABLED
+#include <wtf/text/CString.h>
+#endif
+
+namespace WebCore {
+
+Vector<ContentFilter::Type>& ContentFilter::types()
+{
+ static NeverDestroyed<Vector<ContentFilter::Type>> types {
+ Vector<ContentFilter::Type> {
+#if HAVE(PARENTAL_CONTROLS)
+ type<ParentalControlsContentFilter>(),
+#endif
+#if HAVE(NETWORK_EXTENSION)
+ type<NetworkExtensionContentFilter>()
+#endif
+ }
+ };
+ return types;
+}
+
+std::unique_ptr<ContentFilter> ContentFilter::create(DocumentLoader& documentLoader)
+{
+ Container filters;
+ for (auto& type : types()) {
+ auto filter = type.create();
+ ASSERT(filter);
+ filters.append(WTFMove(filter));
+ }
+
+ if (filters.isEmpty())
+ return nullptr;
+
+ return std::make_unique<ContentFilter>(WTFMove(filters), documentLoader);
+}
+
+ContentFilter::ContentFilter(Container contentFilters, DocumentLoader& documentLoader)
+ : m_contentFilters { WTFMove(contentFilters) }
+ , m_documentLoader { documentLoader }
+{
+ LOG(ContentFiltering, "Creating ContentFilter with %zu platform content filter(s).\n", m_contentFilters.size());
+ ASSERT(!m_contentFilters.isEmpty());
+}
+
+ContentFilter::~ContentFilter()
+{
+ LOG(ContentFiltering, "Destroying ContentFilter.\n");
+}
+
+bool ContentFilter::continueAfterWillSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ Ref<DocumentLoader> protectedDocumentLoader { m_documentLoader };
+
+ LOG(ContentFiltering, "ContentFilter received request for <%s> with redirect response from <%s>.\n", request.url().string().ascii().data(), redirectResponse.url().string().ascii().data());
+#if !LOG_DISABLED
+ ResourceRequest originalRequest { request };
+#endif
+ ASSERT(m_state == State::Stopped || m_state == State::Filtering);
+ forEachContentFilterUntilBlocked([&request, &redirectResponse](PlatformContentFilter& contentFilter) {
+ contentFilter.willSendRequest(request, redirectResponse);
+ });
+ if (m_state == State::Blocked)
+ request = ResourceRequest();
+#if !LOG_DISABLED
+ if (request != originalRequest)
+ LOG(ContentFiltering, "ContentFilter changed request url to <%s>.\n", originalRequest.url().string().ascii().data());
+#endif
+ return !request.isNull();
+}
+
+void ContentFilter::startFilteringMainResource(CachedRawResource& resource)
+{
+ if (m_state != State::Stopped)
+ return;
+
+ LOG(ContentFiltering, "ContentFilter will start filtering main resource at <%s>.\n", resource.url().string().ascii().data());
+ m_state = State::Filtering;
+ ASSERT(!m_mainResource);
+ m_mainResource = &resource;
+}
+
+void ContentFilter::stopFilteringMainResource()
+{
+ if (m_state != State::Blocked)
+ m_state = State::Stopped;
+ m_mainResource = nullptr;
+}
+
+bool ContentFilter::continueAfterResponseReceived(const ResourceResponse& response)
+{
+ Ref<DocumentLoader> protectedDocumentLoader { m_documentLoader };
+
+ if (m_state == State::Filtering) {
+ LOG(ContentFiltering, "ContentFilter received response from <%s>.\n", response.url().string().ascii().data());
+ forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) {
+ contentFilter.responseReceived(response);
+ });
+ }
+
+ return m_state != State::Blocked;
+}
+
+bool ContentFilter::continueAfterDataReceived(const char* data, int length)
+{
+ Ref<DocumentLoader> protectedDocumentLoader { m_documentLoader };
+
+ if (m_state == State::Filtering) {
+ LOG(ContentFiltering, "ContentFilter received %d bytes of data from <%s>.\n", length, m_mainResource->url().string().ascii().data());
+ forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) {
+ contentFilter.addData(data, length);
+ });
+
+ if (m_state == State::Allowed)
+ deliverResourceData(*m_mainResource);
+ return false;
+ }
+
+ return m_state != State::Blocked;
+}
+
+bool ContentFilter::continueAfterNotifyFinished(CachedResource& resource)
+{
+ ASSERT_UNUSED(resource, &resource == m_mainResource);
+ Ref<DocumentLoader> protectedDocumentLoader { m_documentLoader };
+
+ if (m_mainResource->errorOccurred())
+ return true;
+
+ if (m_state == State::Filtering) {
+ LOG(ContentFiltering, "ContentFilter will finish filtering main resource at <%s>.\n", m_mainResource->url().string().ascii().data());
+ forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) {
+ contentFilter.finishedAddingData();
+ });
+
+ if (m_state != State::Blocked) {
+ m_state = State::Allowed;
+ deliverResourceData(*m_mainResource);
+ }
+
+ if (m_state == State::Stopped)
+ return false;
+ }
+
+ return m_state != State::Blocked;
+}
+
+template <typename Function>
+inline void ContentFilter::forEachContentFilterUntilBlocked(Function&& function)
+{
+ bool allFiltersAllowedLoad { true };
+ for (auto& contentFilter : m_contentFilters) {
+ if (!contentFilter->needsMoreData()) {
+ ASSERT(!contentFilter->didBlockData());
+ continue;
+ }
+
+ function(*contentFilter);
+
+ if (contentFilter->didBlockData()) {
+ ASSERT(!m_blockingContentFilter);
+ m_blockingContentFilter = contentFilter.get();
+ didDecide(State::Blocked);
+ return;
+ } else if (contentFilter->needsMoreData())
+ allFiltersAllowedLoad = false;
+ }
+
+ if (allFiltersAllowedLoad)
+ didDecide(State::Allowed);
+}
+
+void ContentFilter::didDecide(State state)
+{
+ ASSERT(m_state != State::Allowed);
+ ASSERT(m_state != State::Blocked);
+ ASSERT(state == State::Allowed || state == State::Blocked);
+ LOG(ContentFiltering, "ContentFilter decided load should be %s for main resource at <%s>.\n", state == State::Allowed ? "allowed" : "blocked", m_mainResource ? m_mainResource->url().string().ascii().data() : "");
+ m_state = state;
+ if (m_state != State::Blocked)
+ return;
+
+ ContentFilterUnblockHandler unblockHandler { m_blockingContentFilter->unblockHandler() };
+ unblockHandler.setUnreachableURL(m_documentLoader.documentURL());
+ RefPtr<Frame> frame { m_documentLoader.frame() };
+ String unblockRequestDeniedScript { m_blockingContentFilter->unblockRequestDeniedScript() };
+ if (!unblockRequestDeniedScript.isEmpty() && frame) {
+ static_assert(std::is_base_of<ThreadSafeRefCounted<Frame>, Frame>::value, "Frame must be ThreadSafeRefCounted.");
+ unblockHandler.wrapWithDecisionHandler([frame = WTFMove(frame), script = unblockRequestDeniedScript.isolatedCopy()](bool unblocked) {
+ if (!unblocked)
+ frame->script().executeScript(script);
+ });
+ }
+ m_documentLoader.frameLoader()->client().contentFilterDidBlockLoad(WTFMove(unblockHandler));
+
+ m_blockedError = m_documentLoader.frameLoader()->blockedByContentFilterError(m_documentLoader.request());
+ m_documentLoader.cancelMainResourceLoad(m_blockedError);
+}
+
+void ContentFilter::deliverResourceData(CachedResource& resource)
+{
+ ASSERT(m_state == State::Allowed);
+ ASSERT(resource.dataBufferingPolicy() == BufferData);
+ if (auto* resourceBuffer = resource.resourceBuffer())
+ m_documentLoader.dataReceived(resource, resourceBuffer->data(), resourceBuffer->size());
+}
+
+static const URL& blockedPageURL()
+{
+ static LazyNeverDestroyed<URL> blockedPageURL;
+ static std::once_flag onceFlag;
+ std::call_once(onceFlag, [] {
+ auto webCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebCore"));
+ auto blockedPageCFURL = adoptCF(CFBundleCopyResourceURL(webCoreBundle, CFSTR("ContentFilterBlockedPage"), CFSTR("html"), nullptr));
+ blockedPageURL.construct(blockedPageCFURL.get());
+ });
+
+ return blockedPageURL;
+}
+
+bool ContentFilter::continueAfterSubstituteDataRequest(const DocumentLoader& activeLoader, const SubstituteData& substituteData)
+{
+ if (auto contentFilter = activeLoader.contentFilter()) {
+ if (contentFilter->m_state == State::Blocked && !contentFilter->m_isLoadingBlockedPage)
+ return contentFilter->m_blockedError.failingURL() != substituteData.failingURL();
+ }
+
+ if (activeLoader.request().url() == blockedPageURL()) {
+ ASSERT(activeLoader.substituteData().isValid());
+ return activeLoader.substituteData().failingURL() != substituteData.failingURL();
+ }
+
+ return true;
+}
+
+void ContentFilter::handleProvisionalLoadFailure(const ResourceError& error)
+{
+ if (m_state != State::Blocked)
+ return;
+
+ if (m_blockedError.errorCode() != error.errorCode() || m_blockedError.domain() != error.domain())
+ return;
+
+ ASSERT(m_blockedError.failingURL() == error.failingURL());
+
+ RefPtr<SharedBuffer> replacementData { m_blockingContentFilter->replacementData() };
+ ResourceResponse response { URL(), ASCIILiteral("text/html"), replacementData->size(), ASCIILiteral("UTF-8") };
+ SubstituteData substituteData { WTFMove(replacementData), error.failingURL(), response, SubstituteData::SessionHistoryVisibility::Hidden };
+ SetForScope<bool> loadingBlockedPage { m_isLoadingBlockedPage, true };
+ m_documentLoader.frameLoader()->load(FrameLoadRequest(m_documentLoader.frame(), blockedPageURL(), ShouldOpenExternalURLsPolicy::ShouldNotAllow, substituteData));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CONTENT_FILTERING)
diff --git a/Source/WebCore/loader/ContentFilter.h b/Source/WebCore/loader/ContentFilter.h
new file mode 100644
index 000000000..8b48166b5
--- /dev/null
+++ b/Source/WebCore/loader/ContentFilter.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(CONTENT_FILTERING)
+
+#include "CachedResourceHandle.h"
+#include "PlatformContentFilter.h"
+#include "ResourceError.h"
+#include <functional>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CachedRawResource;
+class DocumentLoader;
+class ResourceRequest;
+class ResourceResponse;
+class SubstituteData;
+
+class ContentFilter {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(ContentFilter);
+
+public:
+ template <typename T> static void addType() { types().append(type<T>()); }
+
+ static std::unique_ptr<ContentFilter> create(DocumentLoader&);
+ ~ContentFilter();
+
+ static const char* urlScheme() { return "x-apple-content-filter"; }
+
+ void startFilteringMainResource(CachedRawResource&);
+ void stopFilteringMainResource();
+
+ bool continueAfterWillSendRequest(ResourceRequest&, const ResourceResponse&);
+ bool continueAfterResponseReceived(const ResourceResponse&);
+ bool continueAfterDataReceived(const char* data, int length);
+ bool continueAfterNotifyFinished(CachedResource&);
+
+ static bool continueAfterSubstituteDataRequest(const DocumentLoader& activeLoader, const SubstituteData&);
+ void handleProvisionalLoadFailure(const ResourceError&);
+
+private:
+ using State = PlatformContentFilter::State;
+
+ struct Type {
+ const std::function<std::unique_ptr<PlatformContentFilter>()> create;
+ };
+ template <typename T> static Type type();
+ WEBCORE_EXPORT static Vector<Type>& types();
+
+ using Container = Vector<std::unique_ptr<PlatformContentFilter>>;
+ friend std::unique_ptr<ContentFilter> std::make_unique<ContentFilter>(Container&&, DocumentLoader&);
+ ContentFilter(Container, DocumentLoader&);
+
+ template <typename Function> void forEachContentFilterUntilBlocked(Function&&);
+ void didDecide(State);
+ void deliverResourceData(CachedResource&);
+
+ const Container m_contentFilters;
+ DocumentLoader& m_documentLoader;
+ CachedResourceHandle<CachedRawResource> m_mainResource;
+ PlatformContentFilter* m_blockingContentFilter { nullptr };
+ State m_state { State::Stopped };
+ ResourceError m_blockedError;
+ bool m_isLoadingBlockedPage { false };
+};
+
+template <typename T>
+ContentFilter::Type ContentFilter::type()
+{
+ static_assert(std::is_base_of<PlatformContentFilter, T>::value, "Type must be a PlatformContentFilter.");
+ return { T::create };
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CONTENT_FILTERING)
diff --git a/Source/WebCore/loader/CookieJar.cpp b/Source/WebCore/loader/CookieJar.cpp
index e93d1ca20..ef93dff5e 100644
--- a/Source/WebCore/loader/CookieJar.cpp
+++ b/Source/WebCore/loader/CookieJar.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,69 +30,62 @@
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "NetworkStorageSession.h"
#include "NetworkingContext.h"
#include "PlatformCookieJar.h"
#include "PlatformStrategies.h"
namespace WebCore {
-static NetworkingContext* networkingContext(const Document* document)
+static NetworkingContext* networkingContext(const Document& document)
{
// FIXME: Returning 0 means falling back to default context. That's not a choice that is appropriate to do at runtime
- if (!document)
- return 0;
- Frame* frame = document->frame();
+ Frame* frame = document.frame();
if (!frame)
- return 0;
+ return nullptr;
return frame->loader().networkingContext();
}
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(SOUP)
-inline NetworkStorageSession& storageSession(const Document* document)
+inline NetworkStorageSession& storageSession(const Document& document)
{
NetworkingContext* context = networkingContext(document);
return context ? context->storageSession() : NetworkStorageSession::defaultStorageSession();
}
-#define LOCAL_SESSION(document) NetworkStorageSession& session = storageSession(document);
-#else
-#define LOCAL_SESSION(document) NetworkStorageSession session(networkingContext(document));
-#endif
-String cookies(const Document* document, const URL& url)
+String cookies(const Document& document, const URL& url)
{
- LOCAL_SESSION(document)
- return platformStrategies()->cookiesStrategy()->cookiesForDOM(session, document->firstPartyForCookies(), url);
+ return platformStrategies()->cookiesStrategy()->cookiesForDOM(storageSession(document), document.firstPartyForCookies(), url);
}
-void setCookies(Document* document, const URL& url, const String& cookieString)
+void setCookies(Document& document, const URL& url, const String& cookieString)
{
- LOCAL_SESSION(document)
- platformStrategies()->cookiesStrategy()->setCookiesFromDOM(session, document->firstPartyForCookies(), url, cookieString);
+ platformStrategies()->cookiesStrategy()->setCookiesFromDOM(storageSession(document), document.firstPartyForCookies(), url, cookieString);
}
-bool cookiesEnabled(const Document* document)
+bool cookiesEnabled(const Document& document)
{
- LOCAL_SESSION(document)
- return platformStrategies()->cookiesStrategy()->cookiesEnabled(session, document->firstPartyForCookies(), document->cookieURL());
+ return platformStrategies()->cookiesStrategy()->cookiesEnabled(storageSession(document), document.firstPartyForCookies(), document.cookieURL());
}
-String cookieRequestHeaderFieldValue(const Document* document, const URL& url)
+String cookieRequestHeaderFieldValue(const Document& document, const URL& url)
{
- LOCAL_SESSION(document)
- return platformStrategies()->cookiesStrategy()->cookieRequestHeaderFieldValue(session, document->firstPartyForCookies(), url);
+ return platformStrategies()->cookiesStrategy()->cookieRequestHeaderFieldValue(storageSession(document), document.firstPartyForCookies(), url);
}
-bool getRawCookies(const Document* document, const URL& url, Vector<Cookie>& cookies)
+bool getRawCookies(const Document& document, const URL& url, Vector<Cookie>& cookies)
{
- LOCAL_SESSION(document)
- return platformStrategies()->cookiesStrategy()->getRawCookies(session, document->firstPartyForCookies(), url, cookies);
+ return platformStrategies()->cookiesStrategy()->getRawCookies(storageSession(document), document.firstPartyForCookies(), url, cookies);
}
-void deleteCookie(const Document* document, const URL& url, const String& cookieName)
+void deleteCookie(const Document& document, const URL& url, const String& cookieName)
{
- LOCAL_SESSION(document)
- platformStrategies()->cookiesStrategy()->deleteCookie(session, url, cookieName);
+ platformStrategies()->cookiesStrategy()->deleteCookie(storageSession(document), url, cookieName);
+}
+
+void addCookie(const Document& document, const URL& url, const Cookie& cookie)
+{
+ platformStrategies()->cookiesStrategy()->addCookie(storageSession(document), url, cookie);
}
}
diff --git a/Source/WebCore/loader/CookieJar.h b/Source/WebCore/loader/CookieJar.h
index a96ae45ac..0a53d9644 100644
--- a/Source/WebCore/loader/CookieJar.h
+++ b/Source/WebCore/loader/CookieJar.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 2008, 2012, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,11 +23,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CookieJar_h
-#define CookieJar_h
+#pragma once
#include <wtf/Forward.h>
-#include <wtf/HashSet.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
@@ -40,14 +38,13 @@ struct Cookie;
// Functions in this file take a Document pointer to determine which cookie storage to use. We should merge that into call sites, and use PlatformCookieJar directly.
// These two functions implement document.cookie API, with special rules for HttpOnly cookies.
-String cookies(const Document*, const URL&);
-void setCookies(Document*, const URL&, const String& cookieString);
+WEBCORE_EXPORT String cookies(const Document&, const URL&);
+WEBCORE_EXPORT void setCookies(Document&, const URL&, const String& cookieString);
-bool cookiesEnabled(const Document*);
-String cookieRequestHeaderFieldValue(const Document*, const URL&);
-bool getRawCookies(const Document*, const URL&, Vector<Cookie>&);
-void deleteCookie(const Document*, const URL&, const String& cookieName);
+WEBCORE_EXPORT bool cookiesEnabled(const Document&);
+WEBCORE_EXPORT String cookieRequestHeaderFieldValue(const Document&, const URL&);
+WEBCORE_EXPORT bool getRawCookies(const Document&, const URL&, Vector<Cookie>&);
+WEBCORE_EXPORT void deleteCookie(const Document&, const URL&, const String& cookieName);
+WEBCORE_EXPORT void addCookie(const Document&, const URL&, const Cookie&);
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/CrossOriginAccessControl.cpp b/Source/WebCore/loader/CrossOriginAccessControl.cpp
index 257b43ed8..36b55a12d 100644
--- a/Source/WebCore/loader/CrossOriginAccessControl.cpp
+++ b/Source/WebCore/loader/CrossOriginAccessControl.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -27,11 +27,14 @@
#include "config.h"
#include "CrossOriginAccessControl.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "SchemeRegistry.h"
#include "SecurityOrigin.h"
#include <mutex>
+#include <wtf/NeverDestroyed.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/StringBuilder.h>
@@ -42,34 +45,13 @@ bool isOnAccessControlSimpleRequestMethodWhitelist(const String& method)
return method == "GET" || method == "HEAD" || method == "POST";
}
-bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name, const String& value)
-{
- if (equalIgnoringCase(name, "accept")
- || equalIgnoringCase(name, "accept-language")
- || equalIgnoringCase(name, "content-language")
- || equalIgnoringCase(name, "origin")
- || equalIgnoringCase(name, "referer"))
- return true;
-
- // Preflight is required for MIME types that can not be sent via form submission.
- if (equalIgnoringCase(name, "content-type")) {
- String mimeType = extractMIMETypeFromMediaType(value);
- return equalIgnoringCase(mimeType, "application/x-www-form-urlencoded")
- || equalIgnoringCase(mimeType, "multipart/form-data")
- || equalIgnoringCase(mimeType, "text/plain");
- }
-
- return false;
-}
-
bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& headerMap)
{
if (!isOnAccessControlSimpleRequestMethodWhitelist(method))
return false;
- HTTPHeaderMap::const_iterator end = headerMap.end();
- for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) {
- if (!isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value))
+ for (const auto& header : headerMap) {
+ if (!header.keyAsHTTPHeaderName || !isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value))
return false;
}
@@ -79,82 +61,111 @@ bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&
bool isOnAccessControlResponseHeaderWhitelist(const String& name)
{
static std::once_flag onceFlag;
- static HTTPHeaderSet* allowedCrossOriginResponseHeaders;
+ static LazyNeverDestroyed<HTTPHeaderSet> allowedCrossOriginResponseHeaders;
std::call_once(onceFlag, []{
- allowedCrossOriginResponseHeaders = std::make_unique<HTTPHeaderSet, std::initializer_list<String>>({
+ allowedCrossOriginResponseHeaders.construct<std::initializer_list<String>>({
"cache-control",
"content-language",
"content-type",
"expires",
"last-modified",
"pragma"
- }).release();
+ });
});
- return allowedCrossOriginResponseHeaders->contains(name);
+ return allowedCrossOriginResponseHeaders.get().contains(name);
}
-void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin* securityOrigin, StoredCredentials allowCredentials)
+void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin& securityOrigin, StoredCredentials allowCredentials)
{
request.removeCredentials();
request.setAllowCookies(allowCredentials == AllowStoredCredentials);
- request.setHTTPOrigin(securityOrigin->toString());
+ request.setHTTPOrigin(securityOrigin.toString());
}
-ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, SecurityOrigin* securityOrigin)
+ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, SecurityOrigin& securityOrigin, const String& referrer)
{
ResourceRequest preflightRequest(request.url());
+ static const double platformDefaultTimeout = 0;
+ preflightRequest.setTimeoutInterval(platformDefaultTimeout);
updateRequestForAccessControl(preflightRequest, securityOrigin, DoNotAllowStoredCredentials);
preflightRequest.setHTTPMethod("OPTIONS");
- preflightRequest.setHTTPHeaderField("Access-Control-Request-Method", request.httpMethod());
+ preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestMethod, request.httpMethod());
preflightRequest.setPriority(request.priority());
+ if (!referrer.isNull())
+ preflightRequest.setHTTPReferrer(referrer);
const HTTPHeaderMap& requestHeaderFields = request.httpHeaderFields();
- if (requestHeaderFields.size() > 0) {
- StringBuilder headerBuffer;
- HTTPHeaderMap::const_iterator it = requestHeaderFields.begin();
- headerBuffer.append(it->key);
- ++it;
-
- HTTPHeaderMap::const_iterator end = requestHeaderFields.end();
- for (; it != end; ++it) {
- headerBuffer.append(',');
- headerBuffer.append(' ');
- headerBuffer.append(it->key);
+ if (!requestHeaderFields.isEmpty()) {
+ Vector<String> unsafeHeaders;
+ for (const auto& headerField : requestHeaderFields.commonHeaders()) {
+ if (!isCrossOriginSafeRequestHeader(headerField.key, headerField.value))
+ unsafeHeaders.append(httpHeaderNameString(headerField.key).toStringWithoutCopying().convertToASCIILowercase());
}
+ for (const auto& headerField : requestHeaderFields.uncommonHeaders())
+ unsafeHeaders.append(headerField.key.convertToASCIILowercase());
+
+ std::sort(unsafeHeaders.begin(), unsafeHeaders.end(), WTF::codePointCompareLessThan);
+
+ StringBuilder headerBuffer;
+
+ bool appendComma = false;
+ for (const auto& headerField : unsafeHeaders) {
+ if (appendComma)
+ headerBuffer.append(',');
+ else
+ appendComma = true;
- preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", headerBuffer.toString().lower());
+ headerBuffer.append(headerField);
+ }
+ if (!headerBuffer.isEmpty())
+ preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestHeaders, headerBuffer.toString());
}
return preflightRequest;
}
-bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription)
+bool isValidCrossOriginRedirectionURL(const URL& redirectURL)
+{
+ return SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(redirectURL.protocol().toStringWithoutCopying())
+ && redirectURL.user().isEmpty()
+ && redirectURL.pass().isEmpty();
+}
+
+void cleanRedirectedRequestForAccessControl(ResourceRequest& request)
+{
+ // Remove headers that may have been added by the network layer that cause access control to fail.
+ request.clearHTTPContentType();
+ request.clearHTTPReferrer();
+ request.clearHTTPOrigin();
+ request.clearHTTPUserAgent();
+ request.clearHTTPAccept();
+ request.clearHTTPAcceptEncoding();
+}
+
+bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin& securityOrigin, String& errorDescription)
{
// A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
// even with Access-Control-Allow-Credentials set to true.
- const String& accessControlOriginString = response.httpHeaderField("access-control-allow-origin");
+ const String& accessControlOriginString = response.httpHeaderField(HTTPHeaderName::AccessControlAllowOrigin);
if (accessControlOriginString == "*" && includeCredentials == DoNotAllowStoredCredentials)
return true;
- if (securityOrigin->isUnique()) {
- errorDescription = "Cannot make any requests from " + securityOrigin->toString() + ".";
- return false;
- }
-
- // FIXME: Access-Control-Allow-Origin can contain a list of origins.
- if (accessControlOriginString != securityOrigin->toString()) {
+ String securityOriginString = securityOrigin.toString();
+ if (accessControlOriginString != securityOriginString) {
if (accessControlOriginString == "*")
- errorDescription = "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.";
+ errorDescription = ASCIILiteral("Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.");
+ else if (accessControlOriginString.find(',') != notFound)
+ errorDescription = ASCIILiteral("Access-Control-Allow-Origin cannot contain more than one origin.");
else
- errorDescription = "Origin " + securityOrigin->toString() + " is not allowed by Access-Control-Allow-Origin.";
+ errorDescription = makeString("Origin ", securityOriginString, " is not allowed by Access-Control-Allow-Origin.");
return false;
}
if (includeCredentials == AllowStoredCredentials) {
- const String& accessControlCredentialsString = response.httpHeaderField("access-control-allow-credentials");
+ const String& accessControlCredentialsString = response.httpHeaderField(HTTPHeaderName::AccessControlAllowCredentials);
if (accessControlCredentialsString != "true") {
errorDescription = "Credentials flag is true, but Access-Control-Allow-Credentials is not \"true\".";
return false;
@@ -164,15 +175,4 @@ bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential
return true;
}
-void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet& headerSet)
-{
- Vector<String> headers;
- headerValue.split(',', false, headers);
- for (unsigned headerCount = 0; headerCount < headers.size(); headerCount++) {
- String strippedHeader = headers[headerCount].stripWhiteSpace();
- if (!strippedHeader.isEmpty())
- headerSet.add(strippedHeader);
- }
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/loader/CrossOriginAccessControl.h b/Source/WebCore/loader/CrossOriginAccessControl.h
index 0b2d272bd..8a710437d 100644
--- a/Source/WebCore/loader/CrossOriginAccessControl.h
+++ b/Source/WebCore/loader/CrossOriginAccessControl.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,34 +24,30 @@
*
*/
-#ifndef CrossOriginAccessControl_h
-#define CrossOriginAccessControl_h
+#pragma once
#include "ResourceHandleTypes.h"
#include <wtf/Forward.h>
-#include <wtf/HashSet.h>
-#include <wtf/text/StringHash.h>
namespace WebCore {
-typedef HashSet<String, CaseFoldingHash> HTTPHeaderSet;
-
class HTTPHeaderMap;
+enum class HTTPHeaderName;
class ResourceRequest;
class ResourceResponse;
class SecurityOrigin;
+class URL;
bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&);
bool isOnAccessControlSimpleRequestMethodWhitelist(const String&);
-bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name, const String& value);
bool isOnAccessControlResponseHeaderWhitelist(const String&);
-void updateRequestForAccessControl(ResourceRequest&, SecurityOrigin*, StoredCredentials);
-ResourceRequest createAccessControlPreflightRequest(const ResourceRequest&, SecurityOrigin*);
+void updateRequestForAccessControl(ResourceRequest&, SecurityOrigin&, StoredCredentials);
+ResourceRequest createAccessControlPreflightRequest(const ResourceRequest&, SecurityOrigin&, const String&);
-bool passesAccessControlCheck(const ResourceResponse&, StoredCredentials, SecurityOrigin*, String& errorDescription);
-void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet&);
+bool isValidCrossOriginRedirectionURL(const URL&);
+void cleanRedirectedRequestForAccessControl(ResourceRequest&);
-} // namespace WebCore
+bool passesAccessControlCheck(const ResourceResponse&, StoredCredentials, SecurityOrigin&, String& errorDescription);
-#endif // CrossOriginAccessControl_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/CrossOriginPreflightChecker.cpp b/Source/WebCore/loader/CrossOriginPreflightChecker.cpp
new file mode 100644
index 000000000..9886c5180
--- /dev/null
+++ b/Source/WebCore/loader/CrossOriginPreflightChecker.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 Canon Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Canon Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CrossOriginPreflightChecker.h"
+
+#include "CachedRawResource.h"
+#include "CachedResourceLoader.h"
+#include "CachedResourceRequest.h"
+#include "ContentSecurityPolicy.h"
+#include "CrossOriginAccessControl.h"
+#include "CrossOriginPreflightResultCache.h"
+#include "DocumentThreadableLoader.h"
+#include "InspectorInstrumentation.h"
+#include "RuntimeEnabledFeatures.h"
+
+namespace WebCore {
+
+CrossOriginPreflightChecker::CrossOriginPreflightChecker(DocumentThreadableLoader& loader, ResourceRequest&& request)
+ : m_loader(loader)
+ , m_request(WTFMove(request))
+{
+}
+
+CrossOriginPreflightChecker::~CrossOriginPreflightChecker()
+{
+ if (m_resource)
+ m_resource->removeClient(*this);
+}
+
+void CrossOriginPreflightChecker::validatePreflightResponse(DocumentThreadableLoader& loader, ResourceRequest&& request, unsigned long identifier, const ResourceResponse& response)
+{
+ Frame* frame = loader.document().frame();
+ ASSERT(frame);
+
+ if (!response.isSuccessful()) {
+ loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), ASCIILiteral("Preflight response is not successful"), ResourceError::Type::AccessControl));
+ return;
+ }
+
+ String description;
+ if (!passesAccessControlCheck(response, loader.options().allowCredentials, loader.securityOrigin(), description)) {
+ loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), description, ResourceError::Type::AccessControl));
+ return;
+ }
+
+ auto result = std::make_unique<CrossOriginPreflightResultCacheItem>(loader.options().allowCredentials);
+ if (!result->parse(response, description)
+ || !result->allowsCrossOriginMethod(request.httpMethod(), description)
+ || !result->allowsCrossOriginHeaders(request.httpHeaderFields(), description)) {
+ loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), description, ResourceError::Type::AccessControl));
+ return;
+ }
+
+ // FIXME: <https://webkit.org/b/164889> Web Inspector: Show Preflight Request information in inspector
+ // This is only showing success preflight requests and responses but we should show network events
+ // for preflight failures and distinguish them better from non-preflight requests.
+ InspectorInstrumentation::didReceiveResourceResponse(*frame, identifier, frame->loader().documentLoader(), response, nullptr);
+ InspectorInstrumentation::didFinishLoading(frame, frame->loader().documentLoader(), identifier, 0);
+
+ CrossOriginPreflightResultCache::singleton().appendEntry(loader.securityOrigin().toString(), request.url(), WTFMove(result));
+ loader.preflightSuccess(WTFMove(request));
+}
+
+void CrossOriginPreflightChecker::notifyFinished(CachedResource& resource)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+ if (m_resource->loadFailedOrCanceled()) {
+ ResourceError preflightError = m_resource->resourceError();
+ // If the preflight was cancelled by underlying code, it probably means the request was blocked due to some access control policy.
+ // FIXME:: According fetch, we should just pass the error to the layer above. But this may impact some clients like XHR or EventSource.
+ if (preflightError.isNull() || preflightError.isCancellation() || preflightError.isGeneral())
+ preflightError.setType(ResourceError::Type::AccessControl);
+
+ m_loader.preflightFailure(m_resource->identifier(), preflightError);
+ return;
+ }
+ validatePreflightResponse(m_loader, WTFMove(m_request), m_resource->identifier(), m_resource->response());
+}
+
+void CrossOriginPreflightChecker::startPreflight()
+{
+ ResourceLoaderOptions options;
+ options.referrerPolicy = m_loader.options().referrerPolicy;
+ options.redirect = FetchOptions::Redirect::Manual;
+ options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
+
+ CachedResourceRequest preflightRequest(createAccessControlPreflightRequest(m_request, m_loader.securityOrigin(), m_loader.referrer()), options);
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
+ preflightRequest.setInitiator(m_loader.options().initiator);
+
+ ASSERT(!m_resource);
+ m_resource = m_loader.document().cachedResourceLoader().requestRawResource(WTFMove(preflightRequest));
+ if (m_resource)
+ m_resource->addClient(*this);
+}
+
+void CrossOriginPreflightChecker::doPreflight(DocumentThreadableLoader& loader, ResourceRequest&& request)
+{
+ if (!loader.document().frame())
+ return;
+
+ ResourceRequest preflightRequest = createAccessControlPreflightRequest(request, loader.securityOrigin(), loader.referrer());
+ ResourceError error;
+ ResourceResponse response;
+ RefPtr<SharedBuffer> data;
+
+ unsigned identifier = loader.document().frame()->loader().loadResourceSynchronously(preflightRequest, DoNotAllowStoredCredentials, ClientCredentialPolicy::CannotAskClientForCredentials, error, response, data);
+
+ if (!error.isNull()) {
+ // If the preflight was cancelled by underlying code, it probably means the request was blocked due to some access control policy.
+ // FIXME:: According fetch, we should just pass the error to the layer above. But this may impact some clients like XHR or EventSource.
+ if (error.isCancellation() || error.isGeneral())
+ error.setType(ResourceError::Type::AccessControl);
+ loader.preflightFailure(identifier, error);
+ return;
+ }
+
+ // FIXME: Ideally, we should ask platformLoadResourceSynchronously to set ResourceResponse isRedirected and use it here.
+ bool isRedirect = preflightRequest.url().strippedForUseAsReferrer() != response.url().strippedForUseAsReferrer();
+ if (isRedirect || !response.isSuccessful()) {
+ loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), ASCIILiteral("Preflight response is not successful"), ResourceError::Type::AccessControl));
+ return;
+ }
+
+ validatePreflightResponse(loader, WTFMove(request), identifier, response);
+}
+
+void CrossOriginPreflightChecker::setDefersLoading(bool value)
+{
+ if (m_resource)
+ m_resource->setDefersLoading(value);
+}
+
+bool CrossOriginPreflightChecker::isXMLHttpRequest() const
+{
+ return m_loader.isXMLHttpRequest();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/DocumentThreadableLoaderClient.h b/Source/WebCore/loader/CrossOriginPreflightChecker.h
index 146a166ed..6971c31f9 100644
--- a/Source/WebCore/loader/DocumentThreadableLoaderClient.h
+++ b/Source/WebCore/loader/CrossOriginPreflightChecker.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2016, Canon Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +11,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Canon Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -28,28 +28,41 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DocumentThreadableLoaderClient_h
-#define DocumentThreadableLoaderClient_h
+#pragma once
-#include "ThreadableLoaderClient.h"
+#include "CachedRawResourceClient.h"
+#include "CachedResourceHandle.h"
+#include "ResourceRequest.h"
namespace WebCore {
-class ResourceRequest;
-class ResourceResponse;
+class CachedRawResource;
+class Document;
+class DocumentThreadableLoader;
+class ResourceError;
-class DocumentThreadableLoaderClient : public ThreadableLoaderClient {
- WTF_MAKE_NONCOPYABLE(DocumentThreadableLoaderClient);
- WTF_MAKE_FAST_ALLOCATED;
+class CrossOriginPreflightChecker final : private CachedRawResourceClient {
public:
- virtual bool isDocumentThreadableLoaderClient() { return true; }
+ static void doPreflight(DocumentThreadableLoader&, ResourceRequest&&);
- virtual void willSendRequest(ResourceRequest& /*newRequest*/, const ResourceResponse& /*redirectResponse*/) { }
+ CrossOriginPreflightChecker(DocumentThreadableLoader&, ResourceRequest&&);
+ ~CrossOriginPreflightChecker();
-protected:
- DocumentThreadableLoaderClient() { }
+ void startPreflight();
+
+ void setDefersLoading(bool);
+
+private:
+ void notifyFinished(CachedResource&) final;
+
+ static void handleLoadingFailure(DocumentThreadableLoader&, unsigned long, const ResourceError&);
+ static void validatePreflightResponse(DocumentThreadableLoader&, ResourceRequest&&, unsigned long, const ResourceResponse&);
+
+ bool isXMLHttpRequest() const final;
+
+ DocumentThreadableLoader& m_loader;
+ CachedResourceHandle<CachedRawResource> m_resource;
+ ResourceRequest m_request;
};
} // namespace WebCore
-
-#endif // DocumentThreadableLoaderClient_h
diff --git a/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp b/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
index 7398d0f95..47cf73650 100644
--- a/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
+++ b/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -28,22 +28,28 @@
#include "CrossOriginPreflightResultCache.h"
#include "CrossOriginAccessControl.h"
+#include "HTTPHeaderNames.h"
+#include "HTTPParsers.h"
#include "ResourceResponse.h"
-#include <wtf/CurrentTime.h>
#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
// These values are at the discretion of the user agent.
-static const unsigned defaultPreflightCacheTimeoutSeconds = 5;
-static const unsigned maxPreflightCacheTimeoutSeconds = 600; // Should be short enough to minimize the risk of using a poisoned cache after switching to a secure network.
+static const auto defaultPreflightCacheTimeout = 5s;
+static const auto maxPreflightCacheTimeout = 600s; // Should be short enough to minimize the risk of using a poisoned cache after switching to a secure network.
-static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta)
+CrossOriginPreflightResultCache::CrossOriginPreflightResultCache()
+{
+}
+
+static bool parseAccessControlMaxAge(const String& string, std::chrono::seconds& expiryDelta)
{
// FIXME: this will not do the correct thing for a number starting with a '+'
bool ok = false;
- expiryDelta = string.toUIntStrict(&ok);
+ expiryDelta = std::chrono::seconds(string.toUIntStrict(&ok));
return ok;
}
@@ -88,25 +94,25 @@ static bool parseAccessControlAllowList(const String& string, HashSet<String, Ha
bool CrossOriginPreflightResultCacheItem::parse(const ResourceResponse& response, String& errorDescription)
{
m_methods.clear();
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods)) {
+ if (!parseAccessControlAllowList(response.httpHeaderField(HTTPHeaderName::AccessControlAllowMethods), m_methods)) {
errorDescription = "Cannot parse Access-Control-Allow-Methods response header field.";
return false;
}
m_headers.clear();
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers)) {
+ if (!parseAccessControlAllowList(response.httpHeaderField(HTTPHeaderName::AccessControlAllowHeaders), m_headers)) {
errorDescription = "Cannot parse Access-Control-Allow-Headers response header field.";
return false;
}
- unsigned expiryDelta;
- if (parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta)) {
- if (expiryDelta > maxPreflightCacheTimeoutSeconds)
- expiryDelta = maxPreflightCacheTimeoutSeconds;
+ std::chrono::seconds expiryDelta;
+ if (parseAccessControlMaxAge(response.httpHeaderField(HTTPHeaderName::AccessControlMaxAge), expiryDelta)) {
+ if (expiryDelta > maxPreflightCacheTimeout)
+ expiryDelta = maxPreflightCacheTimeout;
} else
- expiryDelta = defaultPreflightCacheTimeoutSeconds;
+ expiryDelta = defaultPreflightCacheTimeout;
- m_absoluteExpiryTime = monotonicallyIncreasingTime() + expiryDelta;
+ m_absoluteExpiryTime = std::chrono::steady_clock::now() + expiryDelta;
return true;
}
@@ -121,10 +127,11 @@ bool CrossOriginPreflightResultCacheItem::allowsCrossOriginMethod(const String&
bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHeaderMap& requestHeaders, String& errorDescription) const
{
- HTTPHeaderMap::const_iterator end = requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
- if (!m_headers.contains(it->key) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value)) {
- errorDescription = "Request header field " + it->key.string() + " is not allowed by Access-Control-Allow-Headers.";
+ for (const auto& header : requestHeaders) {
+ if (header.keyAsHTTPHeaderName && isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value))
+ continue;
+ if (!m_headers.contains(header.key)) {
+ errorDescription = "Request header field " + header.key + " is not allowed by Access-Control-Allow-Headers.";
return false;
}
}
@@ -134,7 +141,7 @@ bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHea
bool CrossOriginPreflightResultCacheItem::allowsRequest(StoredCredentials includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const
{
String ignoredExplanation;
- if (m_absoluteExpiryTime < monotonicallyIncreasingTime())
+ if (m_absoluteExpiryTime < std::chrono::steady_clock::now())
return false;
if (includeCredentials == AllowStoredCredentials && m_credentials == DoNotAllowStoredCredentials)
return false;
@@ -145,30 +152,31 @@ bool CrossOriginPreflightResultCacheItem::allowsRequest(StoredCredentials includ
return true;
}
-CrossOriginPreflightResultCache& CrossOriginPreflightResultCache::shared()
+CrossOriginPreflightResultCache& CrossOriginPreflightResultCache::singleton()
{
- DEFINE_STATIC_LOCAL(CrossOriginPreflightResultCache, cache, ());
ASSERT(isMainThread());
+
+ static NeverDestroyed<CrossOriginPreflightResultCache> cache;
return cache;
}
-void CrossOriginPreflightResultCache::appendEntry(const String& origin, const URL& url, PassOwnPtr<CrossOriginPreflightResultCacheItem> preflightResult)
+void CrossOriginPreflightResultCache::appendEntry(const String& origin, const URL& url, std::unique_ptr<CrossOriginPreflightResultCacheItem> preflightResult)
{
ASSERT(isMainThread());
- m_preflightHashMap.set(std::make_pair(origin, url), preflightResult);
+ m_preflightHashMap.set(std::make_pair(origin, url), WTFMove(preflightResult));
}
bool CrossOriginPreflightResultCache::canSkipPreflight(const String& origin, const URL& url, StoredCredentials includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders)
{
ASSERT(isMainThread());
- CrossOriginPreflightResultHashMap::iterator cacheIt = m_preflightHashMap.find(std::make_pair(origin, url));
- if (cacheIt == m_preflightHashMap.end())
+ auto it = m_preflightHashMap.find(std::make_pair(origin, url));
+ if (it == m_preflightHashMap.end())
return false;
- if (cacheIt->value->allowsRequest(includeCredentials, method, requestHeaders))
+ if (it->value->allowsRequest(includeCredentials, method, requestHeaders))
return true;
- m_preflightHashMap.remove(cacheIt);
+ m_preflightHashMap.remove(it);
return false;
}
diff --git a/Source/WebCore/loader/CrossOriginPreflightResultCache.h b/Source/WebCore/loader/CrossOriginPreflightResultCache.h
index 1c95a439f..094496e58 100644
--- a/Source/WebCore/loader/CrossOriginPreflightResultCache.h
+++ b/Source/WebCore/loader/CrossOriginPreflightResultCache.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,65 +24,59 @@
*
*/
-#ifndef CrossOriginPreflightResultCache_h
-#define CrossOriginPreflightResultCache_h
+#pragma once
#include "URLHash.h"
#include "ResourceHandleTypes.h"
+#include <chrono>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/text/StringHash.h>
namespace WebCore {
- class HTTPHeaderMap;
- class ResourceResponse;
+class HTTPHeaderMap;
+class ResourceResponse;
- class CrossOriginPreflightResultCacheItem {
- WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCacheItem); WTF_MAKE_FAST_ALLOCATED;
- public:
- CrossOriginPreflightResultCacheItem(StoredCredentials credentials)
- : m_absoluteExpiryTime(0)
- , m_credentials(credentials)
- {
- }
+class CrossOriginPreflightResultCacheItem {
+ WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCacheItem); WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit CrossOriginPreflightResultCacheItem(StoredCredentials credentials)
+ : m_credentials(credentials)
+ {
+ }
- bool parse(const ResourceResponse&, String& errorDescription);
- bool allowsCrossOriginMethod(const String&, String& errorDescription) const;
- bool allowsCrossOriginHeaders(const HTTPHeaderMap&, String& errorDescription) const;
- bool allowsRequest(StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;
+ bool parse(const ResourceResponse&, String& errorDescription);
+ bool allowsCrossOriginMethod(const String&, String& errorDescription) const;
+ bool allowsCrossOriginHeaders(const HTTPHeaderMap&, String& errorDescription) const;
+ bool allowsRequest(StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;
- private:
- typedef HashSet<String, CaseFoldingHash> HeadersSet;
+private:
+ // FIXME: A better solution to holding onto the absolute expiration time might be
+ // to start a timer for the expiration delta that removes this from the cache when
+ // it fires.
+ std::chrono::steady_clock::time_point m_absoluteExpiryTime;
+ StoredCredentials m_credentials;
+ HashSet<String> m_methods;
+ HashSet<String, ASCIICaseInsensitiveHash> m_headers;
+};
- // FIXME: A better solution to holding onto the absolute expiration time might be
- // to start a timer for the expiration delta that removes this from the cache when
- // it fires.
- double m_absoluteExpiryTime;
- StoredCredentials m_credentials;
- HashSet<String> m_methods;
- HeadersSet m_headers;
- };
+class CrossOriginPreflightResultCache {
+ WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCache); WTF_MAKE_FAST_ALLOCATED;
- class CrossOriginPreflightResultCache {
- WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCache); WTF_MAKE_FAST_ALLOCATED;
- public:
- static CrossOriginPreflightResultCache& shared();
+public:
+ WEBCORE_EXPORT static CrossOriginPreflightResultCache& singleton();
- void appendEntry(const String& origin, const URL&, PassOwnPtr<CrossOriginPreflightResultCacheItem>);
- bool canSkipPreflight(const String& origin, const URL&, StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
+ void appendEntry(const String& origin, const URL&, std::unique_ptr<CrossOriginPreflightResultCacheItem>);
+ bool canSkipPreflight(const String& origin, const URL&, StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
- void empty();
+ WEBCORE_EXPORT void empty();
- private:
- CrossOriginPreflightResultCache() { }
+private:
+ friend NeverDestroyed<CrossOriginPreflightResultCache>;
+ CrossOriginPreflightResultCache();
- typedef HashMap<std::pair<String, URL>, OwnPtr<CrossOriginPreflightResultCacheItem>> CrossOriginPreflightResultHashMap;
-
- CrossOriginPreflightResultHashMap m_preflightHashMap;
- };
+ HashMap<std::pair<String, URL>, std::unique_ptr<CrossOriginPreflightResultCacheItem>> m_preflightHashMap;
+};
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/DocumentLoadTiming.h b/Source/WebCore/loader/DocumentLoadTiming.h
deleted file mode 100644
index 8540901eb..000000000
--- a/Source/WebCore/loader/DocumentLoadTiming.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DocumentLoadTiming_h
-#define DocumentLoadTiming_h
-
-#include <wtf/CurrentTime.h>
-
-namespace WebCore {
-
-class Frame;
-class URL;
-
-class DocumentLoadTiming {
-public:
- DocumentLoadTiming();
-
- double monotonicTimeToZeroBasedDocumentTime(double) const;
- double monotonicTimeToPseudoWallTime(double) const;
-
- void markNavigationStart();
- void setNavigationStart(double);
- void addRedirect(const URL& redirectingUrl, const URL& redirectedUrl);
-
- void markUnloadEventStart() { m_unloadEventStart = monotonicallyIncreasingTime(); }
- void markUnloadEventEnd() { m_unloadEventEnd = monotonicallyIncreasingTime(); }
- void markRedirectStart() { m_redirectStart = monotonicallyIncreasingTime(); }
- void markRedirectEnd() { m_redirectEnd = monotonicallyIncreasingTime(); }
- void markFetchStart() { m_fetchStart = monotonicallyIncreasingTime(); }
- void setResponseEnd(double monotonicTime) { m_responseEnd = monotonicTime; }
- void markLoadEventStart() { m_loadEventStart = monotonicallyIncreasingTime(); }
- void markLoadEventEnd() { m_loadEventEnd = monotonicallyIncreasingTime(); }
-
- void setHasSameOriginAsPreviousDocument(bool value) { m_hasSameOriginAsPreviousDocument = value; }
-
- double navigationStart() const { return m_navigationStart; }
- double unloadEventStart() const { return m_unloadEventStart; }
- double unloadEventEnd() const { return m_unloadEventEnd; }
- double redirectStart() const { return m_redirectStart; }
- double redirectEnd() const { return m_redirectEnd; }
- short redirectCount() const { return m_redirectCount; }
- double fetchStart() const { return m_fetchStart; }
- double responseEnd() const { return m_responseEnd; }
- double loadEventStart() const { return m_loadEventStart; }
- double loadEventEnd() const { return m_loadEventEnd; }
- bool hasCrossOriginRedirect() const { return m_hasCrossOriginRedirect; }
- bool hasSameOriginAsPreviousDocument() const { return m_hasSameOriginAsPreviousDocument; }
-
-private:
- double m_referenceMonotonicTime;
- double m_referenceWallTime;
- double m_navigationStart;
- double m_unloadEventStart;
- double m_unloadEventEnd;
- double m_redirectStart;
- double m_redirectEnd;
- short m_redirectCount;
- double m_fetchStart;
- double m_responseEnd;
- double m_loadEventStart;
- double m_loadEventEnd;
- bool m_hasCrossOriginRedirect;
- bool m_hasSameOriginAsPreviousDocument;
-};
-
-} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp
index 8acee0a2a..0eb8170c1 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,33 +31,44 @@
#include "DocumentLoader.h"
#include "ApplicationCacheHost.h"
+#include "Archive.h"
#include "ArchiveResourceCollection.h"
#include "CachedPage.h"
#include "CachedRawResource.h"
#include "CachedResourceLoader.h"
+#include "ContentExtensionError.h"
+#include "ContentSecurityPolicy.h"
#include "DOMWindow.h"
#include "Document.h"
#include "DocumentParser.h"
#include "DocumentWriter.h"
+#include "ElementChildIterator.h"
#include "Event.h"
+#include "EventNames.h"
+#include "ExtensionStyleSheets.h"
#include "FormState.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "FrameTree.h"
#include "HTMLFormElement.h"
#include "HTMLFrameOwnerElement.h"
+#include "HTTPHeaderNames.h"
#include "HistoryItem.h"
#include "IconController.h"
+#include "IconLoader.h"
#include "InspectorInstrumentation.h"
+#include "LinkIconCollector.h"
+#include "LinkIconType.h"
#include "Logging.h"
#include "MainFrame.h"
#include "MemoryCache.h"
#include "Page.h"
#include "PolicyChecker.h"
#include "ProgressTracker.h"
-#include "ResourceBuffer.h"
#include "ResourceHandle.h"
+#include "ResourceLoadObserver.h"
#include "SchemeRegistry.h"
+#include "ScriptableDocumentParser.h"
#include "SecurityPolicy.h"
#include "Settings.h"
#include "SubresourceLoader.h"
@@ -67,148 +78,116 @@
#include <wtf/Ref.h>
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
-#include <wtf/unicode/Unicode.h>
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
#include "ArchiveFactory.h"
#endif
-#if USE(CONTENT_FILTERING)
+#if ENABLE(CONTENT_FILTERING)
#include "ContentFilter.h"
#endif
+#if USE(QUICK_LOOK)
+#include "PreviewConverter.h"
+#include "QuickLook.h"
+#endif
+
+#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - DocumentLoader::" fmt, this, ##__VA_ARGS__)
+
namespace WebCore {
-static void cancelAll(const ResourceLoaderSet& loaders)
+static void cancelAll(const ResourceLoaderMap& loaders)
{
Vector<RefPtr<ResourceLoader>> loadersCopy;
- copyToVector(loaders, loadersCopy);
- size_t size = loadersCopy.size();
- for (size_t i = 0; i < size; ++i)
- loadersCopy[i]->cancel();
+ copyValuesToVector(loaders, loadersCopy);
+ for (auto& loader : loadersCopy)
+ loader->cancel();
}
-static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers)
+static void setAllDefersLoading(const ResourceLoaderMap& loaders, bool defers)
{
Vector<RefPtr<ResourceLoader>> loadersCopy;
- copyToVector(loaders, loadersCopy);
- size_t size = loadersCopy.size();
- for (size_t i = 0; i < size; ++i)
- loadersCopy[i]->setDefersLoading(defers);
+ copyValuesToVector(loaders, loadersCopy);
+ for (auto& loader : loadersCopy)
+ loader->setDefersLoading(defers);
}
-static bool areAllLoadersPageCacheAcceptable(const ResourceLoaderSet& loaders)
+static bool areAllLoadersPageCacheAcceptable(const ResourceLoaderMap& loaders)
{
Vector<RefPtr<ResourceLoader>> loadersCopy;
- copyToVector(loaders, loadersCopy);
+ copyValuesToVector(loaders, loadersCopy);
for (auto& loader : loadersCopy) {
- ResourceHandle* handle = loader->handle();
- if (!handle)
+ if (!loader->frameLoader() || !loader->frameLoader()->frame().page())
return false;
- CachedResource* cachedResource = memoryCache()->resourceForURL(handle->firstRequest().url());
+ CachedResource* cachedResource = MemoryCache::singleton().resourceForRequest(loader->request(), loader->frameLoader()->frame().page()->sessionID());
if (!cachedResource)
return false;
+ // Only image and XHR loads do prevent the page from entering the PageCache.
// All non-image loads will prevent the page from entering the PageCache.
- if (!cachedResource->isImage())
+ if (!cachedResource->isImage() && !cachedResource->areAllClientsXMLHttpRequests())
return false;
}
return true;
}
-DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData)
- : m_deferMainResourceDataLoad(true)
- , m_frame(0)
- , m_cachedResourceLoader(CachedResourceLoader::create(this))
+DocumentLoader::DocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
+ : m_cachedResourceLoader(CachedResourceLoader::create(this))
, m_writer(m_frame)
- , m_originalRequest(req)
+ , m_originalRequest(request)
, m_substituteData(substituteData)
- , m_originalRequestCopy(req)
- , m_request(req)
+ , m_originalRequestCopy(request)
+ , m_request(request)
, m_originalSubstituteDataWasValid(substituteData.isValid())
- , m_committed(false)
- , m_isStopping(false)
- , m_gotFirstByte(false)
- , m_isClientRedirect(false)
- , m_isLoadingMultipartContent(false)
- , m_wasOnloadHandled(false)
- , m_stopRecordingResponses(false)
- , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired)
- , m_didCreateGlobalHistoryEntry(false)
- , m_loadingMainResource(false)
- , m_timeOfLastDataReceived(0.0)
- , m_identifierForLoadWithoutResourceLoader(0)
- , m_dataLoadTimer(this, &DocumentLoader::handleSubstituteDataLoadNow)
- , m_waitingForContentPolicy(false)
- , m_subresourceLoadersArePageCacheAcceptable(false)
- , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(this)))
+ , m_substituteResourceDeliveryTimer(*this, &DocumentLoader::substituteResourceDeliveryTimerFired)
+ , m_dataLoadTimer(*this, &DocumentLoader::handleSubstituteDataLoadNow)
+ , m_applicationCacheHost(std::make_unique<ApplicationCacheHost>(*this))
{
}
FrameLoader* DocumentLoader::frameLoader() const
{
if (!m_frame)
- return 0;
+ return nullptr;
return &m_frame->loader();
}
-ResourceLoader* DocumentLoader::mainResourceLoader() const
+SubresourceLoader* DocumentLoader::mainResourceLoader() const
{
- return m_mainResource ? m_mainResource->loader() : 0;
+ if (!m_mainResource)
+ return nullptr;
+ return m_mainResource->loader();
}
DocumentLoader::~DocumentLoader()
{
ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !isLoading());
+ ASSERT_WITH_MESSAGE(!m_waitingForContentPolicy, "The content policy callback should never outlive its DocumentLoader.");
+ ASSERT_WITH_MESSAGE(!m_waitingForNavigationPolicy, "The navigation policy callback should never outlive its DocumentLoader.");
if (m_iconLoadDecisionCallback)
m_iconLoadDecisionCallback->invalidate();
if (m_iconDataCallback)
m_iconDataCallback->invalidate();
m_cachedResourceLoader->clearDocumentLoader();
-
+
clearMainResource();
}
-PassRefPtr<ResourceBuffer> DocumentLoader::mainResourceData() const
+RefPtr<SharedBuffer> DocumentLoader::mainResourceData() const
{
if (m_substituteData.isValid())
- return ResourceBuffer::create(m_substituteData.content()->data(), m_substituteData.content()->size());
+ return m_substituteData.content()->copy();
if (m_mainResource)
return m_mainResource->resourceBuffer();
- return 0;
+ return nullptr;
}
Document* DocumentLoader::document() const
{
if (m_frame && m_frame->loader().documentLoader() == this)
return m_frame->document();
- return 0;
-}
-
-const ResourceRequest& DocumentLoader::originalRequest() const
-{
- return m_originalRequest;
-}
-
-const ResourceRequest& DocumentLoader::originalRequestCopy() const
-{
- return m_originalRequestCopy;
-}
-
-const ResourceRequest& DocumentLoader::request() const
-{
- return m_request;
-}
-
-ResourceRequest& DocumentLoader::request()
-{
- return m_request;
-}
-
-const URL& DocumentLoader::url() const
-{
- return request().url();
+ return nullptr;
}
void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const URL& url)
@@ -225,8 +204,11 @@ void DocumentLoader::setRequest(const ResourceRequest& req)
handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty();
+ bool shouldNotifyAboutProvisionalURLChange = false;
if (handlingUnreachableURL)
m_committed = false;
+ else if (isLoadingMainResource() && req.url() != m_request.url())
+ shouldNotifyAboutProvisionalURLChange = true;
// We should never be getting a redirect callback after the data
// source is committed, except in the unreachable URL case. It
@@ -234,6 +216,8 @@ void DocumentLoader::setRequest(const ResourceRequest& req)
ASSERT(!m_committed);
m_request = req;
+ if (shouldNotifyAboutProvisionalURLChange)
+ frameLoader()->client().dispatchDidChangeProvisionalURL();
}
void DocumentLoader::setMainDocumentError(const ResourceError& error)
@@ -246,6 +230,9 @@ void DocumentLoader::mainReceivedError(const ResourceError& error)
{
ASSERT(!error.isNull());
+ if (!frameLoader())
+ return;
+
if (m_identifierForLoadWithoutResourceLoader) {
ASSERT(!mainResourceLoader());
frameLoader()->client().dispatchDidFailLoading(this, m_identifierForLoadWithoutResourceLoader, error);
@@ -259,8 +246,6 @@ void DocumentLoader::mainReceivedError(const ResourceError& error)
m_applicationCacheHost->failedLoadingMainResource();
- if (!frameLoader())
- return;
setMainDocumentError(error);
clearMainResourceLoader();
frameLoader()->receivedMainResourceError(error);
@@ -272,8 +257,8 @@ void DocumentLoader::mainReceivedError(const ResourceError& error)
// but not loads initiated by child frames' data sources -- that's the WebFrame's job.
void DocumentLoader::stopLoading()
{
- RefPtr<Frame> protectFrame(m_frame);
- Ref<DocumentLoader> protectLoader(*this);
+ RefPtr<Frame> protectedFrame(m_frame);
+ Ref<DocumentLoader> protectedThis(*this);
// In some rare cases, calling FrameLoader::stopLoading could cause isLoading() to return false.
// (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
@@ -300,7 +285,7 @@ void DocumentLoader::stopLoading()
cancelAll(m_multipartSubresourceLoaders);
// Appcache uses ResourceHandle directly, DocumentLoader doesn't count these loads.
- m_applicationCacheHost->stopLoadingInFrame(m_frame);
+ m_applicationCacheHost->stopLoadingInFrame(*m_frame);
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
clearArchiveResources();
@@ -321,19 +306,21 @@ void DocumentLoader::stopLoading()
m_isStopping = true;
- FrameLoader* frameLoader = DocumentLoader::frameLoader();
-
- if (isLoadingMainResource()) {
- // Stop the main resource loader and let it send the cancelled message.
- cancelMainResourceLoad(frameLoader->cancelledError(m_request));
- } else if (!m_subresourceLoaders.isEmpty())
- // The main resource loader already finished loading. Set the cancelled error on the
- // document and let the subresourceLoaders send individual cancelled messages below.
- setMainDocumentError(frameLoader->cancelledError(m_request));
- else
- // If there are no resource loaders, we need to manufacture a cancelled message.
- // (A back/forward navigation has no resource loaders because its resources are cached.)
- mainReceivedError(frameLoader->cancelledError(m_request));
+ // The frame may have been detached from this document by the onunload handler
+ if (auto* frameLoader = DocumentLoader::frameLoader()) {
+ if (isLoadingMainResource()) {
+ // Stop the main resource loader and let it send the cancelled message.
+ cancelMainResourceLoad(frameLoader->cancelledError(m_request));
+ } else if (!m_subresourceLoaders.isEmpty() || !m_plugInStreamLoaders.isEmpty()) {
+ // The main resource loader already finished loading. Set the cancelled error on the
+ // document and let the subresourceLoaders and pluginLoaders send individual cancelled messages below.
+ setMainDocumentError(frameLoader->cancelledError(m_request));
+ } else {
+ // If there are no resource loaders, we need to manufacture a cancelled message.
+ // (A back/forward navigation has no resource loaders because its resources are cached.)
+ mainReceivedError(frameLoader->cancelledError(m_request));
+ }
+ }
// We always need to explicitly cancel the Document's parser when stopping the load.
// Otherwise cancelling the parser while starting the next page load might result
@@ -366,9 +353,14 @@ bool DocumentLoader::isLoading() const
return isLoadingMainResource() || !m_subresourceLoaders.isEmpty() || !m_plugInStreamLoaders.isEmpty();
}
-void DocumentLoader::notifyFinished(CachedResource* resource)
+void DocumentLoader::notifyFinished(CachedResource& resource)
{
- ASSERT_UNUSED(resource, m_mainResource == resource);
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter && !m_contentFilter->continueAfterNotifyFinished(resource))
+ return;
+#endif
+
+ ASSERT_UNUSED(resource, m_mainResource == &resource);
ASSERT(m_mainResource);
if (!m_mainResource->errorOccurred() && !m_mainResource->wasCanceled()) {
finishedLoading(m_mainResource->loadFinishTime());
@@ -388,10 +380,10 @@ void DocumentLoader::finishedLoading(double finishTime)
// There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
// See <rdar://problem/6304600> for more details.
#if !USE(CF)
- ASSERT(!m_frame->page()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
+ ASSERT(!m_frame->page()->defersLoading() || frameLoader()->stateMachine().creatingInitialEmptyDocument() || InspectorInstrumentation::isDebuggerPaused(m_frame));
#endif
- Ref<DocumentLoader> protect(*this);
+ Ref<DocumentLoader> protectedThis(*this);
if (m_identifierForLoadWithoutResourceLoader) {
// A didFinishLoading delegate might try to cancel the load (despite it
@@ -403,27 +395,14 @@ void DocumentLoader::finishedLoading(double finishTime)
frameLoader()->notifier().dispatchDidFinishLoading(this, identifier, finishTime);
}
-#if USE(CONTENT_FILTERING)
- if (m_contentFilter && m_contentFilter->needsMoreData()) {
- m_contentFilter->finishedAddingData();
- int length;
- const char* data = m_contentFilter->getReplacementData(length);
- if (data)
- dataReceived(m_mainResource.get(), data, length);
-
- if (m_contentFilter->didBlockData())
- setContentFilterForBlockedLoad(m_contentFilter);
- }
-#endif
-
maybeFinishLoadingMultipartContent();
- double responseEndTime = finishTime;
+ MonotonicTime responseEndTime = MonotonicTime::fromRawSeconds(finishTime);
if (!responseEndTime)
responseEndTime = m_timeOfLastDataReceived;
if (!responseEndTime)
- responseEndTime = monotonicallyIncreasingTime();
- timing()->setResponseEnd(responseEndTime);
+ responseEndTime = MonotonicTime::now();
+ timing().setResponseEnd(responseEndTime);
commitIfReady();
if (!frameLoader())
@@ -441,14 +420,14 @@ void DocumentLoader::finishedLoading(double finishTime)
if (!m_mainDocumentError.isNull())
return;
clearMainResourceLoader();
- if (!frameLoader()->stateMachine()->creatingInitialEmptyDocument())
+ if (!frameLoader()->stateMachine().creatingInitialEmptyDocument())
frameLoader()->checkLoadComplete();
// If the document specified an application cache manifest, it violates the author's intent if we store it in the memory cache
// and deny the appcache the chance to intercept it in the future, so remove from the memory cache.
if (m_frame) {
if (m_mainResource && m_frame->document()->hasManifest())
- memoryCache()->remove(m_mainResource.get());
+ MemoryCache::singleton().remove(*m_mainResource);
}
m_applicationCacheHost->finishedLoadingMainResource();
}
@@ -466,13 +445,13 @@ bool DocumentLoader::isPostOrRedirectAfterPost(const ResourceRequest& newRequest
return false;
}
-void DocumentLoader::handleSubstituteDataLoadNow(DocumentLoaderTimer*)
+void DocumentLoader::handleSubstituteDataLoadNow()
{
- URL url = m_substituteData.responseURL();
- if (url.isEmpty())
- url = m_request.url();
- ResourceResponse response(url, m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding(), "");
- responseReceived(0, response);
+ ResourceResponse response = m_substituteData.response();
+ if (response.url().isEmpty())
+ response = ResourceResponse(m_request.url(), m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding());
+
+ responseReceived(response);
}
void DocumentLoader::startDataLoadTimer()
@@ -488,14 +467,14 @@ void DocumentLoader::startDataLoadTimer()
void DocumentLoader::handleSubstituteDataLoadSoon()
{
if (!m_deferMainResourceDataLoad || frameLoader()->loadsSynchronously())
- handleSubstituteDataLoadNow(0);
+ handleSubstituteDataLoadNow();
else
startDataLoadTimer();
}
-void DocumentLoader::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
+void DocumentLoader::redirectReceived(CachedResource& resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
- ASSERT_UNUSED(resource, resource == m_mainResource);
+ ASSERT_UNUSED(resource, &resource == m_mainResource);
willSendRequest(request, redirectResponse);
}
@@ -507,27 +486,42 @@ void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const Resource
// callbacks is meant to prevent.
ASSERT(!newRequest.isNull());
- if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) {
+ bool didReceiveRedirectResponse = !redirectResponse.isNull();
+ if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url(), didReceiveRedirectResponse)) {
cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
return;
}
- ASSERT(timing()->fetchStart());
- if (!redirectResponse.isNull()) {
+ ASSERT(timing().fetchStart());
+ if (didReceiveRedirectResponse) {
// If the redirecting url is not allowed to display content from the target origin,
// then block the redirect.
- RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
- if (!redirectingOrigin->canDisplay(newRequest.url())) {
+ Ref<SecurityOrigin> redirectingOrigin(SecurityOrigin::create(redirectResponse.url()));
+ if (!redirectingOrigin.get().canDisplay(newRequest.url())) {
FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string());
cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
return;
}
- timing()->addRedirect(redirectResponse.url(), newRequest.url());
+ if (!portAllowed(newRequest.url())) {
+ FrameLoader::reportBlockedPortFailed(m_frame, newRequest.url().string());
+ cancelMainResourceLoad(frameLoader()->blockedError(newRequest));
+ return;
+ }
+ timing().addRedirect(redirectResponse.url(), newRequest.url());
}
+ ASSERT(m_frame);
+
+ Frame& topFrame = m_frame->tree().top();
+
+ ASSERT(m_frame->document());
+ ASSERT(topFrame.document());
+
+ ResourceLoadObserver::sharedObserver().logFrameNavigation(*m_frame, topFrame, newRequest, redirectResponse);
+
// Update cookie policy base URL as URL changes, except for subframes, which use the
// URL of the main frame which doesn't change when we redirect.
- if (frameLoader()->frame().isMainFrame())
+ if (m_frame->isMainFrame())
newRequest.setFirstPartyForCookies(newRequest.url());
// If we're fielding a redirect in response to a POST, force a load from origin, since
@@ -537,43 +531,58 @@ void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const Resource
if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
newRequest.setCachePolicy(ReloadIgnoringCacheData);
- Frame& topFrame = m_frame->tree().top();
if (&topFrame != m_frame) {
- if (!frameLoader()->mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), newRequest.url())) {
+ if (!m_frame->loader().mixedContentChecker().canDisplayInsecureContent(m_frame->document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url(), MixedContentChecker::AlwaysDisplayInNonStrictMode::Yes)) {
+ cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
+ return;
+ }
+ if (!frameLoader()->mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url())) {
cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
return;
}
}
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter && !m_contentFilter->continueAfterWillSendRequest(newRequest, redirectResponse))
+ return;
+#endif
+
setRequest(newRequest);
- if (!redirectResponse.isNull()) {
+ if (didReceiveRedirectResponse) {
// We checked application cache for initial URL, now we need to check it for redirected one.
ASSERT(!m_substituteData.isValid());
m_applicationCacheHost->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
- if (m_substituteData.isValid())
- m_identifierForLoadWithoutResourceLoader = mainResourceLoader()->identifier();
+ if (m_substituteData.isValid()) {
+ RELEASE_ASSERT(m_mainResource);
+ ResourceLoader* loader = m_mainResource->loader();
+ m_identifierForLoadWithoutResourceLoader = loader ? loader->identifier() : m_mainResource->identifierForLoadWithoutResourceLoader();
+ }
}
// FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
// listener. But there's no way to do that in practice. So instead we cancel later if the
// listener tells us to. In practice that means the navigation policy needs to be decided
// synchronously for these redirect cases.
- if (redirectResponse.isNull())
+ if (!didReceiveRedirectResponse)
return;
- frameLoader()->policyChecker().checkNavigationPolicy(newRequest, [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
+ ASSERT(!m_waitingForNavigationPolicy);
+ m_waitingForNavigationPolicy = true;
+ frameLoader()->policyChecker().checkNavigationPolicy(newRequest, didReceiveRedirectResponse, [this] (const ResourceRequest& request, FormState*, bool shouldContinue) {
continueAfterNavigationPolicy(request, shouldContinue);
});
}
void DocumentLoader::continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue)
{
+ ASSERT(m_waitingForNavigationPolicy);
+ m_waitingForNavigationPolicy = false;
if (!shouldContinue)
stopLoadingForPolicyChange();
else if (m_substituteData.isValid()) {
// A redirect resulted in loading substitute data.
- ASSERT(timing()->redirectCount());
+ ASSERT(timing().redirectCount());
// We need to remove our reference to the CachedResource in favor of a SubstituteData load.
// This will probably trigger the cancellation of the CachedResource's underlying ResourceLoader, though there is a
@@ -582,46 +591,76 @@ void DocumentLoader::continueAfterNavigationPolicy(const ResourceRequest&, bool
// However, from an API perspective, this isn't a cancellation. Therefore, sever our relationship with the network load,
// but prevent the ResourceLoader from sending ResourceLoadNotifier callbacks.
RefPtr<ResourceLoader> resourceLoader = mainResourceLoader();
- ASSERT(resourceLoader->shouldSendResourceLoadCallbacks());
- resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks);
+ if (resourceLoader) {
+ ASSERT(resourceLoader->shouldSendResourceLoadCallbacks());
+ resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks);
+ }
+
clearMainResource();
- resourceLoader->setSendCallbackPolicy(SendCallbacks);
+
+ if (resourceLoader)
+ resourceLoader->setSendCallbackPolicy(SendCallbacks);
handleSubstituteDataLoadSoon();
}
}
-void DocumentLoader::responseReceived(CachedResource* resource, const ResourceResponse& response)
+void DocumentLoader::stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(unsigned long identifier, const ResourceResponse& response)
+{
+ InspectorInstrumentation::continueAfterXFrameOptionsDenied(*m_frame, identifier, *this, response);
+ m_frame->document()->enforceSandboxFlags(SandboxOrigin);
+ if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
+ ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
+
+ // The load event might have detached this frame. In that case, the load will already have been cancelled during detach.
+ if (FrameLoader* frameLoader = this->frameLoader())
+ cancelMainResourceLoad(frameLoader->cancelledError(m_request));
+}
+
+void DocumentLoader::responseReceived(CachedResource& resource, const ResourceResponse& response)
{
- ASSERT_UNUSED(resource, m_mainResource == resource);
- Ref<DocumentLoader> protect(*this);
+ ASSERT_UNUSED(resource, m_mainResource == &resource);
+ responseReceived(response);
+}
+
+void DocumentLoader::responseReceived(const ResourceResponse& response)
+{
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter && !m_contentFilter->continueAfterResponseReceived(response))
+ return;
+#endif
+
+ Ref<DocumentLoader> protectedThis(*this);
bool willLoadFallback = m_applicationCacheHost->maybeLoadFallbackForMainResponse(request(), response);
// The memory cache doesn't understand the application cache or its caching rules. So if a main resource is served
// from the application cache, ensure we don't save the result for future use.
if (willLoadFallback)
- memoryCache()->remove(m_mainResource.get());
+ MemoryCache::singleton().remove(*m_mainResource);
if (willLoadFallback)
return;
- DEFINE_STATIC_LOCAL(AtomicString, xFrameOptionHeader, ("x-frame-options", AtomicString::ConstructFromLiteral));
- HTTPHeaderMap::const_iterator it = response.httpHeaderFields().find(xFrameOptionHeader);
- if (it != response.httpHeaderFields().end()) {
+ ASSERT(m_identifierForLoadWithoutResourceLoader || m_mainResource);
+ unsigned long identifier = m_identifierForLoadWithoutResourceLoader ? m_identifierForLoadWithoutResourceLoader : m_mainResource->identifier();
+ ASSERT(identifier);
+
+ auto url = response.url();
+
+ ContentSecurityPolicy contentSecurityPolicy(SecurityOrigin::create(url), m_frame);
+ contentSecurityPolicy.didReceiveHeaders(ContentSecurityPolicyResponseHeaders(response));
+ if (!contentSecurityPolicy.allowFrameAncestors(*m_frame, url)) {
+ stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(identifier, response);
+ return;
+ }
+
+ const auto& commonHeaders = response.httpHeaderFields().commonHeaders();
+ auto it = commonHeaders.find(HTTPHeaderName::XFrameOptions);
+ if (it != commonHeaders.end()) {
String content = it->value;
- ASSERT(m_mainResource);
- unsigned long identifier = m_identifierForLoadWithoutResourceLoader ? m_identifierForLoadWithoutResourceLoader : m_mainResource->identifier();
- ASSERT(identifier);
- if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, response.url(), identifier)) {
- InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame, this, identifier, response);
- String message = "Refused to display '" + response.url().stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
- frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, identifier);
- frame()->document()->enforceSandboxFlags(SandboxOrigin);
- if (HTMLFrameOwnerElement* ownerElement = frame()->ownerElement())
- ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
-
- // The load event might have detached this frame. In that case, the load will already have been cancelled during detach.
- if (frameLoader())
- cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
+ if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, url, identifier)) {
+ String message = "Refused to display '" + url.stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
+ m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier);
+ stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(identifier, response);
return;
}
}
@@ -635,19 +674,22 @@ void DocumentLoader::responseReceived(CachedResource* resource, const ResourceRe
if (m_isLoadingMultipartContent) {
setupForReplace();
m_mainResource->clear();
- } else if (response.isMultipart()) {
- FeatureObserver::observe(m_frame->document(), FeatureObserver::MultipartMainResource);
+ } else if (response.isMultipart())
m_isLoadingMultipartContent = true;
- }
m_response = response;
if (m_identifierForLoadWithoutResourceLoader) {
+ if (m_mainResource && m_mainResource->wasRedirected()) {
+ ASSERT(m_mainResource->status() == CachedResource::Status::Cached);
+ frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad();
+ }
addResponse(m_response);
frameLoader()->notifier().dispatchDidReceiveResponse(this, m_identifierForLoadWithoutResourceLoader, m_response, 0);
}
ASSERT(!m_waitingForContentPolicy);
+ ASSERT(frameLoader());
m_waitingForContentPolicy = true;
// Always show content with valid substitute data.
@@ -664,16 +706,38 @@ void DocumentLoader::responseReceived(CachedResource* resource, const ResourceRe
}
#endif
-#if USE(CONTENT_FILTERING)
- if (response.url().protocolIsInHTTPFamily() && ContentFilter::isEnabled())
- m_contentFilter = ContentFilter::create(response);
-#endif
-
frameLoader()->policyChecker().checkContentPolicy(m_response, [this](PolicyAction policy) {
continueAfterContentPolicy(policy);
});
}
+static bool isRemoteWebArchive(const DocumentLoader& documentLoader)
+{
+ using MIMETypeHashSet = HashSet<String, ASCIICaseInsensitiveHash>;
+ static NeverDestroyed<MIMETypeHashSet> webArchiveMIMETypes {
+ MIMETypeHashSet {
+ ASCIILiteral("application/x-webarchive"),
+ ASCIILiteral("application/x-mimearchive"),
+ ASCIILiteral("multipart/related"),
+#if PLATFORM(GTK)
+ ASCIILiteral("message/rfc822"),
+#endif
+ }
+ };
+
+ const ResourceResponse& response = documentLoader.response();
+ String mimeType = response.mimeType();
+ if (mimeType.isNull() || !webArchiveMIMETypes.get().contains(mimeType))
+ return false;
+
+#if USE(QUICK_LOOK)
+ if (response.url().protocolIs(QLPreviewProtocol()))
+ return false;
+#endif
+
+ return !documentLoader.substituteData().isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(documentLoader.request().url().protocol().toStringWithoutCopying());
+}
+
void DocumentLoader::continueAfterContentPolicy(PolicyAction policy)
{
ASSERT(m_waitingForContentPolicy);
@@ -681,20 +745,10 @@ void DocumentLoader::continueAfterContentPolicy(PolicyAction policy)
if (isStopping())
return;
- URL url = m_request.url();
- const String& mimeType = m_response.mimeType();
-
switch (policy) {
case PolicyUse: {
// Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255).
- bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType)
- || equalIgnoringCase("application/x-mimearchive", mimeType)
-#if PLATFORM(GTK)
- || equalIgnoringCase("message/rfc822", mimeType)
-#endif
- || equalIgnoringCase("multipart/related", mimeType))
- && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol());
- if (!frameLoader()->client().canShowMIMEType(mimeType) || isRemoteWebArchive) {
+ if (!frameLoader()->client().canShowMIMEType(m_response.mimeType()) || isRemoteWebArchive(*this)) {
frameLoader()->policyChecker().cannotShowMIMEType(m_response);
// Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::.
stopLoadingForPolicyChange();
@@ -711,31 +765,37 @@ void DocumentLoader::continueAfterContentPolicy(PolicyAction policy)
}
if (ResourceLoader* mainResourceLoader = this->mainResourceLoader())
- InspectorInstrumentation::continueWithPolicyDownload(m_frame, this, mainResourceLoader->identifier(), m_response);
+ InspectorInstrumentation::continueWithPolicyDownload(*m_frame, mainResourceLoader->identifier(), *this, m_response);
// When starting the request, we didn't know that it would result in download and not navigation. Now we know that main document URL didn't change.
// Download may use this knowledge for purposes unrelated to cookies, notably for setting file quarantine data.
frameLoader()->setOriginalURLForDownloadRequest(m_request);
- frameLoader()->client().convertMainResourceLoadToDownload(this, m_request, m_response);
+
+ SessionID sessionID = SessionID::defaultSessionID();
+ if (frame() && frame()->page())
+ sessionID = frame()->page()->sessionID();
+
+ if (m_request.url().protocolIsData()) {
+ // We decode data URL internally, there is no resource load to convert.
+ frameLoader()->client().startDownload(m_request);
+ } else
+ frameLoader()->client().convertMainResourceLoadToDownload(this, sessionID, m_request, m_response);
// It might have gone missing
if (mainResourceLoader())
- mainResourceLoader()->didFail(interruptedForPolicyChangeError());
+ static_cast<ResourceLoader*>(mainResourceLoader())->didFail(interruptedForPolicyChangeError());
return;
}
case PolicyIgnore:
if (ResourceLoader* mainResourceLoader = this->mainResourceLoader())
- InspectorInstrumentation::continueWithPolicyIgnore(m_frame, this, mainResourceLoader->identifier(), m_response);
+ InspectorInstrumentation::continueWithPolicyIgnore(*m_frame, mainResourceLoader->identifier(), *this, m_response);
stopLoadingForPolicyChange();
return;
-
- default:
- ASSERT_NOT_REACHED();
}
if (m_response.isHTTP()) {
- int status = m_response.httpStatusCode();
- if (status < 200 || status >= 300) {
+ int status = m_response.httpStatusCode(); // Status may be zero when loading substitute data, in particular from a WebArchive.
+ if (status && (status < 200 || status >= 300)) {
bool hostedByObject = frameLoader()->isHostedByObjectElement();
frameLoader()->handleFallbackContent();
@@ -747,9 +807,10 @@ void DocumentLoader::continueAfterContentPolicy(PolicyAction policy)
}
}
- if (!isStopping() && m_substituteData.isValid()) {
- if (m_substituteData.content()->size())
- dataReceived(0, m_substituteData.content()->data(), m_substituteData.content()->size());
+ if (!isStopping() && m_substituteData.isValid() && isLoadingMainResource()) {
+ auto content = m_substituteData.content();
+ if (content && content->size())
+ dataReceived(content->data(), content->size());
if (isLoadingMainResource())
finishedLoading(0);
}
@@ -759,8 +820,8 @@ void DocumentLoader::commitLoad(const char* data, int length)
{
// Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
// by starting a new load, so retain temporarily.
- RefPtr<Frame> protectFrame(m_frame);
- Ref<DocumentLoader> protectLoader(*this);
+ RefPtr<Frame> protectedFrame(m_frame);
+ Ref<DocumentLoader> protectedThis(*this);
commitIfReady();
FrameLoader* frameLoader = DocumentLoader::frameLoader();
@@ -771,6 +832,9 @@ void DocumentLoader::commitLoad(const char* data, int length)
return;
#endif
frameLoader->client().committedLoad(this, data, length);
+
+ if (isMultipartReplacingLoad())
+ frameLoader->client().didReplaceMultipartContent();
}
ResourceError DocumentLoader::interruptedForPolicyChangeError() const
@@ -781,7 +845,7 @@ ResourceError DocumentLoader::interruptedForPolicyChangeError() const
void DocumentLoader::stopLoadingForPolicyChange()
{
ResourceError error = interruptedForPolicyChangeError();
- error.setIsCancellation(true);
+ error.setType(ResourceError::Type::Cancellation);
cancelMainResourceLoad(error);
}
@@ -797,16 +861,14 @@ void DocumentLoader::commitData(const char* bytes, size_t length)
// load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756
// and https://bugs.webkit.org/show_bug.cgi?id=19760 for further
// discussion.
- m_frame->document()->securityOrigin()->grantLoadLocalResources();
+ m_frame->document()->securityOrigin().grantLoadLocalResources();
}
- if (frameLoader()->stateMachine()->creatingInitialEmptyDocument())
+ if (frameLoader()->stateMachine().creatingInitialEmptyDocument())
return;
-
-#if ENABLE(MHTML)
- // The origin is the MHTML file, we need to set the base URL to the document encoded in the MHTML so
- // relative URLs are resolved properly.
- if (m_archive && m_archive->type() == Archive::MHTML)
+
+#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
+ if (m_archive && m_archive->shouldOverrideBaseURL())
m_frame->document()->setBaseURLOverride(m_archive->mainResource()->url());
#endif
@@ -815,21 +877,17 @@ void DocumentLoader::commitData(const char* bytes, size_t length)
if (!isMultipartReplacingLoad())
frameLoader()->receivedFirstData();
+ // The load could be canceled under receivedFirstData(), which makes delegate calls and even sometimes dispatches DOM events.
+ if (!isLoading())
+ return;
+
bool userChosen;
String encoding;
-#if USE(CONTENT_FILTERING)
- // The content filter's replacement data has a known encoding that might
- // differ from the response's encoding.
- if (m_contentFilter && m_contentFilter->didBlockData()) {
- ASSERT(!m_contentFilter->needsMoreData());
- userChosen = false;
- } else
-#endif
if (overrideEncoding().isNull()) {
userChosen = false;
encoding = response().textEncodingName();
-#if ENABLE(WEB_ARCHIVE)
- if (m_archive && m_archive->type() == Archive::WebArchive)
+#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
+ if (m_archive && m_archive->shouldUseMainResourceEncoding())
encoding = m_archive->mainResource()->textEncoding();
#endif
} else {
@@ -839,68 +897,64 @@ void DocumentLoader::commitData(const char* bytes, size_t length)
m_writer.setEncoding(encoding, userChosen);
}
+
+#if ENABLE(CONTENT_EXTENSIONS)
+ auto& extensionStyleSheets = m_frame->document()->extensionStyleSheets();
+
+ for (auto& pendingStyleSheet : m_pendingNamedContentExtensionStyleSheets)
+ extensionStyleSheets.maybeAddContentExtensionSheet(pendingStyleSheet.key, *pendingStyleSheet.value);
+ for (auto& pendingSelectorEntry : m_pendingContentExtensionDisplayNoneSelectors) {
+ for (const auto& pendingSelector : pendingSelectorEntry.value)
+ extensionStyleSheets.addDisplayNoneSelector(pendingSelectorEntry.key, pendingSelector.first, pendingSelector.second);
+ }
+
+ m_pendingNamedContentExtensionStyleSheets.clear();
+ m_pendingContentExtensionDisplayNoneSelectors.clear();
+#endif
+
ASSERT(m_frame->document()->parsing());
m_writer.addData(bytes, length);
}
-void DocumentLoader::dataReceived(CachedResource* resource, const char* data, int length)
+void DocumentLoader::dataReceived(CachedResource& resource, const char* data, int length)
+{
+ ASSERT_UNUSED(resource, &resource == m_mainResource);
+ dataReceived(data, length);
+}
+
+void DocumentLoader::dataReceived(const char* data, int length)
{
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter && !m_contentFilter->continueAfterDataReceived(data, length))
+ return;
+#endif
+
ASSERT(data);
ASSERT(length);
- ASSERT_UNUSED(resource, resource == m_mainResource);
ASSERT(!m_response.isNull());
-#if USE(CFNETWORK) || PLATFORM(MAC)
- // Workaround for <rdar://problem/6060782>
- if (m_response.isNull())
- m_response = ResourceResponse(URL(), "text/html", 0, String(), String());
-#endif
-
// There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
// See <rdar://problem/6304600> for more details.
#if !USE(CF)
ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
#endif
-#if USE(CONTENT_FILTERING)
- bool loadWasBlockedBeforeFinishing = false;
- if (m_contentFilter && m_contentFilter->needsMoreData()) {
- m_contentFilter->addData(data, length);
-
- if (m_contentFilter->needsMoreData()) {
- // Since the filter still needs more data to make a decision,
- // avoid committing this data to prevent partial rendering of
- // content that might later be blocked.
- return;
- }
-
- data = m_contentFilter->getReplacementData(length);
- loadWasBlockedBeforeFinishing = m_contentFilter->didBlockData();
-
- if (loadWasBlockedBeforeFinishing)
- setContentFilterForBlockedLoad(m_contentFilter);
- }
-#endif
-
if (m_identifierForLoadWithoutResourceLoader)
frameLoader()->notifier().dispatchDidReceiveData(this, m_identifierForLoadWithoutResourceLoader, data, length, -1);
m_applicationCacheHost->mainResourceDataReceived(data, length, -1, false);
- m_timeOfLastDataReceived = monotonicallyIncreasingTime();
+ m_timeOfLastDataReceived = MonotonicTime::now();
if (!isMultipartReplacingLoad())
commitLoad(data, length);
-
-#if USE(CONTENT_FILTERING)
- if (loadWasBlockedBeforeFinishing)
- cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
-#endif
}
void DocumentLoader::setupForReplace()
{
if (!mainResourceData())
return;
+
+ frameLoader()->client().willReplaceMultipartContent();
maybeFinishLoadingMultipartContent();
maybeCreateArchive();
@@ -924,14 +978,19 @@ void DocumentLoader::checkLoadComplete()
m_frame->document()->domWindow()->finishedLoading();
}
-void DocumentLoader::setFrame(Frame* frame)
+void DocumentLoader::attachToFrame(Frame& frame)
{
- if (m_frame == frame)
+ if (m_frame == &frame)
return;
- ASSERT(frame && !m_frame);
- m_frame = frame;
- m_writer.setFrame(frame);
+
+ ASSERT(!m_frame);
+ m_frame = &frame;
+ m_writer.setFrame(&frame);
attachToFrame();
+
+#ifndef NDEBUG
+ m_hasEverBeenAttached = true;
+#endif
}
void DocumentLoader::attachToFrame()
@@ -941,30 +1000,43 @@ void DocumentLoader::attachToFrame()
void DocumentLoader::detachFromFrame()
{
- ASSERT(m_frame);
- RefPtr<Frame> protectFrame(m_frame);
- Ref<DocumentLoader> protectLoader(*this);
+#ifndef NDEBUG
+ if (m_hasEverBeenAttached)
+ ASSERT_WITH_MESSAGE(m_frame, "detachFromFrame() is being called on a DocumentLoader twice without an attachToFrame() inbetween");
+ else
+ ASSERT_WITH_MESSAGE(m_frame, "detachFromFrame() is being called on a DocumentLoader that has never attached to any Frame");
+#endif
+ RefPtr<Frame> protectedFrame(m_frame);
+ Ref<DocumentLoader> protectedThis(*this);
// It never makes sense to have a document loader that is detached from its
- // frame have any loads active, so go ahead and kill all the loads.
+ // frame have any loads active, so kill all the loads.
stopLoading();
- if (m_mainResource && m_mainResource->hasClient(this))
- m_mainResource->removeClient(this);
+ if (m_mainResource && m_mainResource->hasClient(*this))
+ m_mainResource->removeClient(*this);
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter)
+ m_contentFilter->stopFilteringMainResource();
+#endif
- m_applicationCacheHost->setDOMApplicationCache(0);
- InspectorInstrumentation::loaderDetachedFromFrame(m_frame, this);
- m_frame = 0;
+ m_applicationCacheHost->setDOMApplicationCache(nullptr);
+
+ cancelPolicyCheckIfNeeded();
+
+ // Even though we ASSERT at the top of this method that we have an m_frame, we're seeing crashes where m_frame is null.
+ // This means either that a DocumentLoader is detaching twice, or is detaching before ever having attached.
+ // Until we figure out how that is happening, null check m_frame before dereferencing it here.
+ // <rdar://problem/21293082> and https://bugs.webkit.org/show_bug.cgi?id=146786
+ if (m_frame)
+ InspectorInstrumentation::loaderDetachedFromFrame(*m_frame, *this);
+
+ m_frame = nullptr;
}
void DocumentLoader::clearMainResourceLoader()
{
m_loadingMainResource = false;
-#if PLATFORM(IOS)
- // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to ResourceRequest.h.
- m_request.setMainResourceRequest(false);
-#endif
-
if (this == frameLoader()->activeDocumentLoader())
checkLoadComplete();
}
@@ -976,15 +1048,19 @@ bool DocumentLoader::isLoadingInAPISense() const
if (frameLoader()->state() != FrameStateComplete) {
if (m_frame->settings().needsIsLoadingInAPISenseQuirk() && !m_subresourceLoaders.isEmpty())
return true;
-
- Document* doc = m_frame->document();
- if ((isLoadingMainResource() || !m_frame->document()->loadEventFinished()) && isLoading())
+
+ ASSERT(m_frame->document());
+ auto& document = *m_frame->document();
+ if ((isLoadingMainResource() || !document.loadEventFinished()) && isLoading())
return true;
if (m_cachedResourceLoader->requestCount())
return true;
- if (doc->processingLoadEvent())
+ if (document.processingLoadEvent())
+ return true;
+ if (document.hasActiveParser())
return true;
- if (doc->hasActiveParser())
+ auto* scriptableParser = document.scriptableDocumentParser();
+ if (scriptableParser && scriptableParser->hasScriptsWaitingForStylesheets())
return true;
}
return frameLoader()->subframeIsLoading();
@@ -995,65 +1071,55 @@ bool DocumentLoader::maybeCreateArchive()
#if !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
return false;
#else
-
// Give the archive machinery a crack at this document. If the MIME type is not an archive type, it will return 0.
- RefPtr<ResourceBuffer> mainResourceBuffer = mainResourceData();
- m_archive = ArchiveFactory::create(m_response.url(), mainResourceBuffer ? mainResourceBuffer->sharedBuffer() : 0, m_response.mimeType());
+ m_archive = ArchiveFactory::create(m_response.url(), mainResourceData().get(), m_response.mimeType());
if (!m_archive)
return false;
- addAllArchiveResources(m_archive.get());
- ArchiveResource* mainResource = m_archive->mainResource();
- m_parsedArchiveData = mainResource->data();
- m_writer.setMIMEType(mainResource->mimeType());
-
+ addAllArchiveResources(*m_archive);
+ ASSERT(m_archive->mainResource());
+ auto& mainResource = *m_archive->mainResource();
+ m_parsedArchiveData = &mainResource.data();
+ m_writer.setMIMEType(mainResource.mimeType());
+
ASSERT(m_frame->document());
- commitData(mainResource->data()->data(), mainResource->data()->size());
+ commitData(mainResource.data().data(), mainResource.data().size());
return true;
-#endif // !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
+#endif
}
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
-void DocumentLoader::setArchive(PassRefPtr<Archive> archive)
+
+void DocumentLoader::setArchive(Ref<Archive>&& archive)
{
- m_archive = archive;
- addAllArchiveResources(m_archive.get());
+ m_archive = WTFMove(archive);
+ addAllArchiveResources(*m_archive);
}
-void DocumentLoader::addAllArchiveResources(Archive* archive)
+void DocumentLoader::addAllArchiveResources(Archive& archive)
{
if (!m_archiveResourceCollection)
- m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
-
- ASSERT(archive);
- if (!archive)
- return;
-
+ m_archiveResourceCollection = std::make_unique<ArchiveResourceCollection>();
m_archiveResourceCollection->addAllResources(archive);
}
// FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
// Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
-void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
+void DocumentLoader::addArchiveResource(Ref<ArchiveResource>&& resource)
{
if (!m_archiveResourceCollection)
- m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
-
- ASSERT(resource);
- if (!resource)
- return;
-
- m_archiveResourceCollection->addResource(resource);
+ m_archiveResourceCollection = std::make_unique<ArchiveResourceCollection>();
+ m_archiveResourceCollection->addResource(WTFMove(resource));
}
-PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName, const URL& url)
+RefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName, const URL& url)
{
- return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName, url) : PassRefPtr<Archive>(0);
+ return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName, url) : nullptr;
}
void DocumentLoader::clearArchiveResources()
{
- m_archiveResourceCollection.clear();
+ m_archiveResourceCollection = nullptr;
m_substituteResourceDeliveryTimer.stop();
}
@@ -1061,116 +1127,88 @@ SharedBuffer* DocumentLoader::parsedArchiveData() const
{
return m_parsedArchiveData.get();
}
+
#endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
ArchiveResource* DocumentLoader::archiveResourceForURL(const URL& url) const
{
if (!m_archiveResourceCollection)
- return 0;
-
- ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url);
-
- return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0;
+ return nullptr;
+ auto* resource = m_archiveResourceCollection->archiveResourceForURL(url);
+ if (!resource || resource->shouldIgnoreWhenUnarchiving())
+ return nullptr;
+ return resource;
}
-PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const
+RefPtr<ArchiveResource> DocumentLoader::mainResource() const
{
- const ResourceResponse& r = response();
-
- RefPtr<ResourceBuffer> mainResourceBuffer = mainResourceData();
- RefPtr<SharedBuffer> data = mainResourceBuffer ? mainResourceBuffer->sharedBuffer() : 0;
+ RefPtr<SharedBuffer> data = mainResourceData();
if (!data)
data = SharedBuffer::create();
-
- return ArchiveResource::create(data, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree().uniqueName());
+ auto& response = this->response();
+ return ArchiveResource::create(WTFMove(data), response.url(), response.mimeType(), response.textEncodingName(), frame()->tree().uniqueName());
}
-PassRefPtr<ArchiveResource> DocumentLoader::subresource(const URL& url) const
+RefPtr<ArchiveResource> DocumentLoader::subresource(const URL& url) const
{
if (!isCommitted())
- return 0;
+ return nullptr;
- CachedResource* resource = m_cachedResourceLoader->cachedResource(url);
+ auto* resource = m_cachedResourceLoader->cachedResource(url);
if (!resource || !resource->isLoaded())
return archiveResourceForURL(url);
if (resource->type() == CachedResource::MainResource)
- return 0;
+ return nullptr;
- // FIXME: This has the side effect of making the resource non-purgeable.
- // It would be better if it didn't have this permanent effect.
- if (!resource->makePurgeable(false))
- return 0;
-
- ResourceBuffer* data = resource->resourceBuffer();
+ auto* data = resource->resourceBuffer();
if (!data)
- return 0;
+ return nullptr;
- return ArchiveResource::create(data->sharedBuffer(), url, resource->response());
+ return ArchiveResource::create(data, url, resource->response());
}
-void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource>>& subresources) const
+Vector<Ref<ArchiveResource>> DocumentLoader::subresources() const
{
if (!isCommitted())
- return;
+ return { };
- const CachedResourceLoader::DocumentResourceMap& allResources = m_cachedResourceLoader->allCachedResources();
- CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
- for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
- RefPtr<ArchiveResource> subresource = this->subresource(URL(ParsedURLString, it->value->url()));
- if (subresource)
- subresources.append(subresource.release());
+ Vector<Ref<ArchiveResource>> subresources;
+ for (auto& handle : m_cachedResourceLoader->allCachedResources().values()) {
+ if (auto subresource = this->subresource({ ParsedURLString, handle->url() }))
+ subresources.append(subresource.releaseNonNull());
}
-
- return;
+ return subresources;
}
void DocumentLoader::deliverSubstituteResourcesAfterDelay()
{
if (m_pendingSubstituteResources.isEmpty())
return;
- ASSERT(m_frame && m_frame->page());
+ ASSERT(m_frame);
+ ASSERT(m_frame->page());
if (m_frame->page()->defersLoading())
return;
+
if (!m_substituteResourceDeliveryTimer.isActive())
m_substituteResourceDeliveryTimer.startOneShot(0);
}
-void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>&)
+void DocumentLoader::substituteResourceDeliveryTimerFired()
{
if (m_pendingSubstituteResources.isEmpty())
return;
- ASSERT(m_frame && m_frame->page());
+ ASSERT(m_frame);
+ ASSERT(m_frame->page());
if (m_frame->page()->defersLoading())
return;
- SubstituteResourceMap copy;
- copy.swap(m_pendingSubstituteResources);
-
- SubstituteResourceMap::const_iterator end = copy.end();
- for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) {
- RefPtr<ResourceLoader> loader = it->key;
- SubstituteResource* resource = it->value.get();
-
- if (resource) {
- SharedBuffer* data = resource->data();
-
- loader->didReceiveResponse(resource->response());
-
- // Calling ResourceLoader::didReceiveResponse can end up cancelling the load,
- // so we need to check if the loader has reached its terminal state.
- if (loader->reachedTerminalState())
- return;
-
- loader->didReceiveData(data->data(), data->size(), data->size(), DataPayloadWholeResource);
-
- // Calling ResourceLoader::didReceiveData can end up cancelling the load,
- // so we need to check if the loader has reached its terminal state.
- if (loader->reachedTerminalState())
- return;
-
- loader->didFinishLoading(0);
- } else {
+ auto pendingSubstituteResources = WTFMove(m_pendingSubstituteResources);
+ for (auto& pendingSubstituteResource : pendingSubstituteResources) {
+ auto& loader = pendingSubstituteResource.key;
+ if (auto& resource = pendingSubstituteResource.value)
+ resource->deliver(*loader);
+ else {
// A null resource means that we should fail the load.
// FIXME: Maybe we should use another error here - something like "not in cache".
loader->didFail(loader->cannotShowURLError());
@@ -1179,10 +1217,12 @@ void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>&
}
#ifndef NDEBUG
+
bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const
{
return m_pendingSubstituteResources.contains(loader);
}
+
#endif
void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader)
@@ -1195,37 +1235,41 @@ void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader)
}
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
-bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request)
+
+bool DocumentLoader::scheduleArchiveLoad(ResourceLoader& loader, const ResourceRequest& request)
{
- if (ArchiveResource* resource = archiveResourceForURL(request.url())) {
- m_pendingSubstituteResources.set(loader, resource);
- deliverSubstituteResourcesAfterDelay();
+ if (auto* resource = archiveResourceForURL(request.url())) {
+ scheduleSubstituteResourceLoad(loader, *resource);
return true;
}
if (!m_archive)
return false;
- switch (m_archive->type()) {
#if ENABLE(WEB_ARCHIVE)
- case Archive::WebArchive:
- // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive.
- return m_frame->settings().webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType());
+ // The idea of WebArchiveDebugMode is that we should fail instead of trying to fetch from the network.
+ // Returning true ensures the caller will not try to fetch from the network.
+ if (m_frame->settings().webArchiveDebugModeEnabled() && responseMIMEType() == "application/x-webarchive")
+ return true;
#endif
-#if ENABLE(MHTML)
- case Archive::MHTML:
- return true; // Always fail the load for resources not included in the MHTML.
+
+ // If we want to load from the archive only, then we should always return true so that the caller
+ // does not try to fetch form the network.
+ return m_archive->shouldLoadFromArchiveOnly();
+}
+
#endif
- default:
- return false;
- }
+
+void DocumentLoader::scheduleSubstituteResourceLoad(ResourceLoader& loader, SubstituteResource& resource)
+{
+ m_pendingSubstituteResources.set(&loader, &resource);
+ deliverSubstituteResourcesAfterDelay();
}
-#endif // ENABLE(WEB_ARCHIVE)
-void DocumentLoader::addResponse(const ResourceResponse& r)
+void DocumentLoader::addResponse(const ResourceResponse& response)
{
if (!m_stopRecordingResponses)
- m_responses.append(r);
+ m_responses.append(response);
}
void DocumentLoader::stopRecordingResponses()
@@ -1260,52 +1304,29 @@ bool DocumentLoader::urlForHistoryReflectsFailure() const
return m_substituteData.isValid() || m_response.httpStatusCode() >= 400;
}
-const URL& DocumentLoader::originalURL() const
-{
- return m_originalRequestCopy.url();
-}
-
-const URL& DocumentLoader::requestURL() const
-{
- return request().url();
-}
-
-const URL& DocumentLoader::responseURL() const
-{
- return m_response.url();
-}
-
URL DocumentLoader::documentURL() const
{
- URL url = substituteData().responseURL();
+ URL url = substituteData().response().url();
#if ENABLE(WEB_ARCHIVE)
- if (url.isEmpty() && m_archive && m_archive->type() == Archive::WebArchive)
+ if (url.isEmpty() && m_archive && m_archive->shouldUseMainResourceURL())
url = m_archive->mainResource()->url();
#endif
if (url.isEmpty())
- url = requestURL();
+ url = m_request.url();
if (url.isEmpty())
url = m_response.url();
return url;
}
-const String& DocumentLoader::responseMIMEType() const
-{
- return m_response.mimeType();
-}
-
#if PLATFORM(IOS)
+
// FIXME: This method seems to violate the encapsulation of this class.
void DocumentLoader::setResponseMIMEType(const String& responseMimeType)
{
m_response.setMimeType(responseMimeType);
}
-#endif
-const URL& DocumentLoader::unreachableURL() const
-{
- return m_substituteData.failingURL();
-}
+#endif
void DocumentLoader::setDefersLoading(bool defers)
{
@@ -1335,6 +1356,7 @@ void DocumentLoader::stopLoadingPlugIns()
void DocumentLoader::stopLoadingSubresources()
{
cancelAll(m_subresourceLoaders);
+ ASSERT(m_subresourceLoaders.isEmpty());
}
void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
@@ -1346,28 +1368,41 @@ void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
// if we are just starting the main resource load.
if (!m_gotFirstByte)
return;
- ASSERT(!m_subresourceLoaders.contains(loader));
+ ASSERT(loader->identifier());
+ ASSERT(!m_subresourceLoaders.contains(loader->identifier()));
ASSERT(!mainResourceLoader() || mainResourceLoader() != loader);
- m_subresourceLoaders.add(loader);
+
+ // A page in the PageCache or about to enter PageCache should not be able to start loads.
+ ASSERT_WITH_SECURITY_IMPLICATION(!document() || document()->pageCacheState() == Document::NotInPageCache);
+
+ m_subresourceLoaders.add(loader->identifier(), loader);
}
void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
{
- if (!m_subresourceLoaders.remove(loader))
+ ASSERT(loader->identifier());
+
+ if (!m_subresourceLoaders.remove(loader->identifier()))
return;
checkLoadComplete();
if (Frame* frame = m_frame)
frame->loader().checkLoadComplete();
}
-void DocumentLoader::addPlugInStreamLoader(ResourceLoader* loader)
+void DocumentLoader::addPlugInStreamLoader(ResourceLoader& loader)
{
- m_plugInStreamLoaders.add(loader);
+ ASSERT(loader.identifier());
+ ASSERT(!m_plugInStreamLoaders.contains(loader.identifier()));
+
+ m_plugInStreamLoaders.add(loader.identifier(), &loader);
}
-void DocumentLoader::removePlugInStreamLoader(ResourceLoader* loader)
+void DocumentLoader::removePlugInStreamLoader(ResourceLoader& loader)
{
- m_plugInStreamLoaders.remove(loader);
+ ASSERT(loader.identifier());
+ ASSERT(&loader == m_plugInStreamLoaders.get(loader.identifier()));
+
+ m_plugInStreamLoaders.remove(loader.identifier());
checkLoadComplete();
}
@@ -1378,14 +1413,18 @@ bool DocumentLoader::isMultipartReplacingLoad() const
bool DocumentLoader::maybeLoadEmpty()
{
- bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol()));
- if (!shouldLoadEmpty && !frameLoader()->client().representationExistsForURLScheme(m_request.url().protocol()))
+ bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol().toStringWithoutCopying()));
+ if (!shouldLoadEmpty && !frameLoader()->client().representationExistsForURLScheme(m_request.url().protocol().toStringWithoutCopying()))
return false;
- if (m_request.url().isEmpty() && !frameLoader()->stateMachine()->creatingInitialEmptyDocument())
+ if (m_request.url().isEmpty() && !frameLoader()->stateMachine().creatingInitialEmptyDocument()) {
m_request.setURL(blankURL());
- String mimeType = shouldLoadEmpty ? "text/html" : frameLoader()->client().generatedMIMETypeForURLScheme(m_request.url().protocol());
- m_response = ResourceResponse(m_request.url(), mimeType, 0, String(), String());
+ if (isLoadingMainResource())
+ frameLoader()->client().dispatchDidChangeProvisionalURL();
+ }
+
+ String mimeType = shouldLoadEmpty ? "text/html" : frameLoader()->client().generatedMIMETypeForURLScheme(m_request.url().protocol().toStringWithoutCopying());
+ m_response = ResourceResponse(m_request.url(), mimeType, 0, String());
finishedLoading(monotonicallyIncreasingTime());
return true;
}
@@ -1393,13 +1432,19 @@ bool DocumentLoader::maybeLoadEmpty()
void DocumentLoader::startLoadingMainResource()
{
m_mainDocumentError = ResourceError();
- timing()->markNavigationStart();
+ timing().markStartTimeAndFetchStart();
ASSERT(!m_mainResource);
ASSERT(!m_loadingMainResource);
m_loadingMainResource = true;
- if (maybeLoadEmpty())
+ if (maybeLoadEmpty()) {
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Returning empty document (frame = %p, main = %d)", m_frame, m_frame ? m_frame->isMainFrame() : false);
return;
+ }
+
+#if ENABLE(CONTENT_FILTERING)
+ m_contentFilter = !m_substituteData.isValid() ? ContentFilter::create(*this) : nullptr;
+#endif
// FIXME: Is there any way the extra fields could have not been added by now?
// If not, it would be great to remove this line of code.
@@ -1407,18 +1452,22 @@ void DocumentLoader::startLoadingMainResource()
// because we pass a wrong loadType (see FIXME in addExtraFieldsToMainResourceRequest()).
frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
- ASSERT(timing()->navigationStart());
- ASSERT(!timing()->fetchStart());
- timing()->markFetchStart();
+ ASSERT(timing().startTime());
+ ASSERT(timing().fetchStart());
+
+ Ref<DocumentLoader> protectedThis(*this); // willSendRequest() may deallocate the provisional loader (which may be us) if it cancels the load.
willSendRequest(m_request, ResourceResponse());
// willSendRequest() may lead to our Frame being detached or cancelling the load via nulling the ResourceRequest.
- if (!m_frame || m_request.isNull())
+ if (!m_frame || m_request.isNull()) {
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Load canceled after willSendRequest (frame = %p, main = %d)", m_frame, m_frame ? m_frame->isMainFrame() : false);
return;
+ }
m_applicationCacheHost->maybeLoadMainResource(m_request, m_substituteData);
- if (m_substituteData.isValid()) {
+ if (m_substituteData.isValid() && m_frame->page()) {
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Returning cached main resource (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
m_identifierForLoadWithoutResourceLoader = m_frame->page()->progress().createUniqueIdentifier();
frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, m_request);
frameLoader()->notifier().dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, m_request, ResourceResponse());
@@ -1426,21 +1475,38 @@ void DocumentLoader::startLoadingMainResource()
return;
}
-#if PLATFORM(IOS)
- // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to ResourceRequest.h.
- m_request.setMainResourceRequest(true);
+ ResourceRequest request(m_request);
+ request.setRequester(ResourceRequest::Requester::Main);
+ // If this is a reload the cache layer might have made the previous request conditional. DocumentLoader can't handle 304 responses itself.
+ request.makeUnconditional();
+
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Starting load (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
+
+ static NeverDestroyed<ResourceLoaderOptions> mainResourceLoadOptions(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientCredentialPolicy::MayAskClientForCredentials, FetchOptions::Credentials::Include, SkipSecurityCheck, FetchOptions::Mode::NoCors, IncludeCertificateInfo, ContentSecurityPolicyImposition::SkipPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching);
+ m_mainResource = m_cachedResourceLoader->requestMainResource(CachedResourceRequest(ResourceRequest(request), mainResourceLoadOptions));
+
+#if ENABLE(CONTENT_EXTENSIONS)
+ if (m_mainResource && m_mainResource->errorOccurred() && m_frame->page() && m_mainResource->resourceError().domain() == ContentExtensions::WebKitContentBlockerDomain) {
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Blocked by content blocker error (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
+ cancelMainResourceLoad(frameLoader()->blockedByContentBlockerError(m_request));
+ return;
+ }
#endif
- ResourceRequest request(m_request);
- static NeverDestroyed<ResourceLoaderOptions> mainResourceLoadOptions(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForAllCredentials, SkipSecurityCheck, UseDefaultOriginRestrictionsForType);
- CachedResourceRequest cachedResourceRequest(request, mainResourceLoadOptions);
- m_mainResource = m_cachedResourceLoader->requestMainResource(cachedResourceRequest);
if (!m_mainResource) {
+ if (!m_request.url().isValid()) {
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Unable to load main resource, URL is invalid (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
+ cancelMainResourceLoad(frameLoader()->client().cannotShowURLError(m_request));
+ return;
+ }
+
+ RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Unable to load main resource, returning empty document (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
+
setRequest(ResourceRequest());
// If the load was aborted by clearing m_request, it's possible the ApplicationCacheHost
// is now in a state where starting an empty load will be inconsistent. Replace it with
// a new ApplicationCacheHost.
- m_applicationCacheHost = adoptPtr(new ApplicationCacheHost(this));
+ m_applicationCacheHost = std::make_unique<ApplicationCacheHost>(*this);
maybeLoadEmpty();
return;
}
@@ -1450,7 +1516,8 @@ void DocumentLoader::startLoadingMainResource()
frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, request);
frameLoader()->notifier().dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, request, ResourceResponse());
}
- m_mainResource->addClient(this);
+
+ becomeMainResourceClient();
// A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those.
if (mainResourceLoader())
@@ -1462,17 +1529,25 @@ void DocumentLoader::startLoadingMainResource()
setRequest(request);
}
-void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError)
+void DocumentLoader::cancelPolicyCheckIfNeeded()
{
- Ref<DocumentLoader> protect(*this);
- ResourceError error = resourceError.isNull() ? frameLoader()->cancelledError(m_request) : resourceError;
+ RELEASE_ASSERT(frameLoader());
- m_dataLoadTimer.stop();
- if (m_waitingForContentPolicy) {
+ if (m_waitingForContentPolicy || m_waitingForNavigationPolicy) {
frameLoader()->policyChecker().cancelCheck();
- ASSERT(m_waitingForContentPolicy);
m_waitingForContentPolicy = false;
+ m_waitingForNavigationPolicy = false;
}
+}
+
+void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError)
+{
+ Ref<DocumentLoader> protectedThis(*this);
+ ResourceError error = resourceError.isNull() ? frameLoader()->cancelledError(m_request) : resourceError;
+
+ m_dataLoadTimer.stop();
+
+ cancelPolicyCheckIfNeeded();
if (mainResourceLoader())
mainResourceLoader()->cancel(error);
@@ -1482,18 +1557,36 @@ void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError)
mainReceivedError(error);
}
+void DocumentLoader::willContinueMainResourceLoadAfterRedirect(const ResourceRequest& newRequest)
+{
+ setRequest(newRequest);
+}
+
void DocumentLoader::clearMainResource()
{
- if (m_mainResource && m_mainResource->hasClient(this))
- m_mainResource->removeClient(this);
+ if (m_mainResource && m_mainResource->hasClient(*this))
+ m_mainResource->removeClient(*this);
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter)
+ m_contentFilter->stopFilteringMainResource();
+#endif
- m_mainResource = 0;
+ m_mainResource = nullptr;
}
void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
{
- m_multipartSubresourceLoaders.add(loader);
- m_subresourceLoaders.remove(loader);
+ unsigned long identifier = loader->identifier();
+ ASSERT(identifier);
+
+ if (!m_multipartSubresourceLoaders.add(identifier, loader).isNewEntry) {
+ ASSERT(m_multipartSubresourceLoaders.get(identifier) == loader);
+ ASSERT(!m_subresourceLoaders.contains(identifier));
+ } else {
+ ASSERT(m_subresourceLoaders.contains(identifier));
+ m_subresourceLoaders.remove(identifier);
+ }
+
checkLoadComplete();
if (Frame* frame = m_frame)
frame->loader().checkLoadComplete();
@@ -1506,7 +1599,7 @@ void DocumentLoader::maybeFinishLoadingMultipartContent()
frameLoader()->setupForReplace();
m_committed = false;
- RefPtr<ResourceBuffer> resourceData = mainResourceData();
+ RefPtr<SharedBuffer> resourceData = mainResourceData();
commitLoad(resourceData->data(), resourceData->size());
}
@@ -1526,13 +1619,13 @@ void DocumentLoader::getIconLoadDecisionForIconURL(const String& urlString)
if (m_iconLoadDecisionCallback)
m_iconLoadDecisionCallback->invalidate();
m_iconLoadDecisionCallback = IconLoadDecisionCallback::create(this, iconLoadDecisionCallback);
- iconDatabase().loadDecisionForIconURL(urlString, m_iconLoadDecisionCallback);
+ iconDatabase().loadDecisionForIconURL(urlString, *m_iconLoadDecisionCallback);
}
void DocumentLoader::continueIconLoadWithDecision(IconLoadDecision decision)
{
ASSERT(m_iconLoadDecisionCallback);
- m_iconLoadDecisionCallback = 0;
+ m_iconLoadDecisionCallback = nullptr;
if (m_frame)
m_frame->loader().icon().continueLoadWithDecision(decision);
}
@@ -1547,47 +1640,109 @@ void DocumentLoader::getIconDataForIconURL(const String& urlString)
if (m_iconDataCallback)
m_iconDataCallback->invalidate();
m_iconDataCallback = IconDataCallback::create(this, iconDataCallback);
- iconDatabase().iconDataForIconURL(urlString, m_iconDataCallback);
+ iconDatabase().iconDataForIconURL(urlString, *m_iconDataCallback);
}
-void DocumentLoader::handledOnloadEvents()
+void DocumentLoader::startIconLoading()
{
- m_wasOnloadHandled = true;
- applicationCacheHost()->stopDeferringEvents();
+ ASSERT(m_frame->loader().client().useIconLoadingClient());
+
+ static uint64_t nextIconCallbackID = 1;
+
+ auto* document = this->document();
+ if (!document)
+ return;
+
+ Vector<LinkIcon> icons = LinkIconCollector { *document }.iconsOfTypes({ LinkIconType::Favicon, LinkIconType::TouchIcon, LinkIconType::TouchPrecomposedIcon });
+
+ if (icons.isEmpty())
+ icons.append({ m_frame->document()->completeURL(ASCIILiteral("/favicon.ico")), LinkIconType::Favicon, String(), std::nullopt });
+
+ for (auto& icon : icons) {
+ auto result = m_iconsPendingLoadDecision.add(nextIconCallbackID++, icon);
+ m_frame->loader().client().getLoadDecisionForIcon(icon, result.iterator->key);
+ }
}
-#if USE(CONTENT_FILTERING)
-void DocumentLoader::setContentFilterForBlockedLoad(PassRefPtr<ContentFilter> contentFilter)
+void DocumentLoader::didGetLoadDecisionForIcon(bool decision, uint64_t loadIdentifier, uint64_t newCallbackID)
{
- ASSERT(!m_contentFilterForBlockedLoad);
- ASSERT(contentFilter);
- ASSERT(contentFilter->didBlockData());
- m_contentFilterForBlockedLoad = contentFilter;
+ auto icon = m_iconsPendingLoadDecision.take(loadIdentifier);
+ if (!decision || icon.url.isEmpty() || !m_frame)
+ return;
+
+ auto iconLoader = std::make_unique<IconLoader>(*this, icon.url);
+ iconLoader->startLoading();
+ m_iconLoaders.set(WTFMove(iconLoader), newCallbackID);
}
-bool DocumentLoader::handleContentFilterRequest(const ResourceRequest& request)
+void DocumentLoader::finishedLoadingIcon(IconLoader& loader, SharedBuffer* buffer)
{
- // FIXME: Remove PLATFORM(IOS)-guard once we upstream ContentFilterIOS.mm and
- // implement ContentFilter::requestUnblockAndDispatchIfSuccessful() for Mac.
-#if PLATFORM(IOS)
- if (!m_contentFilterForBlockedLoad)
- return false;
+ auto loadIdentifier = m_iconLoaders.take(&loader);
+ ASSERT(loadIdentifier);
- if (!request.url().protocolIs(ContentFilter::scheme()))
- return false;
+ m_frame->loader().client().finishedLoadingIcon(loadIdentifier, buffer);
+}
- if (equalIgnoringCase(request.url().host(), "unblock")) {
- // Tell the FrameLoader to reload if the unblock is successful.
- m_contentFilterForBlockedLoad->requestUnblockAndDispatchIfSuccessful(bind(&FrameLoader::reload, &(m_frame->loader()), false));
- return true;
- }
+void DocumentLoader::dispatchOnloadEvents()
+{
+ m_wasOnloadDispatched = true;
+ m_applicationCacheHost->stopDeferringEvents();
+}
- return false;
-#else
- UNUSED_PARAM(request);
- return false;
+void DocumentLoader::setTriggeringAction(const NavigationAction& action)
+{
+ m_triggeringAction = action.copyWithShouldOpenExternalURLsPolicy(m_frame ? shouldOpenExternalURLsPolicyToPropagate() : m_shouldOpenExternalURLsPolicy);
+}
+
+ShouldOpenExternalURLsPolicy DocumentLoader::shouldOpenExternalURLsPolicyToPropagate() const
+{
+ if (!m_frame || !m_frame->isMainFrame())
+ return ShouldOpenExternalURLsPolicy::ShouldNotAllow;
+
+ return m_shouldOpenExternalURLsPolicy;
+}
+
+void DocumentLoader::becomeMainResourceClient()
+{
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilter)
+ m_contentFilter->startFilteringMainResource(*m_mainResource);
#endif
+ m_mainResource->addClient(*this);
+}
+
+#if ENABLE(CONTENT_EXTENSIONS)
+void DocumentLoader::addPendingContentExtensionSheet(const String& identifier, StyleSheetContents& sheet)
+{
+ ASSERT(!m_gotFirstByte);
+ m_pendingNamedContentExtensionStyleSheets.set(identifier, &sheet);
+}
+
+void DocumentLoader::addPendingContentExtensionDisplayNoneSelector(const String& identifier, const String& selector, uint32_t selectorID)
+{
+ ASSERT(!m_gotFirstByte);
+ auto addResult = m_pendingContentExtensionDisplayNoneSelectors.add(identifier, Vector<std::pair<String, uint32_t>>());
+ addResult.iterator->value.append(std::make_pair(selector, selectorID));
}
#endif
+bool DocumentLoader::isAlwaysOnLoggingAllowed() const
+{
+ return !m_frame || m_frame->isAlwaysOnLoggingAllowed();
+}
+
+#if USE(QUICK_LOOK)
+
+void DocumentLoader::setPreviewConverter(std::unique_ptr<PreviewConverter>&& previewConverter)
+{
+ m_previewConverter = WTFMove(previewConverter);
+}
+
+PreviewConverter* DocumentLoader::previewConverter() const
+{
+ return m_previewConverter.get();
+}
+
+#endif
+
} // namespace WebCore
diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h
index 866fd7caa..138883f82 100644
--- a/Source/WebCore/loader/DocumentLoader.h
+++ b/Source/WebCore/loader/DocumentLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,20 +27,21 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DocumentLoader_h
-#define DocumentLoader_h
+#pragma once
#include "CachedRawResourceClient.h"
#include "CachedResourceHandle.h"
-#include "DocumentLoadTiming.h"
#include "DocumentWriter.h"
#include "IconDatabaseBase.h"
+#include "LinkIcon.h"
+#include "LoadTiming.h"
#include "NavigationAction.h"
#include "ResourceError.h"
#include "ResourceLoaderOptions.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "StringWithDirection.h"
+#include "StyleSheetContents.h"
#include "SubstituteData.h"
#include "Timer.h"
#include <wtf/HashSet.h>
@@ -51,392 +52,524 @@
#include <wtf/RunLoopTimer.h>
#endif
-namespace WTF {
-class SchedulePair;
-}
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+#include <wtf/SchedulePair.h>
+#endif
namespace WebCore {
- class ApplicationCacheHost;
-#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- class Archive;
-#endif
- class ArchiveResource;
- class ArchiveResourceCollection;
- class CachedRawResource;
- class CachedResourceLoader;
- class ContentFilter;
- class FormState;
- class Frame;
- class FrameLoader;
- class Page;
- class ResourceBuffer;
- class ResourceLoader;
- class SharedBuffer;
- class SubstituteResource;
-
- typedef HashSet<RefPtr<ResourceLoader>> ResourceLoaderSet;
- typedef Vector<ResourceResponse> ResponseVector;
-
- class DocumentLoader : public RefCounted<DocumentLoader>, private CachedRawResourceClient {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- static PassRefPtr<DocumentLoader> create(const ResourceRequest& request, const SubstituteData& data)
- {
- return adoptRef(new DocumentLoader(request, data));
- }
- virtual ~DocumentLoader();
-
- void setFrame(Frame*);
- Frame* frame() const { return m_frame; }
-
- virtual void attachToFrame();
- virtual void detachFromFrame();
-
- FrameLoader* frameLoader() const;
- ResourceLoader* mainResourceLoader() const;
- PassRefPtr<ResourceBuffer> mainResourceData() const;
-
- DocumentWriter& writer() const { return m_writer; }
-
- const ResourceRequest& originalRequest() const;
- const ResourceRequest& originalRequestCopy() const;
-
- const ResourceRequest& request() const;
- ResourceRequest& request();
-
- CachedResourceLoader& cachedResourceLoader() { return m_cachedResourceLoader.get(); }
-
- const SubstituteData& substituteData() const { return m_substituteData; }
-
- // FIXME: This is the same as requestURL(). We should remove one of them.
- const URL& url() const;
- const URL& unreachableURL() const;
-
- const URL& originalURL() const;
- const URL& requestURL() const;
- const URL& responseURL() const;
- const String& responseMIMEType() const;
+
+class ApplicationCacheHost;
+class Archive;
+class ArchiveResource;
+class ArchiveResourceCollection;
+class CachedRawResource;
+class CachedResourceLoader;
+class ContentFilter;
+class FormState;
+class Frame;
+class FrameLoader;
+class IconLoader;
+class Page;
+class PreviewConverter;
+class ResourceLoader;
+class SharedBuffer;
+class SubresourceLoader;
+class SubstituteResource;
+
+using ResourceLoaderMap = HashMap<unsigned long, RefPtr<ResourceLoader>>;
+
+enum class AutoplayPolicy {
+ Default, // Uses policies specified in document settings.
+ Allow,
+ AllowWithoutSound,
+ Deny,
+};
+
+class DocumentLoader : public RefCounted<DocumentLoader>, private CachedRawResourceClient {
+ WTF_MAKE_FAST_ALLOCATED;
+ friend class ContentFilter;
+public:
+ static Ref<DocumentLoader> create(const ResourceRequest& request, const SubstituteData& data)
+ {
+ return adoptRef(*new DocumentLoader(request, data));
+ }
+ WEBCORE_EXPORT virtual ~DocumentLoader();
+
+ void attachToFrame(Frame&);
+ Frame* frame() const { return m_frame; }
+
+ WEBCORE_EXPORT virtual void detachFromFrame();
+
+ WEBCORE_EXPORT FrameLoader* frameLoader() const;
+ WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const;
+ WEBCORE_EXPORT RefPtr<SharedBuffer> mainResourceData() const;
+
+ DocumentWriter& writer() const { return m_writer; }
+
+ const ResourceRequest& originalRequest() const;
+ const ResourceRequest& originalRequestCopy() const;
+
+ const ResourceRequest& request() const;
+ ResourceRequest& request();
+
+ CachedResourceLoader& cachedResourceLoader() { return m_cachedResourceLoader; }
+
+ const SubstituteData& substituteData() const { return m_substituteData; }
+
+ const URL& url() const;
+ const URL& unreachableURL() const;
+
+ const URL& originalURL() const;
+ const URL& responseURL() const;
+ const String& responseMIMEType() const;
#if PLATFORM(IOS)
- // FIXME: This method seems to violate the encapsulation of this class.
- void setResponseMIMEType(const String&);
+ // FIXME: This method seems to violate the encapsulation of this class.
+ WEBCORE_EXPORT void setResponseMIMEType(const String&);
#endif
+ const String& currentContentType() const;
+ void replaceRequestURLForSameDocumentNavigation(const URL&);
+ bool isStopping() const { return m_isStopping; }
+ void stopLoading();
+ void setCommitted(bool committed) { m_committed = committed; }
+ bool isCommitted() const { return m_committed; }
+ WEBCORE_EXPORT bool isLoading() const;
- void replaceRequestURLForSameDocumentNavigation(const URL&);
- bool isStopping() const { return m_isStopping; }
- void stopLoading();
- void setCommitted(bool committed) { m_committed = committed; }
- bool isCommitted() const { return m_committed; }
- bool isLoading() const;
+ const ResourceError& mainDocumentError() const { return m_mainDocumentError; }
- const ResourceError& mainDocumentError() const { return m_mainDocumentError; }
-
- const ResourceResponse& response() const { return m_response; }
+ const ResourceResponse& response() const { return m_response; }
#if PLATFORM(IOS)
- // FIXME: This method seems to violate the encapsulation of this class.
- void setResponse(const ResourceResponse& response) { m_response = response; }
+ // FIXME: This method seems to violate the encapsulation of this class.
+ void setResponse(const ResourceResponse& response) { m_response = response; }
#endif
- bool isClientRedirect() const { return m_isClientRedirect; }
- void setIsClientRedirect(bool isClientRedirect) { m_isClientRedirect = isClientRedirect; }
- void handledOnloadEvents();
- bool wasOnloadHandled() { return m_wasOnloadHandled; }
- bool isLoadingInAPISense() const;
- void setTitle(const StringWithDirection&);
- const String& overrideEncoding() const { return m_overrideEncoding; }
-
-#if PLATFORM(MAC)
- void schedule(WTF::SchedulePair*);
- void unschedule(WTF::SchedulePair*);
+ bool isClientRedirect() const { return m_isClientRedirect; }
+ void setIsClientRedirect(bool isClientRedirect) { m_isClientRedirect = isClientRedirect; }
+ void dispatchOnloadEvents();
+ bool wasOnloadDispatched() { return m_wasOnloadDispatched; }
+ WEBCORE_EXPORT bool isLoadingInAPISense() const;
+ WEBCORE_EXPORT void setTitle(const StringWithDirection&);
+ const String& overrideEncoding() const { return m_overrideEncoding; }
+
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ void schedule(SchedulePair&);
+ void unschedule(SchedulePair&);
#endif
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- void setArchive(PassRefPtr<Archive>);
- void addAllArchiveResources(Archive*);
- void addArchiveResource(PassRefPtr<ArchiveResource>);
- PassRefPtr<Archive> popArchiveForSubframe(const String& frameName, const URL&);
- SharedBuffer* parsedArchiveData() const;
+ void setArchive(Ref<Archive>&&);
+ WEBCORE_EXPORT void addAllArchiveResources(Archive&);
+ WEBCORE_EXPORT void addArchiveResource(Ref<ArchiveResource>&&);
+ RefPtr<Archive> popArchiveForSubframe(const String& frameName, const URL&);
+ WEBCORE_EXPORT SharedBuffer* parsedArchiveData() const;
- bool scheduleArchiveLoad(ResourceLoader*, const ResourceRequest&);
-#endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
+ WEBCORE_EXPORT bool scheduleArchiveLoad(ResourceLoader&, const ResourceRequest&);
+#endif
- // Return the ArchiveResource for the URL only when loading an Archive
- ArchiveResource* archiveResourceForURL(const URL&) const;
+ void scheduleSubstituteResourceLoad(ResourceLoader&, SubstituteResource&);
- PassRefPtr<ArchiveResource> mainResource() const;
+ // Return the ArchiveResource for the URL only when loading an Archive
+ WEBCORE_EXPORT ArchiveResource* archiveResourceForURL(const URL&) const;
- // Return an ArchiveResource for the URL, either creating from live data or
- // pulling from the ArchiveResourceCollection
- PassRefPtr<ArchiveResource> subresource(const URL&) const;
- void getSubresources(Vector<PassRefPtr<ArchiveResource>>&) const;
+ WEBCORE_EXPORT RefPtr<ArchiveResource> mainResource() const;
+ // Return an ArchiveResource for the URL, either creating from live data or
+ // pulling from the ArchiveResourceCollection.
+ WEBCORE_EXPORT RefPtr<ArchiveResource> subresource(const URL&) const;
+
+ WEBCORE_EXPORT Vector<Ref<ArchiveResource>> subresources() const;
#ifndef NDEBUG
- bool isSubstituteLoadPending(ResourceLoader*) const;
-#endif
- void cancelPendingSubstituteLoad(ResourceLoader*);
-
- void addResponse(const ResourceResponse&);
- const ResponseVector& responses() const { return m_responses; }
-
- const NavigationAction& triggeringAction() const { return m_triggeringAction; }
- void setTriggeringAction(const NavigationAction& action) { m_triggeringAction = action; }
- void setOverrideEncoding(const String& encoding) { m_overrideEncoding = encoding; }
- void setLastCheckedRequest(const ResourceRequest& request) { m_lastCheckedRequest = request; }
- const ResourceRequest& lastCheckedRequest() { return m_lastCheckedRequest; }
-
- void stopRecordingResponses();
- const StringWithDirection& title() const { return m_pageTitle; }
-
- URL urlForHistory() const;
- bool urlForHistoryReflectsFailure() const;
-
- // These accessors accommodate WebCore's somewhat fickle custom of creating history
- // items for redirects, but only sometimes. For "source" and "destination",
- // these accessors return the URL that would have been used if a history
- // item were created. This allows WebKit to link history items reflecting
- // redirects into a chain from start to finish.
- String clientRedirectSourceForHistory() const { return m_clientRedirectSourceForHistory; } // null if no client redirect occurred.
- String clientRedirectDestinationForHistory() const { return urlForHistory(); }
- void setClientRedirectSourceForHistory(const String& clientRedirectSourceForHistory) { m_clientRedirectSourceForHistory = clientRedirectSourceForHistory; }
-
- String serverRedirectSourceForHistory() const { return (urlForHistory() == url() || url() == blankURL()) ? String() : urlForHistory().string(); } // null if no server redirect occurred.
- String serverRedirectDestinationForHistory() const { return url(); }
-
- bool didCreateGlobalHistoryEntry() const { return m_didCreateGlobalHistoryEntry; }
- void setDidCreateGlobalHistoryEntry(bool didCreateGlobalHistoryEntry) { m_didCreateGlobalHistoryEntry = didCreateGlobalHistoryEntry; }
-
- bool subresourceLoadersArePageCacheAcceptable() const { return m_subresourceLoadersArePageCacheAcceptable; }
-
- void setDefersLoading(bool);
- void setMainResourceDataBufferingPolicy(DataBufferingPolicy);
-
- void startLoadingMainResource();
- void cancelMainResourceLoad(const ResourceError&);
-
- // Support iconDatabase in synchronous mode.
- void iconLoadDecisionAvailable();
-
- // Support iconDatabase in asynchronous mode.
- void continueIconLoadWithDecision(IconLoadDecision);
- void getIconLoadDecisionForIconURL(const String&);
- void getIconDataForIconURL(const String&);
-
- bool isLoadingMainResource() const { return m_loadingMainResource; }
- bool isLoadingMultipartContent() const { return m_isLoadingMultipartContent; }
-
- void stopLoadingPlugIns();
- void stopLoadingSubresources();
-
- void addSubresourceLoader(ResourceLoader*);
- void removeSubresourceLoader(ResourceLoader*);
- void addPlugInStreamLoader(ResourceLoader*);
- void removePlugInStreamLoader(ResourceLoader*);
-
- void subresourceLoaderFinishedLoadingOnePart(ResourceLoader*);
-
- void setDeferMainResourceDataLoad(bool defer) { m_deferMainResourceDataLoad = defer; }
-
- void didTellClientAboutLoad(const String& url)
- {
-#if !PLATFORM(MAC)
- // Don't include data urls here, as if a lot of data is loaded
- // that way, we hold on to the (large) url string for too long.
- if (protocolIs(url, "data"))
- return;
+ bool isSubstituteLoadPending(ResourceLoader*) const;
#endif
- if (!url.isEmpty())
- m_resourcesClientKnowsAbout.add(url);
- }
- bool haveToldClientAboutLoad(const String& url) { return m_resourcesClientKnowsAbout.contains(url); }
- void recordMemoryCacheLoadForFutureClientNotification(const ResourceRequest&);
- void takeMemoryCacheLoadsForClientNotification(Vector<ResourceRequest>& loads);
+ void cancelPendingSubstituteLoad(ResourceLoader*);
+
+ void addResponse(const ResourceResponse&);
+ const Vector<ResourceResponse>& responses() const { return m_responses; }
+
+ const NavigationAction& triggeringAction() const { return m_triggeringAction; }
+ void setTriggeringAction(const NavigationAction&);
+ void setOverrideEncoding(const String& encoding) { m_overrideEncoding = encoding; }
+ void setLastCheckedRequest(const ResourceRequest& request) { m_lastCheckedRequest = request; }
+ const ResourceRequest& lastCheckedRequest() { return m_lastCheckedRequest; }
+
+ void stopRecordingResponses();
+ const StringWithDirection& title() const { return m_pageTitle; }
+
+ WEBCORE_EXPORT URL urlForHistory() const;
+ WEBCORE_EXPORT bool urlForHistoryReflectsFailure() const;
+
+ // These accessors accommodate WebCore's somewhat fickle custom of creating history
+ // items for redirects, but only sometimes. For "source" and "destination",
+ // these accessors return the URL that would have been used if a history
+ // item were created. This allows WebKit to link history items reflecting
+ // redirects into a chain from start to finish.
+ String clientRedirectSourceForHistory() const { return m_clientRedirectSourceForHistory; } // null if no client redirect occurred.
+ String clientRedirectDestinationForHistory() const { return urlForHistory(); }
+ void setClientRedirectSourceForHistory(const String& clientRedirectSourceForHistory) { m_clientRedirectSourceForHistory = clientRedirectSourceForHistory; }
+
+ String serverRedirectSourceForHistory() const { return (urlForHistory() == url() || url() == blankURL()) ? String() : urlForHistory().string(); } // null if no server redirect occurred.
+ String serverRedirectDestinationForHistory() const { return url(); }
+
+ bool didCreateGlobalHistoryEntry() const { return m_didCreateGlobalHistoryEntry; }
+ void setDidCreateGlobalHistoryEntry(bool didCreateGlobalHistoryEntry) { m_didCreateGlobalHistoryEntry = didCreateGlobalHistoryEntry; }
+
+ bool subresourceLoadersArePageCacheAcceptable() const { return m_subresourceLoadersArePageCacheAcceptable; }
+
+ void setDefersLoading(bool);
+ void setMainResourceDataBufferingPolicy(DataBufferingPolicy);
+
+ void startLoadingMainResource();
+ WEBCORE_EXPORT void cancelMainResourceLoad(const ResourceError&);
+ void willContinueMainResourceLoadAfterRedirect(const ResourceRequest&);
+
+ // Support iconDatabase in synchronous mode.
+ void iconLoadDecisionAvailable();
+
+ // Support iconDatabase in asynchronous mode.
+ void continueIconLoadWithDecision(IconLoadDecision);
+ void getIconLoadDecisionForIconURL(const String&);
+ void getIconDataForIconURL(const String&);
- DocumentLoadTiming* timing() { return &m_documentLoadTiming; }
- void resetTiming() { m_documentLoadTiming = DocumentLoadTiming(); }
+ bool isLoadingMainResource() const { return m_loadingMainResource; }
+ bool isLoadingMultipartContent() const { return m_isLoadingMultipartContent; }
- // The WebKit layer calls this function when it's ready for the data to
- // actually be added to the document.
- void commitData(const char* bytes, size_t length);
+ void stopLoadingPlugIns();
+ void stopLoadingSubresources();
- ApplicationCacheHost* applicationCacheHost() const { return m_applicationCacheHost.get(); }
+ bool userContentExtensionsEnabled() const { return m_userContentExtensionsEnabled; }
+ void setUserContentExtensionsEnabled(bool enabled) { m_userContentExtensionsEnabled = enabled; }
- void checkLoadComplete();
+ AutoplayPolicy autoplayPolicy() const { return m_autoplayPolicy; }
+ void setAutoplayPolicy(AutoplayPolicy policy) { m_autoplayPolicy = policy; }
-#if USE(CONTENT_FILTERING)
- void setContentFilterForBlockedLoad(PassRefPtr<ContentFilter>);
- bool handleContentFilterRequest(const ResourceRequest&);
+ void addSubresourceLoader(ResourceLoader*);
+ void removeSubresourceLoader(ResourceLoader*);
+ void addPlugInStreamLoader(ResourceLoader&);
+ void removePlugInStreamLoader(ResourceLoader&);
+
+ void subresourceLoaderFinishedLoadingOnePart(ResourceLoader*);
+
+ void setDeferMainResourceDataLoad(bool defer) { m_deferMainResourceDataLoad = defer; }
+
+ void didTellClientAboutLoad(const String& url);
+ bool haveToldClientAboutLoad(const String& url) { return m_resourcesClientKnowsAbout.contains(url); }
+ void recordMemoryCacheLoadForFutureClientNotification(const ResourceRequest&);
+ void takeMemoryCacheLoadsForClientNotification(Vector<ResourceRequest>& loads);
+
+ LoadTiming& timing() { return m_loadTiming; }
+ void resetTiming() { m_loadTiming = LoadTiming(); }
+
+ // The WebKit layer calls this function when it's ready for the data to actually be added to the document.
+ WEBCORE_EXPORT void commitData(const char* bytes, size_t length);
+
+ ApplicationCacheHost& applicationCacheHost() const;
+ ApplicationCacheHost* applicationCacheHostUnlessBeingDestroyed() const;
+
+ void checkLoadComplete();
+
+ // The URL of the document resulting from this DocumentLoader.
+ URL documentURL() const;
+
+#if USE(QUICK_LOOK)
+ void setPreviewConverter(std::unique_ptr<PreviewConverter>&&);
+ PreviewConverter* previewConverter() const;
+#endif
+
+#if ENABLE(CONTENT_EXTENSIONS)
+ void addPendingContentExtensionSheet(const String& identifier, StyleSheetContents&);
+ void addPendingContentExtensionDisplayNoneSelector(const String& identifier, const String& selector, uint32_t selectorID);
+#endif
+
+ void setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy) { m_shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy; }
+ ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicyToPropagate() const;
+
+#if ENABLE(CONTENT_FILTERING)
+ ContentFilter* contentFilter() const;
#endif
- // The URL of the document resulting from this DocumentLoader.
- URL documentURL() const;
+ bool isAlwaysOnLoggingAllowed() const;
- protected:
- DocumentLoader(const ResourceRequest&, const SubstituteData&);
+ void startIconLoading();
+ WEBCORE_EXPORT void didGetLoadDecisionForIcon(bool decision, uint64_t loadIdentifier, uint64_t newCallbackID);
+ void finishedLoadingIcon(IconLoader&, SharedBuffer*);
- bool m_deferMainResourceDataLoad;
+protected:
+ WEBCORE_EXPORT DocumentLoader(const ResourceRequest&, const SubstituteData&);
- private:
- Document* document() const;
+ WEBCORE_EXPORT virtual void attachToFrame();
- void setRequest(const ResourceRequest&);
+ bool m_deferMainResourceDataLoad { true };
- void commitIfReady();
- void setMainDocumentError(const ResourceError&);
- void commitLoad(const char*, int);
- void clearMainResourceLoader();
+private:
+ Document* document() const;
- void setupForReplace();
- void maybeFinishLoadingMultipartContent();
-
- bool maybeCreateArchive();
+ void setRequest(const ResourceRequest&);
+
+ void commitIfReady();
+ void setMainDocumentError(const ResourceError&);
+ void commitLoad(const char*, int);
+ void clearMainResourceLoader();
+
+ void setupForReplace();
+ void maybeFinishLoadingMultipartContent();
+
+ bool maybeCreateArchive();
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- void clearArchiveResources();
+ void clearArchiveResources();
#endif
- void willSendRequest(ResourceRequest&, const ResourceResponse&);
- void finishedLoading(double finishTime);
- void mainReceivedError(const ResourceError&);
- virtual void redirectReceived(CachedResource*, ResourceRequest&, const ResourceResponse&) override;
- virtual void responseReceived(CachedResource*, const ResourceResponse&) override;
- virtual void dataReceived(CachedResource*, const char* data, int length) override;
- virtual void notifyFinished(CachedResource*) override;
+ void willSendRequest(ResourceRequest&, const ResourceResponse&);
+ void finishedLoading(double finishTime);
+ void mainReceivedError(const ResourceError&);
+ WEBCORE_EXPORT void redirectReceived(CachedResource&, ResourceRequest&, const ResourceResponse&) override;
+ WEBCORE_EXPORT void responseReceived(CachedResource&, const ResourceResponse&) override;
+ WEBCORE_EXPORT void dataReceived(CachedResource&, const char* data, int length) override;
+ WEBCORE_EXPORT void notifyFinished(CachedResource&) override;
+
+ void responseReceived(const ResourceResponse&);
+ void dataReceived(const char* data, int length);
- bool maybeLoadEmpty();
+ bool maybeLoadEmpty();
- bool isMultipartReplacingLoad() const;
- bool isPostOrRedirectAfterPost(const ResourceRequest&, const ResourceResponse&);
+ bool isMultipartReplacingLoad() const;
+ bool isPostOrRedirectAfterPost(const ResourceRequest&, const ResourceResponse&);
- void continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue);
+ void continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue);
+ void continueAfterContentPolicy(PolicyAction);
- void continueAfterContentPolicy(PolicyAction);
+ void stopLoadingForPolicyChange();
+ ResourceError interruptedForPolicyChangeError() const;
- void stopLoadingForPolicyChange();
- ResourceError interruptedForPolicyChangeError() const;
+ void stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(unsigned long identifier, const ResourceResponse&);
#if HAVE(RUNLOOP_TIMER)
- typedef RunLoopTimer<DocumentLoader> DocumentLoaderTimer;
+ typedef RunLoopTimer<DocumentLoader> DocumentLoaderTimer;
#else
- typedef Timer<DocumentLoader> DocumentLoaderTimer;
+ typedef Timer DocumentLoaderTimer;
#endif
- void handleSubstituteDataLoadSoon();
- void handleSubstituteDataLoadNow(DocumentLoaderTimer*);
- void startDataLoadTimer();
-
- void deliverSubstituteResourcesAfterDelay();
- void substituteResourceDeliveryTimerFired(Timer<DocumentLoader>&);
-
- void clearMainResource();
-
- Frame* m_frame;
- Ref<CachedResourceLoader> m_cachedResourceLoader;
-
- CachedResourceHandle<CachedRawResource> m_mainResource;
- ResourceLoaderSet m_subresourceLoaders;
- ResourceLoaderSet m_multipartSubresourceLoaders;
- ResourceLoaderSet m_plugInStreamLoaders;
-
- mutable DocumentWriter m_writer;
-
- // A reference to actual request used to create the data source.
- // This should only be used by the resourceLoadDelegate's
- // identifierForInitialRequest:fromDatasource: method. It is
- // not guaranteed to remain unchanged, as requests are mutable.
- ResourceRequest m_originalRequest;
-
- SubstituteData m_substituteData;
-
- // A copy of the original request used to create the data source.
- // We have to copy the request because requests are mutable.
- ResourceRequest m_originalRequestCopy;
-
- // The 'working' request. It may be mutated
- // several times from the original request to include additional
- // headers, cookie information, canonicalization and redirects.
- ResourceRequest m_request;
-
- ResourceResponse m_response;
+ void handleSubstituteDataLoadSoon();
+ void handleSubstituteDataLoadNow();
+ void startDataLoadTimer();
+
+ void deliverSubstituteResourcesAfterDelay();
+ void substituteResourceDeliveryTimerFired();
+
+ void clearMainResource();
+
+ void cancelPolicyCheckIfNeeded();
+ void becomeMainResourceClient();
+
+ Frame* m_frame { nullptr };
+ Ref<CachedResourceLoader> m_cachedResourceLoader;
+
+ CachedResourceHandle<CachedRawResource> m_mainResource;
+ ResourceLoaderMap m_subresourceLoaders;
+ ResourceLoaderMap m_multipartSubresourceLoaders;
+ ResourceLoaderMap m_plugInStreamLoaders;
- ResourceError m_mainDocumentError;
-
- bool m_originalSubstituteDataWasValid;
- bool m_committed;
- bool m_isStopping;
- bool m_gotFirstByte;
- bool m_isClientRedirect;
- bool m_isLoadingMultipartContent;
-
- // FIXME: Document::m_processingLoadEvent and DocumentLoader::m_wasOnloadHandled are roughly the same
- // and should be merged.
- bool m_wasOnloadHandled;
-
- StringWithDirection m_pageTitle;
-
- String m_overrideEncoding;
-
- // The action that triggered loading - we keep this around for the
- // benefit of the various policy handlers.
- NavigationAction m_triggeringAction;
-
- // The last request that we checked click policy for - kept around
- // so we can avoid asking again needlessly.
- ResourceRequest m_lastCheckedRequest;
-
- // We retain all the received responses so we can play back the
- // WebResourceLoadDelegate messages if the item is loaded from the
- // page cache.
- ResponseVector m_responses;
- bool m_stopRecordingResponses;
-
- typedef HashMap<RefPtr<ResourceLoader>, RefPtr<SubstituteResource>> SubstituteResourceMap;
- SubstituteResourceMap m_pendingSubstituteResources;
- Timer<DocumentLoader> m_substituteResourceDeliveryTimer;
-
- OwnPtr<ArchiveResourceCollection> m_archiveResourceCollection;
+ mutable DocumentWriter m_writer;
+
+ // A reference to actual request used to create the data source.
+ // This should only be used by the resourceLoadDelegate's
+ // identifierForInitialRequest:fromDatasource: method. It is
+ // not guaranteed to remain unchanged, as requests are mutable.
+ ResourceRequest m_originalRequest;
+
+ SubstituteData m_substituteData;
+
+ // A copy of the original request used to create the data source.
+ // We have to copy the request because requests are mutable.
+ ResourceRequest m_originalRequestCopy;
+
+ // The 'working' request. It may be mutated
+ // several times from the original request to include additional
+ // headers, cookie information, canonicalization and redirects.
+ ResourceRequest m_request;
+
+ ResourceResponse m_response;
+
+ ResourceError m_mainDocumentError;
+
+ bool m_originalSubstituteDataWasValid;
+ bool m_committed { false };
+ bool m_isStopping { false };
+ bool m_gotFirstByte { false };
+ bool m_isClientRedirect { false };
+ bool m_isLoadingMultipartContent { false };
+
+ // FIXME: Document::m_processingLoadEvent and DocumentLoader::m_wasOnloadDispatched are roughly the same
+ // and should be merged.
+ bool m_wasOnloadDispatched { false };
+
+ StringWithDirection m_pageTitle;
+
+ String m_overrideEncoding;
+
+ // The action that triggered loading - we keep this around for the
+ // benefit of the various policy handlers.
+ NavigationAction m_triggeringAction;
+
+ // The last request that we checked click policy for - kept around
+ // so we can avoid asking again needlessly.
+ ResourceRequest m_lastCheckedRequest;
+
+ // We retain all the received responses so we can play back the
+ // WebResourceLoadDelegate messages if the item is loaded from the
+ // page cache.
+ Vector<ResourceResponse> m_responses;
+ bool m_stopRecordingResponses { false };
+
+ typedef HashMap<RefPtr<ResourceLoader>, RefPtr<SubstituteResource>> SubstituteResourceMap;
+ SubstituteResourceMap m_pendingSubstituteResources;
+ Timer m_substituteResourceDeliveryTimer;
+
+ std::unique_ptr<ArchiveResourceCollection> m_archiveResourceCollection;
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- RefPtr<Archive> m_archive;
- RefPtr<SharedBuffer> m_parsedArchiveData;
+ RefPtr<Archive> m_archive;
+ RefPtr<SharedBuffer> m_parsedArchiveData;
#endif
- HashSet<String> m_resourcesClientKnowsAbout;
- Vector<ResourceRequest> m_resourcesLoadedFromMemoryCacheForClientNotification;
-
- String m_clientRedirectSourceForHistory;
- bool m_didCreateGlobalHistoryEntry;
+ HashSet<String> m_resourcesClientKnowsAbout;
+ Vector<ResourceRequest> m_resourcesLoadedFromMemoryCacheForClientNotification;
+
+ String m_clientRedirectSourceForHistory;
+ bool m_didCreateGlobalHistoryEntry { false };
- bool m_loadingMainResource;
- DocumentLoadTiming m_documentLoadTiming;
+ bool m_loadingMainResource { false };
+ LoadTiming m_loadTiming;
- double m_timeOfLastDataReceived;
- unsigned long m_identifierForLoadWithoutResourceLoader;
+ MonotonicTime m_timeOfLastDataReceived;
+ unsigned long m_identifierForLoadWithoutResourceLoader { 0 };
- DocumentLoaderTimer m_dataLoadTimer;
- bool m_waitingForContentPolicy;
+ DocumentLoaderTimer m_dataLoadTimer;
+ bool m_waitingForContentPolicy { false };
+ bool m_waitingForNavigationPolicy { false };
- RefPtr<IconLoadDecisionCallback> m_iconLoadDecisionCallback;
- RefPtr<IconDataCallback> m_iconDataCallback;
+ // For IconDatabase-style loads
+ RefPtr<IconLoadDecisionCallback> m_iconLoadDecisionCallback;
+ RefPtr<IconDataCallback> m_iconDataCallback;
- bool m_subresourceLoadersArePageCacheAcceptable;
+ // For IconLoadingClient-style loads
+ HashMap<uint64_t, LinkIcon> m_iconsPendingLoadDecision;
+ HashMap<std::unique_ptr<IconLoader>, uint64_t> m_iconLoaders;
- friend class ApplicationCacheHost; // for substitute resource delivery
- OwnPtr<ApplicationCacheHost> m_applicationCacheHost;
+ bool m_subresourceLoadersArePageCacheAcceptable { false };
+ ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
-#if USE(CONTENT_FILTERING)
- RefPtr<ContentFilter> m_contentFilter;
- RefPtr<ContentFilter> m_contentFilterForBlockedLoad;
+ std::unique_ptr<ApplicationCacheHost> m_applicationCacheHost;
+
+#if ENABLE(CONTENT_FILTERING)
+ std::unique_ptr<ContentFilter> m_contentFilter;
#endif
- };
- inline void DocumentLoader::recordMemoryCacheLoadForFutureClientNotification(const ResourceRequest& request)
- {
- m_resourcesLoadedFromMemoryCacheForClientNotification.append(request);
- }
+#if USE(QUICK_LOOK)
+ std::unique_ptr<PreviewConverter> m_previewConverter;
+#endif
- inline void DocumentLoader::takeMemoryCacheLoadsForClientNotification(Vector<ResourceRequest>& loadsSet)
- {
- loadsSet.swap(m_resourcesLoadedFromMemoryCacheForClientNotification);
- m_resourcesLoadedFromMemoryCacheForClientNotification.clear();
- }
+#if ENABLE(CONTENT_EXTENSIONS)
+ HashMap<String, RefPtr<StyleSheetContents>> m_pendingNamedContentExtensionStyleSheets;
+ HashMap<String, Vector<std::pair<String, uint32_t>>> m_pendingContentExtensionDisplayNoneSelectors;
+#endif
+ bool m_userContentExtensionsEnabled { true };
+ AutoplayPolicy m_autoplayPolicy { AutoplayPolicy::Default };
+
+#ifndef NDEBUG
+ bool m_hasEverBeenAttached { false };
+#endif
+};
+
+inline void DocumentLoader::recordMemoryCacheLoadForFutureClientNotification(const ResourceRequest& request)
+{
+ m_resourcesLoadedFromMemoryCacheForClientNotification.append(request);
+}
+
+inline void DocumentLoader::takeMemoryCacheLoadsForClientNotification(Vector<ResourceRequest>& loadsSet)
+{
+ loadsSet.swap(m_resourcesLoadedFromMemoryCacheForClientNotification);
+ m_resourcesLoadedFromMemoryCacheForClientNotification.clear();
+}
+
+inline const ResourceRequest& DocumentLoader::originalRequest() const
+{
+ return m_originalRequest;
+}
+
+inline const ResourceRequest& DocumentLoader::originalRequestCopy() const
+{
+ return m_originalRequestCopy;
+}
+
+inline const ResourceRequest& DocumentLoader::request() const
+{
+ return m_request;
+}
+
+inline ResourceRequest& DocumentLoader::request()
+{
+ return m_request;
+}
+
+inline const URL& DocumentLoader::url() const
+{
+ return m_request.url();
+}
+
+inline const URL& DocumentLoader::originalURL() const
+{
+ return m_originalRequestCopy.url();
+}
+
+inline const URL& DocumentLoader::responseURL() const
+{
+ return m_response.url();
+}
+
+inline const String& DocumentLoader::responseMIMEType() const
+{
+ return m_response.mimeType();
+}
+
+inline const String& DocumentLoader::currentContentType() const
+{
+ return m_writer.mimeType();
+}
+
+inline const URL& DocumentLoader::unreachableURL() const
+{
+ return m_substituteData.failingURL();
+}
+
+inline ApplicationCacheHost& DocumentLoader::applicationCacheHost() const
+{
+ // For a short time while the document loader is being destroyed, m_applicationCacheHost is null.
+ // It's not acceptable to call this function during that time.
+ ASSERT(m_applicationCacheHost);
+ return *m_applicationCacheHost;
+}
+
+inline ApplicationCacheHost* DocumentLoader::applicationCacheHostUnlessBeingDestroyed() const
+{
+ return m_applicationCacheHost.get();
+}
+#if ENABLE(CONTENT_FILTERING)
+
+inline ContentFilter* DocumentLoader::contentFilter() const
+{
+ return m_contentFilter.get();
}
-#endif // DocumentLoader_h
+#endif
+
+inline void DocumentLoader::didTellClientAboutLoad(const String& url)
+{
+#if !PLATFORM(COCOA)
+ // Don't include data URLs here, as if a lot of data is loaded that way, we hold on to the (large) URL string for too long.
+ if (protocolIs(url, "data"))
+ return;
+#endif
+ if (!url.isEmpty())
+ m_resourcesClientKnowsAbout.add(url);
+}
+
+}
diff --git a/Source/WebCore/loader/DocumentThreadableLoader.cpp b/Source/WebCore/loader/DocumentThreadableLoader.cpp
index a6013706b..b6b91e627 100644
--- a/Source/WebCore/loader/DocumentThreadableLoader.cpp
+++ b/Source/WebCore/loader/DocumentThreadableLoader.cpp
@@ -34,15 +34,22 @@
#include "CachedRawResource.h"
#include "CachedResourceLoader.h"
#include "CachedResourceRequest.h"
+#include "CachedResourceRequestInitiators.h"
#include "CrossOriginAccessControl.h"
+#include "CrossOriginPreflightChecker.h"
#include "CrossOriginPreflightResultCache.h"
+#include "DOMWindow.h"
#include "Document.h"
-#include "DocumentThreadableLoaderClient.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "InspectorInstrumentation.h"
+#include "LoadTiming.h"
+#include "Performance.h"
+#include "ProgressTracker.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
+#include "ResourceTiming.h"
+#include "RuntimeEnabledFeatures.h"
#include "SchemeRegistry.h"
#include "SecurityOrigin.h"
#include "SubresourceLoader.h"
@@ -50,118 +57,153 @@
#include <wtf/Assertions.h>
#include <wtf/Ref.h>
-#if ENABLE(INSPECTOR)
-#include "ProgressTracker.h"
-#endif
-
namespace WebCore {
-void DocumentThreadableLoader::loadResourceSynchronously(Document* document, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
+void DocumentThreadableLoader::loadResourceSynchronously(Document& document, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, RefPtr<SecurityOrigin>&& origin, std::unique_ptr<ContentSecurityPolicy>&& contentSecurityPolicy)
{
// The loader will be deleted as soon as this function exits.
- RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, &client, LoadSynchronously, request, options));
+ Ref<DocumentThreadableLoader> loader = adoptRef(*new DocumentThreadableLoader(document, client, LoadSynchronously, WTFMove(request), options, WTFMove(origin), WTFMove(contentSecurityPolicy), String(), ShouldLogError::Yes));
ASSERT(loader->hasOneRef());
}
-PassRefPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, const ThreadableLoaderOptions& options)
+void DocumentThreadableLoader::loadResourceSynchronously(Document& document, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
+{
+ loadResourceSynchronously(document, WTFMove(request), client, options, nullptr, nullptr);
+}
+
+RefPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document& document, ThreadableLoaderClient& client,
+ResourceRequest&& request, const ThreadableLoaderOptions& options, RefPtr<SecurityOrigin>&& origin,
+std::unique_ptr<ContentSecurityPolicy>&& contentSecurityPolicy, String&& referrer, ShouldLogError shouldLogError)
+{
+ RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, client, LoadAsynchronously, WTFMove(request), options, WTFMove(origin), WTFMove(contentSecurityPolicy), WTFMove(referrer), shouldLogError));
+ if (!loader->isLoading())
+ loader = nullptr;
+ return loader;
+}
+
+RefPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document& document, ThreadableLoaderClient& client, ResourceRequest&& request, const ThreadableLoaderOptions& options, String&& referrer)
{
- RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, client, LoadAsynchronously, request, options));
- if (!loader->m_resource)
- loader = 0;
- return loader.release();
+ return create(document, client, WTFMove(request), options, nullptr, nullptr, WTFMove(referrer), ShouldLogError::Yes);
}
-DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options)
- : m_client(client)
+DocumentThreadableLoader::DocumentThreadableLoader(Document& document, ThreadableLoaderClient& client, BlockingBehavior blockingBehavior, ResourceRequest&& request, const ThreadableLoaderOptions& options, RefPtr<SecurityOrigin>&& origin, std::unique_ptr<ContentSecurityPolicy>&& contentSecurityPolicy, String&& referrer, ShouldLogError shouldLogError)
+ : m_client(&client)
, m_document(document)
, m_options(options)
- , m_sameOriginRequest(securityOrigin()->canRequest(request.url()))
+ , m_origin(WTFMove(origin))
+ , m_referrer(WTFMove(referrer))
+ , m_sameOriginRequest(securityOrigin().canRequest(request.url()))
, m_simpleRequest(true)
, m_async(blockingBehavior == LoadAsynchronously)
+ , m_contentSecurityPolicy(WTFMove(contentSecurityPolicy))
+ , m_shouldLogError(shouldLogError)
{
- ASSERT(document);
- ASSERT(client);
- // Setting an outgoing referer is only supported in the async code path.
- ASSERT(m_async || request.httpReferrer().isEmpty());
+ relaxAdoptionRequirement();
+
+ // Setting a referrer header is only supported in the async code path.
+ ASSERT(m_async || m_referrer.isEmpty());
+
+ // Referrer and Origin headers should be set after the preflight if any.
+ ASSERT(!request.hasHTTPReferrer() && !request.hasHTTPOrigin());
+
+ ASSERT_WITH_SECURITY_IMPLICATION(isAllowedByContentSecurityPolicy(request.url(), ContentSecurityPolicy::RedirectResponseReceived::No));
+
+ m_options.allowCredentials = (m_options.credentials == FetchOptions::Credentials::Include || (m_options.credentials == FetchOptions::Credentials::SameOrigin && m_sameOriginRequest)) ? AllowStoredCredentials : DoNotAllowStoredCredentials;
+
+ ASSERT(!request.httpHeaderFields().contains(HTTPHeaderName::Origin));
+
+ // Copy headers if we need to replay the request after a redirection.
+ if (m_async && m_options.mode == FetchOptions::Mode::Cors)
+ m_originalHeaders = request.httpHeaderFields();
+
+ if (document.page() && document.page()->isRunningUserScripts() && SchemeRegistry::isUserExtensionScheme(request.url().protocol().toStringWithoutCopying())) {
+ m_options.mode = FetchOptions::Mode::NoCors;
+ m_options.filteringPolicy = ResponseFilteringPolicy::Disable;
+ }
- if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) {
- loadRequest(request, DoSecurityCheck);
+ // As per step 11 of https://fetch.spec.whatwg.org/#main-fetch, data scheme (if same-origin data-URL flag is set) and about scheme are considered same-origin.
+ if (request.url().protocolIsData())
+ m_sameOriginRequest = options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set;
+
+ if (m_sameOriginRequest || m_options.mode == FetchOptions::Mode::NoCors) {
+ loadRequest(WTFMove(request), DoSecurityCheck);
return;
}
- if (m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) {
- m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are not supported."));
+ if (m_options.mode == FetchOptions::Mode::SameOrigin) {
+ logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, request.url(), "Cross origin requests are not allowed when using same-origin fetch mode."));
return;
}
- makeCrossOriginAccessRequest(request);
+ makeCrossOriginAccessRequest(WTFMove(request));
}
-void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceRequest& request)
+void DocumentThreadableLoader::makeCrossOriginAccessRequest(ResourceRequest&& request)
{
- ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
-
- OwnPtr<ResourceRequest> crossOriginRequest = adoptPtr(new ResourceRequest(request));
- updateRequestForAccessControl(*crossOriginRequest, securityOrigin(), m_options.allowCredentials);
+ ASSERT(m_options.mode == FetchOptions::Mode::Cors);
- if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight)
- makeSimpleCrossOriginAccessRequest(*crossOriginRequest);
+ if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight)
+ makeSimpleCrossOriginAccessRequest(WTFMove(request));
else {
m_simpleRequest = false;
- m_actualRequest = crossOriginRequest.release();
-
- if (CrossOriginPreflightResultCache::shared().canSkipPreflight(securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials, m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields()))
- preflightSuccess();
+ if (CrossOriginPreflightResultCache::singleton().canSkipPreflight(securityOrigin().toString(), request.url(), m_options.allowCredentials, request.httpMethod(), request.httpHeaderFields()))
+ preflightSuccess(WTFMove(request));
else
- makeCrossOriginAccessRequestWithPreflight(*m_actualRequest);
+ makeCrossOriginAccessRequestWithPreflight(WTFMove(request));
}
}
-void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const ResourceRequest& request)
+void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(ResourceRequest&& request)
{
ASSERT(m_options.preflightPolicy != ForcePreflight);
ASSERT(m_options.preflightPolicy == PreventPreflight || isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields()));
// Cross-origin requests are only allowed for HTTP and registered schemes. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied.
- if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())) {
- m_client->didFailAccessControlCheck(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are only supported for HTTP."));
+ if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol().toStringWithoutCopying())) {
+ logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, request.url(), "Cross origin requests are only supported for HTTP.", ResourceError::Type::AccessControl));
return;
}
- loadRequest(request, DoSecurityCheck);
+ updateRequestForAccessControl(request, securityOrigin(), m_options.allowCredentials);
+ loadRequest(WTFMove(request), DoSecurityCheck);
}
-void DocumentThreadableLoader::makeCrossOriginAccessRequestWithPreflight(const ResourceRequest& request)
+void DocumentThreadableLoader::makeCrossOriginAccessRequestWithPreflight(ResourceRequest&& request)
{
- ResourceRequest preflightRequest = createAccessControlPreflightRequest(request, securityOrigin());
- loadRequest(preflightRequest, DoSecurityCheck);
+ if (m_async) {
+ m_preflightChecker.emplace(*this, WTFMove(request));
+ m_preflightChecker->startPreflight();
+ return;
+ }
+ CrossOriginPreflightChecker::doPreflight(*this, WTFMove(request));
}
DocumentThreadableLoader::~DocumentThreadableLoader()
{
if (m_resource)
- m_resource->removeClient(this);
+ m_resource->removeClient(*this);
}
void DocumentThreadableLoader::cancel()
{
- Ref<DocumentThreadableLoader> protect(*this);
+ Ref<DocumentThreadableLoader> protectedThis(*this);
// Cancel can re-enter and m_resource might be null here as a result.
if (m_client && m_resource) {
// FIXME: This error is sent to the client in didFail(), so it should not be an internal one. Use FrameLoaderClient::cancelledError() instead.
- ResourceError error(errorDomainWebKitInternal, 0, m_resource->url(), "Load cancelled");
- error.setIsCancellation(true);
- didFail(m_resource->identifier(), error);
+ ResourceError error(errorDomainWebKitInternal, 0, m_resource->url(), "Load cancelled", ResourceError::Type::Cancellation);
+ m_client->didFail(error);
}
clearResource();
- m_client = 0;
+ m_client = nullptr;
}
void DocumentThreadableLoader::setDefersLoading(bool value)
{
if (m_resource)
m_resource->setDefersLoading(value);
+ if (m_preflightChecker)
+ m_preflightChecker->setDefersLoading(value);
}
void DocumentThreadableLoader::clearResource()
@@ -171,142 +213,146 @@ void DocumentThreadableLoader::clearResource()
// this DocumentThreadableLoader. Save off a copy of m_resource and clear it to
// prevent the reentrancy.
if (CachedResourceHandle<CachedRawResource> resource = m_resource) {
- m_resource = 0;
- resource->removeClient(this);
+ m_resource = nullptr;
+ resource->removeClient(*this);
}
+ if (m_preflightChecker)
+ m_preflightChecker = std::nullopt;
}
-void DocumentThreadableLoader::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
+void DocumentThreadableLoader::redirectReceived(CachedResource& resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
ASSERT(m_client);
- ASSERT_UNUSED(resource, resource == m_resource);
+ ASSERT_UNUSED(resource, &resource == m_resource);
- Ref<DocumentThreadableLoader> protect(*this);
- // Allow same origin requests to continue after allowing clients to audit the redirect.
- if (isAllowedRedirect(request.url())) {
- if (m_client->isDocumentThreadableLoaderClient())
- static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequest(request, redirectResponse);
+ Ref<DocumentThreadableLoader> protectedThis(*this);
+ --m_options.maxRedirectCount;
+
+ // FIXME: We restrict this check to Fetch API for the moment, as this might disrupt WorkerScriptLoader.
+ // Reassess this check based on https://github.com/whatwg/fetch/issues/393 discussions.
+ // We should also disable that check in navigation mode.
+ if (!request.url().protocolIsInHTTPFamily() && m_options.initiator == cachedResourceRequestInitiators().fetch) {
+ reportRedirectionWithBadScheme(request.url());
+ clearResource();
return;
}
- // When using access control, only simple cross origin requests are allowed to redirect. The new request URL must have a supported
- // scheme and not contain the userinfo production. In addition, the redirect response must pass the access control check.
- if (m_options.crossOriginRequestPolicy == UseAccessControl) {
- bool allowRedirect = false;
- if (m_simpleRequest) {
- String accessControlErrorDescription;
- allowRedirect = SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())
- && request.url().user().isEmpty()
- && request.url().pass().isEmpty()
- && passesAccessControlCheck(redirectResponse, m_options.allowCredentials, securityOrigin(), accessControlErrorDescription);
- }
-
- if (allowRedirect) {
- if (m_resource)
- clearResource();
-
- RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::createFromString(redirectResponse.url());
- RefPtr<SecurityOrigin> requestOrigin = SecurityOrigin::createFromString(request.url());
- // If the request URL origin is not same origin with the original URL origin, set source origin to a globally unique identifier.
- if (!originalOrigin->isSameSchemeHostPort(requestOrigin.get()))
- m_options.securityOrigin = SecurityOrigin::createUnique();
- // Force any subsequent requests to use these checks.
- m_sameOriginRequest = false;
-
- // Remove any headers that may have been added by the network layer that cause access control to fail.
- request.clearHTTPContentType();
- request.clearHTTPReferrer();
- request.clearHTTPOrigin();
- request.clearHTTPUserAgent();
- request.clearHTTPAccept();
- makeCrossOriginAccessRequest(request);
- return;
- }
+ if (!isAllowedByContentSecurityPolicy(request.url(), redirectResponse.isNull() ? ContentSecurityPolicy::RedirectResponseReceived::No : ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
+ reportContentSecurityPolicyError(redirectResponse.url());
+ clearResource();
+ return;
}
- m_client->didFailRedirectCheck();
- request = ResourceRequest();
+ // Allow same origin requests to continue after allowing clients to audit the redirect.
+ if (isAllowedRedirect(request.url()))
+ return;
+
+ // Force any subsequent request to use these checks.
+ m_sameOriginRequest = false;
+
+ ASSERT(m_resource);
+ ASSERT(m_originalHeaders);
+
+ // Use a unique for subsequent loads if needed.
+ // https://fetch.spec.whatwg.org/#concept-http-redirect-fetch (Step 10).
+ ASSERT(m_options.mode == FetchOptions::Mode::Cors);
+ if (!securityOrigin().canRequest(redirectResponse.url()) && !protocolHostAndPortAreEqual(redirectResponse.url(), request.url()))
+ m_origin = SecurityOrigin::createUnique();
+
+ // Except in case where preflight is needed, loading should be able to continue on its own.
+ // But we also handle credentials here if it is restricted to SameOrigin.
+ if (m_options.credentials != FetchOptions::Credentials::SameOrigin && m_simpleRequest && isSimpleCrossOriginAccessRequest(request.httpMethod(), *m_originalHeaders))
+ return;
+
+ m_options.allowCredentials = DoNotAllowStoredCredentials;
+
+ clearResource();
+
+ // Let's fetch the request with the original headers (equivalent to request cloning specified by fetch algorithm).
+ // Do not copy the Authorization header if removed by the network layer.
+ if (!request.httpHeaderFields().contains(HTTPHeaderName::Authorization))
+ m_originalHeaders->remove(HTTPHeaderName::Authorization);
+ request.setHTTPHeaderFields(*m_originalHeaders);
+
+ makeCrossOriginAccessRequest(ResourceRequest(request));
}
-void DocumentThreadableLoader::dataSent(CachedResource* resource, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+void DocumentThreadableLoader::dataSent(CachedResource& resource, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
ASSERT(m_client);
- ASSERT_UNUSED(resource, resource == m_resource);
+ ASSERT_UNUSED(resource, &resource == m_resource);
m_client->didSendData(bytesSent, totalBytesToBeSent);
}
-void DocumentThreadableLoader::responseReceived(CachedResource* resource, const ResourceResponse& response)
+void DocumentThreadableLoader::responseReceived(CachedResource& resource, const ResourceResponse& response)
{
- ASSERT_UNUSED(resource, resource == m_resource);
- didReceiveResponse(m_resource->identifier(), response);
+ ASSERT_UNUSED(resource, &resource == m_resource);
+ didReceiveResponse(m_resource->identifier(), response, m_resource->responseTainting());
}
-void DocumentThreadableLoader::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
+void DocumentThreadableLoader::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, ResourceResponse::Tainting tainting)
{
ASSERT(m_client);
+ ASSERT(response.type() != ResourceResponse::Type::Error);
- String accessControlErrorDescription;
- if (m_actualRequest) {
-#if ENABLE(INSPECTOR)
- DocumentLoader* loader = m_document->frame()->loader().documentLoader();
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceResponse(m_document->frame(), identifier, response);
- InspectorInstrumentation::didReceiveResourceResponse(cookie, identifier, loader, response, 0);
-#endif
+ InspectorInstrumentation::didReceiveThreadableLoaderResponse(*this, identifier);
- if (!passesAccessControlCheck(response, m_options.allowCredentials, securityOrigin(), accessControlErrorDescription)) {
- preflightFailure(identifier, response.url(), accessControlErrorDescription);
- return;
- }
+ if (options().filteringPolicy == ResponseFilteringPolicy::Disable) {
+ m_client->didReceiveResponse(identifier, response);
+ return;
+ }
- OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new CrossOriginPreflightResultCacheItem(m_options.allowCredentials));
- if (!preflightResult->parse(response, accessControlErrorDescription)
- || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod(), accessControlErrorDescription)
- || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields(), accessControlErrorDescription)) {
- preflightFailure(identifier, response.url(), accessControlErrorDescription);
- return;
+ if (response.type() == ResourceResponse::Type::Default) {
+ m_client->didReceiveResponse(identifier, ResourceResponse::filterResponse(response, tainting));
+ if (tainting == ResourceResponse::Tainting::Opaque) {
+ clearResource();
+ if (m_client)
+ m_client->didFinishLoading(identifier, 0.0);
}
-
- CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toString(), m_actualRequest->url(), preflightResult.release());
} else {
- if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessControl) {
- if (!passesAccessControlCheck(response, m_options.allowCredentials, securityOrigin(), accessControlErrorDescription)) {
- m_client->didFailAccessControlCheck(ResourceError(errorDomainWebKitInternal, 0, response.url().string(), accessControlErrorDescription));
- return;
- }
- }
-
+ ASSERT(response.type() == ResourceResponse::Type::Opaqueredirect);
m_client->didReceiveResponse(identifier, response);
}
}
-void DocumentThreadableLoader::dataReceived(CachedResource* resource, const char* data, int dataLength)
+void DocumentThreadableLoader::dataReceived(CachedResource& resource, const char* data, int dataLength)
{
- ASSERT_UNUSED(resource, resource == m_resource);
+ ASSERT_UNUSED(resource, &resource == m_resource);
didReceiveData(m_resource->identifier(), data, dataLength);
}
-void DocumentThreadableLoader::didReceiveData(unsigned long identifier, const char* data, int dataLength)
+void DocumentThreadableLoader::didReceiveData(unsigned long, const char* data, int dataLength)
{
ASSERT(m_client);
- // Preflight data should be invisible to clients.
- if (m_actualRequest) {
-#if ENABLE(INSPECTOR)
- InspectorInstrumentation::didReceiveData(m_document->frame(), identifier, 0, 0, dataLength);
-#else
- UNUSED_PARAM(identifier);
+ m_client->didReceiveData(data, dataLength);
+}
+
+void DocumentThreadableLoader::finishedTimingForWorkerLoad(CachedResource& resource, const ResourceTiming& resourceTiming)
+{
+ ASSERT(m_client);
+ ASSERT_UNUSED(resource, &resource == m_resource);
+ UNUSED_PARAM(resourceTiming);
+
+#if ENABLE(WEB_TIMING)
+ finishedTimingForWorkerLoad(resourceTiming);
#endif
- return;
- }
+}
- m_client->didReceiveData(data, dataLength);
+#if ENABLE(WEB_TIMING)
+void DocumentThreadableLoader::finishedTimingForWorkerLoad(const ResourceTiming& resourceTiming)
+{
+ ASSERT(m_options.initiatorContext == InitiatorContext::Worker);
+
+ m_client->didFinishTiming(resourceTiming);
}
+#endif
-void DocumentThreadableLoader::notifyFinished(CachedResource* resource)
+void DocumentThreadableLoader::notifyFinished(CachedResource& resource)
{
ASSERT(m_client);
- ASSERT_UNUSED(resource, resource == m_resource);
-
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
if (m_resource->errorOccurred())
didFail(m_resource->identifier(), m_resource->resourceError());
else
@@ -315,137 +361,226 @@ void DocumentThreadableLoader::notifyFinished(CachedResource* resource)
void DocumentThreadableLoader::didFinishLoading(unsigned long identifier, double finishTime)
{
- if (m_actualRequest) {
-#if ENABLE(INSPECTOR)
- InspectorInstrumentation::didFinishLoading(m_document->frame(), m_document->frame()->loader().documentLoader(), identifier, finishTime);
-#endif
- ASSERT(!m_sameOriginRequest);
- ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
- preflightSuccess();
- } else
- m_client->didFinishLoading(identifier, finishTime);
+ ASSERT(m_client);
+ m_client->didFinishLoading(identifier, finishTime);
}
-void DocumentThreadableLoader::didFail(unsigned long identifier, const ResourceError& error)
+void DocumentThreadableLoader::didFail(unsigned long, const ResourceError& error)
{
-#if ENABLE(INSPECTOR)
- if (m_actualRequest)
- InspectorInstrumentation::didFailLoading(m_document->frame(), m_document->frame()->loader().documentLoader(), identifier, error);
-#else
- UNUSED_PARAM(identifier);
-#endif
-
- m_client->didFail(error);
+ ASSERT(m_client);
+ logErrorAndFail(error);
}
-void DocumentThreadableLoader::preflightSuccess()
+void DocumentThreadableLoader::preflightSuccess(ResourceRequest&& request)
{
- OwnPtr<ResourceRequest> actualRequest;
- actualRequest.swap(m_actualRequest);
+ ResourceRequest actualRequest(WTFMove(request));
+ updateRequestForAccessControl(actualRequest, securityOrigin(), m_options.allowCredentials);
- actualRequest->setHTTPOrigin(securityOrigin()->toString());
-
- clearResource();
+ m_preflightChecker = std::nullopt;
// It should be ok to skip the security check since we already asked about the preflight request.
- loadRequest(*actualRequest, SkipSecurityCheck);
+ loadRequest(WTFMove(actualRequest), SkipSecurityCheck);
}
-void DocumentThreadableLoader::preflightFailure(unsigned long identifier, const String& url, const String& errorDescription)
+void DocumentThreadableLoader::preflightFailure(unsigned long identifier, const ResourceError& error)
{
- ResourceError error(errorDomainWebKitInternal, 0, url, errorDescription);
-#if ENABLE(INSPECTOR)
- if (m_actualRequest)
- InspectorInstrumentation::didFailLoading(m_document->frame(), m_document->frame()->loader().documentLoader(), identifier, error);
-#else
- UNUSED_PARAM(identifier);
-#endif
- m_actualRequest = nullptr; // Prevent didFinishLoading() from bypassing access check.
- m_client->didFailAccessControlCheck(error);
+ m_preflightChecker = std::nullopt;
+
+ InspectorInstrumentation::didFailLoading(m_document.frame(), m_document.frame()->loader().documentLoader(), identifier, error);
+ ASSERT(m_client);
+ logErrorAndFail(error);
}
-void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck)
+void DocumentThreadableLoader::loadRequest(ResourceRequest&& request, SecurityCheckPolicy securityCheck)
{
+ Ref<DocumentThreadableLoader> protectedThis(*this);
+
// Any credential should have been removed from the cross-site requests.
const URL& requestURL = request.url();
m_options.securityCheck = securityCheck;
ASSERT(m_sameOriginRequest || requestURL.user().isEmpty());
ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty());
+ if (!m_referrer.isNull())
+ request.setHTTPReferrer(m_referrer);
+
if (m_async) {
- ThreadableLoaderOptions options = m_options;
- options.clientCredentialPolicy = DoNotAskClientForCrossOriginCredentials;
- if (m_actualRequest) {
- // Don't sniff content or send load callbacks for the preflight request.
- options.sendLoadCallbacks = DoNotSendCallbacks;
- options.sniffContent = DoNotSniffContent;
- // Keep buffering the data for the preflight request.
- options.dataBufferingPolicy = BufferData;
- }
+ ResourceLoaderOptions options = m_options;
+ options.clientCredentialPolicy = m_sameOriginRequest ? ClientCredentialPolicy::MayAskClientForCredentials : ClientCredentialPolicy::CannotAskClientForCredentials;
+ options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
+
+ request.setAllowCookies(m_options.allowCredentials == AllowStoredCredentials);
+ CachedResourceRequest newRequest(WTFMove(request), options);
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
+ newRequest.setInitiator(m_options.initiator);
+ newRequest.setOrigin(securityOrigin());
- CachedResourceRequest newRequest(request, options);
-#if ENABLE(RESOURCE_TIMING)
- newRequest.setInitiator(m_options.initiator);
-#endif
ASSERT(!m_resource);
- m_resource = m_document->cachedResourceLoader()->requestRawResource(newRequest);
if (m_resource) {
-#if ENABLE(INSPECTOR)
- if (m_resource->loader()) {
- unsigned long identifier = m_resource->loader()->identifier();
- InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client);
- }
-#endif
- m_resource->addClient(this);
+ CachedResourceHandle<CachedRawResource> resource = std::exchange(m_resource, nullptr);
+ resource->removeClient(*this);
+ }
+
+ // We create an URL here as the request will be moved in requestRawResource
+ URL requestUrl = newRequest.resourceRequest().url();
+ m_resource = m_document.cachedResourceLoader().requestRawResource(WTFMove(newRequest));
+ if (m_resource)
+ m_resource->addClient(*this);
+ else {
+ // FIXME: Since we receive a synchronous error, this is probably due to some AccessControl checks. We should try to retrieve the actual error.
+ logErrorAndFail(ResourceError(String(), 0, requestUrl, String(), ResourceError::Type::AccessControl));
}
return;
}
-
+
+ // If credentials mode is 'Omit', we should disable cookie sending.
+ ASSERT(m_options.credentials != FetchOptions::Credentials::Omit);
+
+#if ENABLE(WEB_TIMING)
+ LoadTiming loadTiming;
+ loadTiming.markStartTimeAndFetchStart();
+#endif
+
// FIXME: ThreadableLoaderOptions.sniffContent is not supported for synchronous requests.
- Vector<char> data;
+ RefPtr<SharedBuffer> data;
ResourceError error;
ResourceResponse response;
unsigned long identifier = std::numeric_limits<unsigned long>::max();
- if (m_document->frame())
- identifier = m_document->frame()->loader().loadResourceSynchronously(request, m_options.allowCredentials, m_options.clientCredentialPolicy, error, response, data);
+ if (m_document.frame()) {
+ auto& frameLoader = m_document.frame()->loader();
+ if (!frameLoader.mixedContentChecker().canRunInsecureContent(m_document.securityOrigin(), requestURL))
+ return;
+ identifier = frameLoader.loadResourceSynchronously(request, m_options.allowCredentials, m_options.clientCredentialPolicy, error, response, data);
+ }
- InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client);
+#if ENABLE(WEB_TIMING)
+ loadTiming.setResponseEnd(MonotonicTime::now());
+#endif
- // No exception for file:/// resources, see <rdar://problem/4962298>.
- // Also, if we have an HTTP response, then it wasn't a network error in fact.
- if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode() <= 0) {
- m_client->didFail(error);
+ if (!error.isNull() && response.httpStatusCode() <= 0) {
+ if (requestURL.isLocalFile()) {
+ // We don't want XMLHttpRequest to raise an exception for file:// resources, see <rdar://problem/4962298>.
+ // FIXME: XMLHttpRequest quirks should be in XMLHttpRequest code, not in DocumentThreadableLoader.cpp.
+ didReceiveResponse(identifier, response, ResourceResponse::Tainting::Basic);
+ didFinishLoading(identifier, 0.0);
+ return;
+ }
+ logErrorAndFail(error);
return;
}
// FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the
// request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was
// requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials.
- if (requestURL != response.url() && !isAllowedRedirect(response.url())) {
- m_client->didFailRedirectCheck();
- return;
+ bool didRedirect = requestURL != response.url();
+ if (didRedirect) {
+ if (!isAllowedByContentSecurityPolicy(response.url(), ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
+ reportContentSecurityPolicyError(requestURL);
+ return;
+ }
+ if (!isAllowedRedirect(response.url())) {
+ reportCrossOriginResourceSharingError(requestURL);
+ return;
+ }
}
- didReceiveResponse(identifier, response);
-
- const char* bytes = static_cast<const char*>(data.data());
- int len = static_cast<int>(data.size());
- didReceiveData(identifier, bytes, len);
+ ResourceResponse::Tainting tainting = ResourceResponse::Tainting::Basic;
+ if (!m_sameOriginRequest) {
+ if (m_options.mode == FetchOptions::Mode::NoCors)
+ tainting = ResourceResponse::Tainting::Opaque;
+ else {
+ ASSERT(m_options.mode == FetchOptions::Mode::Cors);
+ tainting = ResourceResponse::Tainting::Cors;
+ String accessControlErrorDescription;
+ if (!passesAccessControlCheck(response, m_options.allowCredentials, securityOrigin(), accessControlErrorDescription)) {
+ logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, response.url(), accessControlErrorDescription, ResourceError::Type::AccessControl));
+ return;
+ }
+ }
+ }
+ didReceiveResponse(identifier, response, tainting);
+
+ if (data)
+ didReceiveData(identifier, data->data(), data->size());
+
+#if ENABLE(WEB_TIMING)
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()) {
+ ResourceTiming resourceTiming = ResourceTiming::fromSynchronousLoad(requestURL, m_options.initiator, loadTiming, response.networkLoadTiming(), response, securityOrigin());
+ if (options().initiatorContext == InitiatorContext::Worker)
+ finishedTimingForWorkerLoad(resourceTiming);
+ else {
+ if (document().domWindow() && document().domWindow()->performance())
+ document().domWindow()->performance()->addResourceTiming(WTFMove(resourceTiming));
+ }
+ }
+#endif
didFinishLoading(identifier, 0.0);
}
+bool DocumentThreadableLoader::isAllowedByContentSecurityPolicy(const URL& url, ContentSecurityPolicy::RedirectResponseReceived redirectResponseReceived)
+{
+ switch (m_options.contentSecurityPolicyEnforcement) {
+ case ContentSecurityPolicyEnforcement::DoNotEnforce:
+ return true;
+ case ContentSecurityPolicyEnforcement::EnforceChildSrcDirective:
+ return contentSecurityPolicy().allowChildContextFromSource(url, redirectResponseReceived);
+ case ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective:
+ return contentSecurityPolicy().allowConnectToSource(url, redirectResponseReceived);
+ case ContentSecurityPolicyEnforcement::EnforceScriptSrcDirective:
+ return contentSecurityPolicy().allowScriptFromSource(url, redirectResponseReceived);
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
bool DocumentThreadableLoader::isAllowedRedirect(const URL& url)
{
- if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests)
+ if (m_options.mode == FetchOptions::Mode::NoCors)
return true;
- return m_sameOriginRequest && securityOrigin()->canRequest(url);
+ return m_sameOriginRequest && securityOrigin().canRequest(url);
+}
+
+bool DocumentThreadableLoader::isXMLHttpRequest() const
+{
+ return m_options.initiator == cachedResourceRequestInitiators().xmlhttprequest;
}
-SecurityOrigin* DocumentThreadableLoader::securityOrigin() const
+SecurityOrigin& DocumentThreadableLoader::securityOrigin() const
{
- return m_options.securityOrigin ? m_options.securityOrigin.get() : m_document->securityOrigin();
+ return m_origin ? *m_origin : m_document.securityOrigin();
+}
+
+const ContentSecurityPolicy& DocumentThreadableLoader::contentSecurityPolicy() const
+{
+ if (m_contentSecurityPolicy)
+ return *m_contentSecurityPolicy.get();
+ ASSERT(m_document.contentSecurityPolicy());
+ return *m_document.contentSecurityPolicy();
+}
+
+void DocumentThreadableLoader::reportRedirectionWithBadScheme(const URL& url)
+{
+ logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, url, "Redirection to URL with a scheme that is not HTTP(S).", ResourceError::Type::AccessControl));
+}
+
+void DocumentThreadableLoader::reportContentSecurityPolicyError(const URL& url)
+{
+ logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, url, "Cross-origin redirection denied by Content Security Policy.", ResourceError::Type::AccessControl));
+}
+
+void DocumentThreadableLoader::reportCrossOriginResourceSharingError(const URL& url)
+{
+ logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, url, "Cross-origin redirection denied by Cross-Origin Resource Sharing policy.", ResourceError::Type::AccessControl));
+}
+
+void DocumentThreadableLoader::logErrorAndFail(const ResourceError& error)
+{
+ if (m_shouldLogError == ShouldLogError::Yes)
+ logError(m_document, error, m_options.initiator);
+ ASSERT(m_client);
+ m_client->didFail(error);
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/DocumentThreadableLoader.h b/Source/WebCore/loader/DocumentThreadableLoader.h
index bf31ba310..37f951f75 100644
--- a/Source/WebCore/loader/DocumentThreadableLoader.h
+++ b/Source/WebCore/loader/DocumentThreadableLoader.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009, 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,44 +29,45 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DocumentThreadableLoader_h
-#define DocumentThreadableLoader_h
+#pragma once
-#include "CachedRawResourceClient.h"
-#include "CachedResourceHandle.h"
-#include "FrameLoaderTypes.h"
+#include "ContentSecurityPolicy.h"
+#include "CrossOriginPreflightChecker.h"
+#include "ResourceResponse.h"
+#include "SecurityOrigin.h"
#include "ThreadableLoader.h"
-#include <wtf/Forward.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-#include <wtf/text/WTFString.h>
namespace WebCore {
class CachedRawResource;
+ class ContentSecurityPolicy;
class Document;
- class URL;
- class ResourceRequest;
- class SecurityOrigin;
class ThreadableLoaderClient;
class DocumentThreadableLoader : public RefCounted<DocumentThreadableLoader>, public ThreadableLoader, private CachedRawResourceClient {
WTF_MAKE_FAST_ALLOCATED;
public:
- static void loadResourceSynchronously(Document*, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&);
- static PassRefPtr<DocumentThreadableLoader> create(Document*, ThreadableLoaderClient*, const ResourceRequest&, const ThreadableLoaderOptions&);
+ static void loadResourceSynchronously(Document&, ResourceRequest&&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, RefPtr<SecurityOrigin>&&, std::unique_ptr<ContentSecurityPolicy>&&);
+ static void loadResourceSynchronously(Document&, ResourceRequest&&, ThreadableLoaderClient&, const ThreadableLoaderOptions&);
+
+ enum class ShouldLogError { No, Yes };
+ static RefPtr<DocumentThreadableLoader> create(Document&, ThreadableLoaderClient&, ResourceRequest&&, const ThreadableLoaderOptions&, RefPtr<SecurityOrigin>&&, std::unique_ptr<ContentSecurityPolicy>&&, String&& referrer, ShouldLogError);
+ static RefPtr<DocumentThreadableLoader> create(Document&, ThreadableLoaderClient&, ResourceRequest&&, const ThreadableLoaderOptions&, String&& referrer = String());
+
virtual ~DocumentThreadableLoader();
- virtual void cancel();
+ void cancel() override;
virtual void setDefersLoading(bool);
+ friend CrossOriginPreflightChecker;
+ friend class InspectorInstrumentation;
+ friend class InspectorNetworkAgent;
+
using RefCounted<DocumentThreadableLoader>::ref;
using RefCounted<DocumentThreadableLoader>::deref;
protected:
- virtual void refThreadableLoader() { ref(); }
- virtual void derefThreadableLoader() { deref(); }
+ void refThreadableLoader() override { ref(); }
+ void derefThreadableLoader() override { deref(); }
private:
enum BlockingBehavior {
@@ -73,42 +75,65 @@ namespace WebCore {
LoadAsynchronously
};
- DocumentThreadableLoader(Document*, ThreadableLoaderClient*, BlockingBehavior, const ResourceRequest&, const ThreadableLoaderOptions&);
+ DocumentThreadableLoader(Document&, ThreadableLoaderClient&, BlockingBehavior, ResourceRequest&&, const ThreadableLoaderOptions&, RefPtr<SecurityOrigin>&&, std::unique_ptr<ContentSecurityPolicy>&&, String&&, ShouldLogError);
void clearResource();
// CachedRawResourceClient
- virtual void dataSent(CachedResource*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
- virtual void responseReceived(CachedResource*, const ResourceResponse&);
- virtual void dataReceived(CachedResource*, const char* data, int dataLength);
- virtual void redirectReceived(CachedResource*, ResourceRequest&, const ResourceResponse&);
- virtual void notifyFinished(CachedResource*);
-
- void didReceiveResponse(unsigned long identifier, const ResourceResponse&);
+ void dataSent(CachedResource&, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ void responseReceived(CachedResource&, const ResourceResponse&) override;
+ void dataReceived(CachedResource&, const char* data, int dataLength) override;
+ void redirectReceived(CachedResource&, ResourceRequest&, const ResourceResponse&) override;
+ void finishedTimingForWorkerLoad(CachedResource&, const ResourceTiming&) override;
+ void notifyFinished(CachedResource&) override;
+
+ void didReceiveResponse(unsigned long identifier, const ResourceResponse&, ResourceResponse::Tainting);
void didReceiveData(unsigned long identifier, const char* data, int dataLength);
void didFinishLoading(unsigned long identifier, double finishTime);
void didFail(unsigned long identifier, const ResourceError&);
- void makeCrossOriginAccessRequest(const ResourceRequest&);
- void makeSimpleCrossOriginAccessRequest(const ResourceRequest& request);
- void makeCrossOriginAccessRequestWithPreflight(const ResourceRequest& request);
- void preflightSuccess();
- void preflightFailure(unsigned long identifier, const String& url, const String& errorDescription);
+ void makeCrossOriginAccessRequest(ResourceRequest&&);
+ void makeSimpleCrossOriginAccessRequest(ResourceRequest&&);
+ void makeCrossOriginAccessRequestWithPreflight(ResourceRequest&&);
+ void preflightSuccess(ResourceRequest&&);
+ void preflightFailure(unsigned long identifier, const ResourceError&);
+
+#if ENABLE(WEB_TIMING)
+ void finishedTimingForWorkerLoad(const ResourceTiming&);
+#endif
- void loadRequest(const ResourceRequest&, SecurityCheckPolicy);
+ void loadRequest(ResourceRequest&&, SecurityCheckPolicy);
bool isAllowedRedirect(const URL&);
+ bool isAllowedByContentSecurityPolicy(const URL&, ContentSecurityPolicy::RedirectResponseReceived);
- SecurityOrigin* securityOrigin() const;
+ bool isXMLHttpRequest() const final;
+
+ SecurityOrigin& securityOrigin() const;
+ const ContentSecurityPolicy& contentSecurityPolicy() const;
+
+ Document& document() { return m_document; }
+ const ThreadableLoaderOptions& options() const { return m_options; }
+ const String& referrer() const { return m_referrer; }
+ bool isLoading() { return m_resource || m_preflightChecker; }
+
+ void reportRedirectionWithBadScheme(const URL&);
+ void reportContentSecurityPolicyError(const URL&);
+ void reportCrossOriginResourceSharingError(const URL&);
+ void logErrorAndFail(const ResourceError&);
CachedResourceHandle<CachedRawResource> m_resource;
ThreadableLoaderClient* m_client;
- Document* m_document;
+ Document& m_document;
ThreadableLoaderOptions m_options;
+ RefPtr<SecurityOrigin> m_origin;
+ String m_referrer;
bool m_sameOriginRequest;
bool m_simpleRequest;
bool m_async;
- OwnPtr<ResourceRequest> m_actualRequest; // non-null during Access Control preflight checks
+ std::unique_ptr<ContentSecurityPolicy> m_contentSecurityPolicy;
+ std::optional<CrossOriginPreflightChecker> m_preflightChecker;
+ std::optional<HTTPHeaderMap> m_originalHeaders;
+
+ ShouldLogError m_shouldLogError;
};
} // namespace WebCore
-
-#endif // DocumentThreadableLoader_h
diff --git a/Source/WebCore/loader/DocumentWriter.cpp b/Source/WebCore/loader/DocumentWriter.cpp
index 742eb9907..24b214cd3 100644
--- a/Source/WebCore/loader/DocumentWriter.cpp
+++ b/Source/WebCore/loader/DocumentWriter.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010. Adam Barth. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,6 +30,7 @@
#include "config.h"
#include "DocumentWriter.h"
+#include "ContentSecurityPolicy.h"
#include "DOMImplementation.h"
#include "DOMWindow.h"
#include "Frame.h"
@@ -36,26 +38,25 @@
#include "FrameLoaderClient.h"
#include "FrameLoaderStateMachine.h"
#include "FrameView.h"
+#include "MIMETypeRegistry.h"
+#include "MainFrame.h"
#include "PluginDocument.h"
#include "RawDataDocumentParser.h"
#include "ScriptController.h"
#include "ScriptableDocumentParser.h"
#include "SecurityOrigin.h"
+#include "SecurityOriginPolicy.h"
#include "SegmentedString.h"
#include "Settings.h"
#include "SinkDocument.h"
#include "TextResourceDecoder.h"
#include <wtf/Ref.h>
-#if PLATFORM(IOS)
-#include "PDFDocument.h"
-#endif
-
namespace WebCore {
static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
{
- return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
+ return parentFrame && parentFrame->document()->securityOrigin().canAccess(frame->document()->securityOrigin());
}
DocumentWriter::DocumentWriter(Frame* frame)
@@ -72,12 +73,23 @@ DocumentWriter::DocumentWriter(Frame* frame)
void DocumentWriter::replaceDocument(const String& source, Document* ownerDocument)
{
m_frame->loader().stopAllLoaders();
+
+ // If we are in the midst of changing the frame's document, don't execute script
+ // that modifies the document further:
+ if (m_frame->documentIsBeingReplaced())
+ return;
+
begin(m_frame->document()->url(), true, ownerDocument);
+ // begin() might fire an unload event, which will result in a situation where no new document has been attached,
+ // and the old document has been detached. Therefore, bail out if no document is attached.
+ if (!m_frame->document())
+ return;
+
if (!source.isNull()) {
if (!m_hasReceivedSomeData) {
m_hasReceivedSomeData = true;
- m_frame->document()->setCompatibilityMode(Document::NoQuirksMode);
+ m_frame->document()->setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
}
// FIXME: This should call DocumentParser::appendBytes instead of append
@@ -91,7 +103,7 @@ void DocumentWriter::replaceDocument(const String& source, Document* ownerDocume
void DocumentWriter::clear()
{
- m_decoder = 0;
+ m_decoder = nullptr;
m_hasReceivedSomeData = false;
if (!m_encodingWasChosenByUser)
m_encoding = String();
@@ -102,17 +114,17 @@ void DocumentWriter::begin()
begin(URL());
}
-PassRefPtr<Document> DocumentWriter::createDocument(const URL& url)
+Ref<Document> DocumentWriter::createDocument(const URL& url)
{
- if (!m_frame->loader().stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader().client().shouldAlwaysUsePluginDocument(m_mimeType))
+ if (!m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->loader().client().shouldAlwaysUsePluginDocument(m_mimeType))
return PluginDocument::create(m_frame, url);
#if PLATFORM(IOS)
- if (equalIgnoringCase(m_mimeType, "application/pdf"))
- return PDFDocument::create(m_frame, url);
+ if (MIMETypeRegistry::isPDFMIMEType(m_mimeType) && (m_frame->isMainFrame() || !m_frame->settings().useImageDocumentForSubframePDF()))
+ return SinkDocument::create(m_frame, url);
#endif
if (!m_frame->loader().client().hasHTMLView())
return Document::createNonRenderedPlaceholder(m_frame, url);
- return DOMImplementation::createDocument(m_mimeType, m_frame, url, m_frame->inViewSourceMode());
+ return DOMImplementation::createDocument(m_mimeType, m_frame, url);
}
void DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* ownerDocument)
@@ -124,7 +136,7 @@ void DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* own
// Create a new document before clearing the frame, because it may need to
// inherit an aliased security context.
- RefPtr<Document> document = createDocument(url);
+ Ref<Document> document = createDocument(url);
// If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
// then replace the document with one whose parser will ignore the incoming data (bug 39323)
@@ -133,26 +145,42 @@ void DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* own
// FIXME: Do we need to consult the content security policy here about blocked plug-ins?
- bool shouldReuseDefaultView = m_frame->loader().stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url);
+ bool shouldReuseDefaultView = m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url);
if (shouldReuseDefaultView)
document->takeDOMWindowFrom(m_frame->document());
else
document->createDOMWindow();
- m_frame->loader().clear(document.get(), !shouldReuseDefaultView, !shouldReuseDefaultView);
+ // Per <http://www.w3.org/TR/upgrade-insecure-requests/>, we need to retain an ongoing set of upgraded
+ // requests in new navigation contexts. Although this information is present when we construct the
+ // Document object, it is discard in the subsequent 'clear' statements below. So, we must capture it
+ // so we can restore it.
+ HashSet<RefPtr<SecurityOrigin>> insecureNavigationRequestsToUpgrade;
+ if (auto* existingDocument = m_frame->document())
+ insecureNavigationRequestsToUpgrade = existingDocument->contentSecurityPolicy()->takeNavigationRequestsToUpgrade();
+
+ m_frame->loader().clear(document.ptr(), !shouldReuseDefaultView, !shouldReuseDefaultView);
clear();
+ // m_frame->loader().clear() might fire unload event which could remove the view of the document.
+ // Bail out if document has no view.
+ if (!document->view())
+ return;
+
if (!shouldReuseDefaultView)
m_frame->script().updatePlatformScriptObjects();
m_frame->loader().setOutgoingReferrer(url);
- m_frame->setDocument(document);
+ m_frame->setDocument(document.copyRef());
+
+ document->contentSecurityPolicy()->setInsecureNavigationRequestsToUpgrade(WTFMove(insecureNavigationRequestsToUpgrade));
if (m_decoder)
document->setDecoder(m_decoder.get());
if (ownerDocument) {
document->setCookieURL(ownerDocument->cookieURL());
- document->setSecurityOrigin(ownerDocument->securityOrigin());
+ document->setSecurityOriginPolicy(ownerDocument->securityOriginPolicy());
+ document->setStrictMixedContentMode(ownerDocument->isStrictMixedContentMode());
}
m_frame->loader().didBeginDocument(dispatch);
@@ -190,7 +218,7 @@ TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
m_decoder->setHintEncoding(parentFrame->document()->decoder());
if (m_encoding.isEmpty()) {
if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
+ m_decoder->setEncoding(parentFrame->document()->textEncoding(), TextResourceDecoder::EncodingFromParentFrame);
} else {
m_decoder->setEncoding(m_encoding,
m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
@@ -246,7 +274,7 @@ void DocumentWriter::end()
if (!m_parser)
return;
m_parser->finish();
- m_parser = 0;
+ m_parser = nullptr;
}
void DocumentWriter::setEncoding(const String& name, bool userChosen)
diff --git a/Source/WebCore/loader/DocumentWriter.h b/Source/WebCore/loader/DocumentWriter.h
index 81d0f129d..3f9518440 100644
--- a/Source/WebCore/loader/DocumentWriter.h
+++ b/Source/WebCore/loader/DocumentWriter.h
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DocumentWriter_h
-#define DocumentWriter_h
+#pragma once
#include "URL.h"
#include <wtf/text/WTFString.h>
@@ -52,11 +51,11 @@ public:
void begin();
void begin(const URL&, bool dispatchWindowObjectAvailable = true, Document* ownerDocument = 0);
void addData(const char* bytes, size_t length);
- void end();
+ WEBCORE_EXPORT void end();
void setFrame(Frame* frame) { m_frame = frame; }
- void setEncoding(const String& encoding, bool userChosen);
+ WEBCORE_EXPORT void setEncoding(const String& encoding, bool userChosen);
const String& mimeType() const { return m_mimeType; }
void setMIMEType(const String& type) { m_mimeType = type; }
@@ -68,7 +67,7 @@ public:
void setDocumentWasLoadedAsPartOfNavigation();
private:
- PassRefPtr<Document> createDocument(const URL&);
+ Ref<Document> createDocument(const URL&);
void clear();
Frame* m_frame;
@@ -90,5 +89,3 @@ private:
};
} // namespace WebCore
-
-#endif // DocumentWriter_h
diff --git a/Source/WebCore/loader/EmptyClients.cpp b/Source/WebCore/loader/EmptyClients.cpp
index faf4ce8f3..fb537cbb3 100644
--- a/Source/WebCore/loader/EmptyClients.cpp
+++ b/Source/WebCore/loader/EmptyClients.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,167 +28,715 @@
#include "config.h"
#include "EmptyClients.h"
-#include "DateTimeChooser.h"
+#include "ApplicationCacheStorage.h"
+#include "BackForwardClient.h"
+#include "ColorChooser.h"
+#include "ContextMenuClient.h"
+#include "DatabaseProvider.h"
+#include "DiagnosticLoggingClient.h"
+#include "DocumentFragment.h"
#include "DocumentLoader.h"
+#include "DragClient.h"
+#include "EditorClient.h"
#include "FileChooser.h"
#include "FormState.h"
#include "Frame.h"
+#include "FrameLoaderClient.h"
#include "FrameNetworkingContext.h"
#include "HTMLFormElement.h"
+#include "InProcessIDBServer.h"
+#include "InspectorClient.h"
+#include "NetworkStorageSession.h"
+#include "Page.h"
+#include "PageConfiguration.h"
+#include "PaymentCoordinatorClient.h"
+#include "PluginInfoProvider.h"
+#include "ProgressTrackerClient.h"
+#include "SecurityOriginData.h"
+#include "StorageArea.h"
+#include "StorageNamespace.h"
+#include "StorageNamespaceProvider.h"
+#include "StorageType.h"
+#include "TextCheckerClient.h"
+#include "ThreadableWebSocketChannel.h"
+#include "UserContentProvider.h"
+#include "VisitedLinkStore.h"
+#include <heap/HeapInlines.h>
#include <wtf/NeverDestroyed.h>
-#if ENABLE(INPUT_TYPE_COLOR)
-#include "ColorChooser.h"
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "CompiledContentExtension.h"
+#endif
+
+#if USE(QUICK_LOOK)
+#include "QuickLookHandleClient.h"
#endif
namespace WebCore {
-void fillWithEmptyClients(Page::PageClients& pageClients)
-{
- static NeverDestroyed<EmptyChromeClient> dummyChromeClient;
- pageClients.chromeClient = &dummyChromeClient.get();
+class UserMessageHandlerDescriptor;
+
+class EmptyBackForwardClient final : public BackForwardClient {
+ void addItem(Ref<HistoryItem>&&) final { }
+ void goToItem(HistoryItem*) final { }
+ HistoryItem* itemAtIndex(int) final { return nullptr; }
+ int backListCount() final { return 0; }
+ int forwardListCount() final { return 0; }
+ void close() final { }
+};
#if ENABLE(CONTEXT_MENUS)
- static NeverDestroyed<EmptyContextMenuClient> dummyContextMenuClient;
- pageClients.contextMenuClient = &dummyContextMenuClient.get();
+
+class EmptyContextMenuClient final : public ContextMenuClient {
+ void contextMenuDestroyed() final { }
+
+ void downloadURL(const URL&) final { }
+ void searchWithGoogle(const Frame*) final { }
+ void lookUpInDictionary(Frame*) final { }
+ bool isSpeaking() final { return false; }
+ void speak(const String&) final { }
+ void stopSpeaking() final { }
+
+#if PLATFORM(COCOA)
+ void searchWithSpotlight() final { }
+#endif
+
+#if USE(ACCESSIBILITY_CONTEXT_MENUS)
+ void showContextMenu() final { }
#endif
+};
+
+#endif // ENABLE(CONTEXT_MENUS)
+
+class EmptyDatabaseProvider final : public DatabaseProvider {
+#if ENABLE(INDEXED_DATABASE)
+ IDBClient::IDBConnectionToServer& idbConnectionToServerForSession(const SessionID&) final
+ {
+ static NeverDestroyed<Ref<InProcessIDBServer>> sharedConnection(InProcessIDBServer::create());
+ return sharedConnection.get()->connectionToServer();
+ }
+#endif
+};
+
+class EmptyDiagnosticLoggingClient final : public DiagnosticLoggingClient {
+ void logDiagnosticMessage(const String&, const String&, ShouldSample) final { }
+ void logDiagnosticMessageWithResult(const String&, const String&, DiagnosticLoggingResultType, ShouldSample) final { }
+ void logDiagnosticMessageWithValue(const String&, const String&, double, unsigned, ShouldSample) final { }
+ void logDiagnosticMessageWithEnhancedPrivacy(const String&, const String&, ShouldSample) final { }
+};
#if ENABLE(DRAG_SUPPORT)
- static NeverDestroyed<EmptyDragClient> dummyDragClient;
- pageClients.dragClient = &dummyDragClient.get();
+
+class EmptyDragClient final : public DragClient {
+ void willPerformDragDestinationAction(DragDestinationAction, const DragData&) final { }
+ void willPerformDragSourceAction(DragSourceAction, const IntPoint&, DataTransfer&) final { }
+ DragDestinationAction actionMaskForDrag(const DragData&) final { return DragDestinationActionNone; }
+ DragSourceAction dragSourceActionMaskForPoint(const IntPoint&) final { return DragSourceActionNone; }
+ void startDrag(DragImage, const IntPoint&, const IntPoint&, const FloatPoint&, DataTransfer&, Frame&, DragSourceAction) final { }
+ void dragControllerDestroyed() final { }
+};
+
+#endif // ENABLE(DRAG_SUPPORT)
+
+class EmptyEditorClient final : public EditorClient {
+ WTF_MAKE_FAST_ALLOCATED;
+
+public:
+ EmptyEditorClient() = default;
+
+private:
+ bool shouldDeleteRange(Range*) final { return false; }
+ bool smartInsertDeleteEnabled() final { return false; }
+ bool isSelectTrailingWhitespaceEnabled() final { return false; }
+ bool isContinuousSpellCheckingEnabled() final { return false; }
+ void toggleContinuousSpellChecking() final { }
+ bool isGrammarCheckingEnabled() final { return false; }
+ void toggleGrammarChecking() final { }
+ int spellCheckerDocumentTag() final { return -1; }
+
+ bool shouldBeginEditing(Range*) final { return false; }
+ bool shouldEndEditing(Range*) final { return false; }
+ bool shouldInsertNode(Node*, Range*, EditorInsertAction) final { return false; }
+ bool shouldInsertText(const String&, Range*, EditorInsertAction) final { return false; }
+ bool shouldChangeSelectedRange(Range*, Range*, EAffinity, bool) final { return false; }
+
+ bool shouldApplyStyle(StyleProperties*, Range*) final { return false; }
+ void didApplyStyle() final { }
+ bool shouldMoveRangeAfterDelete(Range*, Range*) final { return false; }
+
+ void didBeginEditing() final { }
+ void respondToChangedContents() final { }
+ void respondToChangedSelection(Frame*) final { }
+ void didChangeSelectionAndUpdateLayout() final { }
+ void updateEditorStateAfterLayoutIfEditabilityChanged() final { }
+ void discardedComposition(Frame*) final { }
+ void canceledComposition() final { }
+ void didEndEditing() final { }
+ void willWriteSelectionToPasteboard(Range*) final { }
+ void didWriteSelectionToPasteboard() final { }
+ void getClientPasteboardDataForRange(Range*, Vector<String>&, Vector<RefPtr<SharedBuffer>>&) final { }
+ void requestCandidatesForSelection(const VisibleSelection&) final { }
+ void handleAcceptedCandidateWithSoftSpaces(TextCheckingResult) final { }
+
+ void registerUndoStep(UndoStep&) final;
+ void registerRedoStep(UndoStep&) final;
+ void clearUndoRedoOperations() final { }
+
+ bool canCopyCut(Frame*, bool defaultValue) const final { return defaultValue; }
+ bool canPaste(Frame*, bool defaultValue) const final { return defaultValue; }
+ bool canUndo() const final { return false; }
+ bool canRedo() const final { return false; }
+
+ void undo() final { }
+ void redo() final { }
+
+ void handleKeyboardEvent(KeyboardEvent*) final { }
+ void handleInputMethodKeydown(KeyboardEvent*) final { }
+
+ void textFieldDidBeginEditing(Element*) final { }
+ void textFieldDidEndEditing(Element*) final { }
+ void textDidChangeInTextField(Element*) final { }
+ bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*) final { return false; }
+ void textWillBeDeletedInTextField(Element*) final { }
+ void textDidChangeInTextArea(Element*) final { }
+ void overflowScrollPositionChanged() final { }
+
+#if PLATFORM(IOS)
+ void startDelayingAndCoalescingContentChangeNotifications() final { }
+ void stopDelayingAndCoalescingContentChangeNotifications() final { }
+ void writeDataToPasteboard(NSDictionary*) final { }
+ NSArray* supportedPasteboardTypesForCurrentSelection() final { return nullptr; }
+ NSArray* readDataFromPasteboard(NSString*, int) final { return nullptr; }
+ bool hasRichlyEditableSelection() final { return false; }
+ int getPasteboardItemsCount() final { return 0; }
+ RefPtr<DocumentFragment> documentFragmentFromDelegate(int) final { return nullptr; }
+ bool performsTwoStepPaste(DocumentFragment*) final { return false; }
+ int pasteboardChangeCount() final { return 0; }
#endif
- static NeverDestroyed<EmptyEditorClient> dummyEditorClient;
- pageClients.editorClient = &dummyEditorClient.get();
+#if PLATFORM(COCOA)
+ NSString *userVisibleString(NSURL *) final { return nullptr; }
+ void setInsertionPasteboard(const String&) final { };
+ NSURL *canonicalizeURL(NSURL *) final { return nullptr; }
+ NSURL *canonicalizeURLString(NSString *) final { return nullptr; }
+#endif
- static NeverDestroyed<EmptyInspectorClient> dummyInspectorClient;
- pageClients.inspectorClient = &dummyInspectorClient.get();
+#if USE(APPKIT)
+ void uppercaseWord() final { }
+ void lowercaseWord() final { }
+ void capitalizeWord() final { }
+#endif
- static NeverDestroyed<EmptyFrameLoaderClient> dummyFrameLoaderClient;
- pageClients.loaderClientForMainFrame = &dummyFrameLoaderClient.get();
-
- static NeverDestroyed<EmptyProgressTrackerClient> dummyProgressTrackerClient;
- pageClients.progressTrackerClient = &dummyProgressTrackerClient.get();
-}
+#if USE(AUTOMATIC_TEXT_REPLACEMENT)
+ void showSubstitutionsPanel(bool) final { }
+ bool substitutionsPanelIsShowing() final { return false; }
+ void toggleSmartInsertDelete() final { }
+ bool isAutomaticQuoteSubstitutionEnabled() final { return false; }
+ void toggleAutomaticQuoteSubstitution() final { }
+ bool isAutomaticLinkDetectionEnabled() final { return false; }
+ void toggleAutomaticLinkDetection() final { }
+ bool isAutomaticDashSubstitutionEnabled() final { return false; }
+ void toggleAutomaticDashSubstitution() final { }
+ bool isAutomaticTextReplacementEnabled() final { return false; }
+ void toggleAutomaticTextReplacement() final { }
+ bool isAutomaticSpellingCorrectionEnabled() final { return false; }
+ void toggleAutomaticSpellingCorrection() final { }
+#endif
+
+#if PLATFORM(GTK)
+ bool shouldShowUnicodeMenu() final { return false; }
+#endif
+
+ TextCheckerClient* textChecker() final { return &m_textCheckerClient; }
+
+ void updateSpellingUIWithGrammarString(const String&, const GrammarDetail&) final { }
+ void updateSpellingUIWithMisspelledWord(const String&) final { }
+ void showSpellingUI(bool) final { }
+ bool spellingUIIsShowing() final { return false; }
+
+ void willSetInputMethodState() final { }
+ void setInputMethodState(bool) final { }
+
+ class EmptyTextCheckerClient final : public TextCheckerClient {
+ bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const final { return true; }
+ void ignoreWordInSpellDocument(const String&) final { }
+ void learnWord(const String&) final { }
+ void checkSpellingOfString(StringView, int*, int*) final { }
+ String getAutoCorrectSuggestionForMisspelledWord(const String&) final { return { }; }
+ void checkGrammarOfString(StringView, Vector<GrammarDetail>&, int*, int*) final { }
+
+#if USE(UNIFIED_TEXT_CHECKING)
+ Vector<TextCheckingResult> checkTextOfParagraph(StringView, TextCheckingTypeMask, const VisibleSelection&) final { return Vector<TextCheckingResult>(); }
+#endif
+
+ void getGuessesForWord(const String&, const String&, const VisibleSelection&, Vector<String>&) final { }
+ void requestCheckingOfString(TextCheckingRequest&, const VisibleSelection&) final;
+ };
+
+ EmptyTextCheckerClient m_textCheckerClient;
+};
+
+class EmptyFrameLoaderClient final : public FrameLoaderClient {
+ void frameLoaderDestroyed() final { }
+
+ bool hasWebView() const final { return true; } // mainly for assertions
+
+ void makeRepresentation(DocumentLoader*) final { }
+#if PLATFORM(IOS)
+ bool forceLayoutOnRestoreFromPageCache() final { return false; }
+#endif
+ void forceLayoutForNonHTML() final { }
+
+ void setCopiesOnScroll() final { }
+
+ void detachedFromParent2() final { }
+ void detachedFromParent3() final { }
+
+ void convertMainResourceLoadToDownload(DocumentLoader*, SessionID, const ResourceRequest&, const ResourceResponse&) final { }
+
+ void assignIdentifierToInitialRequest(unsigned long, DocumentLoader*, const ResourceRequest&) final { }
+ bool shouldUseCredentialStorage(DocumentLoader*, unsigned long) final { return false; }
+ void dispatchWillSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, const ResourceResponse&) final { }
+ void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) final { }
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long, const ProtectionSpace&) final { return false; }
+#endif
+
+#if PLATFORM(IOS)
+ RetainPtr<CFDictionaryRef> connectionProperties(DocumentLoader*, unsigned long) final { return nullptr; }
+#endif
+
+ void dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse&) final { }
+ void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long, int) final { }
+ void dispatchDidFinishLoading(DocumentLoader*, unsigned long) final { }
+#if ENABLE(DATA_DETECTION)
+ void dispatchDidFinishDataDetection(NSArray *) final { }
+#endif
+ void dispatchDidFailLoading(DocumentLoader*, unsigned long, const ResourceError&) final { }
+ bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int) final { return false; }
+
+ void dispatchDidDispatchOnloadEvents() final { }
+ void dispatchDidReceiveServerRedirectForProvisionalLoad() final { }
+ void dispatchDidCancelClientRedirect() final { }
+ void dispatchWillPerformClientRedirect(const URL&, double, double) final { }
+ void dispatchDidChangeLocationWithinPage() final { }
+ void dispatchDidPushStateWithinPage() final { }
+ void dispatchDidReplaceStateWithinPage() final { }
+ void dispatchDidPopStateWithinPage() final { }
+ void dispatchWillClose() final { }
+ void dispatchDidReceiveIcon() final { }
+ void dispatchDidStartProvisionalLoad() final { }
+ void dispatchDidReceiveTitle(const StringWithDirection&) final { }
+ void dispatchDidCommitLoad(std::optional<HasInsecureContent>) final { }
+ void dispatchDidFailProvisionalLoad(const ResourceError&) final { }
+ void dispatchDidFailLoad(const ResourceError&) final { }
+ void dispatchDidFinishDocumentLoad() final { }
+ void dispatchDidFinishLoad() final { }
+ void dispatchDidReachLayoutMilestone(LayoutMilestones) final { }
+
+ Frame* dispatchCreatePage(const NavigationAction&) final { return nullptr; }
+ void dispatchShow() final { }
+
+ void dispatchDecidePolicyForResponse(const ResourceResponse&, const ResourceRequest&, FramePolicyFunction) final { }
+ void dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, FormState*, const String&, FramePolicyFunction) final;
+ void dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, FormState*, FramePolicyFunction) final;
+ void cancelPolicyCheck() final { }
+
+ void dispatchUnableToImplementPolicy(const ResourceError&) final { }
+
+ void dispatchWillSendSubmitEvent(Ref<FormState>&&) final;
+ void dispatchWillSubmitForm(FormState&, FramePolicyFunction) final;
+
+ void revertToProvisionalState(DocumentLoader*) final { }
+ void setMainDocumentError(DocumentLoader*, const ResourceError&) final { }
+
+ void setMainFrameDocumentReady(bool) final { }
+
+ void startDownload(const ResourceRequest&, const String&) final { }
+
+ void willChangeTitle(DocumentLoader*) final { }
+ void didChangeTitle(DocumentLoader*) final { }
+
+ void willReplaceMultipartContent() final { }
+ void didReplaceMultipartContent() final { }
+
+ void committedLoad(DocumentLoader*, const char*, int) final { }
+ void finishedLoading(DocumentLoader*) final { }
+
+ ResourceError cancelledError(const ResourceRequest&) final { return { ResourceError::Type::Cancellation }; }
+ ResourceError blockedError(const ResourceRequest&) final { return { }; }
+ ResourceError blockedByContentBlockerError(const ResourceRequest&) final { return { }; }
+ ResourceError cannotShowURLError(const ResourceRequest&) final { return { }; }
+ ResourceError interruptedForPolicyChangeError(const ResourceRequest&) final { return { }; }
+#if ENABLE(CONTENT_FILTERING)
+ ResourceError blockedByContentFilterError(const ResourceRequest&) final { return { }; }
+#endif
+
+ ResourceError cannotShowMIMETypeError(const ResourceResponse&) final { return { }; }
+ ResourceError fileDoesNotExistError(const ResourceResponse&) final { return { }; }
+ ResourceError pluginWillHandleLoadError(const ResourceResponse&) final { return { }; }
+
+ bool shouldFallBack(const ResourceError&) final { return false; }
+
+ bool canHandleRequest(const ResourceRequest&) const final { return false; }
+ bool canShowMIMEType(const String&) const final { return false; }
+ bool canShowMIMETypeAsHTML(const String&) const final { return false; }
+ bool representationExistsForURLScheme(const String&) const final { return false; }
+ String generatedMIMETypeForURLScheme(const String&) const final { return emptyString(); }
+
+ void frameLoadCompleted() final { }
+ void restoreViewState() final { }
+ void provisionalLoadStarted() final { }
+ void didFinishLoad() final { }
+ void prepareForDataSourceReplacement() final { }
+
+ Ref<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) final;
+ void updateCachedDocumentLoader(DocumentLoader&) final { }
+ void setTitle(const StringWithDirection&, const URL&) final { }
+
+ String userAgent(const URL&) final { return emptyString(); }
+
+ void savePlatformDataToCachedFrame(CachedFrame*) final { }
+ void transitionToCommittedFromCachedFrame(CachedFrame*) final { }
+#if PLATFORM(IOS)
+ void didRestoreFrameHierarchyForCachedFrame() final { }
+#endif
+ void transitionToCommittedForNewPage() final { }
+
+ void didSaveToPageCache() final { }
+ void didRestoreFromPageCache() final { }
+
+ void dispatchDidBecomeFrameset(bool) final { }
+
+ void updateGlobalHistory() final { }
+ void updateGlobalHistoryRedirectLinks() final { }
+ bool shouldGoToHistoryItem(HistoryItem*) const final { return false; }
+ void updateGlobalHistoryItemForPage() final { }
+ void saveViewStateToItem(HistoryItem&) final { }
+ bool canCachePage() const final { return false; }
+ void didDisplayInsecureContent() final { }
+ void didRunInsecureContent(SecurityOrigin&, const URL&) final { }
+ void didDetectXSS(const URL&, bool) final { }
+ RefPtr<Frame> createFrame(const URL&, const String&, HTMLFrameOwnerElement&, const String&, bool, int, int) final;
+ RefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement&, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool) final;
+ void recreatePlugin(Widget*) final;
+ RefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement&, const URL&, const Vector<String>&, const Vector<String>&) final;
+
+ ObjectContentType objectContentType(const URL&, const String&) final { return ObjectContentType::None; }
+ String overrideMediaType() const final { return { }; }
+
+ void redirectDataToPlugin(Widget&) final { }
+ void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&) final { }
+
+ void registerForIconNotification(bool) final { }
+
+#if PLATFORM(COCOA)
+ RemoteAXObjectRef accessibilityRemoteObject() final { return nullptr; }
+ NSCachedURLResponse *willCacheResponse(DocumentLoader*, unsigned long, NSCachedURLResponse *response) const final { return response; }
+#endif
+
+#if PLATFORM(WIN) && USE(CFURLCONNECTION)
+ bool shouldCacheResponse(DocumentLoader*, unsigned long, const ResourceResponse&, const unsigned char*, unsigned long long) final { return true; }
+#endif
+
+ Ref<FrameNetworkingContext> createNetworkingContext() final;
+
+#if ENABLE(REQUEST_AUTOCOMPLETE)
+ void didRequestAutocomplete(Ref<FormState>&&) final { }
+#endif
+
+ bool isEmptyFrameLoaderClient() final { return true; }
+ void prefetchDNS(const String&) final { }
+
+#if USE(QUICK_LOOK)
+ RefPtr<QuickLookHandleClient> createQuickLookHandleClient(const String&, const String&) final { return nullptr; }
+#endif
+};
+
+class EmptyFrameNetworkingContext final : public FrameNetworkingContext {
+public:
+ static Ref<EmptyFrameNetworkingContext> create() { return adoptRef(*new EmptyFrameNetworkingContext); }
+
+private:
+ EmptyFrameNetworkingContext();
+
+ bool shouldClearReferrerOnHTTPSToHTTPRedirect() const { return true; }
+ NetworkStorageSession& storageSession() const final { return NetworkStorageSession::defaultStorageSession(); }
+
+#if PLATFORM(COCOA)
+ bool localFileContentSniffingEnabled() const { return false; }
+ SchedulePairHashSet* scheduledRunLoopPairs() const { return nullptr; }
+ RetainPtr<CFDataRef> sourceApplicationAuditData() const { return nullptr; };
+#endif
+
+#if PLATFORM(COCOA) || PLATFORM(WIN)
+ ResourceError blockedError(const ResourceRequest&) const final { return { }; }
+#endif
+};
+
+class EmptyInspectorClient final : public InspectorClient {
+ void inspectedPageDestroyed() final { }
+ Inspector::FrontendChannel* openLocalFrontend(InspectorController*) final { return nullptr; }
+ void bringFrontendToFront() final { }
+ void highlight() final { }
+ void hideHighlight() final { }
+};
+
+#if ENABLE(APPLE_PAY)
+
+class EmptyPaymentCoordinatorClient final : public PaymentCoordinatorClient {
+ bool supportsVersion(unsigned) final { return false; }
+ bool canMakePayments() final { return false; }
+ void canMakePaymentsWithActiveCard(const String&, const String&, std::function<void(bool)> completionHandler) final { callOnMainThread([completionHandler] { completionHandler(false); }); }
+ void openPaymentSetup(const String&, const String&, std::function<void(bool)> completionHandler) final { callOnMainThread([completionHandler] { completionHandler(false); }); }
+ bool showPaymentUI(const URL&, const Vector<URL>&, const PaymentRequest&) final { return false; }
+ void completeMerchantValidation(const PaymentMerchantSession&) final { }
+ void completeShippingMethodSelection(PaymentAuthorizationStatus, std::optional<PaymentRequest::TotalAndLineItems>) final { }
+ void completeShippingContactSelection(PaymentAuthorizationStatus, const Vector<PaymentRequest::ShippingMethod>&, std::optional<PaymentRequest::TotalAndLineItems>) final { }
+ void completePaymentMethodSelection(std::optional<WebCore::PaymentRequest::TotalAndLineItems>) final { }
+ void completePaymentSession(PaymentAuthorizationStatus) final { }
+ void abortPaymentSession() final { }
+ void paymentCoordinatorDestroyed() final { }
+};
+
+#endif
+
+class EmptyPluginInfoProvider final : public PluginInfoProvider {
+ void refreshPlugins() final { };
+ void getPluginInfo(Page&, Vector<PluginInfo>&) final { }
+ void getWebVisiblePluginInfo(Page&, Vector<PluginInfo>&) final { }
+};
class EmptyPopupMenu : public PopupMenu {
public:
- virtual void show(const IntRect&, FrameView*, int) { }
- virtual void hide() { }
- virtual void updateFromElement() { }
- virtual void disconnectClient() { }
+ EmptyPopupMenu() = default;
+private:
+ void show(const IntRect&, FrameView*, int) final { }
+ void hide() final { }
+ void updateFromElement() final { }
+ void disconnectClient() final { }
+};
+
+class EmptyProgressTrackerClient final : public ProgressTrackerClient {
+ void willChangeEstimatedProgress() final { }
+ void didChangeEstimatedProgress() final { }
+ void progressStarted(Frame&) final { }
+ void progressEstimateChanged(Frame&) final { }
+ void progressFinished(Frame&) final { }
};
class EmptySearchPopupMenu : public SearchPopupMenu {
public:
- virtual PopupMenu* popupMenu() { return m_popup.get(); }
- virtual void saveRecentSearches(const AtomicString&, const Vector<String>&) { }
- virtual void loadRecentSearches(const AtomicString&, Vector<String>&) { }
- virtual bool enabled() { return false; }
+ EmptySearchPopupMenu()
+ : m_popup(adoptRef(*new EmptyPopupMenu))
+ {
+ }
private:
- RefPtr<EmptyPopupMenu> m_popup;
+ PopupMenu* popupMenu() final { return m_popup.ptr(); }
+ void saveRecentSearches(const AtomicString&, const Vector<RecentSearch>&) final { }
+ void loadRecentSearches(const AtomicString&, Vector<RecentSearch>&) final { }
+ bool enabled() final { return false; }
+
+ Ref<EmptyPopupMenu> m_popup;
+};
+
+class EmptyStorageNamespaceProvider final : public StorageNamespaceProvider {
+ struct EmptyStorageArea : public StorageArea {
+ unsigned length() final { return 0; }
+ String key(unsigned) final { return { }; }
+ String item(const String&) final { return { }; }
+ void setItem(Frame*, const String&, const String&, bool&) final { }
+ void removeItem(Frame*, const String&) final { }
+ void clear(Frame*) final { }
+ bool contains(const String&) final { return false; }
+ bool canAccessStorage(Frame*) final { return false; }
+ StorageType storageType() const final { return StorageType::Local; }
+ size_t memoryBytesUsedByCache() final { return 0; }
+ SecurityOriginData securityOrigin() const final { return { }; }
+ };
+
+ struct EmptyStorageNamespace final : public StorageNamespace {
+ RefPtr<StorageArea> storageArea(const SecurityOriginData&) final { return adoptRef(*new EmptyStorageArea); }
+ RefPtr<StorageNamespace> copy(Page*) final { return adoptRef(*new EmptyStorageNamespace); }
+ };
+
+ RefPtr<StorageNamespace> createSessionStorageNamespace(Page&, unsigned) final;
+ RefPtr<StorageNamespace> createLocalStorageNamespace(unsigned) final;
+ RefPtr<StorageNamespace> createEphemeralLocalStorageNamespace(Page&, unsigned) final;
+ RefPtr<StorageNamespace> createTransientLocalStorageNamespace(SecurityOrigin&, unsigned) final;
+};
+
+class EmptyUserContentProvider final : public UserContentProvider {
+ void forEachUserScript(const std::function<void(DOMWrapperWorld&, const UserScript&)>&) const final { }
+ void forEachUserStyleSheet(const std::function<void(const UserStyleSheet&)>&) const final { }
+#if ENABLE(USER_MESSAGE_HANDLERS)
+ void forEachUserMessageHandler(const std::function<void(const UserMessageHandlerDescriptor&)>&) const final { }
+#endif
+#if ENABLE(CONTENT_EXTENSIONS)
+ ContentExtensions::ContentExtensionsBackend& userContentExtensionBackend() final { static NeverDestroyed<ContentExtensions::ContentExtensionsBackend> backend; return backend.get(); };
+#endif
};
-PassRefPtr<PopupMenu> EmptyChromeClient::createPopupMenu(PopupMenuClient*) const
+class EmptyVisitedLinkStore final : public VisitedLinkStore {
+ bool isLinkVisited(Page&, LinkHash, const URL&, const AtomicString&) final { return false; }
+ void addVisitedLink(Page&, LinkHash) final { }
+};
+
+RefPtr<PopupMenu> EmptyChromeClient::createPopupMenu(PopupMenuClient&) const
{
- return adoptRef(new EmptyPopupMenu());
+ return adoptRef(*new EmptyPopupMenu);
}
-PassRefPtr<SearchPopupMenu> EmptyChromeClient::createSearchPopupMenu(PopupMenuClient*) const
+RefPtr<SearchPopupMenu> EmptyChromeClient::createSearchPopupMenu(PopupMenuClient&) const
{
- return adoptRef(new EmptySearchPopupMenu());
+ return adoptRef(*new EmptySearchPopupMenu);
}
#if ENABLE(INPUT_TYPE_COLOR)
-PassOwnPtr<ColorChooser> EmptyChromeClient::createColorChooser(ColorChooserClient*, const Color&)
-{
- return nullptr;
-}
-#endif
-#if ENABLE(DATE_AND_TIME_INPUT_TYPES) && !PLATFORM(IOS)
-PassRefPtr<DateTimeChooser> EmptyChromeClient::openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&)
+std::unique_ptr<ColorChooser> EmptyChromeClient::createColorChooser(ColorChooserClient&, const Color&)
{
return nullptr;
}
+
#endif
-void EmptyChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser>)
+void EmptyChromeClient::runOpenPanel(Frame&, FileChooser&)
{
}
-void EmptyFrameLoaderClient::dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String&, FramePolicyFunction)
+void EmptyFrameLoaderClient::dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, FormState*, const String&, FramePolicyFunction)
{
}
-void EmptyFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, FramePolicyFunction)
+void EmptyFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, FormState*, FramePolicyFunction)
{
}
-void EmptyFrameLoaderClient::dispatchWillSendSubmitEvent(PassRefPtr<FormState>)
+void EmptyFrameLoaderClient::dispatchWillSendSubmitEvent(Ref<FormState>&&)
{
}
-void EmptyFrameLoaderClient::dispatchWillSubmitForm(PassRefPtr<FormState>, FramePolicyFunction)
+void EmptyFrameLoaderClient::dispatchWillSubmitForm(FormState&, FramePolicyFunction)
{
}
-PassRefPtr<DocumentLoader> EmptyFrameLoaderClient::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
+Ref<DocumentLoader> EmptyFrameLoaderClient::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
{
return DocumentLoader::create(request, substituteData);
}
-PassRefPtr<Frame> EmptyFrameLoaderClient::createFrame(const URL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int)
+RefPtr<Frame> EmptyFrameLoaderClient::createFrame(const URL&, const String&, HTMLFrameOwnerElement&, const String&, bool, int, int)
{
- return 0;
+ return nullptr;
}
-PassRefPtr<Widget> EmptyFrameLoaderClient::createPlugin(const IntSize&, HTMLPlugInElement*, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool)
+RefPtr<Widget> EmptyFrameLoaderClient::createPlugin(const IntSize&, HTMLPlugInElement&, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool)
{
- return 0;
+ return nullptr;
}
void EmptyFrameLoaderClient::recreatePlugin(Widget*)
{
}
-PassRefPtr<Widget> EmptyFrameLoaderClient::createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const URL&, const Vector<String>&, const Vector<String>&)
+RefPtr<Widget> EmptyFrameLoaderClient::createJavaAppletWidget(const IntSize&, HTMLAppletElement&, const URL&, const Vector<String>&, const Vector<String>&)
{
- return 0;
+ return nullptr;
}
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-PassRefPtr<Widget> EmptyFrameLoaderClient::createMediaPlayerProxyPlugin(const IntSize&, HTMLMediaElement*, const URL&, const Vector<String>&, const Vector<String>&, const String&)
+inline EmptyFrameNetworkingContext::EmptyFrameNetworkingContext()
+ : FrameNetworkingContext { nullptr }
{
- return 0;
}
-#endif
-PassRefPtr<FrameNetworkingContext> EmptyFrameLoaderClient::createNetworkingContext()
+Ref<FrameNetworkingContext> EmptyFrameLoaderClient::createNetworkingContext()
{
- return PassRefPtr<FrameNetworkingContext>();
+ return EmptyFrameNetworkingContext::create();
}
-void EmptyTextCheckerClient::requestCheckingOfString(PassRefPtr<TextCheckingRequest>)
+void EmptyEditorClient::EmptyTextCheckerClient::requestCheckingOfString(TextCheckingRequest&, const VisibleSelection&)
{
}
-void EmptyEditorClient::registerUndoStep(PassRefPtr<UndoStep>)
+void EmptyEditorClient::registerUndoStep(UndoStep&)
{
}
-void EmptyEditorClient::registerRedoStep(PassRefPtr<UndoStep>)
+void EmptyEditorClient::registerRedoStep(UndoStep&)
{
}
-#if ENABLE(CONTEXT_MENUS)
-#if USE(CROSS_PLATFORM_CONTEXT_MENUS)
-PassOwnPtr<ContextMenu> EmptyContextMenuClient::customizeMenu(PassOwnPtr<ContextMenu>)
+RefPtr<StorageNamespace> EmptyStorageNamespaceProvider::createSessionStorageNamespace(Page&, unsigned)
{
- return nullptr;
+ return adoptRef(*new EmptyStorageNamespace);
+}
+
+RefPtr<StorageNamespace> EmptyStorageNamespaceProvider::createLocalStorageNamespace(unsigned)
+{
+ return adoptRef(*new EmptyStorageNamespace);
+}
+
+RefPtr<StorageNamespace> EmptyStorageNamespaceProvider::createEphemeralLocalStorageNamespace(Page&, unsigned)
+{
+ return adoptRef(*new EmptyStorageNamespace);
}
+
+RefPtr<StorageNamespace> EmptyStorageNamespaceProvider::createTransientLocalStorageNamespace(SecurityOrigin&, unsigned)
+{
+ return adoptRef(*new EmptyStorageNamespace);
+}
+
+void fillWithEmptyClients(PageConfiguration& pageConfiguration)
+{
+ static NeverDestroyed<EmptyChromeClient> dummyChromeClient;
+ pageConfiguration.chromeClient = &dummyChromeClient.get();
+
+#if ENABLE(APPLE_PAY)
+ static NeverDestroyed<EmptyPaymentCoordinatorClient> dummyPaymentCoordinatorClient;
+ pageConfiguration.paymentCoordinatorClient = &dummyPaymentCoordinatorClient.get();
#endif
+
+#if ENABLE(CONTEXT_MENUS)
+ static NeverDestroyed<EmptyContextMenuClient> dummyContextMenuClient;
+ pageConfiguration.contextMenuClient = &dummyContextMenuClient.get();
#endif
+#if ENABLE(DRAG_SUPPORT)
+ static NeverDestroyed<EmptyDragClient> dummyDragClient;
+ pageConfiguration.dragClient = &dummyDragClient.get();
+#endif
+
+ static NeverDestroyed<EmptyInspectorClient> dummyInspectorClient;
+ pageConfiguration.inspectorClient = &dummyInspectorClient.get();
+
+ static NeverDestroyed<EmptyFrameLoaderClient> dummyFrameLoaderClient;
+ pageConfiguration.loaderClientForMainFrame = &dummyFrameLoaderClient.get();
+
+ static NeverDestroyed<EmptyProgressTrackerClient> dummyProgressTrackerClient;
+ pageConfiguration.progressTrackerClient = &dummyProgressTrackerClient.get();
+
+ pageConfiguration.backForwardClient = adoptRef(*new EmptyBackForwardClient);
+ pageConfiguration.diagnosticLoggingClient = std::make_unique<EmptyDiagnosticLoggingClient>();
+
+ pageConfiguration.applicationCacheStorage = ApplicationCacheStorage::create({ }, { });
+ pageConfiguration.databaseProvider = adoptRef(*new EmptyDatabaseProvider);
+ pageConfiguration.pluginInfoProvider = adoptRef(*new EmptyPluginInfoProvider);
+ pageConfiguration.storageNamespaceProvider = adoptRef(*new EmptyStorageNamespaceProvider);
+ pageConfiguration.userContentProvider = adoptRef(*new EmptyUserContentProvider);
+ pageConfiguration.visitedLinkStore = adoptRef(*new EmptyVisitedLinkStore);
+}
+
+UniqueRef<EditorClient> createEmptyEditorClient()
+{
+ return makeUniqueRef<EmptyEditorClient>();
+}
+
+DiagnosticLoggingClient& emptyDiagnosticLoggingClient()
+{
+ static NeverDestroyed<EmptyDiagnosticLoggingClient> client;
+ return client;
+}
+
}
diff --git a/Source/WebCore/loader/EmptyClients.h b/Source/WebCore/loader/EmptyClients.h
index 199c9cc4a..e2aa60ed7 100644
--- a/Source/WebCore/loader/EmptyClients.h
+++ b/Source/WebCore/loader/EmptyClients.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Eric Seidel (eric@webkit.org)
- * Copyright (C) 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2012 Samsung Electronics. All rights reserved.
*
@@ -13,10 +13,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -26,617 +26,188 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef EmptyClients_h
-#define EmptyClients_h
+#pragma once
#include "ChromeClient.h"
-#include "ContextMenuClient.h"
-#include "DeviceMotionClient.h"
-#include "DeviceOrientationClient.h"
-#include "DragClient.h"
-#include "EditorClient.h"
-#include "TextCheckerClient.h"
-#include "FloatRect.h"
-#include "FocusDirection.h"
-#include "FrameLoaderClient.h"
-#include "InspectorClient.h"
-#include "Page.h"
-#include "ProgressTrackerClient.h"
-#include "ResourceError.h"
-#include <wtf/text/StringView.h>
+#include <wtf/UniqueRef.h>
-/*
- This file holds empty Client stubs for use by WebCore.
- Viewless element needs to create a dummy Page->Frame->FrameView tree for use in parsing or executing JavaScript.
- This tree depends heavily on Clients (usually provided by WebKit classes).
-
- This file was first created for SVGImage as it had no way to access the current Page (nor should it,
- since Images are not tied to a page).
- See http://bugs.webkit.org/show_bug.cgi?id=5971 for the original discussion about this file.
-
- Ideally, whenever you change a Client class, you should add a stub here.
- Brittle, yes. Unfortunate, yes. Hopefully temporary.
-*/
+// Empty client classes for use by WebCore.
+//
+// First created for SVGImage as it had no way to access the current Page (nor should it, since Images are not tied to a page).
+// See http://bugs.webkit.org/show_bug.cgi?id=5971 for the original discussion about this file.
namespace WebCore {
-class GraphicsContext3D;
+class DiagnosticLoggingClient;
+class EditorClient;
+class PageConfiguration;
class EmptyChromeClient : public ChromeClient {
WTF_MAKE_FAST_ALLOCATED;
-public:
- virtual ~EmptyChromeClient() { }
- virtual void chromeDestroyed() override { }
-
- virtual void setWindowRect(const FloatRect&) override { }
- virtual FloatRect windowRect() override { return FloatRect(); }
-
- virtual FloatRect pageRect() override { return FloatRect(); }
-
- virtual void focus() override { }
- virtual void unfocus() override { }
-
- virtual bool canTakeFocus(FocusDirection) override { return false; }
- virtual void takeFocus(FocusDirection) override { }
-
- virtual void focusedElementChanged(Element*) override { }
- virtual void focusedFrameChanged(Frame*) override { }
-
- virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) override { return 0; }
- virtual void show() override { }
-
- virtual bool canRunModal() override { return false; }
- virtual void runModal() override { }
-
- virtual void setToolbarsVisible(bool) override { }
- virtual bool toolbarsVisible() override { return false; }
- virtual void setStatusbarVisible(bool) override { }
- virtual bool statusbarVisible() override { return false; }
+ void chromeDestroyed() override { }
- virtual void setScrollbarsVisible(bool) override { }
- virtual bool scrollbarsVisible() override { return false; }
+ void setWindowRect(const FloatRect&) final { }
+ FloatRect windowRect() final { return FloatRect(); }
- virtual void setMenubarVisible(bool) override { }
- virtual bool menubarVisible() override { return false; }
+ FloatRect pageRect() final { return FloatRect(); }
- virtual void setResizable(bool) override { }
+ void focus() final { }
+ void unfocus() final { }
- virtual void addMessageToConsole(MessageSource, MessageLevel, const String&, unsigned, unsigned, const String&) override { }
+ bool canTakeFocus(FocusDirection) final { return false; }
+ void takeFocus(FocusDirection) final { }
- virtual bool canRunBeforeUnloadConfirmPanel() override { return false; }
- virtual bool runBeforeUnloadConfirmPanel(const String&, Frame*) override { return true; }
+ void focusedElementChanged(Element*) final { }
+ void focusedFrameChanged(Frame*) final { }
- virtual void closeWindowSoon() override { }
+ Page* createWindow(Frame&, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) final { return nullptr; }
+ void show() final { }
- virtual void runJavaScriptAlert(Frame*, const String&) override { }
- virtual bool runJavaScriptConfirm(Frame*, const String&) override { return false; }
- virtual bool runJavaScriptPrompt(Frame*, const String&, const String&, String&) override { return false; }
- virtual bool shouldInterruptJavaScript() override { return false; }
+ bool canRunModal() final { return false; }
+ void runModal() final { }
- virtual bool selectItemWritingDirectionIsNatural() override { return false; }
- virtual bool selectItemAlignmentFollowsMenuWritingDirection() override { return false; }
- virtual bool hasOpenedPopup() const override { return false; }
- virtual PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const override;
- virtual PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const override;
+ void setToolbarsVisible(bool) final { }
+ bool toolbarsVisible() final { return false; }
- virtual void setStatusbarText(const String&) override { }
+ void setStatusbarVisible(bool) final { }
+ bool statusbarVisible() final { return false; }
- virtual KeyboardUIMode keyboardUIMode() override { return KeyboardAccessDefault; }
+ void setScrollbarsVisible(bool) final { }
+ bool scrollbarsVisible() final { return false; }
- virtual IntRect windowResizerRect() const override { return IntRect(); }
+ void setMenubarVisible(bool) final { }
+ bool menubarVisible() final { return false; }
- virtual void invalidateRootView(const IntRect&, bool) override { }
- virtual void invalidateContentsAndRootView(const IntRect&, bool) override { }
- virtual void invalidateContentsForSlowScroll(const IntRect&, bool) override { }
- virtual void scroll(const IntSize&, const IntRect&, const IntRect&) override { }
-#if USE(TILED_BACKING_STORE)
- virtual void delegatedScrollRequested(const IntPoint&) { }
-#endif
-#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER)
- virtual void scheduleAnimation() { }
-#endif
+ void setResizable(bool) final { }
- virtual IntPoint screenToRootView(const IntPoint& p) const override { return p; }
- virtual IntRect rootViewToScreen(const IntRect& r) const override { return r; }
- virtual PlatformPageClient platformPageClient() const override { return 0; }
- virtual void contentsSizeChanged(Frame*, const IntSize&) const override { }
+ void addMessageToConsole(MessageSource, MessageLevel, const String&, unsigned, unsigned, const String&) final { }
- virtual void scrollbarsModeDidChange() const override { }
- virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned) override { }
+ bool canRunBeforeUnloadConfirmPanel() final { return false; }
+ bool runBeforeUnloadConfirmPanel(const String&, Frame&) final { return true; }
- virtual void setToolTip(const String&, TextDirection) override { }
+ void closeWindowSoon() final { }
- virtual void print(Frame*) override { }
+ void runJavaScriptAlert(Frame&, const String&) final { }
+ bool runJavaScriptConfirm(Frame&, const String&) final { return false; }
+ bool runJavaScriptPrompt(Frame&, const String&, const String&, String&) final { return false; }
-#if ENABLE(SQL_DATABASE)
- virtual void exceededDatabaseQuota(Frame*, const String&, DatabaseDetails) override { }
-#endif
+ bool selectItemWritingDirectionIsNatural() final { return false; }
+ bool selectItemAlignmentFollowsMenuWritingDirection() final { return false; }
+ bool hasOpenedPopup() const final { return false; }
+ RefPtr<PopupMenu> createPopupMenu(PopupMenuClient&) const final;
+ RefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient&) const final;
- virtual void reachedMaxAppCacheSize(int64_t) override { }
- virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*, int64_t) override { }
+ void setStatusbarText(const String&) final { }
-#if ENABLE(DIRECTORY_UPLOAD)
- virtual void enumerateChosenDirectory(FileChooser*) { }
-#endif
+ KeyboardUIMode keyboardUIMode() final { return KeyboardAccessDefault; }
-#if ENABLE(INPUT_TYPE_COLOR)
- virtual PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color&) override;
-#endif
+ void invalidateRootView(const IntRect&) final { }
+ void invalidateContentsAndRootView(const IntRect&) override { }
+ void invalidateContentsForSlowScroll(const IntRect&) final { }
+ void scroll(const IntSize&, const IntRect&, const IntRect&) final { }
-#if ENABLE(DATE_AND_TIME_INPUT_TYPES) && !PLATFORM(IOS)
- virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) override;
+#if USE(COORDINATED_GRAPHICS)
+ void delegatedScrollRequested(const IntPoint&) final { }
#endif
- virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) override;
- virtual void loadIconForFiles(const Vector<String>&, FileIconLoader*) override { }
-
- virtual void formStateDidChange(const Node*) override { }
-
- virtual void elementDidFocus(const Node*) override { }
- virtual void elementDidBlur(const Node*) override { }
-
-#if !PLATFORM(IOS)
- virtual void setCursor(const Cursor&) override { }
- virtual void setCursorHiddenUntilMouseMoves(bool) override { }
+#if !USE(REQUEST_ANIMATION_FRAME_TIMER)
+ void scheduleAnimation() final { }
#endif
- virtual void scrollRectIntoView(const IntRect&) const override { }
-
-#if USE(ACCELERATED_COMPOSITING)
- virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) override { }
- virtual void setNeedsOneShotDrawingSynchronization() override { }
- virtual void scheduleCompositingLayerFlush() override { }
-#endif
-
-#if PLATFORM(WIN)
- virtual void setLastSetCursorToCurrentCursor() override { }
- virtual void AXStartFrameLoad() override { }
- virtual void AXFinishFrameLoad() override { }
-#endif
+ IntPoint screenToRootView(const IntPoint& p) const final { return p; }
+ IntRect rootViewToScreen(const IntRect& r) const final { return r; }
#if PLATFORM(IOS)
-#if ENABLE(TOUCH_EVENTS)
- virtual void didPreventDefaultForEvent() override { }
+ IntPoint accessibilityScreenToRootView(const IntPoint& p) const final { return p; };
+ IntRect rootViewToAccessibilityScreen(const IntRect& r) const final { return r; };
#endif
- virtual void didReceiveMobileDocType() override { }
- virtual void setNeedsScrollNotifications(Frame*, bool) override { }
- virtual void observedContentChange(Frame*) override { }
- virtual void clearContentChangeObservers(Frame*) override { }
- virtual void notifyRevealedSelectionByScrollingFrame(Frame*) override { }
- virtual void didLayout(LayoutType) override { }
- virtual void didStartOverflowScroll() override { }
- virtual void didEndOverflowScroll() override { }
-
- virtual void suppressFormNotifications() override { }
- virtual void restoreFormNotifications() override { }
-
- virtual void addOrUpdateScrollingLayer(Node*, PlatformLayer*, PlatformLayer*, const IntSize&, bool, bool) override { }
- virtual void removeScrollingLayer(Node*, PlatformLayer*, PlatformLayer*) override { }
-
- virtual void webAppOrientationsUpdated() override { };
-#endif // PLATFORM(IOS)
-#if PLATFORM(IOS)
- virtual bool isStopping() override { return false; }
-#endif
+ PlatformPageClient platformPageClient() const final { return 0; }
+ void contentsSizeChanged(Frame&, const IntSize&) const final { }
-#if ENABLE(TOUCH_EVENTS)
- virtual void needTouchEvents(bool) override { }
-#endif
-
- virtual void numWheelEventHandlersChanged(unsigned) override { }
-
- virtual bool isEmptyChromeClient() const override { return true; }
+ void scrollbarsModeDidChange() const final { }
+ void mouseDidMoveOverElement(const HitTestResult&, unsigned) final { }
- virtual void didAssociateFormControls(const Vector<RefPtr<Element>>&) override { }
- virtual bool shouldNotifyOnFormChanges() override { return false; }
-};
+ void setToolTip(const String&, TextDirection) final { }
-// FIXME (bug 116233): Get rid of EmptyFrameLoaderClient. It is a travesty.
+ void print(Frame&) final { }
-class EmptyFrameLoaderClient : public FrameLoaderClient {
- WTF_MAKE_NONCOPYABLE(EmptyFrameLoaderClient); WTF_MAKE_FAST_ALLOCATED;
-public:
- EmptyFrameLoaderClient() { }
- virtual ~EmptyFrameLoaderClient() { }
- virtual void frameLoaderDestroyed() override { }
+ void exceededDatabaseQuota(Frame&, const String&, DatabaseDetails) final { }
- virtual bool hasWebView() const override { return true; } // mainly for assertions
+ void reachedMaxAppCacheSize(int64_t) final { }
+ void reachedApplicationCacheOriginQuota(SecurityOrigin&, int64_t) final { }
- virtual void makeRepresentation(DocumentLoader*) override { }
- virtual void forceLayout() override { }
-#if PLATFORM(IOS)
- virtual void forceLayoutWithoutRecalculatingStyles() override { }
+#if ENABLE(INPUT_TYPE_COLOR)
+ std::unique_ptr<ColorChooser> createColorChooser(ColorChooserClient&, const Color&) final;
#endif
- virtual void forceLayoutForNonHTML() override { }
-
- virtual void setCopiesOnScroll() override { }
-
- virtual void detachedFromParent2() override { }
- virtual void detachedFromParent3() override { }
-
- virtual void convertMainResourceLoadToDownload(DocumentLoader*, const ResourceRequest&, const ResourceResponse&) override { }
- virtual void assignIdentifierToInitialRequest(unsigned long, DocumentLoader*, const ResourceRequest&) override { }
- virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long) override { return false; }
- virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, const ResourceResponse&) override { }
- virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) override { }
- virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) override { }
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
- virtual bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long, const ProtectionSpace&) override { return false; }
-#endif
+ void runOpenPanel(Frame&, FileChooser&) final;
+ void loadIconForFiles(const Vector<String>&, FileIconLoader&) final { }
-#if PLATFORM(IOS)
- virtual RetainPtr<CFDictionaryRef> connectionProperties(DocumentLoader*, unsigned long) override { return nullptr; }
-#endif
+ void elementDidFocus(Element&) final { }
+ void elementDidBlur(Element&) final { }
- virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse&) override { }
- virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long, int) override { }
- virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long) override { }
- virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long, const ResourceError&) override { }
- virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int) override { return false; }
-
- virtual void dispatchDidHandleOnloadEvents() override { }
- virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() override { }
- virtual void dispatchDidCancelClientRedirect() override { }
- virtual void dispatchWillPerformClientRedirect(const URL&, double, double) override { }
- virtual void dispatchDidChangeLocationWithinPage() override { }
- virtual void dispatchDidPushStateWithinPage() override { }
- virtual void dispatchDidReplaceStateWithinPage() override { }
- virtual void dispatchDidPopStateWithinPage() override { }
- virtual void dispatchWillClose() override { }
- virtual void dispatchDidReceiveIcon() override { }
- virtual void dispatchDidStartProvisionalLoad() override { }
- virtual void dispatchDidReceiveTitle(const StringWithDirection&) override { }
- virtual void dispatchDidChangeIcons(IconType) override { }
- virtual void dispatchDidCommitLoad() override { }
- virtual void dispatchDidFailProvisionalLoad(const ResourceError&) override { }
- virtual void dispatchDidFailLoad(const ResourceError&) override { }
- virtual void dispatchDidFinishDocumentLoad() override { }
- virtual void dispatchDidFinishLoad() override { }
- virtual void dispatchDidLayout(LayoutMilestones) override { }
-
- virtual Frame* dispatchCreatePage(const NavigationAction&) override { return 0; }
- virtual void dispatchShow() override { }
-
- virtual void dispatchDecidePolicyForResponse(const ResourceResponse&, const ResourceRequest&, FramePolicyFunction) override { }
- virtual void dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String&, FramePolicyFunction) override;
- virtual void dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, FramePolicyFunction) override;
- virtual void cancelPolicyCheck() override { }
-
- virtual void dispatchUnableToImplementPolicy(const ResourceError&) override { }
-
- virtual void dispatchWillSendSubmitEvent(PassRefPtr<FormState>) override;
- virtual void dispatchWillSubmitForm(PassRefPtr<FormState>, FramePolicyFunction) override;
-
- virtual void revertToProvisionalState(DocumentLoader*) override { }
- virtual void setMainDocumentError(DocumentLoader*, const ResourceError&) override { }
-
- virtual void setMainFrameDocumentReady(bool) override { }
-
- virtual void startDownload(const ResourceRequest&, const String& suggestedName = String()) override { UNUSED_PARAM(suggestedName); }
-
- virtual void willChangeTitle(DocumentLoader*) override { }
- virtual void didChangeTitle(DocumentLoader*) override { }
-
- virtual void committedLoad(DocumentLoader*, const char*, int) override { }
- virtual void finishedLoading(DocumentLoader*) override { }
-
- virtual ResourceError cancelledError(const ResourceRequest&) override { ResourceError error("", 0, "", ""); error.setIsCancellation(true); return error; }
- virtual ResourceError blockedError(const ResourceRequest&) override { return ResourceError("", 0, "", ""); }
- virtual ResourceError cannotShowURLError(const ResourceRequest&) override { return ResourceError("", 0, "", ""); }
- virtual ResourceError interruptedForPolicyChangeError(const ResourceRequest&) override { return ResourceError("", 0, "", ""); }
-
- virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&) override { return ResourceError("", 0, "", ""); }
- virtual ResourceError fileDoesNotExistError(const ResourceResponse&) override { return ResourceError("", 0, "", ""); }
- virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&) override { return ResourceError("", 0, "", ""); }
-
- virtual bool shouldFallBack(const ResourceError&) override { return false; }
-
- virtual bool canHandleRequest(const ResourceRequest&) const override { return false; }
- virtual bool canShowMIMEType(const String&) const override { return false; }
- virtual bool canShowMIMETypeAsHTML(const String&) const override { return false; }
- virtual bool representationExistsForURLScheme(const String&) const override { return false; }
- virtual String generatedMIMETypeForURLScheme(const String&) const override { return ""; }
-
- virtual void frameLoadCompleted() override { }
- virtual void restoreViewState() override { }
- virtual void provisionalLoadStarted() override { }
- virtual void didFinishLoad() override { }
- virtual void prepareForDataSourceReplacement() override { }
-
- virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) override;
- virtual void setTitle(const StringWithDirection&, const URL&) override { }
-
- virtual String userAgent(const URL&) override { return ""; }
-
- virtual void savePlatformDataToCachedFrame(CachedFrame*) override { }
- virtual void transitionToCommittedFromCachedFrame(CachedFrame*) override { }
-#if PLATFORM(IOS)
- virtual void didRestoreFrameHierarchyForCachedFrame() override { }
-#endif
- virtual void transitionToCommittedForNewPage() override { }
-
- virtual void didSaveToPageCache() override { }
- virtual void didRestoreFromPageCache() override { }
-
- virtual void dispatchDidBecomeFrameset(bool) override { }
-
- virtual void updateGlobalHistory() override { }
- virtual void updateGlobalHistoryRedirectLinks() override { }
- virtual bool shouldGoToHistoryItem(HistoryItem*) const override { return false; }
- virtual void updateGlobalHistoryItemForPage() override { }
- virtual void saveViewStateToItem(HistoryItem*) override { }
- virtual bool canCachePage() const override { return false; }
- virtual void didDisplayInsecureContent() override { }
- virtual void didRunInsecureContent(SecurityOrigin*, const URL&) override { }
- virtual void didDetectXSS(const URL&, bool) override { }
- virtual PassRefPtr<Frame> createFrame(const URL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) override;
- virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool) override;
- virtual void recreatePlugin(Widget*) override;
- virtual PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const URL&, const Vector<String>&, const Vector<String>&) override;
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- virtual PassRefPtr<Widget> createMediaPlayerProxyPlugin(const IntSize&, HTMLMediaElement*, const URL&, const Vector<String>&, const Vector<String>&, const String&) override;
- virtual void hideMediaPlayerProxyPlugin(Widget*) override { }
- virtual void showMediaPlayerProxyPlugin(Widget*) override { }
+#if !PLATFORM(IOS)
+ void setCursor(const Cursor&) final { }
+ void setCursorHiddenUntilMouseMoves(bool) final { }
#endif
- virtual ObjectContentType objectContentType(const URL&, const String&, bool) override { return ObjectContentType(); }
- virtual String overrideMediaType() const override { return String(); }
-
- virtual void redirectDataToPlugin(Widget*) override { }
- virtual void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&) override { }
+ void scrollRectIntoView(const IntRect&) const final { }
- virtual void registerForIconNotification(bool) override { }
+ void attachRootGraphicsLayer(Frame&, GraphicsLayer*) final { }
+ void attachViewOverlayGraphicsLayer(Frame&, GraphicsLayer*) final { }
+ void setNeedsOneShotDrawingSynchronization() final { }
+ void scheduleCompositingLayerFlush() final { }
-#if PLATFORM(MAC)
- virtual RemoteAXObjectRef accessibilityRemoteObject() override { return 0; }
- virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long, NSCachedURLResponse* response) const override { return response; }
-#endif
-#if PLATFORM(WIN) && USE(CFNETWORK)
- // FIXME: Windows should use willCacheResponse - <https://bugs.webkit.org/show_bug.cgi?id=57257>.
- virtual bool shouldCacheResponse(DocumentLoader*, unsigned long, const ResourceResponse&, const unsigned char*, unsigned long long) override { return true; }
+#if PLATFORM(WIN)
+ void setLastSetCursorToCurrentCursor() final { }
+ void AXStartFrameLoad() final { }
+ void AXFinishFrameLoad() final { }
#endif
- virtual PassRefPtr<FrameNetworkingContext> createNetworkingContext() override;
-
- virtual bool isEmptyFrameLoaderClient() override { return true; }
-};
-
-class EmptyTextCheckerClient : public TextCheckerClient {
-public:
- virtual bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const override { return true; }
- virtual void ignoreWordInSpellDocument(const String&) override { }
- virtual void learnWord(const String&) override { }
- virtual void checkSpellingOfString(const UChar*, int, int*, int*) override { }
- virtual String getAutoCorrectSuggestionForMisspelledWord(const String&) override { return String(); }
- virtual void checkGrammarOfString(const UChar*, int, Vector<GrammarDetail>&, int*, int*) override { }
-
-#if USE(UNIFIED_TEXT_CHECKING)
- virtual Vector<TextCheckingResult> checkTextOfParagraph(StringView, TextCheckingTypeMask) override { return Vector<TextCheckingResult>(); }
+#if ENABLE(IOS_TOUCH_EVENTS)
+ void didPreventDefaultForEvent() final { }
#endif
- virtual void getGuessesForWord(const String&, const String&, Vector<String>&) override { }
- virtual void requestCheckingOfString(PassRefPtr<TextCheckingRequest>) override;
-};
-
-class EmptyEditorClient : public EditorClient {
- WTF_MAKE_NONCOPYABLE(EmptyEditorClient); WTF_MAKE_FAST_ALLOCATED;
-public:
- EmptyEditorClient() { }
- virtual ~EmptyEditorClient() { }
- virtual void pageDestroyed() override { }
-
- virtual bool shouldDeleteRange(Range*) override { return false; }
- virtual bool smartInsertDeleteEnabled() override { return false; }
- virtual bool isSelectTrailingWhitespaceEnabled() override { return false; }
- virtual bool isContinuousSpellCheckingEnabled() override { return false; }
- virtual void toggleContinuousSpellChecking() override { }
- virtual bool isGrammarCheckingEnabled() override { return false; }
- virtual void toggleGrammarChecking() override { }
- virtual int spellCheckerDocumentTag() override { return -1; }
-
-
- virtual bool shouldBeginEditing(Range*) override { return false; }
- virtual bool shouldEndEditing(Range*) override { return false; }
- virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction) override { return false; }
- virtual bool shouldInsertText(const String&, Range*, EditorInsertAction) override { return false; }
- virtual bool shouldChangeSelectedRange(Range*, Range*, EAffinity, bool) override { return false; }
-
- virtual bool shouldApplyStyle(StyleProperties*, Range*) override { return false; }
- virtual bool shouldMoveRangeAfterDelete(Range*, Range*) override { return false; }
-
- virtual void didBeginEditing() override { }
- virtual void respondToChangedContents() override { }
- virtual void respondToChangedSelection(Frame*) override { }
- virtual void didEndEditing() override { }
- virtual void willWriteSelectionToPasteboard(Range*) override { }
- virtual void didWriteSelectionToPasteboard() override { }
- virtual void getClientPasteboardDataForRange(Range*, Vector<String>&, Vector<RefPtr<SharedBuffer>>&) override { }
-
- virtual void registerUndoStep(PassRefPtr<UndoStep>) override;
- virtual void registerRedoStep(PassRefPtr<UndoStep>) override;
- virtual void clearUndoRedoOperations() override { }
-
- virtual bool canCopyCut(Frame*, bool defaultValue) const override { return defaultValue; }
- virtual bool canPaste(Frame*, bool defaultValue) const override { return defaultValue; }
- virtual bool canUndo() const override { return false; }
- virtual bool canRedo() const override { return false; }
-
- virtual void undo() override { }
- virtual void redo() override { }
-
- virtual void handleKeyboardEvent(KeyboardEvent*) override { }
- virtual void handleInputMethodKeydown(KeyboardEvent*) override { }
-
- virtual void textFieldDidBeginEditing(Element*) override { }
- virtual void textFieldDidEndEditing(Element*) override { }
- virtual void textDidChangeInTextField(Element*) override { }
- virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*) override { return false; }
- virtual void textWillBeDeletedInTextField(Element*) override { }
- virtual void textDidChangeInTextArea(Element*) override { }
-
#if PLATFORM(IOS)
- virtual void suppressSelectionNotifications() override { }
- virtual void restoreSelectionNotifications() override { }
- virtual void startDelayingAndCoalescingContentChangeNotifications() override { }
- virtual void stopDelayingAndCoalescingContentChangeNotifications() override { }
- virtual void writeDataToPasteboard(NSDictionary*) override { }
- virtual NSArray* supportedPasteboardTypesForCurrentSelection() override { return nullptr; }
- virtual NSArray* readDataFromPasteboard(NSString*, int) override { return nullptr; }
- virtual bool hasRichlyEditableSelection() override { return false; }
- virtual int getPasteboardItemsCount() override { return 0; }
- virtual DocumentFragment* documentFragmentFromDelegate(int) override { return nullptr; }
- virtual bool performsTwoStepPaste(DocumentFragment*) override { return false; }
- virtual int pasteboardChangeCount() override { return 0; }
-#endif
-
-#if PLATFORM(MAC)
- virtual NSString* userVisibleString(NSURL*) override { return 0; }
- virtual DocumentFragment* documentFragmentFromAttributedString(NSAttributedString*, Vector<RefPtr<ArchiveResource>>&) override { return 0; };
- virtual void setInsertionPasteboard(const String&) override { };
- virtual NSURL *canonicalizeURL(NSURL*) override { return 0; }
- virtual NSURL *canonicalizeURLString(NSString*) override { return 0; }
-#endif
-
-#if USE(APPKIT)
- virtual void uppercaseWord() override { }
- virtual void lowercaseWord() override { }
- virtual void capitalizeWord() override { }
-#endif
-
-#if USE(AUTOMATIC_TEXT_REPLACEMENT)
- virtual void showSubstitutionsPanel(bool) override { }
- virtual bool substitutionsPanelIsShowing() override { return false; }
- virtual void toggleSmartInsertDelete() override { }
- virtual bool isAutomaticQuoteSubstitutionEnabled() override { return false; }
- virtual void toggleAutomaticQuoteSubstitution() override { }
- virtual bool isAutomaticLinkDetectionEnabled() override { return false; }
- virtual void toggleAutomaticLinkDetection() override { }
- virtual bool isAutomaticDashSubstitutionEnabled() override { return false; }
- virtual void toggleAutomaticDashSubstitution() override { }
- virtual bool isAutomaticTextReplacementEnabled() override { return false; }
- virtual void toggleAutomaticTextReplacement() override { }
- virtual bool isAutomaticSpellingCorrectionEnabled() override { return false; }
- virtual void toggleAutomaticSpellingCorrection() override { }
-#endif
-
-#if ENABLE(DELETION_UI)
- virtual bool shouldShowDeleteInterface(HTMLElement*) override { return false; }
-#endif
-
-#if PLATFORM(GTK)
- virtual bool shouldShowUnicodeMenu() override { return false; }
-#endif
- virtual TextCheckerClient* textChecker() override { return &m_textCheckerClient; }
-
- virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail&) override { }
- virtual void updateSpellingUIWithMisspelledWord(const String&) override { }
- virtual void showSpellingUI(bool) override { }
- virtual bool spellingUIIsShowing() override { return false; }
-
- virtual void willSetInputMethodState() override { }
- virtual void setInputMethodState(bool) override { }
-
-private:
- EmptyTextCheckerClient m_textCheckerClient;
-};
-
-#if ENABLE(CONTEXT_MENUS)
-class EmptyContextMenuClient : public ContextMenuClient {
- WTF_MAKE_NONCOPYABLE(EmptyContextMenuClient); WTF_MAKE_FAST_ALLOCATED;
-public:
- EmptyContextMenuClient() { }
- virtual ~EmptyContextMenuClient() { }
- virtual void contextMenuDestroyed() override { }
-
-#if USE(CROSS_PLATFORM_CONTEXT_MENUS)
- virtual PassOwnPtr<ContextMenu> customizeMenu(PassOwnPtr<ContextMenu>) override;
-#else
- virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*) override { return 0; }
-#endif
- virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) override { }
-
- virtual void downloadURL(const URL&) override { }
- virtual void searchWithGoogle(const Frame*) override { }
- virtual void lookUpInDictionary(Frame*) override { }
- virtual bool isSpeaking() override { return false; }
- virtual void speak(const String&) override { }
- virtual void stopSpeaking() override { }
+ void didReceiveMobileDocType(bool) final { }
+ void setNeedsScrollNotifications(Frame&, bool) final { }
+ void observedContentChange(Frame&) final { }
+ void clearContentChangeObservers(Frame&) final { }
+ void notifyRevealedSelectionByScrollingFrame(Frame&) final { }
+ void didLayout(LayoutType) final { }
+ void didStartOverflowScroll() final { }
+ void didEndOverflowScroll() final { }
+
+ void suppressFormNotifications() final { }
+ void restoreFormNotifications() final { }
+
+ void addOrUpdateScrollingLayer(Node*, PlatformLayer*, PlatformLayer*, const IntSize&, bool, bool) final { }
+ void removeScrollingLayer(Node*, PlatformLayer*, PlatformLayer*) final { }
+
+ void webAppOrientationsUpdated() final { };
+ void showPlaybackTargetPicker(bool) final { };
+#endif // PLATFORM(IOS)
-#if PLATFORM(MAC)
- virtual void searchWithSpotlight() override { }
+#if ENABLE(ORIENTATION_EVENTS)
+ int deviceOrientation() const final { return 0; }
#endif
-#if USE(ACCESSIBILITY_CONTEXT_MENUS)
- virtual void showContextMenu() override { }
+#if PLATFORM(IOS)
+ bool isStopping() final { return false; }
#endif
-};
-#endif // ENABLE(CONTEXT_MENUS)
-
-#if ENABLE(DRAG_SUPPORT)
-class EmptyDragClient : public DragClient {
- WTF_MAKE_NONCOPYABLE(EmptyDragClient); WTF_MAKE_FAST_ALLOCATED;
-public:
- EmptyDragClient() { }
- virtual ~EmptyDragClient() {}
- virtual void willPerformDragDestinationAction(DragDestinationAction, DragData&) override { }
- virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard&) override { }
- virtual DragDestinationAction actionMaskForDrag(DragData&) override { return DragDestinationActionNone; }
- virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&) override { return DragSourceActionNone; }
- virtual void startDrag(DragImageRef, const IntPoint&, const IntPoint&, Clipboard&, Frame&, bool) override { }
- virtual void dragControllerDestroyed() override { }
-};
-#endif // ENABLE(DRAG_SUPPORT)
-
-class EmptyInspectorClient : public InspectorClient {
- WTF_MAKE_NONCOPYABLE(EmptyInspectorClient); WTF_MAKE_FAST_ALLOCATED;
-public:
- EmptyInspectorClient() { }
- virtual ~EmptyInspectorClient() { }
- virtual void inspectorDestroyed() override { }
+ void wheelEventHandlersChanged(bool) final { }
- virtual InspectorFrontendChannel* openInspectorFrontend(InspectorController*) override { return 0; }
- virtual void closeInspectorFrontend() override { }
- virtual void bringFrontendToFront() override { }
+ bool isEmptyChromeClient() const final { return true; }
- virtual void highlight() override { }
- virtual void hideHighlight() override { }
+ void didAssociateFormControls(const Vector<RefPtr<Element>>&) final { }
+ bool shouldNotifyOnFormChanges() final { return false; }
};
-class EmptyDeviceClient : public DeviceClient {
-public:
- virtual void startUpdating() override { }
- virtual void stopUpdating() override { }
-};
-
-class EmptyDeviceMotionClient : public DeviceMotionClient {
-public:
- virtual void setController(DeviceMotionController*) override { }
- virtual DeviceMotionData* lastMotion() const override { return 0; }
- virtual void deviceMotionControllerDestroyed() override { }
-};
-
-class EmptyDeviceOrientationClient : public DeviceOrientationClient {
-public:
- virtual void setController(DeviceOrientationController*) override { }
- virtual DeviceOrientationData* lastOrientation() const override { return 0; }
- virtual void deviceOrientationControllerDestroyed() override { }
-};
-
-class EmptyProgressTrackerClient : public ProgressTrackerClient {
- virtual void willChangeEstimatedProgress() override { }
- virtual void didChangeEstimatedProgress() override { }
-
- virtual void progressStarted(Frame&) override { }
- virtual void progressEstimateChanged(Frame&) override { }
- virtual void progressFinished(Frame&) override { }
-};
-
-void fillWithEmptyClients(Page::PageClients&);
+void fillWithEmptyClients(PageConfiguration&);
+UniqueRef<EditorClient> createEmptyEditorClient();
+DiagnosticLoggingClient& emptyDiagnosticLoggingClient();
}
-
-#endif // EmptyClients_h
diff --git a/Source/WebCore/loader/FTPDirectoryParser.cpp b/Source/WebCore/loader/FTPDirectoryParser.cpp
index 9a5b6114b..c9326c72e 100644
--- a/Source/WebCore/loader/FTPDirectoryParser.cpp
+++ b/Source/WebCore/loader/FTPDirectoryParser.cpp
@@ -505,7 +505,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res
* So its rounded up to the next block, so what, its better
* than not showing the size at all.
*/
- uint64_t size = strtoul(tokens[1], NULL, 10) * 512;
+ uint64_t size = strtoull(tokens[1], 0, 10) * 512;
result.fileSize = String::number(size);
}
@@ -1152,7 +1152,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res
if (!state.now)
{
- time_t now = time(NULL);
+ time_t now = time(nullptr);
state.now = now * 1000000.0;
// FIXME: This code has the year 2038 bug
@@ -1617,7 +1617,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res
result.modifiedTime.tm_min = atoi(p+3);
if (!state.now)
{
- time_t now = time(NULL);
+ time_t now = time(nullptr);
state.now = now * 1000000.0;
// FIXME: This code has the year 2038 bug
diff --git a/Source/WebCore/loader/FTPDirectoryParser.h b/Source/WebCore/loader/FTPDirectoryParser.h
index 642b3c3b9..325b37a6f 100644
--- a/Source/WebCore/loader/FTPDirectoryParser.h
+++ b/Source/WebCore/loader/FTPDirectoryParser.h
@@ -68,8 +68,7 @@
// This was originally Mozilla code, titled ParseFTPList.h
// Original version of this file can currently be found at: http://mxr.mozilla.org/mozilla1.8/source/netwerk/streamconv/converters/ParseFTPList.h
-#ifndef FTPDirectoryParser_h
-#define FTPDirectoryParser_h
+#pragma once
#include <wtf/text/WTFString.h>
@@ -127,9 +126,9 @@ struct ListResult
{
valid = false;
type = FTPJunkEntry;
- filename = 0;
+ filename = nullptr;
filenameLength = 0;
- linkname = 0;
+ linkname = nullptr;
linknameLength = 0;
fileSize.truncate(0);
caseSensitive = false;
@@ -153,5 +152,3 @@ struct ListResult
FTPEntryType parseOneFTPLine(const char* inputLine, ListState&, ListResult&);
} // namespace WebCore
-
-#endif // FTPDirectoryParser_h
diff --git a/Source/WebCore/loader/FetchOptions.h b/Source/WebCore/loader/FetchOptions.h
new file mode 100644
index 000000000..b733461c6
--- /dev/null
+++ b/Source/WebCore/loader/FetchOptions.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 Canon Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Canon Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+struct FetchOptions {
+ enum class Type { EmptyString, Audio, Font, Image, Script, Style, Track, Video };
+ Type type { Type::EmptyString };
+
+ enum class Destination { EmptyString, Document, Sharedworker, Subresource, Unknown, Worker };
+ Destination destination { Destination::EmptyString };
+
+ enum class Mode { Navigate, SameOrigin, NoCors, Cors };
+ Mode mode { Mode::NoCors };
+
+ enum class Credentials { Omit, SameOrigin, Include };
+ Credentials credentials { Credentials::Omit };
+
+ enum class Cache { Default, NoStore, Reload, NoCache, ForceCache, OnlyIfCached };
+ Cache cache { Cache::Default };
+
+ enum class Redirect { Follow, Error, Manual };
+ Redirect redirect { Redirect::Follow };
+
+ enum class ReferrerPolicy { EmptyString, NoReferrer, NoReferrerWhenDowngrade, Origin, OriginWhenCrossOrigin, UnsafeUrl };
+ ReferrerPolicy referrerPolicy { ReferrerPolicy::EmptyString };
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/FormState.cpp b/Source/WebCore/loader/FormState.cpp
index e214aaa7b..5e896e7f8 100644
--- a/Source/WebCore/loader/FormState.cpp
+++ b/Source/WebCore/loader/FormState.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -34,17 +34,17 @@
namespace WebCore {
-inline FormState::FormState(PassRefPtr<HTMLFormElement> form, StringPairVector& textFieldValuesToAdopt, PassRefPtr<Document> sourceDocument, FormSubmissionTrigger formSubmissionTrigger)
+inline FormState::FormState(HTMLFormElement& form, StringPairVector&& textFieldValues, Document& sourceDocument, FormSubmissionTrigger formSubmissionTrigger)
: m_form(form)
+ , m_textFieldValues(WTFMove(textFieldValues))
, m_sourceDocument(sourceDocument)
, m_formSubmissionTrigger(formSubmissionTrigger)
{
- m_textFieldValues.swap(textFieldValuesToAdopt);
}
-PassRefPtr<FormState> FormState::create(PassRefPtr<HTMLFormElement> form, StringPairVector& textFieldValuesToAdopt, PassRefPtr<Document> sourceDocument, FormSubmissionTrigger formSubmissionTrigger)
+Ref<FormState> FormState::create(HTMLFormElement& form, StringPairVector&& textFieldValues, Document& sourceDocument, FormSubmissionTrigger formSubmissionTrigger)
{
- return adoptRef(new FormState(form, textFieldValuesToAdopt, sourceDocument, formSubmissionTrigger));
+ return adoptRef(*new FormState(form, WTFMove(textFieldValues), sourceDocument, formSubmissionTrigger));
}
}
diff --git a/Source/WebCore/loader/FormState.h b/Source/WebCore/loader/FormState.h
index 6f55943fe..2dedd09be 100644
--- a/Source/WebCore/loader/FormState.h
+++ b/Source/WebCore/loader/FormState.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,42 +26,35 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FormState_h
-#define FormState_h
+#pragma once
-#include <wtf/RefCounted.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
- class Document;
- class HTMLFormElement;
+class Document;
+class HTMLFormElement;
- enum FormSubmissionTrigger {
- SubmittedByJavaScript,
- NotSubmittedByJavaScript
- };
-
- typedef Vector<std::pair<String, String>> StringPairVector;
+enum FormSubmissionTrigger { SubmittedByJavaScript, NotSubmittedByJavaScript };
- class FormState : public RefCounted<FormState> {
- public:
- static PassRefPtr<FormState> create(PassRefPtr<HTMLFormElement>, StringPairVector& textFieldValuesToAdopt, PassRefPtr<Document>, FormSubmissionTrigger);
+using StringPairVector = Vector<std::pair<String, String>>;
- HTMLFormElement* form() const { return m_form.get(); }
- const StringPairVector& textFieldValues() const { return m_textFieldValues; }
- Document* sourceDocument() const { return m_sourceDocument.get(); }
- FormSubmissionTrigger formSubmissionTrigger() const { return m_formSubmissionTrigger; }
+class FormState : public RefCounted<FormState> {
+public:
+ static Ref<FormState> create(HTMLFormElement&, StringPairVector&& textFieldValues, Document&, FormSubmissionTrigger);
- private:
- FormState(PassRefPtr<HTMLFormElement>, StringPairVector& textFieldValuesToAdopt, PassRefPtr<Document>, FormSubmissionTrigger);
+ HTMLFormElement& form() const { return m_form; }
+ const StringPairVector& textFieldValues() const { return m_textFieldValues; }
+ Document& sourceDocument() const { return m_sourceDocument; }
+ FormSubmissionTrigger formSubmissionTrigger() const { return m_formSubmissionTrigger; }
- RefPtr<HTMLFormElement> m_form;
- StringPairVector m_textFieldValues;
- RefPtr<Document> m_sourceDocument;
- FormSubmissionTrigger m_formSubmissionTrigger;
- };
+private:
+ FormState(HTMLFormElement&, StringPairVector&& textFieldValues, Document&, FormSubmissionTrigger);
-}
+ Ref<HTMLFormElement> m_form;
+ StringPairVector m_textFieldValues;
+ Ref<Document> m_sourceDocument;
+ FormSubmissionTrigger m_formSubmissionTrigger;
+};
-#endif // FormState_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/FormSubmission.cpp b/Source/WebCore/loader/FormSubmission.cpp
index 4d1a6e85b..1d742ea33 100644
--- a/Source/WebCore/loader/FormSubmission.cpp
+++ b/Source/WebCore/loader/FormSubmission.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,6 +32,7 @@
#include "config.h"
#include "FormSubmission.h"
+#include "ContentSecurityPolicy.h"
#include "DOMFormData.h"
#include "Document.h"
#include "Event.h"
@@ -45,9 +47,9 @@
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
+#include "NoEventDispatchAssertion.h"
#include "TextEncoding.h"
#include <wtf/CurrentTime.h>
-#include <wtf/RandomNumber.h>
namespace WebCore {
@@ -65,7 +67,7 @@ static void appendMailtoPostFormDataToURL(URL& url, const FormData& data, const
{
String body = data.flattenToString();
- if (equalIgnoringCase(encodingType, "text/plain")) {
+ if (equalLettersIgnoringASCIICase(encodingType, "text/plain")) {
// Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20.
body = decodeURLEscapeSequences(body.replaceWithLiteral('&', "\r\n").replace('+', ' ') + "\r\n");
}
@@ -76,10 +78,10 @@ static void appendMailtoPostFormDataToURL(URL& url, const FormData& data, const
body = String(bodyData.data(), bodyData.size()).replaceWithLiteral('+', "%20");
String query = url.query();
- if (!query.isEmpty())
- query.append('&');
- query.append(body);
- url.setQuery(query);
+ if (query.isEmpty())
+ url.setQuery(body);
+ else
+ url.setQuery(query + '&' + body);
}
void FormSubmission::Attributes::parseAction(const String& action)
@@ -90,11 +92,11 @@ void FormSubmission::Attributes::parseAction(const String& action)
String FormSubmission::Attributes::parseEncodingType(const String& type)
{
- if (equalIgnoringCase(type, "multipart/form-data"))
- return "multipart/form-data";
- if (equalIgnoringCase(type, "text/plain"))
- return "text/plain";
- return "application/x-www-form-urlencoded";
+ if (equalLettersIgnoringASCIICase(type, "multipart/form-data"))
+ return ASCIILiteral("multipart/form-data");
+ if (equalLettersIgnoringASCIICase(type, "text/plain"))
+ return ASCIILiteral("text/plain");
+ return ASCIILiteral("application/x-www-form-urlencoded");
}
void FormSubmission::Attributes::updateEncodingType(const String& type)
@@ -105,7 +107,7 @@ void FormSubmission::Attributes::updateEncodingType(const String& type)
FormSubmission::Method FormSubmission::Attributes::parseMethodType(const String& type)
{
- return equalIgnoringCase(type, "post") ? FormSubmission::PostMethod : FormSubmission::GetMethod;
+ return equalLettersIgnoringASCIICase(type, "post") ? FormSubmission::Method::Post : FormSubmission::Method::Get;
}
void FormSubmission::Attributes::updateMethodType(const String& type)
@@ -113,65 +115,70 @@ void FormSubmission::Attributes::updateMethodType(const String& type)
m_method = parseMethodType(type);
}
-void FormSubmission::Attributes::copyFrom(const Attributes& other)
-{
- m_method = other.m_method;
- m_isMultiPartForm = other.m_isMultiPartForm;
-
- m_action = other.m_action;
- m_target = other.m_target;
- m_encodingType = other.m_encodingType;
- m_acceptCharset = other.m_acceptCharset;
-}
-
-inline FormSubmission::FormSubmission(Method method, const URL& action, const String& target, const String& contentType, PassRefPtr<FormState> state, PassRefPtr<FormData> data, const String& boundary, bool lockHistory, PassRefPtr<Event> event)
+inline FormSubmission::FormSubmission(Method method, const URL& action, const String& target, const String& contentType, Ref<FormState>&& state, Ref<FormData>&& data, const String& boundary, LockHistory lockHistory, Event* event)
: m_method(method)
, m_action(action)
, m_target(target)
, m_contentType(contentType)
- , m_formState(state)
- , m_formData(data)
+ , m_formState(WTFMove(state))
+ , m_formData(WTFMove(data))
, m_boundary(boundary)
, m_lockHistory(lockHistory)
, m_event(event)
{
}
-PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const Attributes& attributes, PassRefPtr<Event> event, bool lockHistory, FormSubmissionTrigger trigger)
+static TextEncoding encodingFromAcceptCharset(const String& acceptCharset, Document& document)
{
- ASSERT(form);
+ String normalizedAcceptCharset = acceptCharset;
+ normalizedAcceptCharset.replace(',', ' ');
+
+ Vector<String> charsets;
+ normalizedAcceptCharset.split(' ', charsets);
+
+ for (auto& charset : charsets) {
+ TextEncoding encoding(charset);
+ if (encoding.isValid())
+ return encoding;
+ }
- HTMLFormControlElement* submitButton = 0;
+ return document.textEncoding();
+}
+
+Ref<FormSubmission> FormSubmission::create(HTMLFormElement& form, const Attributes& attributes, Event* event, LockHistory lockHistory, FormSubmissionTrigger trigger)
+{
+ HTMLFormControlElement* submitButton = nullptr;
if (event && event->target()) {
for (Node* node = event->target()->toNode(); node; node = node->parentNode()) {
- if (node->isElementNode() && toElement(node)->isFormControlElement()) {
- submitButton = toHTMLFormControlElement(node);
+ if (is<HTMLFormControlElement>(*node)) {
+ submitButton = downcast<HTMLFormControlElement>(node);
break;
}
}
}
- FormSubmission::Attributes copiedAttributes;
- copiedAttributes.copyFrom(attributes);
+ auto copiedAttributes = attributes;
if (submitButton) {
- String attributeValue;
- if (!(attributeValue = submitButton->getAttribute(formactionAttr)).isNull())
+ AtomicString attributeValue;
+ if (!(attributeValue = submitButton->attributeWithoutSynchronization(formactionAttr)).isNull())
copiedAttributes.parseAction(attributeValue);
- if (!(attributeValue = submitButton->getAttribute(formenctypeAttr)).isNull())
+ if (!(attributeValue = submitButton->attributeWithoutSynchronization(formenctypeAttr)).isNull())
copiedAttributes.updateEncodingType(attributeValue);
- if (!(attributeValue = submitButton->getAttribute(formmethodAttr)).isNull())
+ if (!(attributeValue = submitButton->attributeWithoutSynchronization(formmethodAttr)).isNull())
copiedAttributes.updateMethodType(attributeValue);
- if (!(attributeValue = submitButton->getAttribute(formtargetAttr)).isNull())
+ if (!(attributeValue = submitButton->attributeWithoutSynchronization(formtargetAttr)).isNull())
copiedAttributes.setTarget(attributeValue);
}
- Document& document = form->document();
- URL actionURL = document.completeURL(copiedAttributes.action().isEmpty() ? document.url().string() : copiedAttributes.action());
+ auto& document = form.document();
+ auto actionURL = document.completeURL(copiedAttributes.action().isEmpty() ? document.url().string() : copiedAttributes.action());
bool isMailtoForm = actionURL.protocolIs("mailto");
bool isMultiPartForm = false;
- String encodingType = copiedAttributes.encodingType();
+ auto encodingType = copiedAttributes.encodingType();
+
+ document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(actionURL, ContentSecurityPolicy::InsecureRequestType::FormSubmission);
- if (copiedAttributes.method() == PostMethod) {
+ if (copiedAttributes.method() == Method::Post) {
isMultiPartForm = copiedAttributes.isMultiPartForm();
if (isMultiPartForm && isMailtoForm) {
encodingType = "application/x-www-form-urlencoded";
@@ -179,24 +186,27 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
}
}
- TextEncoding dataEncoding = isMailtoForm ? UTF8Encoding() : FormDataBuilder::encodingFromAcceptCharset(copiedAttributes.acceptCharset(), document);
- RefPtr<DOMFormData> domFormData = DOMFormData::create(dataEncoding.encodingForFormSubmission());
- Vector<std::pair<String, String>> formValues;
+ auto dataEncoding = isMailtoForm ? UTF8Encoding() : encodingFromAcceptCharset(copiedAttributes.acceptCharset(), document);
+ auto domFormData = DOMFormData::create(dataEncoding.encodingForFormSubmission());
+ StringPairVector formValues;
bool containsPasswordData = false;
- for (unsigned i = 0; i < form->associatedElements().size(); ++i) {
- FormAssociatedElement& control = *form->associatedElements()[i];
- HTMLElement& element = control.asHTMLElement();
- if (!element.isDisabledFormControl())
- control.appendFormData(*domFormData, isMultiPartForm);
- if (isHTMLInputElement(element)) {
- HTMLInputElement& input = toHTMLInputElement(element);
- if (input.isTextField()) {
- formValues.append(std::pair<String, String>(input.name().string(), input.value()));
- input.addSearchResult();
+ {
+ NoEventDispatchAssertion noEventDispatchAssertion;
+
+ for (auto& control : form.associatedElements()) {
+ auto& element = control->asHTMLElement();
+ if (!element.isDisabledFormControl())
+ control->appendFormData(domFormData, isMultiPartForm);
+ if (is<HTMLInputElement>(element)) {
+ auto& input = downcast<HTMLInputElement>(element);
+ if (input.isTextField()) {
+ formValues.append({ input.name().string(), input.value() });
+ input.addSearchResult();
+ }
+ if (input.isPasswordField() && !input.value().isEmpty())
+ containsPasswordData = true;
}
- if (input.isPasswordField() && !input.value().isEmpty())
- containsPasswordData = true;
}
}
@@ -204,11 +214,11 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
String boundary;
if (isMultiPartForm) {
- formData = FormData::createMultiPart(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding(), &document);
+ formData = FormData::createMultiPart(domFormData, domFormData->encoding(), &document);
boundary = formData->boundary().data();
} else {
- formData = FormData::create(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding(), attributes.method() == GetMethod ? FormData::FormURLEncoded : FormData::parseEncodingType(encodingType));
- if (copiedAttributes.method() == PostMethod && isMailtoForm) {
+ formData = FormData::create(domFormData, domFormData->encoding(), attributes.method() == Method::Get ? FormData::FormURLEncoded : FormData::parseEncodingType(encodingType));
+ if (copiedAttributes.method() == Method::Post && isMailtoForm) {
// Convert the form data into a string that we put into the URL.
appendMailtoPostFormDataToURL(actionURL, *formData, encodingType);
formData = FormData::create();
@@ -217,14 +227,17 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
formData->setIdentifier(generateFormDataIdentifier());
formData->setContainsPasswordData(containsPasswordData);
+
String targetOrBaseTarget = copiedAttributes.target().isEmpty() ? document.baseTarget() : copiedAttributes.target();
- RefPtr<FormState> formState = FormState::create(form, formValues, &document, trigger);
- return adoptRef(new FormSubmission(copiedAttributes.method(), actionURL, targetOrBaseTarget, encodingType, formState.release(), formData.release(), boundary, lockHistory, event));
+
+ auto formState = FormState::create(form, WTFMove(formValues), document, trigger);
+
+ return adoptRef(*new FormSubmission(copiedAttributes.method(), actionURL, targetOrBaseTarget, encodingType, WTFMove(formState), formData.releaseNonNull(), boundary, lockHistory, event));
}
URL FormSubmission::requestURL() const
{
- if (m_method == FormSubmission::PostMethod)
+ if (m_method == Method::Post)
return m_action;
URL requestURL(m_action);
@@ -240,9 +253,9 @@ void FormSubmission::populateFrameLoadRequest(FrameLoadRequest& frameRequest)
if (!m_referrer.isEmpty())
frameRequest.resourceRequest().setHTTPReferrer(m_referrer);
- if (m_method == FormSubmission::PostMethod) {
+ if (m_method == Method::Post) {
frameRequest.resourceRequest().setHTTPMethod("POST");
- frameRequest.resourceRequest().setHTTPBody(m_formData);
+ frameRequest.resourceRequest().setHTTPBody(m_formData.copyRef());
// construct some user headers if necessary
if (m_boundary.isEmpty())
@@ -253,6 +266,7 @@ void FormSubmission::populateFrameLoadRequest(FrameLoadRequest& frameRequest)
frameRequest.resourceRequest().setURL(requestURL());
FrameLoader::addHTTPOriginIfNeeded(frameRequest.resourceRequest(), m_origin);
+ FrameLoader::addHTTPUpgradeInsecureRequestsIfNeeded(frameRequest.resourceRequest());
}
}
diff --git a/Source/WebCore/loader/FormSubmission.h b/Source/WebCore/loader/FormSubmission.h
index c2f83d53f..252412c0c 100644
--- a/Source/WebCore/loader/FormSubmission.h
+++ b/Source/WebCore/loader/FormSubmission.h
@@ -28,39 +28,29 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FormSubmission_h
-#define FormSubmission_h
+#pragma once
#include "FormState.h"
+#include "FrameLoaderTypes.h"
#include "URL.h"
namespace WebCore {
-class Document;
class Event;
class FormData;
+
struct FrameLoadRequest;
-class HTMLFormElement;
-class TextEncoding;
class FormSubmission : public RefCounted<FormSubmission> {
public:
- enum Method { GetMethod, PostMethod };
+ enum class Method { Get, Post };
class Attributes {
- WTF_MAKE_NONCOPYABLE(Attributes);
public:
- Attributes()
- : m_method(GetMethod)
- , m_isMultiPartForm(false)
- , m_encodingType("application/x-www-form-urlencoded")
- {
- }
-
Method method() const { return m_method; }
static Method parseMethodType(const String&);
void updateMethodType(const String&);
- static String methodString(Method method) { return method == PostMethod ? "post" : "get"; }
+ static ASCIILiteral methodString(Method method) { return ASCIILiteral { method == Method::Post ? "post" : "get" }; }
const String& action() const { return m_action; }
void parseAction(const String&);
@@ -76,57 +66,51 @@ public:
const String& acceptCharset() const { return m_acceptCharset; }
void setAcceptCharset(const String& value) { m_acceptCharset = value; }
- void copyFrom(const Attributes&);
-
private:
- Method m_method;
- bool m_isMultiPartForm;
-
+ Method m_method { Method::Get };
+ bool m_isMultiPartForm { false };
String m_action;
String m_target;
- String m_encodingType;
+ String m_encodingType { ASCIILiteral { "application/x-www-form-urlencoded" } };
String m_acceptCharset;
};
- static PassRefPtr<FormSubmission> create(HTMLFormElement*, const Attributes&, PassRefPtr<Event> event, bool lockHistory, FormSubmissionTrigger);
+ static Ref<FormSubmission> create(HTMLFormElement&, const Attributes&, Event*, LockHistory, FormSubmissionTrigger);
void populateFrameLoadRequest(FrameLoadRequest&);
-
URL requestURL() const;
Method method() const { return m_method; }
const URL& action() const { return m_action; }
const String& target() const { return m_target; }
- void clearTarget() { m_target = String(); }
const String& contentType() const { return m_contentType; }
- FormState* state() const { return m_formState.get(); }
- FormData* data() const { return m_formData.get(); }
+ FormState& state() const { return m_formState; }
+ FormData& data() const { return m_formData; }
const String boundary() const { return m_boundary; }
- bool lockHistory() const { return m_lockHistory; }
+ LockHistory lockHistory() const { return m_lockHistory; }
Event* event() const { return m_event.get(); }
-
const String& referrer() const { return m_referrer; }
- void setReferrer(const String& referrer) { m_referrer = referrer; }
const String& origin() const { return m_origin; }
+
+ void clearTarget() { m_target = { }; }
+ void setReferrer(const String& referrer) { m_referrer = referrer; }
void setOrigin(const String& origin) { m_origin = origin; }
private:
- FormSubmission(Method, const URL& action, const String& target, const String& contentType, PassRefPtr<FormState>, PassRefPtr<FormData>, const String& boundary, bool lockHistory, PassRefPtr<Event>);
+ FormSubmission(Method, const URL& action, const String& target, const String& contentType, Ref<FormState>&&, Ref<FormData>&&, const String& boundary, LockHistory, Event*);
// FIXME: Hold an instance of Attributes instead of individual members.
Method m_method;
URL m_action;
String m_target;
String m_contentType;
- RefPtr<FormState> m_formState;
- RefPtr<FormData> m_formData;
+ Ref<FormState> m_formState;
+ Ref<FormData> m_formData;
String m_boundary;
- bool m_lockHistory;
+ LockHistory m_lockHistory;
RefPtr<Event> m_event;
String m_referrer;
String m_origin;
};
-}
-
-#endif // FormSubmission_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/FrameLoadRequest.cpp b/Source/WebCore/loader/FrameLoadRequest.cpp
index 014678823..8a1e7514c 100644
--- a/Source/WebCore/loader/FrameLoadRequest.cpp
+++ b/Source/WebCore/loader/FrameLoadRequest.cpp
@@ -36,12 +36,18 @@
namespace WebCore {
-FrameLoadRequest::FrameLoadRequest(Frame* frame, const ResourceRequest& resourceRequest, const SubstituteData& substituteData)
- : m_requester(frame->document()->securityOrigin())
+FrameLoadRequest::FrameLoadRequest(Frame* frame, const ResourceRequest& resourceRequest, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, const SubstituteData& substituteData)
+ : m_requester(&frame->document()->securityOrigin())
, m_resourceRequest(resourceRequest)
- , m_lockHistory(false)
, m_shouldCheckNewWindowPolicy(false)
, m_substituteData(substituteData)
+ , m_lockHistory(LockHistory::No)
+ , m_lockBackForwardList(LockBackForwardList::No)
+ , m_shouldSendReferrer(MaybeSendReferrer)
+ , m_allowNavigationToInvalidURL(AllowNavigationToInvalidURL::Yes)
+ , m_newFrameOpenerPolicy(NewFrameOpenerPolicy::Allow)
+ , m_shouldReplaceDocumentIfJavaScriptURL(ReplaceDocumentIfJavaScriptURL)
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
{
}
diff --git a/Source/WebCore/loader/FrameLoadRequest.h b/Source/WebCore/loader/FrameLoadRequest.h
index 1b7789986..1cbebbb82 100644
--- a/Source/WebCore/loader/FrameLoadRequest.h
+++ b/Source/WebCore/loader/FrameLoadRequest.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,9 +23,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FrameLoadRequest_h
-#define FrameLoadRequest_h
+#pragma once
+#include "FrameLoaderTypes.h"
#include "ResourceRequest.h"
#include "SecurityOrigin.h"
#include "SubstituteData.h"
@@ -35,31 +35,75 @@ class Frame;
struct FrameLoadRequest {
public:
- explicit FrameLoadRequest(SecurityOrigin* requester)
- : m_requester(requester)
- , m_lockHistory(false)
- , m_shouldCheckNewWindowPolicy(false)
+ FrameLoadRequest(SecurityOrigin& requester, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy newFrameOpenerPolicy, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : m_requester(&requester)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_shouldSendReferrer(shouldSendReferrer)
+ , m_allowNavigationToInvalidURL(allowNavigationToInvalidURL)
+ , m_newFrameOpenerPolicy(newFrameOpenerPolicy)
+ , m_shouldReplaceDocumentIfJavaScriptURL(ReplaceDocumentIfJavaScriptURL)
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
{
}
- FrameLoadRequest(SecurityOrigin* requester, const ResourceRequest& resourceRequest)
- : m_requester(requester)
+ FrameLoadRequest(SecurityOrigin& requester, const ResourceRequest& resourceRequest, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy newFrameOpenerPolicy, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : m_requester(&requester)
, m_resourceRequest(resourceRequest)
- , m_lockHistory(false)
- , m_shouldCheckNewWindowPolicy(false)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_shouldSendReferrer(shouldSendReferrer)
+ , m_allowNavigationToInvalidURL(allowNavigationToInvalidURL)
+ , m_newFrameOpenerPolicy(newFrameOpenerPolicy)
+ , m_shouldReplaceDocumentIfJavaScriptURL(ReplaceDocumentIfJavaScriptURL)
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
{
}
- FrameLoadRequest(SecurityOrigin* requester, const ResourceRequest& resourceRequest, const String& frameName)
- : m_requester(requester)
+ FrameLoadRequest(SecurityOrigin& requester, const ResourceRequest& resourceRequest, const String& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy newFrameOpenerPolicy, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : m_requester(&requester)
, m_resourceRequest(resourceRequest)
, m_frameName(frameName)
- , m_lockHistory(false)
- , m_shouldCheckNewWindowPolicy(false)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_shouldSendReferrer(shouldSendReferrer)
+ , m_allowNavigationToInvalidURL(allowNavigationToInvalidURL)
+ , m_newFrameOpenerPolicy(newFrameOpenerPolicy)
+ , m_shouldReplaceDocumentIfJavaScriptURL(ReplaceDocumentIfJavaScriptURL)
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
{
}
- FrameLoadRequest(Frame*, const ResourceRequest&, const SubstituteData& = SubstituteData());
+ FrameLoadRequest(SecurityOrigin& requester, const ResourceRequest& resourceRequest, const String& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy newFrameOpenerPolicy, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : m_requester(&requester)
+ , m_resourceRequest(resourceRequest)
+ , m_frameName(frameName)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_shouldSendReferrer(shouldSendReferrer)
+ , m_allowNavigationToInvalidURL(allowNavigationToInvalidURL)
+ , m_newFrameOpenerPolicy(newFrameOpenerPolicy)
+ , m_shouldReplaceDocumentIfJavaScriptURL(shouldReplaceDocumentIfJavaScriptURL)
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
+ {
+ }
+
+ FrameLoadRequest(SecurityOrigin& requester, const ResourceRequest& resourceRequest, const String& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy newFrameOpenerPolicy, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, const AtomicString& downloadAttribute)
+ : m_requester(&requester)
+ , m_resourceRequest(resourceRequest)
+ , m_frameName(frameName)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_shouldSendReferrer(shouldSendReferrer)
+ , m_allowNavigationToInvalidURL(allowNavigationToInvalidURL)
+ , m_newFrameOpenerPolicy(newFrameOpenerPolicy)
+ , m_shouldReplaceDocumentIfJavaScriptURL(shouldReplaceDocumentIfJavaScriptURL)
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
+ , m_downloadAttribute(downloadAttribute)
+ {
+ }
+
+ WEBCORE_EXPORT FrameLoadRequest(Frame*, const ResourceRequest&, ShouldOpenExternalURLsPolicy, const SubstituteData& = SubstituteData());
bool isEmpty() const { return m_resourceRequest.isEmpty(); }
@@ -71,9 +115,6 @@ public:
const String& frameName() const { return m_frameName; }
void setFrameName(const String& frameName) { m_frameName = frameName; }
- void setLockHistory(bool lockHistory) { m_lockHistory = lockHistory; }
- bool lockHistory() const { return m_lockHistory; }
-
void setShouldCheckNewWindowPolicy(bool checkPolicy) { m_shouldCheckNewWindowPolicy = checkPolicy; }
bool shouldCheckNewWindowPolicy() const { return m_shouldCheckNewWindowPolicy; }
@@ -81,15 +122,36 @@ public:
void setSubstituteData(const SubstituteData& data) { m_substituteData = data; }
bool hasSubstituteData() { return m_substituteData.isValid(); }
+ LockHistory lockHistory() const { return m_lockHistory; }
+ LockBackForwardList lockBackForwardList() const { return m_lockBackForwardList; }
+ ShouldSendReferrer shouldSendReferrer() const { return m_shouldSendReferrer; }
+ AllowNavigationToInvalidURL allowNavigationToInvalidURL() const { return m_allowNavigationToInvalidURL; }
+ NewFrameOpenerPolicy newFrameOpenerPolicy() const { return m_newFrameOpenerPolicy; }
+
+ // The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
+ // corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
+ ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL() const { return m_shouldReplaceDocumentIfJavaScriptURL; }
+
+ void setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy policy) { m_shouldOpenExternalURLsPolicy = policy; }
+ ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy() const { return m_shouldOpenExternalURLsPolicy; }
+
+ const AtomicString& downloadAttribute() const { return m_downloadAttribute; }
+
private:
RefPtr<SecurityOrigin> m_requester;
ResourceRequest m_resourceRequest;
String m_frameName;
- bool m_lockHistory;
- bool m_shouldCheckNewWindowPolicy;
+ bool m_shouldCheckNewWindowPolicy { false };
SubstituteData m_substituteData;
-};
-}
+ LockHistory m_lockHistory;
+ LockBackForwardList m_lockBackForwardList;
+ ShouldSendReferrer m_shouldSendReferrer;
+ AllowNavigationToInvalidURL m_allowNavigationToInvalidURL;
+ NewFrameOpenerPolicy m_newFrameOpenerPolicy;
+ ShouldReplaceDocumentIfJavaScriptURL m_shouldReplaceDocumentIfJavaScriptURL;
+ ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
+ AtomicString m_downloadAttribute;
+};
-#endif // FrameLoadRequest_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index c3cc3c559..f5a0a3ed1 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
@@ -12,13 +12,13 @@
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -43,13 +43,13 @@
#include "CachedResourceLoader.h"
#include "Chrome.h"
#include "ChromeClient.h"
-#include "Console.h"
+#include "ContentFilter.h"
#include "ContentSecurityPolicy.h"
-#include "DOMImplementation.h"
#include "DOMWindow.h"
#include "DatabaseManager.h"
+#include "DiagnosticLoggingClient.h"
+#include "DiagnosticLoggingKeys.h"
#include "Document.h"
-#include "DocumentLoadTiming.h"
#include "DocumentLoader.h"
#include "Editor.h"
#include "EditorClient.h"
@@ -65,37 +65,47 @@
#include "FrameNetworkingContext.h"
#include "FrameTree.h"
#include "FrameView.h"
-#include "HTMLAnchorElement.h"
+#include "GCController.h"
#include "HTMLFormElement.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTMLParserIdioms.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
#include "HistoryController.h"
#include "HistoryItem.h"
#include "IconController.h"
+#include "IgnoreOpensDuringUnloadCountIncrementer.h"
#include "InspectorController.h"
#include "InspectorInstrumentation.h"
+#include "LinkLoader.h"
+#include "LoadTiming.h"
#include "LoaderStrategy.h"
#include "Logging.h"
-#include "MIMETypeRegistry.h"
#include "MainFrame.h"
#include "MemoryCache.h"
+#include "MemoryRelease.h"
+#include "NoEventDispatchAssertion.h"
#include "Page.h"
-#include "PageActivityAssertionToken.h"
#include "PageCache.h"
#include "PageTransitionEvent.h"
+#include "PerformanceLogging.h"
#include "PlatformStrategies.h"
#include "PluginData.h"
-#include "PluginDatabase.h"
#include "PluginDocument.h"
#include "PolicyChecker.h"
#include "ProgressTracker.h"
+#include "PublicSuffix.h"
#include "ResourceHandle.h"
+#include "ResourceLoadInfo.h"
+#include "ResourceLoadObserver.h"
#include "ResourceRequest.h"
-#include "SchemeRegistry.h"
-#include "ScriptCallStack.h"
+#include "SVGDocument.h"
+#include "SVGLocatable.h"
+#include "SVGNames.h"
+#include "SVGViewElement.h"
+#include "SVGViewSpec.h"
#include "ScriptController.h"
#include "ScriptSourceCode.h"
#include "ScrollAnimator.h"
@@ -106,6 +116,7 @@
#include "Settings.h"
#include "SubframeLoader.h"
#include "TextResourceDecoder.h"
+#include "UserContentController.h"
#include "WindowFeatures.h"
#include "XMLDocumentParser.h"
#include <wtf/CurrentTime.h>
@@ -114,61 +125,44 @@
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
-#if ENABLE(SHARED_WORKERS)
-#include "SharedWorkerRepository.h"
-#endif
-
-#if ENABLE(SVG)
-#include "SVGDocument.h"
-#include "SVGLocatable.h"
-#include "SVGNames.h"
-#include "SVGPreserveAspectRatio.h"
-#include "SVGSVGElement.h"
-#include "SVGViewElement.h"
-#include "SVGViewSpec.h"
-#endif
-
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
#include "Archive.h"
#endif
+#if ENABLE(DATA_DETECTION)
+#include "DataDetection.h"
+#endif
+
#if PLATFORM(IOS)
#include "DocumentType.h"
-#include "MemoryPressureHandler.h"
#include "ResourceLoader.h"
-#include "RuntimeApplicationChecksIOS.h"
-#include "SystemMemory.h"
+#include "RuntimeApplicationChecks.h"
#include "WKContentObservation.h"
#endif
+#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - FrameLoader::" fmt, this, ##__VA_ARGS__)
+
namespace WebCore {
using namespace HTMLNames;
-
-#if ENABLE(SVG)
using namespace SVGNames;
-#endif
static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
-#if PLATFORM(IOS)
-const int memoryLevelThresholdToPrunePageCache = 20;
-#endif
-
bool isBackForwardLoadType(FrameLoadType type)
{
switch (type) {
- case FrameLoadTypeStandard:
- case FrameLoadTypeReload:
- case FrameLoadTypeReloadFromOrigin:
- case FrameLoadTypeSame:
- case FrameLoadTypeRedirectWithLockedBackForwardList:
- case FrameLoadTypeReplace:
- return false;
- case FrameLoadTypeBack:
- case FrameLoadTypeForward:
- case FrameLoadTypeIndexedBackForward:
- return true;
+ case FrameLoadType::Standard:
+ case FrameLoadType::Reload:
+ case FrameLoadType::ReloadFromOrigin:
+ case FrameLoadType::Same:
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ case FrameLoadType::Replace:
+ return false;
+ case FrameLoadType::Back:
+ case FrameLoadType::Forward:
+ case FrameLoadType::IndexedBackForward:
+ return true;
}
ASSERT_NOT_REACHED();
return false;
@@ -180,12 +174,31 @@ bool isBackForwardLoadType(FrameLoadType type)
// non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
// API simpler.
//
-static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
+static bool isDocumentSandboxed(Frame& frame, SandboxFlags mask)
{
- return frame->document() && frame->document()->isSandboxed(mask);
+ return frame.document() && frame.document()->isSandboxed(mask);
}
+struct ForbidPromptsScope {
+ ForbidPromptsScope(Page* page) : m_page(page)
+ {
+ if (!m_page)
+ return;
+ m_page->forbidPrompts();
+ }
+
+ ~ForbidPromptsScope()
+ {
+ if (!m_page)
+ return;
+ m_page->allowPrompts();
+ }
+
+ Page* m_page;
+};
+
class FrameLoader::FrameProgressTracker {
+ WTF_MAKE_FAST_ALLOCATED;
public:
explicit FrameProgressTracker(Frame& frame)
: m_frame(frame)
@@ -230,23 +243,20 @@ FrameLoader::FrameLoader(Frame& frame, FrameLoaderClient& client)
, m_icon(std::make_unique<IconController>(frame))
, m_mixedContentChecker(frame)
, m_state(FrameStateProvisional)
- , m_loadType(FrameLoadTypeStandard)
- , m_delegateIsHandlingProvisionalLoadError(false)
+ , m_loadType(FrameLoadType::Standard)
, m_quickRedirectComing(false)
, m_sentRedirectNotification(false)
, m_inStopAllLoaders(false)
, m_isExecutingJavaScriptFormAction(false)
, m_didCallImplicitClose(true)
, m_wasUnloadEventEmitted(false)
- , m_pageDismissalEventBeingDispatched(NoDismissal)
, m_isComplete(false)
, m_needsClear(false)
- , m_checkTimer(this, &FrameLoader::checkTimerFired)
+ , m_checkTimer(*this, &FrameLoader::checkTimerFired)
, m_shouldCallCheckCompleted(false)
, m_shouldCallCheckLoadComplete(false)
, m_opener(nullptr)
, m_loadingFromCachedPage(false)
- , m_suppressOpenerInNewFrame(false)
, m_currentNavigationHasShownBeforeUnloadConfirmPanel(false)
, m_loadsSynchronously(false)
, m_forcedSandboxFlags(SandboxNone)
@@ -257,9 +267,8 @@ FrameLoader::~FrameLoader()
{
setOpener(nullptr);
- HashSet<Frame*>::iterator end = m_openedFrames.end();
- for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
- (*it)->loader().m_opener = 0;
+ for (auto& frame : m_openedFrames)
+ frame->loader().m_opener = nullptr;
m_client.frameLoaderDestroyed();
@@ -270,7 +279,7 @@ FrameLoader::~FrameLoader()
void FrameLoader::init()
{
// This somewhat odd set of steps gives the frame an initial empty document.
- setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).get());
+ setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).ptr());
setProvisionalDocumentLoader(m_policyDocumentLoader.get());
m_provisionalDocumentLoader->startLoadingMainResource();
@@ -289,8 +298,8 @@ void FrameLoader::initForSynthesizedDocument(const URL&)
// FrameLoader::checkCompleted() will overwrite the URL of the document to be activeDocumentLoader()->documentURL().
RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData());
- loader->setFrame(&m_frame);
- loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String(), String()));
+ loader->attachToFrame(m_frame);
+ loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String()));
loader->setCommitted(true);
setDocumentLoader(loader.get());
@@ -305,6 +314,7 @@ void FrameLoader::initForSynthesizedDocument(const URL&)
m_needsClear = true;
m_networkingContext = m_client.createNetworkingContext();
+ m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
}
#endif
@@ -324,60 +334,50 @@ void FrameLoader::setDefersLoading(bool defers)
}
}
-void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const URL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh)
+void FrameLoader::changeLocation(const FrameLoadRequest& request)
{
- urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
- 0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL);
+ urlSelected(request, nullptr);
}
-void FrameLoader::urlSelected(const URL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
+void FrameLoader::urlSelected(const URL& url, const String& passedTarget, Event* triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, std::optional<NewFrameOpenerPolicy> openerPolicy, const AtomicString& downloadAttribute)
{
- urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget),
- triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL);
+ NewFrameOpenerPolicy newFrameOpenerPolicy = openerPolicy.value_or(shouldSendReferrer == NeverSendReferrer ? NewFrameOpenerPolicy::Suppress : NewFrameOpenerPolicy::Allow);
+ urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget, lockHistory, lockBackForwardList, shouldSendReferrer, AllowNavigationToInvalidURL::Yes, newFrameOpenerPolicy, DoNotReplaceDocumentIfJavaScriptURL, shouldOpenExternalURLsPolicy, downloadAttribute), triggeringEvent);
}
-// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
-// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
-void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
+void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, Event* triggeringEvent)
{
- ASSERT(!m_suppressOpenerInNewFrame);
-
Ref<Frame> protect(m_frame);
FrameLoadRequest frameRequest(passedRequest);
- if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
+ if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), frameRequest.shouldReplaceDocumentIfJavaScriptURL()))
return;
if (frameRequest.frameName().isEmpty())
frameRequest.setFrameName(m_frame.document()->baseTarget());
- if (shouldSendReferrer == NeverSendReferrer)
- m_suppressOpenerInNewFrame = true;
addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
+ m_frame.document()->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(frameRequest.resourceRequest(), ContentSecurityPolicy::InsecureRequestType::Navigation);
- loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer);
-
- m_suppressOpenerInNewFrame = false;
+ loadFrameRequest(frameRequest, triggeringEvent, nullptr);
}
-void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
+void FrameLoader::submitForm(Ref<FormSubmission>&& submission)
{
- ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
+ ASSERT(submission->method() == FormSubmission::Method::Post || submission->method() == FormSubmission::Method::Get);
// FIXME: Find a good spot for these.
- ASSERT(submission->data());
- ASSERT(submission->state());
- ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == &m_frame);
-
+ ASSERT(!submission->state().sourceDocument().frame() || submission->state().sourceDocument().frame() == &m_frame);
+
if (!m_frame.page())
return;
-
+
if (submission->action().isEmpty())
return;
- if (isDocumentSandboxed(&m_frame, SandboxForms)) {
+ if (isDocumentSandboxed(m_frame, SandboxForms)) {
// FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
- m_frame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
+ m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
return;
}
@@ -391,12 +391,12 @@ void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
return;
}
- Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
+ Frame* targetFrame = findFrameForNavigation(submission->target(), &submission->state().sourceDocument());
if (!targetFrame) {
- if (!DOMWindow::allowPopUp(&m_frame) && !ScriptController::processingUserGesture())
+ if (!DOMWindow::allowPopUp(m_frame) && !ScriptController::processingUserGesture())
return;
- // FIXME: targetFrame can be 0 for two distinct reasons:
+ // FIXME: targetFrame can be null for two distinct reasons:
// 1. The frame was not found by name, so we should try opening a new window.
// 2. The frame was found, but navigating it was not allowed, e.g. by HTML5 sandbox or by origin checks.
// Continuing form submission makes no sense in the latter case.
@@ -413,7 +413,7 @@ void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
// We do not want to submit more than one form from the same page, nor do we want to submit a single
// form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
- // The flag is reset in each time we start handle a new mouse or key down event, and
+ // The flag is reset in each time we start dispatching a new mouse or key down event, and
// also in setView since this part may get reused for a page from the back/forward cache.
// The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
@@ -427,11 +427,11 @@ void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
m_submittedFormURL = submission->requestURL();
}
- submission->data()->generateFiles(m_frame.document());
+ submission->data().generateFiles(m_frame.document());
submission->setReferrer(outgoingReferrer());
submission->setOrigin(outgoingOrigin());
- targetFrame->navigationScheduler().scheduleFormSubmission(submission);
+ targetFrame->navigationScheduler().scheduleFormSubmission(WTFMove(submission));
}
void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
@@ -439,55 +439,8 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
if (m_frame.document() && m_frame.document()->parser())
m_frame.document()->parser()->stopParsing();
- if (unloadEventPolicy != UnloadEventPolicyNone) {
- if (m_frame.document()) {
- if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
- Element* currentFocusedElement = m_frame.document()->focusedElement();
- if (currentFocusedElement && currentFocusedElement->toInputElement())
- currentFocusedElement->toInputElement()->endEditing();
- if (m_pageDismissalEventBeingDispatched == NoDismissal) {
- if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
- m_pageDismissalEventBeingDispatched = PageHideDismissal;
- m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->inPageCache()), m_frame.document());
- }
-
- // FIXME: update Page Visibility state here.
- // https://bugs.webkit.org/show_bug.cgi?id=116770
-
- if (!m_frame.document()->inPageCache()) {
- RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
- // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
- // while dispatching the event, so protect it to prevent writing the end
- // time into freed memory.
- RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
- m_pageDismissalEventBeingDispatched = UnloadDismissal;
- if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
- DocumentLoadTiming* timing = documentLoader->timing();
- ASSERT(timing->navigationStart());
- timing->markUnloadEventStart();
- m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
- timing->markUnloadEventEnd();
- } else
- m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
- }
- }
- m_pageDismissalEventBeingDispatched = NoDismissal;
- if (m_frame.document())
- m_frame.document()->updateStyleIfNeeded();
- m_wasUnloadEventEmitted = true;
- }
- }
-
- // Dispatching the unload event could have made m_frame.document() null.
- if (m_frame.document() && !m_frame.document()->inPageCache()) {
- // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
- bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
- && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
-
- if (!keepEventListeners)
- m_frame.document()->removeAllEventListeners();
- }
- }
+ if (unloadEventPolicy != UnloadEventPolicyNone)
+ dispatchUnloadEvents(unloadEventPolicy);
m_isComplete = true; // to avoid calling completed() in finishedParsing()
m_didCallImplicitClose = true; // don't want that one either
@@ -497,15 +450,13 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
m_frame.document()->setParsing(false);
}
- if (Document* doc = m_frame.document()) {
+ if (auto* document = m_frame.document()) {
// FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
- doc->setReadyState(Document::Complete);
+ document->setReadyState(Document::Complete);
-#if ENABLE(SQL_DATABASE)
// FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here?
- DatabaseManager::manager().stopDatabases(doc, 0);
-#endif
+ DatabaseManager::singleton().stopDatabases(*document, nullptr);
}
// FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
@@ -533,18 +484,28 @@ void FrameLoader::willTransitionToCommitted()
if (m_frame.editor().hasComposition()) {
// The text was already present in DOM, so it's better to confirm than to cancel the composition.
m_frame.editor().confirmComposition();
- if (EditorClient* editorClient = m_frame.editor().client())
+ if (EditorClient* editorClient = m_frame.editor().client()) {
editorClient->respondToChangedSelection(&m_frame);
+ editorClient->discardedComposition(&m_frame);
+ }
}
}
bool FrameLoader::closeURL()
{
history().saveDocumentState();
-
- // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
+
Document* currentDocument = m_frame.document();
- stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly);
+ UnloadEventPolicy unloadEventPolicy;
+ if (m_frame.page() && m_frame.page()->chrome().client().isSVGImageChromeClient()) {
+ // If this is the SVGDocument of an SVGImage, no need to dispatch events or recalcStyle.
+ unloadEventPolicy = UnloadEventPolicyNone;
+ } else {
+ // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
+ unloadEventPolicy = currentDocument && currentDocument->pageCacheState() == Document::NotInPageCache ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly;
+ }
+
+ stopLoading(unloadEventPolicy);
m_frame.editor().clearUndoRedoOperations();
return true;
@@ -606,6 +567,17 @@ void FrameLoader::cancelAndClear()
m_frame.script().updatePlatformScriptObjects();
}
+static inline bool shouldClearWindowName(const Frame& frame, const Document& newDocument)
+{
+ if (!frame.isMainFrame())
+ return false;
+
+ if (frame.loader().opener())
+ return false;
+
+ return !newDocument.securityOrigin().isSameOriginAs(frame.document()->securityOrigin());
+}
+
void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
{
m_frame.editor().clear();
@@ -614,33 +586,43 @@ void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool
return;
m_needsClear = false;
- if (!m_frame.document()->inPageCache()) {
+ if (m_frame.document()->pageCacheState() != Document::InPageCache) {
m_frame.document()->cancelParsing();
m_frame.document()->stopActiveDOMObjects();
- if (m_frame.document()->hasLivingRenderTree()) {
- m_frame.document()->prepareForDestruction();
- m_frame.document()->removeFocusedNodeOfSubtree(m_frame.document());
- }
+ bool hadLivingRenderTree = m_frame.document()->hasLivingRenderTree();
+ m_frame.document()->prepareForDestruction();
+ if (hadLivingRenderTree)
+ m_frame.document()->removeFocusedNodeOfSubtree(*m_frame.document());
}
// Do this after detaching the document so that the unload event works.
if (clearWindowProperties) {
- InspectorInstrumentation::frameWindowDiscarded(&m_frame, m_frame.document()->domWindow());
- m_frame.document()->domWindow()->resetUnlessSuspendedForPageCache();
- m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->inPageCache());
+ InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame.document()->domWindow());
+ m_frame.document()->domWindow()->resetUnlessSuspendedForDocumentSuspension();
+ m_frame.script().clearWindowShellsNotMatchingDOMWindow(newDocument->domWindow(), m_frame.document()->pageCacheState() == Document::AboutToEnterPageCache);
+
+ if (shouldClearWindowName(m_frame, *newDocument))
+ m_frame.tree().setName(nullAtom);
}
m_frame.selection().prepareForDestruction();
- m_frame.eventHandler().clear();
+
+ // We may call this code during object destruction, so need to make sure eventHandler is present.
+ if (auto eventHandler = m_frame.eventHandlerPtr())
+ eventHandler->clear();
+
if (clearFrameView && m_frame.view())
m_frame.view()->clear();
// Do not drop the document before the ScriptController and view are cleared
// as some destructors might still try to access the document.
- m_frame.setDocument(0);
+ m_frame.setDocument(nullptr);
subframeLoader().clear();
+ if (clearWindowProperties)
+ m_frame.script().setDOMWindowForWindowShell(newDocument->domWindow());
+
if (clearScriptObjects)
m_frame.script().clearScriptObjects();
@@ -658,36 +640,35 @@ void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool
void FrameLoader::receivedFirstData()
{
- dispatchDidCommitLoad();
+ dispatchDidCommitLoad(std::nullopt);
dispatchDidClearWindowObjectsInAllWorlds();
dispatchGlobalObjectAvailableInAllWorlds();
if (m_documentLoader) {
- StringWithDirection ptitle = m_documentLoader->title();
- // If we have a title let the WebView know about it.
- if (!ptitle.isNull())
- m_client.dispatchDidReceiveTitle(ptitle);
+ auto& title = m_documentLoader->title();
+ if (!title.string.isNull())
+ m_client.dispatchDidReceiveTitle(title);
}
if (!m_documentLoader)
return;
- if (m_frame.document()->isViewSource())
- return;
+
+ ASSERT(m_frame.document());
+ auto& document = *m_frame.document();
+
+ ASSERT(m_frame.document());
+ LinkLoader::loadLinksFromHeader(m_documentLoader->response().httpHeaderField(HTTPHeaderName::Link), m_frame.document()->url(), *m_frame.document());
double delay;
- String url;
- if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
+ String urlString;
+ if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField(HTTPHeaderName::Refresh), delay, urlString))
return;
- if (url.isEmpty())
- url = m_frame.document()->url().string();
- else
- url = m_frame.document()->completeURL(url).string();
-
- if (!protocolIsJavaScript(url))
- m_frame.navigationScheduler().scheduleRedirect(delay, url);
+ auto completedURL = urlString.isEmpty() ? document.url() : document.completeURL(urlString);
+ if (!protocolIsJavaScript(completedURL))
+ m_frame.navigationScheduler().scheduleRedirect(document, delay, completedURL);
else {
- String message = "Refused to refresh " + m_frame.document()->url().stringCenterEllipsizedToLength() + " to a javascript: URL";
- m_frame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
+ auto message = "Refused to refresh " + document.url().stringCenterEllipsizedToLength() + " to a javascript: URL";
+ m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
}
}
@@ -704,8 +685,8 @@ void FrameLoader::didBeginDocument(bool dispatch)
m_frame.document()->setReadyState(Document::Loading);
if (m_pendingStateObject) {
- m_frame.document()->statePopped(m_pendingStateObject.get());
- m_pendingStateObject.clear();
+ m_frame.document()->statePopped(*m_pendingStateObject);
+ m_pendingStateObject = nullptr;
}
if (dispatch)
@@ -715,31 +696,17 @@ void FrameLoader::didBeginDocument(bool dispatch)
m_frame.document()->initContentSecurityPolicy();
const Settings& settings = m_frame.settings();
- m_frame.document()->cachedResourceLoader()->setImagesEnabled(settings.areImagesEnabled());
- m_frame.document()->cachedResourceLoader()->setAutoLoadImages(settings.loadsImagesAutomatically());
+ m_frame.document()->cachedResourceLoader().setImagesEnabled(settings.areImagesEnabled());
+ m_frame.document()->cachedResourceLoader().setAutoLoadImages(settings.loadsImagesAutomatically());
if (m_documentLoader) {
- String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
+ String dnsPrefetchControl = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XDNSPrefetchControl);
if (!dnsPrefetchControl.isEmpty())
m_frame.document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
- String policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy");
- if (!policyValue.isEmpty())
- m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce);
-
- policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy-Report-Only");
- if (!policyValue.isEmpty())
- m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report);
-
- policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP");
- if (!policyValue.isEmpty())
- m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce);
+ m_frame.document()->contentSecurityPolicy()->didReceiveHeaders(ContentSecurityPolicyResponseHeaders(m_documentLoader->response()), ContentSecurityPolicy::ReportParsingErrors::No);
- policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP-Report-Only");
- if (!policyValue.isEmpty())
- m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport);
-
- String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
+ String headerContentLanguage = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentLanguage);
if (!headerContentLanguage.isEmpty()) {
size_t commaIndex = headerContentLanguage.find(',');
headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate
@@ -766,6 +733,8 @@ void FrameLoader::finishedParsing()
m_client.dispatchDidFinishDocumentLoad();
+ scrollToFragmentWithParentBoundary(m_frame.document()->url());
+
checkCompleted();
if (!m_frame.view())
@@ -774,7 +743,6 @@ void FrameLoader::finishedParsing()
// Check if the scrollbars are really needed for the content.
// If not, remove them, relayout, and repaint.
m_frame.view()->restoreScrollbar();
- scrollToFragmentWithParentBoundary(m_frame.document()->url());
}
void FrameLoader::loadDone()
@@ -802,32 +770,47 @@ bool FrameLoader::allAncestorsAreComplete() const
void FrameLoader::checkCompleted()
{
- Ref<Frame> protect(m_frame);
m_shouldCallCheckCompleted = false;
// Have we completed before?
if (m_isComplete)
return;
+ // FIXME: It would be better if resource loads were kicked off after render tree update (or didn't complete synchronously).
+ // https://bugs.webkit.org/show_bug.cgi?id=171729
+ if (m_frame.document()->inRenderTreeUpdate()) {
+ scheduleCheckCompleted();
+ return;
+ }
+
// Are we still parsing?
if (m_frame.document()->parsing())
return;
// Still waiting for images/scripts?
- if (m_frame.document()->cachedResourceLoader()->requestCount())
+ if (m_frame.document()->cachedResourceLoader().requestCount())
return;
// Still waiting for elements that don't go through a FrameLoader?
if (m_frame.document()->isDelayingLoadEvent())
return;
+ auto* scriptableParser = m_frame.document()->scriptableDocumentParser();
+ if (scriptableParser && scriptableParser->hasScriptsWaitingForStylesheets())
+ return;
+
// Any frame that hasn't completed yet?
if (!allChildrenAreComplete())
return;
+ // Important not to protect earlier in this function, because earlier parts
+ // of this function can be called in the frame's destructor, and it's not legal
+ // to ref an object while it's being destroyed.
+ Ref<Frame> protect(m_frame);
+
// OK, completed.
m_isComplete = true;
- m_requestedHistoryItem = 0;
+ m_requestedHistoryItem = nullptr;
m_frame.document()->setReadyState(Document::Complete);
#if PLATFORM(IOS)
@@ -851,7 +834,7 @@ void FrameLoader::checkCompleted()
checkLoadComplete();
}
-void FrameLoader::checkTimerFired(Timer<FrameLoader>&)
+void FrameLoader::checkTimerFired()
{
Ref<Frame> protect(m_frame);
@@ -904,110 +887,78 @@ void FrameLoader::loadURLIntoChildFrame(const URL& url, const String& referer, F
ASSERT(childFrame);
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree().uniqueName(), url);
- if (subframeArchive) {
- childFrame->loader().loadArchive(subframeArchive.release());
- return;
+ if (auto activeLoader = activeDocumentLoader()) {
+ if (auto subframeArchive = activeLoader->popArchiveForSubframe(childFrame->tree().uniqueName(), url)) {
+ childFrame->loader().loadArchive(RefPtr<Archive> { subframeArchive }.releaseNonNull());
+ return;
+ }
}
-#endif // ENABLE(WEB_ARCHIVE)
+#endif
- HistoryItem* parentItem = history().currentItem();
// If we're moving in the back/forward list, we might want to replace the content
// of this child frame with whatever was there at that point.
- if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType())
- && !m_frame.document()->loadEventFinished()) {
- HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree().uniqueName());
- if (childItem) {
+ auto* parentItem = history().currentItem();
+ if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType()) && !m_frame.document()->loadEventFinished()) {
+ if (auto* childItem = parentItem->childItemWithTarget(childFrame->tree().uniqueName())) {
childFrame->loader().m_requestedHistoryItem = childItem;
- childFrame->loader().loadDifferentDocumentItem(childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem);
+ childFrame->loader().loadDifferentDocumentItem(*childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem);
return;
}
}
- childFrame->loader().loadURL(url, referer, "_self", false, FrameLoadTypeRedirectWithLockedBackForwardList, 0, 0);
+ FrameLoadRequest frameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), "_self", LockHistory::No, LockBackForwardList::Yes, ShouldSendReferrer::MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Suppress, ReplaceDocumentIfJavaScriptURL, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
+ childFrame->loader().loadURL(frameLoadRequest, referer, FrameLoadType::RedirectWithLockedBackForwardList, 0, 0);
}
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
-void FrameLoader::loadArchive(PassRefPtr<Archive> archive)
+
+void FrameLoader::loadArchive(Ref<Archive>&& archive)
{
ArchiveResource* mainResource = archive->mainResource();
ASSERT(mainResource);
if (!mainResource)
return;
-
- SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), URL());
+
+ ResourceResponse response(URL(), mainResource->mimeType(), mainResource->data().size(), mainResource->textEncoding());
+ SubstituteData substituteData(&mainResource->data(), URL(), response, SubstituteData::SessionHistoryVisibility::Hidden);
ResourceRequest request(mainResource->url());
-#if PLATFORM(MAC)
- request.applyWebArchiveHackForMail();
-#endif
- RefPtr<DocumentLoader> documentLoader = m_client.createDocumentLoader(request, substituteData);
- documentLoader->setArchive(archive.get());
- load(documentLoader.get());
+ auto documentLoader = m_client.createDocumentLoader(request, substituteData);
+ documentLoader->setArchive(WTFMove(archive));
+ load(documentLoader.ptr());
}
-#endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
-
-ObjectContentType FrameLoader::defaultObjectContentType(const URL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages)
-{
- String mimeType = mimeTypeIn;
-
- if (mimeType.isEmpty())
- mimeType = mimeTypeFromURL(url);
-
-#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does EFL
- if (mimeType.isEmpty()) {
- String decodedPath = decodeURLEscapeSequences(url.path());
- mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(decodedPath.substring(decodedPath.reverseFind('.') + 1));
- }
-#endif
-
- if (mimeType.isEmpty())
- return ObjectContentFrame; // Go ahead and hope that we can display the content.
-
-#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does EFL
- bool plugInSupportsMIMEType = PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType);
-#else
- bool plugInSupportsMIMEType = false;
-#endif
- if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
- return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? WebCore::ObjectContentNetscapePlugin : WebCore::ObjectContentImage;
-
- if (plugInSupportsMIMEType)
- return WebCore::ObjectContentNetscapePlugin;
-
- if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
- return WebCore::ObjectContentFrame;
-
- return WebCore::ObjectContentNone;
-}
+#endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
String FrameLoader::outgoingReferrer() const
{
// See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
// for why we walk the parent chain for srcdoc documents.
Frame* frame = &m_frame;
- while (frame->document()->isSrcdocDocument()) {
+ while (frame && frame->document()->isSrcdocDocument()) {
frame = frame->tree().parent();
// Srcdoc documents cannot be top-level documents, by definition,
// because they need to be contained in iframes with the srcdoc.
ASSERT(frame);
}
+ if (!frame)
+ return emptyString();
return frame->loader().m_outgoingReferrer;
}
String FrameLoader::outgoingOrigin() const
{
- return m_frame.document()->securityOrigin()->toString();
+ return m_frame.document()->securityOrigin().toString();
}
-bool FrameLoader::checkIfFormActionAllowedByCSP(const URL& url) const
+bool FrameLoader::checkIfFormActionAllowedByCSP(const URL& url, bool didReceiveRedirectResponse) const
{
if (m_submittedFormURL.isEmpty())
return true;
- return m_frame.document()->contentSecurityPolicy()->allowFormAction(url);
+ auto redirectResponseReceived = didReceiveRedirectResponse ? ContentSecurityPolicy::RedirectResponseReceived::Yes : ContentSecurityPolicy::RedirectResponseReceived::No;
+ return m_frame.document()->contentSecurityPolicy()->allowFormAction(url, redirectResponseReceived);
}
Frame* FrameLoader::opener()
@@ -1034,9 +985,9 @@ void FrameLoader::setOpener(Frame* opener)
void FrameLoader::handleFallbackContent()
{
HTMLFrameOwnerElement* owner = m_frame.ownerElement();
- if (!owner || !owner->hasTagName(objectTag))
+ if (!is<HTMLObjectElement>(owner))
return;
- toHTMLObjectElement(owner)->renderFallbackContent();
+ downcast<HTMLObjectElement>(*owner).renderFallbackContent();
}
void FrameLoader::provisionalLoadStarted()
@@ -1045,6 +996,11 @@ void FrameLoader::provisionalLoadStarted()
m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
m_frame.navigationScheduler().cancel(true);
m_client.provisionalLoadStarted();
+
+ if (m_frame.isMainFrame()) {
+ if (auto* page = m_frame.page())
+ page->didStartProvisionalLoad();
+ }
}
void FrameLoader::resetMultipleFormSubmissionProtection()
@@ -1068,7 +1024,7 @@ void FrameLoader::setFirstPartyForCookies(const URL& url)
// This does the same kind of work that didOpenURL does, except it relies on the fact
// that a higher level already checked that the URLs match and the scrolling is the right thing to do.
-void FrameLoader::loadInSameDocument(const URL& url, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation)
+void FrameLoader::loadInSameDocument(const URL& url, SerializedScriptValue* stateObject, bool isNewNavigation)
{
// If we have a state object, we cannot also be a new navigation.
ASSERT(!stateObject || (stateObject && !isNewNavigation));
@@ -1121,7 +1077,7 @@ void FrameLoader::loadInSameDocument(const URL& url, PassRefPtr<SerializedScript
m_client.dispatchDidNavigateWithinPage();
- m_frame.document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
+ m_frame.document()->statePopped(stateObject ? Ref<SerializedScriptValue> { *stateObject } : SerializedScriptValue::nullValue());
m_client.dispatchDidPopStateWithinPage();
if (hashChange) {
@@ -1149,45 +1105,25 @@ void FrameLoader::completed()
parent->loader().checkCompleted();
if (m_frame.view())
- m_frame.view()->maintainScrollPositionAtAnchor(0);
- m_activityAssertion = nullptr;
+ m_frame.view()->maintainScrollPositionAtAnchor(nullptr);
}
void FrameLoader::started()
{
- if (m_frame.page())
- m_activityAssertion = m_frame.page()->createActivityToken();
for (Frame* frame = &m_frame; frame; frame = frame->tree().parent())
frame->loader().m_isComplete = false;
}
-void FrameLoader::prepareForHistoryNavigation()
-{
- // If there is no currentItem, but we still want to engage in
- // history navigation we need to manufacture one, and update
- // the state machine of this frame to impersonate having
- // loaded it.
- RefPtr<HistoryItem> currentItem = history().currentItem();
- if (!currentItem) {
- currentItem = HistoryItem::create();
- currentItem->setLastVisitWasFailure(true);
- history().setCurrentItem(currentItem.get());
- m_frame.page()->backForward().setCurrentItem(currentItem.get());
-
- ASSERT(stateMachine()->isDisplayingInitialEmptyDocument());
- stateMachine()->advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
- stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
- }
-}
-
void FrameLoader::prepareForLoadStart()
{
+ RELEASE_LOG_IF_ALLOWED("prepareForLoadStart: Starting frame load (frame = %p, main = %d)", &m_frame, m_frame.isMainFrame());
+
m_progressTracker->progressStarted();
m_client.dispatchDidStartProvisionalLoad();
if (AXObjectCache::accessibilityEnabled()) {
if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache()) {
- AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadTypeReload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
+ AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadType::Reload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
cache->frameLoadingEventNotification(&m_frame, loadingEvent);
}
}
@@ -1198,15 +1134,14 @@ void FrameLoader::setupForReplace()
m_client.revertToProvisionalState(m_documentLoader.get());
setState(FrameStateProvisional);
m_provisionalDocumentLoader = m_documentLoader;
- m_documentLoader = 0;
+ m_documentLoader = nullptr;
detachChildren();
}
-void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList,
- PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer)
-{
+void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, Event* event, FormState* formState)
+{
// Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader.
- Ref<Frame> protect(m_frame);
+ auto protectFrame = makeRef(m_frame);
URL url = request.resourceRequest().url();
@@ -1221,25 +1156,25 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
argsReferrer = outgoingReferrer();
String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), url, argsReferrer);
- if (shouldSendReferrer == NeverSendReferrer)
+ if (request.shouldSendReferrer() == NeverSendReferrer)
referrer = String();
-
+
FrameLoadType loadType;
if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
- loadType = FrameLoadTypeReload;
- else if (lockBackForwardList)
- loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
+ loadType = FrameLoadType::Reload;
+ else if (request.lockBackForwardList() == LockBackForwardList::Yes)
+ loadType = FrameLoadType::RedirectWithLockedBackForwardList;
else
- loadType = FrameLoadTypeStandard;
+ loadType = FrameLoadType::Standard;
if (request.resourceRequest().httpMethod() == "POST")
- loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
+ loadPostRequest(request, referrer, loadType, event, formState);
else
- loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
+ loadURL(request, referrer, loadType, event, formState);
// FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
// load if frame names have changed.
- Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : &m_frame;
+ Frame* sourceFrame = formState ? formState->sourceDocument().frame() : &m_frame;
if (!sourceFrame)
sourceFrame = &m_frame;
Frame* targetFrame = sourceFrame->loader().findFrameForNavigation(request.frameName());
@@ -1249,48 +1184,67 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
}
}
-void FrameLoader::loadURL(const URL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
- PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
+static ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicyToApply(Frame& sourceFrame, ShouldOpenExternalURLsPolicy propagatedPolicy)
+{
+ if (!sourceFrame.isMainFrame())
+ return ShouldOpenExternalURLsPolicy::ShouldNotAllow;
+ if (ScriptController::processingUserGesture())
+ return ShouldOpenExternalURLsPolicy::ShouldAllow;
+ return propagatedPolicy;
+}
+
+bool FrameLoader::isNavigationAllowed() const
+{
+ return m_pageDismissalEventBeingDispatched == PageDismissalType::None && NavigationDisabler::isNavigationAllowed();
+}
+
+void FrameLoader::loadURL(const FrameLoadRequest& frameLoadRequest, const String& referrer, FrameLoadType newLoadType, Event* event, FormState* formState)
{
if (m_inStopAllLoaders)
return;
Ref<Frame> protect(m_frame);
- RefPtr<FormState> formState = prpFormState;
+ String frameName = frameLoadRequest.frameName();
+ AllowNavigationToInvalidURL allowNavigationToInvalidURL = frameLoadRequest.allowNavigationToInvalidURL();
+ NewFrameOpenerPolicy openerPolicy = frameLoadRequest.newFrameOpenerPolicy();
+ LockHistory lockHistory = frameLoadRequest.lockHistory();
bool isFormSubmission = formState;
-
+
+ const URL& newURL = frameLoadRequest.resourceRequest().url();
ResourceRequest request(newURL);
if (!referrer.isEmpty()) {
request.setHTTPReferrer(referrer);
RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
addHTTPOriginIfNeeded(request, referrerOrigin->toString());
}
-#if ENABLE(CACHE_PARTITIONING)
if (&m_frame.tree().top() != &m_frame)
- request.setCachePartition(m_frame.tree().top().document()->securityOrigin()->cachePartition());
-#endif
+ request.setDomainForCachePartition(m_frame.tree().top().document()->securityOrigin().domainForCachePartition());
+
addExtraFieldsToRequest(request, newLoadType, true);
- if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
+ if (newLoadType == FrameLoadType::Reload || newLoadType == FrameLoadType::ReloadFromOrigin)
request.setCachePolicy(ReloadIgnoringCacheData);
- ASSERT(newLoadType != FrameLoadTypeSame);
+ ASSERT(newLoadType != FrameLoadType::Same);
// The search for a target frame is done earlier in the case of form submission.
Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
if (targetFrame && targetFrame != &m_frame) {
- targetFrame->loader().loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release());
+ FrameLoadRequest newFrameLoadRequest(frameLoadRequest);
+ newFrameLoadRequest.setFrameName("_self");
+ targetFrame->loader().loadURL(newFrameLoadRequest, referrer, newLoadType, event, formState);
return;
}
- if (m_pageDismissalEventBeingDispatched != NoDismissal)
+ if (!isNavigationAllowed())
return;
- NavigationAction action(request, newLoadType, isFormSubmission, event);
+ NavigationAction action(request, newLoadType, isFormSubmission, event, frameLoadRequest.shouldOpenExternalURLsPolicy(), frameLoadRequest.downloadAttribute());
if (!targetFrame && !frameName.isEmpty()) {
- policyChecker().checkNewWindowPolicy(action, request, formState.release(), frameName, [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
- continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue);
+ action = action.copyWithShouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicyToApply(m_frame, frameLoadRequest.shouldOpenExternalURLsPolicy()));
+ policyChecker().checkNewWindowPolicy(action, request, formState, frameName, [this, allowNavigationToInvalidURL, openerPolicy] (const ResourceRequest& request, FormState* formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
+ continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL, openerPolicy);
});
return;
}
@@ -1308,7 +1262,7 @@ void FrameLoader::loadURL(const URL& newURL, const String& referrer, const Strin
oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
policyChecker().stopCheck();
policyChecker().setLoadType(newLoadType);
- policyChecker().checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
+ policyChecker().checkNavigationPolicy(request, false /* didReceiveRedirectResponse */, oldDocumentLoader.get(), formState, [this] (const ResourceRequest& request, FormState*, bool shouldContinue) {
continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
});
return;
@@ -1316,16 +1270,16 @@ void FrameLoader::loadURL(const URL& newURL, const String& referrer, const Strin
// must grab this now, since this load may stop the previous load and clear this flag
bool isRedirect = m_quickRedirectComing;
- loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release());
+ loadWithNavigationAction(request, action, lockHistory, newLoadType, formState, allowNavigationToInvalidURL);
if (isRedirect) {
m_quickRedirectComing = false;
if (m_provisionalDocumentLoader)
m_provisionalDocumentLoader->setIsClientRedirect(true);
- } else if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin) {
+ } else if (sameURL && newLoadType != FrameLoadType::Reload && newLoadType != FrameLoadType::ReloadFromOrigin) {
// Example of this case are sites that reload the same URL with a different cookie
// driving the generated content, or a master frame with links that drive a target
// frame, where the user has clicked on the same link repeatedly.
- m_loadType = FrameLoadTypeSame;
+ m_loadType = FrameLoadType::Same;
}
}
@@ -1333,10 +1287,12 @@ SubstituteData FrameLoader::defaultSubstituteDataForURL(const URL& url)
{
if (!shouldTreatURLAsSrcdocDocument(url))
return SubstituteData();
- String srcdoc = m_frame.ownerElement()->fastGetAttribute(srcdocAttr);
+ String srcdoc = m_frame.ownerElement()->attributeWithoutSynchronization(srcdocAttr);
ASSERT(!srcdoc.isNull());
CString encodedSrcdoc = srcdoc.utf8();
- return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", URL());
+
+ ResourceResponse response(URL(), ASCIILiteral("text/html"), encodedSrcdoc.length(), ASCIILiteral("UTF-8"));
+ return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), URL(), response, SubstituteData::SessionHistoryVisibility::Hidden);
}
void FrameLoader::load(const FrameLoadRequest& passedRequest)
@@ -1358,8 +1314,9 @@ void FrameLoader::load(const FrameLoadRequest& passedRequest)
}
if (request.shouldCheckNewWindowPolicy()) {
- policyChecker().checkNewWindowPolicy(NavigationAction(request.resourceRequest(), NavigationTypeOther), request.resourceRequest(), nullptr, request.frameName(), [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
- continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue);
+ NavigationAction action(request.resourceRequest(), NavigationType::Other, passedRequest.shouldOpenExternalURLsPolicy());
+ policyChecker().checkNewWindowPolicy(action, request.resourceRequest(), nullptr, request.frameName(), [this] (const ResourceRequest& request, FormState* formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
+ continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Suppress);
});
return;
@@ -1368,23 +1325,25 @@ void FrameLoader::load(const FrameLoadRequest& passedRequest)
if (!request.hasSubstituteData())
request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url()));
- RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData());
- if (request.lockHistory() && m_documentLoader)
- loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
- load(loader.get());
+ Ref<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData());
+ applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, request.shouldOpenExternalURLsPolicy());
+
+ load(loader.ptr());
}
-void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
+void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, LockHistory lockHistory, FrameLoadType type, FormState* formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
{
- RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
- if (lockHistory && m_documentLoader)
+ Ref<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
+ applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, action.shouldOpenExternalURLsPolicy());
+
+ if (lockHistory == LockHistory::Yes && m_documentLoader)
loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
loader->setTriggeringAction(action);
if (m_documentLoader)
loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
- loadWithDocumentLoader(loader.get(), type, formState);
+ loadWithDocumentLoader(loader.ptr(), type, formState, allowNavigationToInvalidURL);
}
void FrameLoader::load(DocumentLoader* newDocumentLoader)
@@ -1395,11 +1354,13 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader)
if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
r.setCachePolicy(ReloadIgnoringCacheData);
- type = FrameLoadTypeSame;
- } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadTypeReload)
- type = FrameLoadTypeReload;
+ type = FrameLoadType::Same;
+ } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadType::Reload)
+ type = FrameLoadType::Reload;
+ else if (m_loadType == FrameLoadType::RedirectWithLockedBackForwardList && !newDocumentLoader->unreachableURL().isEmpty() && newDocumentLoader->substituteData().isValid())
+ type = FrameLoadType::RedirectWithLockedBackForwardList;
else
- type = FrameLoadTypeStandard;
+ type = FrameLoadType::Standard;
if (m_documentLoader)
newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
@@ -1408,7 +1369,7 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader)
// visiting in the history list, we treat it as a reload so the history list
// is appropriately maintained.
//
- // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
+ // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadType::Reload" ...
// shouldn't a more explicit type of reload be defined, that means roughly
// "load without affecting history" ?
if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
@@ -1417,14 +1378,55 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader)
// changed and updateForBackForwardNavigation() will not be called when loading is committed.
history().saveDocumentAndScrollState();
- ASSERT(type == FrameLoadTypeStandard);
- type = FrameLoadTypeReload;
+ ASSERT(type == FrameLoadType::Standard);
+ type = FrameLoadType::Reload;
}
- loadWithDocumentLoader(newDocumentLoader, type, 0);
+ loadWithDocumentLoader(newDocumentLoader, type, 0, AllowNavigationToInvalidURL::Yes);
+}
+
+static void logNavigation(MainFrame& frame, const URL& destinationURL, FrameLoadType type)
+{
+ if (!frame.page())
+ return;
+
+ String navigationDescription;
+ switch (type) {
+ case FrameLoadType::Standard:
+ navigationDescription = ASCIILiteral("standard");
+ break;
+ case FrameLoadType::Back:
+ navigationDescription = ASCIILiteral("back");
+ break;
+ case FrameLoadType::Forward:
+ navigationDescription = ASCIILiteral("forward");
+ break;
+ case FrameLoadType::IndexedBackForward:
+ navigationDescription = ASCIILiteral("indexedBackForward");
+ break;
+ case FrameLoadType::Reload:
+ navigationDescription = ASCIILiteral("reload");
+ break;
+ case FrameLoadType::Same:
+ navigationDescription = ASCIILiteral("same");
+ break;
+ case FrameLoadType::ReloadFromOrigin:
+ navigationDescription = ASCIILiteral("reloadFromOrigin");
+ break;
+ case FrameLoadType::Replace:
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ // Not logging those for now.
+ return;
+ }
+ frame.page()->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::navigationKey(), navigationDescription, ShouldSample::No);
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+ String domain = topPrivatelyControlledDomain(destinationURL.host());
+ if (!domain.isEmpty())
+ frame.page()->diagnosticLoggingClient().logDiagnosticMessageWithEnhancedPrivacy(DiagnosticLoggingKeys::domainVisitedKey(), domain, ShouldSample::No);
+#endif
}
-void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
+void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, FormState* formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
{
// Retain because dispatchBeforeLoadEvent may release the last reference to it.
Ref<Frame> protect(m_frame);
@@ -1436,17 +1438,23 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ASSERT(m_frame.view());
- if (m_pageDismissalEventBeingDispatched != NoDismissal)
+ if (!isNavigationAllowed())
return;
if (m_frame.document())
m_previousURL = m_frame.document()->url();
+ const URL& newURL = loader->request().url();
+
+ // Log main frame navigation types.
+ if (m_frame.isMainFrame()) {
+ logNavigation(static_cast<MainFrame&>(m_frame), newURL, type);
+ static_cast<MainFrame&>(m_frame).performanceLogging().didReachPointOfInterest(PerformanceLogging::MainFrameLoadStarted);
+ }
+
policyChecker().setLoadType(type);
- RefPtr<FormState> formState = prpFormState;
bool isFormSubmission = formState;
- const URL& newURL = loader->request().url();
const String& httpMethod = loader->request().httpMethod();
if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) {
@@ -1456,7 +1464,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
oldDocumentLoader->setTriggeringAction(action);
oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
policyChecker().stopCheck();
- policyChecker().checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
+ policyChecker().checkNavigationPolicy(loader->request(), false /* didReceiveRedirectResponse */, oldDocumentLoader.get(), formState, [this] (const ResourceRequest& request, FormState*, bool shouldContinue) {
continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
});
return;
@@ -1478,13 +1486,13 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
// a new URL, the parent frame shouldn't learn the URL.
if (!m_stateMachine.committedFirstRealDocumentLoad()
&& !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
- continueLoadAfterNavigationPolicy(loader->request(), formState, false);
+ continueLoadAfterNavigationPolicy(loader->request(), formState, false, allowNavigationToInvalidURL);
return;
}
}
- policyChecker().checkNavigationPolicy(loader->request(), loader, formState, [this](const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) {
- continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
+ policyChecker().checkNavigationPolicy(loader->request(), false /* didReceiveRedirectResponse */, loader, formState, [this, allowNavigationToInvalidURL] (const ResourceRequest& request, FormState* formState, bool shouldContinue) {
+ continueLoadAfterNavigationPolicy(request, formState, shouldContinue, allowNavigationToInvalidURL);
});
}
@@ -1494,7 +1502,16 @@ void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
if (!frame)
return;
- frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url);
+ frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to load local resource: " + url);
+}
+
+void FrameLoader::reportBlockedPortFailed(Frame* frame, const String& url)
+{
+ ASSERT(!url.isEmpty());
+ if (!frame)
+ return;
+
+ frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to use restricted network port: " + url);
}
const ResourceRequest& FrameLoader::initialRequest() const
@@ -1507,7 +1524,7 @@ bool FrameLoader::willLoadMediaElementURL(URL& url)
#if PLATFORM(IOS)
// MobileStore depends on the iOS 4.0 era client delegate method because webView:resource:willSendRequest:redirectResponse:fromDataSource
// doesn't let them tell when a load request is coming from a media element. See <rdar://problem/8266916> for more details.
- if (applicationIsMobileStore())
+ if (IOSApplication::isMobileStore())
return m_client.shouldLoadMediaElementURL(url);
#endif
@@ -1516,7 +1533,7 @@ bool FrameLoader::willLoadMediaElementURL(URL& url)
unsigned long identifier;
ResourceError error;
requestFromDelegate(request, identifier, error);
- notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String(), String()), 0, -1, -1, error);
+ notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String()), 0, -1, -1, error);
url = request.url();
@@ -1538,13 +1555,10 @@ bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
// case handles well-formed URLs that can't be loaded, and the latter
// case handles malformed URLs and unknown schemes. Loading alternate content
// at other times behaves like a standard load.
- DocumentLoader* compareDocumentLoader = 0;
if (policyChecker().delegateIsDecidingNavigationPolicy() || policyChecker().delegateIsHandlingUnimplementablePolicy())
- compareDocumentLoader = m_policyDocumentLoader.get();
- else if (m_delegateIsHandlingProvisionalLoadError)
- compareDocumentLoader = m_provisionalDocumentLoader.get();
+ return m_policyDocumentLoader && unreachableURL == m_policyDocumentLoader->request().url();
- return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
+ return unreachableURL == m_provisionalLoadErrorBeingHandledURL;
}
void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
@@ -1561,28 +1575,17 @@ void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
// We should ask the user for confirmation in this case.
request.setCachePolicy(ReturnCacheDataElseLoad);
- RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
- setPolicyDocumentLoader(loader.get());
-
- loader->setOverrideEncoding(encoding);
-
- loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
-}
+ Ref<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
+ applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, m_documentLoader->shouldOpenExternalURLsPolicyToPropagate());
-void FrameLoader::reloadWithOverrideURL(const URL& overrideUrl, bool endToEndReload)
-{
- if (!m_documentLoader)
- return;
+ setPolicyDocumentLoader(loader.ptr());
- if (overrideUrl.isEmpty())
- return;
+ loader->setOverrideEncoding(encoding);
- ResourceRequest request = m_documentLoader->request();
- request.setURL(overrideUrl);
- reloadWithRequest(request, endToEndReload);
+ loadWithDocumentLoader(loader.ptr(), FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
}
-void FrameLoader::reload(bool endToEndReload)
+void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled)
{
if (!m_documentLoader)
return;
@@ -1598,17 +1601,13 @@ void FrameLoader::reload(bool endToEndReload)
if (!unreachableURL.isEmpty())
initialRequest.setURL(unreachableURL);
- reloadWithRequest(initialRequest, endToEndReload);
-}
-
-void FrameLoader::reloadWithRequest(const ResourceRequest& initialRequest, bool endToEndReload)
-{
- ASSERT(m_documentLoader);
-
// Create a new document loader for the reload, this will become m_documentLoader eventually,
// but first it has to be the "policy" document loader, and then the "provisional" document loader.
- RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
+ Ref<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
+ applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, m_documentLoader->shouldOpenExternalURLsPolicyToPropagate());
+ loader->setUserContentExtensionsEnabled(contentBlockersEnabled);
+
ResourceRequest& request = loader->request();
// FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
@@ -1616,17 +1615,17 @@ void FrameLoader::reloadWithRequest(const ResourceRequest& initialRequest, bool
// If we're about to re-post, set up action so the application can warn the user.
if (request.httpMethod() == "POST")
- loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted));
+ loader->setTriggeringAction(NavigationAction(request, NavigationType::FormResubmitted));
loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
- loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
+ loadWithDocumentLoader(loader.ptr(), endToEndReload ? FrameLoadType::ReloadFromOrigin : FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
}
void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
{
- ASSERT(!m_frame.document() || !m_frame.document()->inPageCache());
- if (m_pageDismissalEventBeingDispatched != NoDismissal)
+ ASSERT(!m_frame.document() || m_frame.document()->pageCacheState() != Document::InPageCache);
+ if (!isNavigationAllowed())
return;
// If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
@@ -1644,7 +1643,7 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem
// If no new load is in progress, we should clear the provisional item from history
// before we call stopLoading.
if (clearProvisionalItemPolicy == ShouldClearProvisionalItem)
- history().setProvisionalItem(0);
+ history().setProvisionalItem(nullptr);
for (RefPtr<Frame> child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
child->loader().stopAllLoaders(clearProvisionalItemPolicy);
@@ -1653,7 +1652,7 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem
if (m_documentLoader)
m_documentLoader->stopLoading();
- setProvisionalDocumentLoader(0);
+ setProvisionalDocumentLoader(nullptr);
m_checkTimer.stop();
@@ -1662,6 +1661,9 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem
void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
{
+ // Calling stopAllLoaders can cause the frame to be deallocated, including the frame loader.
+ Ref<Frame> protectedFrame(m_frame);
+
stopAllLoaders();
#if PLATFORM(IOS)
@@ -1731,7 +1733,7 @@ void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
return;
if (loader)
- loader->setFrame(&m_frame);
+ loader->attachToFrame(m_frame);
if (m_policyDocumentLoader
&& m_policyDocumentLoader != m_provisionalDocumentLoader
&& m_policyDocumentLoader != m_documentLoader)
@@ -1752,7 +1754,8 @@ void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
}
void FrameLoader::setState(FrameState newState)
-{
+{
+ FrameState oldState = m_state;
m_state = newState;
if (newState == FrameStateProvisional)
@@ -1761,12 +1764,14 @@ void FrameLoader::setState(FrameState newState)
frameLoadCompleted();
if (m_documentLoader)
m_documentLoader->stopRecordingResponses();
+ if (m_frame.isMainFrame() && oldState != newState)
+ static_cast<MainFrame&>(m_frame).didCompleteLoad();
}
}
void FrameLoader::clearProvisionalLoad()
{
- setProvisionalDocumentLoader(0);
+ setProvisionalDocumentLoader(nullptr);
m_progressTracker->progressCompleted();
setState(FrameStateComplete);
}
@@ -1777,42 +1782,24 @@ void FrameLoader::commitProvisionalLoad()
Ref<Frame> protect(m_frame);
std::unique_ptr<CachedPage> cachedPage;
- if (m_loadingFromCachedPage)
- cachedPage = pageCache()->take(history().provisionalItem());
+ if (m_loadingFromCachedPage && history().provisionalItem())
+ cachedPage = PageCache::singleton().take(*history().provisionalItem(), m_frame.page());
LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame.tree().uniqueName().string().utf8().data(),
m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "",
pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>");
-#if PLATFORM(IOS)
- // In the case where we are not navigating to a cached page, and the system is under (speculative) memory pressure,
- // we can try to preemptively release some of the pages in the cache.
- // FIXME: Right now the capacity is 1 on iOS devices with 256 MB of RAM, so this will always blow away the whole
- // page cache. We could still preemptively prune the page cache while navigating to a cached page if capacity > 1.
- // See <rdar://problem/11779846> for more details.
- if (!cachedPage) {
- if (memoryPressureHandler().hasReceivedMemoryPressure()) {
- LOG(MemoryPressure, "Pruning page cache because under memory pressure at: %s", __PRETTY_FUNCTION__);
- LOG(PageCache, "Pruning page cache to 0 due to memory pressure");
- // Don't cache any page if we are under memory pressure.
- pageCache()->pruneToCapacityNow(0);
- } else if (systemMemoryLevel() <= memoryLevelThresholdToPrunePageCache) {
- LOG(MemoryPressure, "Pruning page cache because system memory level is %d at: %s", systemMemoryLevel(), __PRETTY_FUNCTION__);
- LOG(PageCache, "Pruning page cache to %d due to low memory (level %d less or equal to %d threshold)", pageCache()->capacity() / 2, systemMemoryLevel(), memoryLevelThresholdToPrunePageCache);
- pageCache()->pruneToCapacityNow(pageCache()->capacity() / 2);
- }
- }
-#endif
-
willTransitionToCommitted();
- // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
- // We are doing this here because we know for sure that a new page is about to be loaded.
- HistoryItem* item = history().currentItem();
- if (!m_frame.tree().parent() && pageCache()->canCache(m_frame.page()) && !item->isInPageCache())
- pageCache()->add(item, *m_frame.page());
+ if (!m_frame.tree().parent() && history().currentItem()) {
+ // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
+ // We are doing this here because we know for sure that a new page is about to be loaded.
+ PageCache::singleton().addIfCacheable(*history().currentItem(), m_frame.page());
+
+ WebCore::jettisonExpensiveObjectsOnTopLevelNavigation();
+ }
- if (m_loadType != FrameLoadTypeReplace)
+ if (m_loadType != FrameLoadType::Replace)
closeOldDataSources();
if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
@@ -1822,8 +1809,8 @@ void FrameLoader::commitProvisionalLoad()
if (pdl && m_documentLoader) {
// Check if the destination page is allowed to access the previous page's timing information.
- RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
- m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_previousURL));
+ Ref<SecurityOrigin> securityOrigin(SecurityOrigin::create(pdl->request().url()));
+ m_documentLoader->timing().setHasSameOriginAsPreviousDocument(securityOrigin.get().canRequest(m_previousURL));
}
// Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
@@ -1839,21 +1826,44 @@ void FrameLoader::commitProvisionalLoad()
// commit to happen before any changes to viewport arguments and dealing with this there is difficult.
m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(true);
#endif
- prepareForCachedPageRestore();
+ willRestoreFromCachedPage();
+
+ // Start request for the main resource and dispatch didReceiveResponse before the load is committed for
+ // consistency with all other loads. See https://bugs.webkit.org/show_bug.cgi?id=150927.
+ ResourceError mainResouceError;
+ unsigned long mainResourceIdentifier;
+ ResourceRequest mainResourceRequest(cachedPage->documentLoader()->request());
+ requestFromDelegate(mainResourceRequest, mainResourceIdentifier, mainResouceError);
+ notifier().dispatchDidReceiveResponse(cachedPage->documentLoader(), mainResourceIdentifier, cachedPage->documentLoader()->response());
+
+ std::optional<HasInsecureContent> hasInsecureContent = cachedPage->cachedMainFrame()->hasInsecureContent();
+
+ {
+ // Do not dispatch DOM events as their JavaScript listeners could cause the page to be put
+ // into the page cache before we have finished restoring it from the page cache.
+ NoEventDispatchAssertion assertNoEventDispatch;
+
+ // FIXME: This API should be turned around so that we ground CachedPage into the Page.
+ cachedPage->restore(*m_frame.page());
+ }
+
+ dispatchDidCommitLoad(hasInsecureContent);
- // FIXME: This API should be turned around so that we ground CachedPage into the Page.
- cachedPage->restore(*m_frame.page());
+ didRestoreFromCachedPage();
- dispatchDidCommitLoad();
#if PLATFORM(IOS)
m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(false);
m_frame.page()->chrome().dispatchViewportPropertiesDidChange(m_frame.page()->viewportArguments());
#endif
- // If we have a title let the WebView know about it.
- StringWithDirection title = m_documentLoader->title();
- if (!title.isNull())
+
+ auto& title = m_documentLoader->title();
+ if (!title.string.isNull())
m_client.dispatchDidReceiveTitle(title);
+ // Send remaining notifications for the main resource.
+ notifier().sendRemainingDelegateMessages(m_documentLoader.get(), mainResourceIdentifier, mainResourceRequest, ResourceResponse(),
+ nullptr, static_cast<int>(m_documentLoader->response().expectedContentLength()), 0, mainResouceError);
+
checkCompleted();
} else
didOpenURL();
@@ -1861,28 +1871,26 @@ void FrameLoader::commitProvisionalLoad()
LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame.tree().uniqueName().string().utf8().data(),
m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "");
- if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
+ if (m_loadType == FrameLoadType::Standard && m_documentLoader->isClientRedirect())
history().updateForClientRedirect();
if (m_loadingFromCachedPage) {
-#if PLATFORM(IOS)
// Note, didReceiveDocType is expected to be called for cached pages. See <rdar://problem/5906758> for more details.
- if (m_frame.document()->doctype() && m_frame.page())
- m_frame.page()->chrome().didReceiveDocType(&m_frame);
-#endif
- m_frame.document()->documentDidResumeFromPageCache();
+ if (auto* page = m_frame.page())
+ page->chrome().didReceiveDocType(m_frame);
+ m_frame.document()->resume(ActiveDOMObject::PageCache);
// Force a layout to update view size and thereby update scrollbars.
#if PLATFORM(IOS)
- m_client.forceLayoutWithoutRecalculatingStyles();
+ if (!m_client.forceLayoutOnRestoreFromPageCache())
+ m_frame.view()->forceLayout();
#else
m_frame.view()->forceLayout();
#endif
- const ResponseVector& responses = m_documentLoader->responses();
- size_t count = responses.size();
- for (size_t i = 0; i < count; i++) {
- const ResourceResponse& response = responses[i];
+ // Main resource delegates were already sent, so we skip the first response here.
+ for (unsigned i = 1; i < m_documentLoader->responses().size(); ++i) {
+ const auto& response = m_documentLoader->responses()[i];
// FIXME: If the WebKit client changes or cancels the request, this is not respected.
ResourceError error;
unsigned long identifier;
@@ -1924,82 +1932,77 @@ void FrameLoader::transitionToCommitted(CachedPage* cachedPage)
if (pdl != m_provisionalDocumentLoader)
return;
- // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
if (m_documentLoader)
m_documentLoader->stopLoadingSubresources();
if (m_documentLoader)
m_documentLoader->stopLoadingPlugIns();
+ // Setting our document loader invokes the unload event handler of our child frames.
+ // Script can do anything. If the script initiates a new load, we need to abandon the
+ // current load or the two will stomp each other.
setDocumentLoader(m_provisionalDocumentLoader.get());
- setProvisionalDocumentLoader(0);
-
- if (pdl != m_documentLoader) {
- ASSERT(m_state == FrameStateComplete);
+ if (pdl != m_provisionalDocumentLoader)
return;
- }
+ setProvisionalDocumentLoader(nullptr);
+ // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
setState(FrameStateCommittedPage);
-#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
- if (m_frame.isMainFrame())
- m_frame.page()->chrome().client().needTouchEvents(false);
-#endif
-
// Handle adding the URL to the back/forward list.
DocumentLoader* dl = m_documentLoader.get();
switch (m_loadType) {
- case FrameLoadTypeForward:
- case FrameLoadTypeBack:
- case FrameLoadTypeIndexedBackForward:
- if (m_frame.page()) {
- // If the first load within a frame is a navigation within a back/forward list that was attached
- // without any of the items being loaded then we need to update the history in a similar manner as
- // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
- if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame())
- history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
-
- history().updateForBackForwardNavigation();
-
- // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
- if (history().currentItem() && !cachedPage)
- m_pendingStateObject = history().currentItem()->stateObject();
-
- // Create a document view for this document, or used the cached view.
- if (cachedPage) {
- DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
- ASSERT(cachedDocumentLoader);
- cachedDocumentLoader->setFrame(&m_frame);
- m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
- } else
- m_client.transitionToCommittedForNewPage();
- }
- break;
-
- case FrameLoadTypeReload:
- case FrameLoadTypeReloadFromOrigin:
- case FrameLoadTypeSame:
- case FrameLoadTypeReplace:
- history().updateForReload();
- m_client.transitionToCommittedForNewPage();
- break;
-
- case FrameLoadTypeStandard:
- history().updateForStandardLoad();
- if (m_frame.view())
- m_frame.view()->setScrollbarsSuppressed(true);
- m_client.transitionToCommittedForNewPage();
- break;
-
- case FrameLoadTypeRedirectWithLockedBackForwardList:
- history().updateForRedirectWithLockedBackForwardList();
- m_client.transitionToCommittedForNewPage();
- break;
-
- // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
- // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
- default:
- ASSERT_NOT_REACHED();
+ case FrameLoadType::Forward:
+ case FrameLoadType::Back:
+ case FrameLoadType::IndexedBackForward:
+ if (m_frame.page()) {
+ // If the first load within a frame is a navigation within a back/forward list that was attached
+ // without any of the items being loaded then we need to update the history in a similar manner as
+ // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
+ if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame())
+ history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
+
+ history().updateForBackForwardNavigation();
+
+ // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
+ if (history().currentItem() && !cachedPage)
+ m_pendingStateObject = history().currentItem()->stateObject();
+
+ // Create a document view for this document, or used the cached view.
+ if (cachedPage) {
+ DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
+ ASSERT(cachedDocumentLoader);
+ cachedDocumentLoader->attachToFrame(m_frame);
+ m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
+ } else
+ m_client.transitionToCommittedForNewPage();
+ }
+ break;
+
+ case FrameLoadType::Reload:
+ case FrameLoadType::ReloadFromOrigin:
+ case FrameLoadType::Same:
+ case FrameLoadType::Replace:
+ history().updateForReload();
+ m_client.transitionToCommittedForNewPage();
+ break;
+
+ case FrameLoadType::Standard:
+ history().updateForStandardLoad();
+ if (m_frame.view())
+ m_frame.view()->setScrollbarsSuppressed(true);
+ m_client.transitionToCommittedForNewPage();
+ break;
+
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ history().updateForRedirectWithLockedBackForwardList();
+ m_client.transitionToCommittedForNewPage();
+ break;
+
+ // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
+ // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
+ default:
+ ASSERT_NOT_REACHED();
}
m_documentLoader->writer().setMIMEType(dl->responseMIMEType());
@@ -2027,7 +2030,7 @@ void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres
m_sentRedirectNotification = false;
}
-void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, bool lockBackForwardList)
+void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, LockBackForwardList lockBackForwardList)
{
m_client.dispatchWillPerformClientRedirect(url, seconds, fireDate);
@@ -2039,7 +2042,7 @@ void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDa
// load as part of the original navigation. If we don't have a document loader, we have
// no "original" load on which to base a redirect, so we treat the redirect as a normal load.
// Loads triggered by JavaScript form submissions never count as quick redirects.
- m_quickRedirectComing = (lockBackForwardList || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
+ m_quickRedirectComing = (lockBackForwardList == LockBackForwardList::Yes || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
}
bool FrameLoader::shouldReload(const URL& currentURL, const URL& destinationURL)
@@ -2066,7 +2069,7 @@ void FrameLoader::closeOldDataSources()
m_client.setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
}
-void FrameLoader::prepareForCachedPageRestore()
+void FrameLoader::willRestoreFromCachedPage()
{
ASSERT(!m_frame.tree().parent());
ASSERT(m_frame.page());
@@ -2085,6 +2088,31 @@ void FrameLoader::prepareForCachedPageRestore()
}
}
+void FrameLoader::didRestoreFromCachedPage()
+{
+ // Dispatching JavaScript events can cause frame destruction.
+ auto& mainFrame = m_frame.page()->mainFrame();
+ Vector<Ref<Frame>> childFrames;
+ for (auto* child = mainFrame.tree().traverseNextInPostOrderWithWrap(true); child; child = child->tree().traverseNextInPostOrderWithWrap(false))
+ childFrames.append(*child);
+
+ for (auto& child : childFrames) {
+ if (!child->tree().isDescendantOf(&mainFrame))
+ continue;
+ auto* document = child->document();
+ if (!document)
+ continue;
+
+ // FIXME: Update Page Visibility state here.
+ // https://bugs.webkit.org/show_bug.cgi?id=116770
+ document->dispatchPageshowEvent(PageshowEventPersisted);
+
+ auto* historyItem = child->loader().history().currentItem();
+ if (historyItem && historyItem->stateObject())
+ document->dispatchPopstateEvent(historyItem->stateObject());
+ }
+}
+
void FrameLoader::open(CachedFrameBase& cachedFrame)
{
m_isComplete = false;
@@ -2105,7 +2133,7 @@ void FrameLoader::open(CachedFrameBase& cachedFrame)
clear(document, true, true, cachedFrame.isMainFrame());
- document->setInPageCache(false);
+ document->setPageCacheState(Document::NotInPageCache);
m_needsClear = true;
m_isComplete = false;
@@ -2118,13 +2146,15 @@ void FrameLoader::open(CachedFrameBase& cachedFrame)
ASSERT(view);
view->setWasScrolledByUser(false);
- // Use the current ScrollView's frame rect.
- if (m_frame.view())
- view->setFrameRect(m_frame.view()->frameRect());
+ std::optional<IntRect> previousViewFrameRect = m_frame.view() ? m_frame.view()->frameRect() : std::optional<IntRect>(std::nullopt);
m_frame.setView(view);
+
+ // Use the previous ScrollView's frame rect.
+ if (previousViewFrameRect)
+ view->setFrameRect(previousViewFrameRect.value());
m_frame.setDocument(document);
- document->domWindow()->resumeFromPageCache();
+ document->domWindow()->resumeFromDocumentSuspension();
updateFirstPartyForCookies();
@@ -2139,12 +2169,12 @@ bool FrameLoader::isHostedByObjectElement() const
bool FrameLoader::isReplacing() const
{
- return m_loadType == FrameLoadTypeReplace;
+ return m_loadType == FrameLoadType::Replace;
}
void FrameLoader::setReplacing()
{
- m_loadType = FrameLoadTypeReplace;
+ m_loadType = FrameLoadType::Replace;
}
bool FrameLoader::subframeIsLoading() const
@@ -2177,10 +2207,15 @@ FrameLoadType FrameLoader::loadType() const
CachePolicy FrameLoader::subresourceCachePolicy() const
{
+ if (Page* page = m_frame.page()) {
+ if (page->isResourceCachingDisabled())
+ return CachePolicyReload;
+ }
+
if (m_isComplete)
return CachePolicyVerify;
- if (m_loadType == FrameLoadTypeReloadFromOrigin)
+ if (m_loadType == FrameLoadType::ReloadFromOrigin)
return CachePolicyReload;
if (Frame* parentFrame = m_frame.tree().parent()) {
@@ -2189,18 +2224,24 @@ CachePolicy FrameLoader::subresourceCachePolicy() const
return parentCachePolicy;
}
- if (m_loadType == FrameLoadTypeReload)
- return CachePolicyRevalidate;
-
- const ResourceRequest& request(documentLoader()->request());
-#if PLATFORM(MAC)
- if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post") && ResourceRequest::useQuickLookResourceCachingQuirks())
+ switch (m_loadType) {
+ case FrameLoadType::Reload:
return CachePolicyRevalidate;
-#endif
-
- if (request.cachePolicy() == ReturnCacheDataElseLoad)
+ case FrameLoadType::Back:
+ case FrameLoadType::Forward:
+ case FrameLoadType::IndexedBackForward:
return CachePolicyHistoryBuffer;
+ case FrameLoadType::ReloadFromOrigin:
+ ASSERT_NOT_REACHED(); // Already handled above.
+ return CachePolicyReload;
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ case FrameLoadType::Replace:
+ case FrameLoadType::Same:
+ case FrameLoadType::Standard:
+ return CachePolicyVerify;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
return CachePolicyVerify;
}
@@ -2210,7 +2251,11 @@ void FrameLoader::checkLoadCompleteForThisFrame()
switch (m_state) {
case FrameStateProvisional: {
- if (m_delegateIsHandlingProvisionalLoadError)
+ // FIXME: Prohibiting any provisional load failures from being sent to clients
+ // while handling provisional load failures is too heavy. For example, the current
+ // load will fail to cancel another ongoing load. That might prevent clients' page
+ // load state being handled properly.
+ if (!m_provisionalLoadErrorBeingHandledURL.isEmpty())
return;
RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
@@ -2232,9 +2277,13 @@ void FrameLoader::checkLoadCompleteForThisFrame()
// Only reset if we aren't already going to a new provisional item.
bool shouldReset = !history().provisionalItem();
if (!pdl->isLoadingInAPISense() || pdl->isStopping()) {
- m_delegateIsHandlingProvisionalLoadError = true;
+ m_provisionalLoadErrorBeingHandledURL = m_provisionalDocumentLoader->url();
m_client.dispatchDidFailProvisionalLoad(error);
- m_delegateIsHandlingProvisionalLoadError = false;
+#if ENABLE(CONTENT_FILTERING)
+ if (auto contentFilter = pdl->contentFilter())
+ contentFilter->handleProvisionalLoadFailure(error);
+#endif
+ m_provisionalLoadErrorBeingHandledURL = { };
ASSERT(!pdl->isLoading());
@@ -2275,7 +2324,7 @@ void FrameLoader::checkLoadCompleteForThisFrame()
// If the user had a scroll point, scroll to it, overriding the anchor point if any.
if (m_frame.page()) {
- if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin)
+ if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadType::Reload || m_loadType == FrameLoadType::ReloadFromOrigin)
history().restoreScrollPositionAndViewState();
}
@@ -2283,31 +2332,55 @@ void FrameLoader::checkLoadCompleteForThisFrame()
return;
m_progressTracker->progressCompleted();
- if (Page* page = m_frame.page()) {
+ Page* page = m_frame.page();
+ if (page) {
if (m_frame.isMainFrame())
- page->resetRelevantPaintedObjectCounter();
+ page->didFinishLoad();
}
const ResourceError& error = dl->mainDocumentError();
AXObjectCache::AXLoadingEvent loadingEvent;
if (!error.isNull()) {
+ RELEASE_LOG_IF_ALLOWED("checkLoadCompleteForThisFrame: Finished frame load with error (frame = %p, main = %d, isTimeout = %d, isCancellation = %d, errorCode = %d)", &m_frame, m_frame.isMainFrame(), error.isTimeout(), error.isCancellation(), error.errorCode());
m_client.dispatchDidFailLoad(error);
loadingEvent = AXObjectCache::AXLoadingFailed;
} else {
+ RELEASE_LOG_IF_ALLOWED("checkLoadCompleteForThisFrame: Finished frame load (frame = %p, main = %d)", &m_frame, m_frame.isMainFrame());
+#if ENABLE(DATA_DETECTION)
+ auto* document = m_frame.document();
+ if (m_frame.settings().dataDetectorTypes() != DataDetectorTypeNone && document) {
+ if (auto* documentElement = document->documentElement()) {
+ RefPtr<Range> documentRange = makeRange(firstPositionInNode(documentElement), lastPositionInNode(documentElement));
+ m_frame.setDataDetectionResults(DataDetection::detectContentInRange(documentRange, m_frame.settings().dataDetectorTypes(), m_client.dataDetectionContext()));
+ if (m_frame.isMainFrame())
+ m_client.dispatchDidFinishDataDetection(m_frame.dataDetectionResults());
+ }
+ }
+#endif
m_client.dispatchDidFinishLoad();
loadingEvent = AXObjectCache::AXLoadingFinished;
}
// Notify accessibility.
- if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache())
- cache->frameLoadingEventNotification(&m_frame, loadingEvent);
+ if (auto* document = m_frame.document()) {
+ if (AXObjectCache* cache = document->existingAXObjectCache())
+ cache->frameLoadingEventNotification(&m_frame, loadingEvent);
+ }
+
+ // The above calls to dispatchDidFinishLoad() might have detached the Frame
+ // from its Page and also might have caused Page to be deleted.
+ // Don't assume 'page' is still available to use.
+ if (m_frame.isMainFrame() && m_frame.page()) {
+ ASSERT(&m_frame.page()->mainFrame() == &m_frame);
+ m_frame.page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageLoadedKey(), emptyString(), error.isNull() ? DiagnosticLoggingResultPass : DiagnosticLoggingResultFail, ShouldSample::Yes);
+ }
return;
}
case FrameStateComplete:
- m_loadType = FrameLoadTypeStandard;
+ m_loadType = FrameLoadType::Standard;
frameLoadCompleted();
return;
}
@@ -2324,76 +2397,46 @@ void FrameLoader::continueLoadAfterWillSubmitForm()
// The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
// so we need to null check it again.
- if (!m_provisionalDocumentLoader)
+ if (!m_provisionalDocumentLoader) {
+ RELEASE_LOG_IF_ALLOWED("continueLoadAfterWillSubmitForm: Frame load canceled (frame = %p, main = %d)", &m_frame, m_frame.isMainFrame());
return;
+ }
DocumentLoader* activeDocLoader = activeDocumentLoader();
- if (activeDocLoader && activeDocLoader->isLoadingMainResource())
+ if (activeDocLoader && activeDocLoader->isLoadingMainResource()) {
+ RELEASE_LOG_IF_ALLOWED("continueLoadAfterWillSubmitForm: Main frame already being loaded (frame = %p, main = %d)", &m_frame, m_frame.isMainFrame());
return;
+ }
m_loadingFromCachedPage = false;
m_provisionalDocumentLoader->startLoadingMainResource();
}
-static URL originatingURLFromBackForwardList(Page* page)
-{
- // FIXME: Can this logic be replaced with m_frame.document()->firstPartyForCookies()?
- // It has the same meaning of "page a user thinks is the current one".
-
- URL originalURL;
- int backCount = page->backForward().backCount();
- for (int backIndex = 0; backIndex <= backCount; backIndex++) {
- // FIXME: At one point we had code here to check a "was user gesture" flag.
- // Do we need to restore that logic?
- HistoryItem* historyItem = page->backForward().itemAtIndex(-backIndex);
- if (!historyItem)
- continue;
-
- originalURL = historyItem->originalURL();
- if (!originalURL.isNull())
- return originalURL;
- }
-
- return URL();
-}
-
void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request)
{
+ // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
+ // The originalURL is defined as the URL of the page where the download was initiated.
URL originalURL;
-
- // If there is no referrer, assume that the download was initiated directly, so current document is
- // completely unrelated to it. See <rdar://problem/5294691>.
- // FIXME: Referrer is not sent in many other cases, so we will often miss this important information.
- // Find a better way to decide whether the download was unrelated to current document.
- if (!request.httpReferrer().isNull()) {
- // find the first item in the history that was originated by the user
- originalURL = originatingURLFromBackForwardList(m_frame.page());
- }
-
- if (originalURL.isNull())
- originalURL = request.url();
-
- if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) {
- unsigned port = originalURL.port();
-
- // Original URL is needed to show the user where a file was downloaded from. We should make a URL that won't result in downloading the file again.
- // FIXME: Using host-only URL is a very heavy-handed approach. We should attempt to provide the actual page where the download was initiated from, as a reminder to the user.
- String hostOnlyURLString;
- if (port)
- hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ":", String::number(port));
- else
- hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host());
-
- // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
- request.setFirstPartyForCookies(URL(URL(), hostOnlyURLString));
- }
+ if (m_frame.document()) {
+ originalURL = m_frame.document()->firstPartyForCookies();
+ // If there is no main document URL, it means that this document is newly opened and just for download purpose.
+ // In this case, we need to set the originalURL to this document's opener's main document URL.
+ if (originalURL.isEmpty() && opener() && opener()->document())
+ originalURL = opener()->document()->firstPartyForCookies();
+ }
+ // If the originalURL is the same as the requested URL, we are processing a download
+ // initiated directly without a page and do not need to specify the originalURL.
+ if (originalURL == request.url())
+ request.setFirstPartyForCookies(URL());
+ else
+ request.setFirstPartyForCookies(originalURL);
}
-void FrameLoader::didLayout(LayoutMilestones milestones)
+void FrameLoader::didReachLayoutMilestone(LayoutMilestones milestones)
{
ASSERT(m_frame.isMainFrame());
- m_client.dispatchDidLayout(milestones);
+ m_client.dispatchDidReachLayoutMilestone(milestones);
}
void FrameLoader::didFirstLayout()
@@ -2428,23 +2471,34 @@ void FrameLoader::frameLoadCompleted()
void FrameLoader::detachChildren()
{
+ // detachChildren() will fire the unload event in each subframe and the
+ // HTML specification states that the parent document's ignore-opens-during-unload counter while
+ // this event is being fired in its subframes:
+ // https://html.spec.whatwg.org/multipage/browsers.html#unload-a-document
+ IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(m_frame.document());
+
+ // Any subframe inserted by unload event handlers executed in the loop below will not get unloaded
+ // because we create a copy of the subframes list before looping. Therefore, it would be unsafe to
+ // allow loading of subframes at this point.
+ SubframeLoadingDisabler subframeLoadingDisabler(m_frame.document());
+
Vector<Ref<Frame>, 16> childrenToDetach;
childrenToDetach.reserveInitialCapacity(m_frame.tree().childCount());
for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling())
childrenToDetach.uncheckedAppend(*child);
- for (unsigned i = 0; i < childrenToDetach.size(); ++i)
- childrenToDetach[i]->loader().detachFromParent();
+ for (auto& child : childrenToDetach)
+ child->loader().detachFromParent();
}
-void FrameLoader::closeAndRemoveChild(Frame* child)
+void FrameLoader::closeAndRemoveChild(Frame& child)
{
- child->tree().detachFromParent();
+ child.tree().detachFromParent();
- child->setView(0);
- if (child->ownerElement() && child->page())
- child->page()->decrementSubframeCount();
- child->willDetachPage();
- child->detachFromPage();
+ child.setView(nullptr);
+ if (child.ownerElement() && child.page())
+ child.page()->decrementSubframeCount();
+ child.willDetachPage();
+ child.detachFromPage();
m_frame.tree().removeChild(child);
}
@@ -2466,18 +2520,20 @@ void FrameLoader::checkLoadComplete()
frames.append(*frame);
// To process children before their parents, iterate the vector backwards.
- for (unsigned i = frames.size(); i; --i)
- frames[i - 1]->loader().checkLoadCompleteForThisFrame();
+ for (auto frame = frames.rbegin(); frame != frames.rend(); ++frame) {
+ if ((*frame)->page())
+ (*frame)->loader().checkLoadCompleteForThisFrame();
+ }
}
int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
{
if (!recurse)
- return m_frame.document()->cachedResourceLoader()->requestCount();
+ return m_frame.document()->cachedResourceLoader().requestCount();
int count = 0;
for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
- count += frame->document()->cachedResourceLoader()->requestCount();
+ count += frame->document()->cachedResourceLoader().requestCount();
return count;
}
@@ -2486,44 +2542,53 @@ String FrameLoader::userAgent(const URL& url) const
return m_client.userAgent(url);
}
-void FrameLoader::handledOnloadEvents()
+void FrameLoader::dispatchOnloadEvents()
{
- m_client.dispatchDidHandleOnloadEvents();
+ m_client.dispatchDidDispatchOnloadEvents();
if (documentLoader())
- documentLoader()->handledOnloadEvents();
+ documentLoader()->dispatchOnloadEvents();
}
void FrameLoader::frameDetached()
{
- stopAllLoaders();
- m_frame.document()->stopActiveDOMObjects();
+ // Calling stopAllLoaders() can cause the frame to be deallocated, including the frame loader.
+ Ref<Frame> protectedFrame(m_frame);
+
+ if (m_frame.document()->pageCacheState() != Document::InPageCache) {
+ stopAllLoaders();
+ m_frame.document()->stopActiveDOMObjects();
+ }
+
detachFromParent();
}
void FrameLoader::detachFromParent()
{
+ // Calling stopAllLoaders() can cause the frame to be deallocated, including the frame loader.
Ref<Frame> protect(m_frame);
closeURL();
history().saveScrollPositionAndViewStateToItem(history().currentItem());
detachChildren();
- // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
- // will trigger the unload event handlers of any child frames, and those event
- // handlers might start a new subresource load in this frame.
- stopAllLoaders();
+ if (m_frame.document()->pageCacheState() != Document::InPageCache) {
+ // stopAllLoaders() needs to be called after detachChildren() if the document is not in the page cache,
+ // because detachedChildren() will trigger the unload event handlers of any child frames, and those event
+ // handlers might start a new subresource load in this frame.
+ stopAllLoaders();
+ }
- InspectorInstrumentation::frameDetachedFromParent(&m_frame);
+ InspectorInstrumentation::frameDetachedFromParent(m_frame);
detachViewsAndDocumentLoader();
m_progressTracker = nullptr;
if (Frame* parent = m_frame.tree().parent()) {
- parent->loader().closeAndRemoveChild(&m_frame);
+ parent->loader().closeAndRemoveChild(m_frame);
parent->loader().scheduleCheckCompleted();
} else {
- m_frame.setView(0);
+ m_frame.setView(nullptr);
m_frame.willDetachPage();
m_frame.detachFromPage();
}
@@ -2532,7 +2597,7 @@ void FrameLoader::detachFromParent()
void FrameLoader::detachViewsAndDocumentLoader()
{
m_client.detachedFromParent2();
- setDocumentLoader(0);
+ setDocumentLoader(nullptr);
m_client.detachedFromParent3();
}
@@ -2546,29 +2611,19 @@ void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
// FIXME: Using m_loadType seems wrong for some callers.
// If we are only preparing to load the main resource, that is previous load's load type!
addExtraFieldsToRequest(request, m_loadType, true);
+
+ // Upgrade-Insecure-Requests should only be added to main resource requests
+ addHTTPUpgradeInsecureRequestsIfNeeded(request);
}
-void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource)
+ResourceRequestCachePolicy FrameLoader::defaultRequestCachingPolicy(const ResourceRequest& request, FrameLoadType loadType, bool isMainResource)
{
- // Don't set the cookie policy URL if it's already been set.
- // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>).
- if (request.firstPartyForCookies().isEmpty()) {
- if (mainResource && m_frame.isMainFrame())
- request.setFirstPartyForCookies(request.url());
- else if (Document* document = m_frame.document())
- request.setFirstPartyForCookies(document->firstPartyForCookies());
- }
-
- // The remaining modifications are only necessary for HTTP and HTTPS.
- if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
- return;
-
- applyUserAgent(request);
-
- if (!mainResource) {
+ if (m_overrideCachePolicyForTesting)
+ return m_overrideCachePolicyForTesting.value();
+ if (!isMainResource) {
if (request.isConditional())
- request.setCachePolicy(ReloadIgnoringCacheData);
- else if (documentLoader()->isLoadingInAPISense()) {
+ return ReloadIgnoringCacheData;
+ if (documentLoader()->isLoadingInAPISense()) {
// If we inherit cache policy from a main resource, we use the DocumentLoader's
// original request cache policy for two reasons:
// 1. For POST requests, we mutate the cache policy for the main resource,
@@ -2579,26 +2634,55 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp
ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
// Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails.
// This policy is set on initial request too, but should not be inherited.
- ResourceRequestCachePolicy subresourceCachePolicy = (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
- request.setCachePolicy(subresourceCachePolicy);
- } else
- request.setCachePolicy(UseProtocolCachePolicy);
-
+ return (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
+ }
// FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading.
// It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest().
- } else if (loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin || request.isConditional())
+ } else if (loadType == FrameLoadType::Reload || loadType == FrameLoadType::ReloadFromOrigin || request.isConditional())
+ return ReloadIgnoringCacheData;
+
+ return UseProtocolCachePolicy;
+}
+
+void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool isMainResource)
+{
+ // Don't set the cookie policy URL if it's already been set.
+ // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>).
+ if (request.firstPartyForCookies().isEmpty()) {
+ if (isMainResource && m_frame.isMainFrame())
+ request.setFirstPartyForCookies(request.url());
+ else if (Document* document = m_frame.document())
+ request.setFirstPartyForCookies(document->firstPartyForCookies());
+ }
+
+ Page* page = frame().page();
+ bool hasSpecificCachePolicy = request.cachePolicy() != UseProtocolCachePolicy;
+
+ if (page && page->isResourceCachingDisabled()) {
request.setCachePolicy(ReloadIgnoringCacheData);
+ loadType = FrameLoadType::ReloadFromOrigin;
+ } else if (!hasSpecificCachePolicy)
+ request.setCachePolicy(defaultRequestCachingPolicy(request, loadType, isMainResource));
+
+ // The remaining modifications are only necessary for HTTP and HTTPS.
+ if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
+ return;
- if (request.cachePolicy() == ReloadIgnoringCacheData) {
- if (loadType == FrameLoadTypeReload)
- request.setHTTPHeaderField("Cache-Control", "max-age=0");
- else if (loadType == FrameLoadTypeReloadFromOrigin) {
- request.setHTTPHeaderField("Cache-Control", "no-cache");
- request.setHTTPHeaderField("Pragma", "no-cache");
+ if (!hasSpecificCachePolicy && request.cachePolicy() == ReloadIgnoringCacheData) {
+ if (loadType == FrameLoadType::Reload)
+ request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
+ else if (loadType == FrameLoadType::ReloadFromOrigin) {
+ request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
+ request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
}
}
-
- if (mainResource)
+
+ if (m_overrideResourceLoadPriorityForTesting)
+ request.setPriority(m_overrideResourceLoadPriorityForTesting.value());
+
+ applyUserAgent(request);
+
+ if (isMainResource)
request.setHTTPAccept(defaultAcceptHeader);
// Make sure we send the Origin header.
@@ -2638,16 +2722,25 @@ void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String&
request.setHTTPOrigin(origin);
}
-void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
+void FrameLoader::addHTTPUpgradeInsecureRequestsIfNeeded(ResourceRequest& request)
+{
+ if (request.url().protocolIs("https")) {
+ // FIXME: Identify HSTS cases and avoid adding the header. <https://bugs.webkit.org/show_bug.cgi?id=157885>
+ return;
+ }
+
+ request.setHTTPHeaderField(HTTPHeaderName::UpgradeInsecureRequests, ASCIILiteral("1"));
+}
+
+void FrameLoader::loadPostRequest(const FrameLoadRequest& request, const String& referrer, FrameLoadType loadType, Event* event, FormState* formState)
{
- RefPtr<FormState> formState = prpFormState;
+ String frameName = request.frameName();
+ LockHistory lockHistory = request.lockHistory();
+ AllowNavigationToInvalidURL allowNavigationToInvalidURL = request.allowNavigationToInvalidURL();
+ NewFrameOpenerPolicy openerPolicy = request.newFrameOpenerPolicy();
- // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
- // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case
- // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
- // from scratch as it did all along.
+ const ResourceRequest& inRequest = request.resourceRequest();
const URL& url = inRequest.url();
- RefPtr<FormData> formData = inRequest.httpBody();
const String& contentType = inRequest.httpContentType();
String origin = inRequest.httpOrigin();
@@ -2657,28 +2750,31 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
workingResourceRequest.setHTTPReferrer(referrer);
workingResourceRequest.setHTTPOrigin(origin);
workingResourceRequest.setHTTPMethod("POST");
- workingResourceRequest.setHTTPBody(formData);
+ workingResourceRequest.setHTTPBody(inRequest.httpBody());
workingResourceRequest.setHTTPContentType(contentType);
addExtraFieldsToRequest(workingResourceRequest, loadType, true);
- NavigationAction action(workingResourceRequest, loadType, true, event);
+ if (Document* document = m_frame.document())
+ document->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(workingResourceRequest, ContentSecurityPolicy::InsecureRequestType::Load);
+
+ NavigationAction action(workingResourceRequest, loadType, true, event, request.shouldOpenExternalURLsPolicy(), request.downloadAttribute());
if (!frameName.isEmpty()) {
// The search for a target frame is done earlier in the case of form submission.
if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) {
- targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
+ targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, WTFMove(formState), allowNavigationToInvalidURL);
return;
}
- policyChecker().checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName, [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
- continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue);
+ policyChecker().checkNewWindowPolicy(action, workingResourceRequest, WTFMove(formState), frameName, [this, allowNavigationToInvalidURL, openerPolicy] (const ResourceRequest& request, FormState* formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
+ continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL, openerPolicy);
});
return;
}
// must grab this now, since this load may stop the previous load and clear this flag
bool isRedirect = m_quickRedirectComing;
- loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
+ loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, WTFMove(formState), allowNavigationToInvalidURL);
if (isRedirect) {
m_quickRedirectComing = false;
if (m_provisionalDocumentLoader)
@@ -2686,7 +2782,7 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
}
}
-unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data)
{
ASSERT(m_frame.document());
String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), request.url(), outgoingReferrer());
@@ -2706,15 +2802,37 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
ResourceRequest newRequest(initialRequest);
requestFromDelegate(newRequest, identifier, error);
+#if ENABLE(CONTENT_EXTENSIONS)
+ if (error.isNull()) {
+ if (auto* page = m_frame.page()) {
+ if (m_documentLoader) {
+ auto blockedStatus = page->userContentProvider().processContentExtensionRulesForLoad(newRequest.url(), ResourceType::Raw, *m_documentLoader);
+ applyBlockedStatusToRequest(blockedStatus, newRequest);
+ if (blockedStatus.blockedLoad) {
+ newRequest = { };
+ error = ResourceError(errorDomainWebKitInternal, 0, initialRequest.url(), emptyString());
+ response = { };
+ data = nullptr;
+ }
+ }
+ }
+ }
+#endif
+
+ m_frame.document()->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(newRequest, ContentSecurityPolicy::InsecureRequestType::Load);
+
if (error.isNull()) {
ASSERT(!newRequest.isNull());
-
- if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
- platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data);
- documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
+
+ if (!documentLoader()->applicationCacheHost().maybeLoadSynchronously(newRequest, error, response, data)) {
+ Vector<char> buffer;
+ platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, buffer);
+ data = SharedBuffer::adoptVector(buffer);
+ documentLoader()->applicationCacheHost().maybeLoadFallbackSynchronously(newRequest, error, response, data);
+ ResourceLoadObserver::sharedObserver().logSubresourceLoading(&m_frame, newRequest, response);
}
}
- notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error);
+ notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data ? data->data() : nullptr, data ? data->size() : 0, -1, error);
return identifier;
}
@@ -2765,13 +2883,17 @@ void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequ
if (!shouldContinue)
return;
+ // Calling stopLoading() on the provisional document loader can cause the underlying
+ // frame to be deallocated.
+ Ref<Frame> protectedFrame(m_frame);
+
// If we have a provisional request for a different document, a fragment scroll should cancel it.
if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
m_provisionalDocumentLoader->stopLoading();
- setProvisionalDocumentLoader(0);
+ setProvisionalDocumentLoader(nullptr);
}
- bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;
+ bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadType::RedirectWithLockedBackForwardList;
loadInSameDocument(request.url(), 0, !isRedirect);
}
@@ -2783,10 +2905,10 @@ bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const S
// FIXME: What about load types other than Standard and Reload?
- return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
- && loadType != FrameLoadTypeReload
- && loadType != FrameLoadTypeReloadFromOrigin
- && loadType != FrameLoadTypeSame
+ return (!isFormSubmission || equalLettersIgnoringASCIICase(httpMethod, "get"))
+ && loadType != FrameLoadType::Reload
+ && loadType != FrameLoadType::ReloadFromOrigin
+ && loadType != FrameLoadType::Same
&& !shouldReload(m_frame.document()->url(), url)
// We don't want to just scroll if a link from within a
// frameset is trying to reload the frameset into _top.
@@ -2827,13 +2949,13 @@ bool FrameLoader::shouldClose()
bool shouldClose = false;
{
- NavigationDisablerForBeforeUnload navigationDisabler;
+ NavigationDisabler navigationDisabler;
size_t i;
for (i = 0; i < targetFrames.size(); i++) {
if (!targetFrames[i]->tree().isDescendantOf(&m_frame))
continue;
- if (!targetFrames[i]->loader().handleBeforeUnloadEvent(page->chrome(), this))
+ if (!targetFrames[i]->loader().dispatchBeforeUnloadEvent(page->chrome(), this))
break;
}
@@ -2848,36 +2970,105 @@ bool FrameLoader::shouldClose()
return shouldClose;
}
-bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
+void FrameLoader::dispatchUnloadEvents(UnloadEventPolicy unloadEventPolicy)
+{
+ if (!m_frame.document())
+ return;
+
+ // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent.
+ ForbidPromptsScope forbidPrompts(m_frame.page());
+ IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(m_frame.document());
+
+ if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
+ auto* currentFocusedElement = m_frame.document()->focusedElement();
+ if (is<HTMLInputElement>(currentFocusedElement))
+ downcast<HTMLInputElement>(*currentFocusedElement).endEditing();
+ if (m_pageDismissalEventBeingDispatched == PageDismissalType::None) {
+ if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
+ m_pageDismissalEventBeingDispatched = PageDismissalType::PageHide;
+ m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->pageCacheState() == Document::AboutToEnterPageCache), m_frame.document());
+ }
+
+ // FIXME: update Page Visibility state here.
+ // https://bugs.webkit.org/show_bug.cgi?id=116770
+
+ if (m_frame.document()->pageCacheState() == Document::NotInPageCache) {
+ Ref<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
+ // The DocumentLoader (and thus its LoadTiming) might get destroyed
+ // while dispatching the event, so protect it to prevent writing the end
+ // time into freed memory.
+ RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
+ m_pageDismissalEventBeingDispatched = PageDismissalType::Unload;
+ if (documentLoader && documentLoader->timing().startTime() && !documentLoader->timing().unloadEventStart() && !documentLoader->timing().unloadEventEnd()) {
+ auto& timing = documentLoader->timing();
+ timing.markUnloadEventStart();
+ m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
+ timing.markUnloadEventEnd();
+ } else
+ m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
+ }
+ }
+ m_pageDismissalEventBeingDispatched = PageDismissalType::None;
+ m_wasUnloadEventEmitted = true;
+ }
+
+ // Dispatching the unload event could have made m_frame.document() null.
+ if (!m_frame.document())
+ return;
+
+ if (m_frame.document()->pageCacheState() != Document::NotInPageCache)
+ return;
+
+ // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
+ bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
+ && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
+
+ if (!keepEventListeners)
+ m_frame.document()->removeAllEventListeners();
+}
+
+static bool shouldAskForNavigationConfirmation(Document& document, const BeforeUnloadEvent& event)
+{
+ bool userDidInteractWithPage = document.topDocument().userDidInteractWithPage();
+ // Web pages can request we ask for confirmation before navigating by:
+ // - Cancelling the BeforeUnloadEvent (modern way)
+ // - Setting the returnValue attribute on the BeforeUnloadEvent to a non-empty string.
+ // - Returning a non-empty string from the event handler, which is then set as returnValue
+ // attribute on the BeforeUnloadEvent.
+ return userDidInteractWithPage && (event.defaultPrevented() || !event.returnValue().isEmpty());
+}
+
+bool FrameLoader::dispatchBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
{
DOMWindow* domWindow = m_frame.document()->domWindow();
if (!domWindow)
return true;
RefPtr<Document> document = m_frame.document();
- if (!document->body())
+ if (!document->bodyOrFrameset())
return true;
- RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
- m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal;
+ Ref<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
+ m_pageDismissalEventBeingDispatched = PageDismissalType::BeforeUnload;
- // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent.
- Page* page = m_frame.page();
- page->incrementFrameHandlingBeforeUnloadEventCount();
- domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
- page->decrementFrameHandlingBeforeUnloadEventCount();
+ {
+ ForbidPromptsScope forbidPrompts(m_frame.page());
+ IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(m_frame.document());
+ domWindow->dispatchEvent(beforeUnloadEvent, domWindow->document());
+ }
- m_pageDismissalEventBeingDispatched = NoDismissal;
+ m_pageDismissalEventBeingDispatched = PageDismissalType::None;
if (!beforeUnloadEvent->defaultPrevented())
document->defaultEventHandler(beforeUnloadEvent.get());
- if (beforeUnloadEvent->returnValue().isNull())
+
+ if (!shouldAskForNavigationConfirmation(*document, beforeUnloadEvent))
return true;
// If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt,
// this frame is not allowed to cause another one to be shown.
if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) {
- document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation.");
+ document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation."));
return true;
}
@@ -2889,8 +3080,8 @@ bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoad
Document* parentDocument = parentFrame->document();
if (!parentDocument)
return true;
- if (!m_frame.document() || !m_frame.document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) {
- document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match.");
+ if (!m_frame.document() || !m_frame.document()->securityOrigin().canAccess(parentDocument->securityOrigin())) {
+ document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match."));
return true;
}
@@ -2908,10 +3099,10 @@ bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoad
frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel = true;
String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->returnValue());
- return chrome.runBeforeUnloadConfirmPanel(text, &m_frame);
+ return chrome.runBeforeUnloadConfirmPanel(text, m_frame);
}
-void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
+void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, FormState* formState, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
{
// If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
// nil policyDataSource because loading the alternate page will have passed
@@ -2920,19 +3111,23 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
bool isTargetItem = history().provisionalItem() ? history().provisionalItem()->isTargetItem() : false;
- // Two reasons we can't continue:
+ bool urlIsDisallowed = allowNavigationToInvalidURL == AllowNavigationToInvalidURL::No && !request.url().isValid();
+
+ // Three reasons we can't continue:
// 1) Navigation policy delegate said we can't so request is nil. A primary case of this
// is the user responding Cancel to the form repost nag sheet.
// 2) User responded Cancel to an alert popped up by the before unload event handler.
- bool canContinue = shouldContinue && shouldClose();
+ // 3) The request's URL is invalid and navigation to invalid URLs is disallowed.
+ bool canContinue = shouldContinue && shouldClose() && !urlIsDisallowed;
if (!canContinue) {
// If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
// need to report that the client redirect was cancelled.
+ // FIXME: The client should be told about ignored non-quick redirects, too.
if (m_quickRedirectComing)
clientRedirectCancelledOrFinished(false);
- setPolicyDocumentLoader(0);
+ setPolicyDocumentLoader(nullptr);
// If the navigation request came from the back/forward menu, and we punt on it, we have the
// problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
@@ -2957,22 +3152,20 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
if (!m_frame.page())
return;
-#if ENABLE(INSPECTOR)
- if (Page* page = m_frame.page()) {
- if (m_frame.isMainFrame())
- page->inspectorController().resume();
- }
-#endif
-
setProvisionalDocumentLoader(m_policyDocumentLoader.get());
m_loadType = type;
setState(FrameStateProvisional);
- setPolicyDocumentLoader(0);
+ setPolicyDocumentLoader(nullptr);
- if (isBackForwardLoadType(type) && history().provisionalItem()->isInPageCache()) {
- loadProvisionalItemFromCachedPage();
- return;
+ if (isBackForwardLoadType(type)) {
+ auto& diagnosticLoggingClient = m_frame.page()->diagnosticLoggingClient();
+ if (history().provisionalItem()->isInPageCache()) {
+ diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::retrievalKey(), DiagnosticLoggingResultPass, ShouldSample::Yes);
+ loadProvisionalItemFromCachedPage();
+ return;
+ }
+ diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::retrievalKey(), DiagnosticLoggingResultFail, ShouldSample::Yes);
}
if (!formState) {
@@ -2980,13 +3173,13 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
return;
}
- m_client.dispatchWillSubmitForm(formState, [this](PolicyAction action) {
+ m_client.dispatchWillSubmitForm(*formState, [this] (PolicyAction action) {
policyChecker().continueLoadAfterWillSubmitForm(action);
});
}
void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
- PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
+ FormState* formState, const String& frameName, const NavigationAction& action, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy openerPolicy)
{
if (!shouldContinue)
return;
@@ -2996,16 +3189,20 @@ void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques
if (!mainFrame)
return;
+ mainFrame->loader().forceSandboxFlags(frame->loader().effectiveSandboxFlags());
+
if (frameName != "_blank")
mainFrame->tree().setName(frameName);
mainFrame->page()->setOpenedByDOM();
mainFrame->loader().m_client.dispatchShow();
- if (!m_suppressOpenerInNewFrame) {
- mainFrame->loader().setOpener(&frame.get());
+ if (openerPolicy == NewFrameOpenerPolicy::Allow) {
+ mainFrame->loader().setOpener(frame.ptr());
mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy());
}
- mainFrame->loader().loadWithNavigationAction(request, NavigationAction(request), false, FrameLoadTypeStandard, formState);
+
+ NavigationAction newAction(request, action.shouldOpenExternalURLsPolicy());
+ mainFrame->loader().loadWithNavigationAction(request, newAction, LockHistory::No, FrameLoadType::Standard, formState, allowNavigationToInvalidURL);
}
void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
@@ -3031,8 +3228,6 @@ void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& i
void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest)
{
- newRequest = ResourceRequest(resource->url());
-
Page* page = m_frame.page();
if (!page)
return;
@@ -3045,14 +3240,14 @@ void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, Resour
return;
if (!page->areMemoryCacheClientCallsEnabled()) {
- InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
+ InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource);
m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest());
m_documentLoader->didTellClientAboutLoad(resource->url());
return;
}
if (m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) {
- InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
+ InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource);
m_documentLoader->didTellClientAboutLoad(resource->url());
return;
}
@@ -3060,7 +3255,7 @@ void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, Resour
unsigned long identifier;
ResourceError error;
requestFromDelegate(newRequest, identifier, error);
- InspectorInstrumentation::markResourceAsCached(page, identifier);
+ InspectorInstrumentation::markResourceAsCached(*page, identifier);
notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error);
}
@@ -3073,8 +3268,6 @@ void FrameLoader::applyUserAgent(ResourceRequest& request)
bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const URL& url, unsigned long requestIdentifier)
{
- FeatureObserver::observe(m_frame.document(), FeatureObserver::XFrameOptions);
-
Frame& topFrame = m_frame.tree().top();
if (&m_frame == &topFrame)
return false;
@@ -3083,15 +3276,12 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con
switch (disposition) {
case XFrameOptionsSameOrigin: {
- FeatureObserver::observe(m_frame.document(), FeatureObserver::XFrameOptionsSameOrigin);
RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
if (!origin->isSameSchemeHostPort(topFrame.document()->securityOrigin()))
return true;
for (Frame* frame = m_frame.tree().parent(); frame; frame = frame->tree().parent()) {
- if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin())) {
- FeatureObserver::observe(m_frame.document(), FeatureObserver::XFrameOptionsSameOriginWithBadAncestorChain);
+ if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin()))
break;
- }
}
return false;
}
@@ -3100,15 +3290,16 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con
case XFrameOptionsAllowAll:
return false;
case XFrameOptionsConflict:
- m_frame.document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier);
+ m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier);
return true;
case XFrameOptionsInvalid:
- m_frame.document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier);
+ m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier);
return false;
- default:
- ASSERT_NOT_REACHED();
+ case XFrameOptionsNone:
return false;
}
+ ASSERT_NOT_REACHED();
+ return false;
}
void FrameLoader::loadProvisionalItemFromCachedPage()
@@ -3121,9 +3312,9 @@ void FrameLoader::loadProvisionalItemFromCachedPage()
m_loadingFromCachedPage = true;
// Should have timing data from previous time(s) the page was shown.
- ASSERT(provisionalLoader->timing()->navigationStart());
+ ASSERT(provisionalLoader->timing().startTime());
provisionalLoader->resetTiming();
- provisionalLoader->timing()->markNavigationStart();
+ provisionalLoader->timing().markStartTime();
provisionalLoader->setCommitted(true);
commitProvisionalLoad();
@@ -3138,52 +3329,35 @@ bool FrameLoader::shouldTreatURLAsSameAsCurrent(const URL& url) const
bool FrameLoader::shouldTreatURLAsSrcdocDocument(const URL& url) const
{
- if (!equalIgnoringCase(url.string(), "about:srcdoc"))
+ if (!equalLettersIgnoringASCIICase(url.string(), "about:srcdoc"))
return false;
HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement();
if (!ownerElement)
return false;
if (!ownerElement->hasTagName(iframeTag))
return false;
- return ownerElement->fastHasAttribute(srcdocAttr);
+ return ownerElement->hasAttributeWithoutSynchronization(srcdocAttr);
}
Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
{
Frame* frame = m_frame.tree().find(name);
- // From http://www.whatwg.org/specs/web-apps/current-work/#seamlessLinks:
- //
- // If the source browsing context is the same as the browsing context
- // being navigated, and this browsing context has its seamless browsing
- // context flag set, and the browsing context being navigated was not
- // chosen using an explicit self-navigation override, then find the
- // nearest ancestor browsing context that does not have its seamless
- // browsing context flag set, and continue these steps as if that
- // browsing context was the one that was going to be navigated instead.
- if (frame == &m_frame && name != "_self" && m_frame.document()->shouldDisplaySeamlesslyWithParent()) {
- for (Frame* ancestor = &m_frame; ancestor; ancestor = ancestor->tree().parent()) {
- if (!ancestor->document()->shouldDisplaySeamlesslyWithParent()) {
- frame = ancestor;
- break;
- }
- }
- ASSERT(frame != &m_frame);
- }
-
// FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document.
if (!activeDocument)
activeDocument = m_frame.document();
if (!activeDocument->canNavigate(frame))
- return 0;
+ return nullptr;
return frame;
}
-void FrameLoader::loadSameDocumentItem(HistoryItem* item)
+void FrameLoader::loadSameDocumentItem(HistoryItem& item)
{
- ASSERT(item->documentSequenceNumber() == history().currentItem()->documentSequenceNumber());
+ ASSERT(item.documentSequenceNumber() == history().currentItem()->documentSequenceNumber());
+
+ Ref<Frame> protect(m_frame);
// Save user view state to the current history item here since we don't do a normal load.
// FIXME: Does form state need to be saved here too?
@@ -3191,10 +3365,10 @@ void FrameLoader::loadSameDocumentItem(HistoryItem* item)
if (FrameView* view = m_frame.view())
view->setWasScrolledByUser(false);
- history().setCurrentItem(item);
+ history().setCurrentItem(&item);
// loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
- loadInSameDocument(item->url(), item->stateObject(), false);
+ loadInSameDocument(item.url(), item.stateObject(), false);
// Restore user view state from the current history item here since we don't do a normal load.
history().restoreScrollPositionAndViewState();
@@ -3203,38 +3377,47 @@ void FrameLoader::loadSameDocumentItem(HistoryItem* item)
// FIXME: This function should really be split into a couple pieces, some of
// which should be methods of HistoryController and some of which should be
// methods of FrameLoader.
-void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy)
+void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy)
{
// Remember this item so we can traverse any child items as child frames load
- history().setProvisionalItem(item);
+ history().setProvisionalItem(&item);
- if (CachedPage* cachedPage = pageCache()->get(item)) {
- loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
+ if (CachedPage* cachedPage = PageCache::singleton().get(item, m_frame.page())) {
+ auto documentLoader = cachedPage->documentLoader();
+ m_client.updateCachedDocumentLoader(*documentLoader);
+ documentLoader->setTriggeringAction(NavigationAction(documentLoader->request(), loadType, false));
+ documentLoader->setLastCheckedRequest(ResourceRequest());
+ loadWithDocumentLoader(documentLoader, loadType, 0, AllowNavigationToInvalidURL::Yes);
return;
}
- URL itemURL = item->url();
- URL itemOriginalURL = item->originalURL();
+ URL itemURL = item.url();
+ URL itemOriginalURL = item.originalURL();
URL currentURL;
if (documentLoader())
currentURL = documentLoader()->url();
- RefPtr<FormData> formData = item->formData();
+ RefPtr<FormData> formData = item.formData();
ResourceRequest request(itemURL);
- if (!item->referrer().isNull())
- request.setHTTPReferrer(item->referrer());
-
+ if (!item.referrer().isNull())
+ request.setHTTPReferrer(item.referrer());
+
+ ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicyToApply(m_frame, item.shouldOpenExternalURLsPolicy());
+ bool isFormSubmission = false;
+ Event* event = nullptr;
+
// If this was a repost that failed the page cache, we might try to repost the form.
NavigationAction action;
if (formData) {
formData->generateFiles(m_frame.document());
request.setHTTPMethod("POST");
- request.setHTTPBody(formData);
- request.setHTTPContentType(item->formContentType());
- RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
+ request.setHTTPBody(WTFMove(formData));
+ request.setHTTPContentType(item.formContentType());
+ RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item.referrer());
addHTTPOriginIfNeeded(request, securityOrigin->toString());
+ addHTTPUpgradeInsecureRequestsIfNeeded(request);
// Make sure to add extra fields to the request after the Origin header is added for the FormData case.
// See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
@@ -3250,49 +3433,54 @@ void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loa
if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) {
request.setCachePolicy(ReturnCacheDataDontLoad);
- action = NavigationAction(request, loadType, false);
+ action = NavigationAction(request, loadType, isFormSubmission, event, shouldOpenExternalURLsPolicy);
} else {
request.setCachePolicy(ReturnCacheDataElseLoad);
- action = NavigationAction(request, NavigationTypeFormResubmitted);
+ action = NavigationAction(request, NavigationType::FormResubmitted, event, shouldOpenExternalURLsPolicy);
}
} else {
switch (loadType) {
- case FrameLoadTypeReload:
- case FrameLoadTypeReloadFromOrigin:
- request.setCachePolicy(ReloadIgnoringCacheData);
- break;
- case FrameLoadTypeBack:
- case FrameLoadTypeForward:
- case FrameLoadTypeIndexedBackForward:
- // If the first load within a frame is a navigation within a back/forward list that was attached
- // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
- if (m_stateMachine.committedFirstRealDocumentLoad())
- request.setCachePolicy(ReturnCacheDataElseLoad);
- break;
- case FrameLoadTypeStandard:
- case FrameLoadTypeRedirectWithLockedBackForwardList:
- break;
- case FrameLoadTypeSame:
- default:
- ASSERT_NOT_REACHED();
+ case FrameLoadType::Reload:
+ case FrameLoadType::ReloadFromOrigin:
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ break;
+ case FrameLoadType::Back:
+ case FrameLoadType::Forward:
+ case FrameLoadType::IndexedBackForward: {
+#if PLATFORM(COCOA)
+ bool allowStaleData = true;
+#else
+ bool allowStaleData = !item.wasRestoredFromSession();
+#endif
+ if (allowStaleData)
+ request.setCachePolicy(ReturnCacheDataElseLoad);
+ item.setWasRestoredFromSession(false);
+ break;
+ }
+ case FrameLoadType::Standard:
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ break;
+ case FrameLoadType::Same:
+ default:
+ ASSERT_NOT_REACHED();
}
addExtraFieldsToRequest(request, loadType, true);
ResourceRequest requestForOriginalURL(request);
requestForOriginalURL.setURL(itemOriginalURL);
- action = NavigationAction(requestForOriginalURL, loadType, false);
+ action = NavigationAction(requestForOriginalURL, loadType, isFormSubmission, event, shouldOpenExternalURLsPolicy);
}
- loadWithNavigationAction(request, action, false, loadType, 0);
+ loadWithNavigationAction(request, action, LockHistory::No, loadType, 0, AllowNavigationToInvalidURL::Yes);
}
// Loads content into this frame, as specified by history item
-void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
+void FrameLoader::loadItem(HistoryItem& item, FrameLoadType loadType)
{
- m_requestedHistoryItem = item;
+ m_requestedHistoryItem = &item;
HistoryItem* currentItem = history().currentItem();
- bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem);
+ bool sameDocumentNavigation = currentItem && item.shouldDoSameDocumentNavigationTo(*currentItem);
if (sameDocumentNavigation)
loadSameDocumentItem(item);
@@ -3304,13 +3492,12 @@ void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad()
{
ASSERT(m_state == FrameStateProvisional);
ASSERT(!m_loadingFromCachedPage);
- // We only use cache-only loads to avoid resubmitting forms.
- ASSERT(isBackForwardLoadType(m_loadType));
+ ASSERT(history().provisionalItem());
ASSERT(history().provisionalItem()->formData());
ASSERT(history().provisionalItem() == m_requestedHistoryItem.get());
FrameLoadType loadType = m_loadType;
- HistoryItem* item = history().provisionalItem();
+ HistoryItem& item = *history().provisionalItem();
stopAllLoaders(ShouldNotClearProvisionalItem);
loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem);
@@ -3319,10 +3506,31 @@ void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad()
ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
{
ResourceError error = m_client.cancelledError(request);
- error.setIsCancellation(true);
+ error.setType(ResourceError::Type::Cancellation);
+ return error;
+}
+
+ResourceError FrameLoader::blockedByContentBlockerError(const ResourceRequest& request) const
+{
+ return m_client.blockedByContentBlockerError(request);
+}
+
+ResourceError FrameLoader::blockedError(const ResourceRequest& request) const
+{
+ ResourceError error = m_client.blockedError(request);
+ error.setType(ResourceError::Type::Cancellation);
return error;
}
+#if ENABLE(CONTENT_FILTERING)
+ResourceError FrameLoader::blockedByContentFilterError(const ResourceRequest& request) const
+{
+ ResourceError error = m_client.blockedByContentFilterError(request);
+ error.setType(ResourceError::Type::General);
+ return error;
+}
+#endif
+
#if PLATFORM(IOS)
RetainPtr<CFDictionaryRef> FrameLoader::connectionProperties(ResourceLoader* loader)
{
@@ -3332,7 +3540,7 @@ RetainPtr<CFDictionaryRef> FrameLoader::connectionProperties(ResourceLoader* loa
String FrameLoader::referrer() const
{
- return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
+ return m_documentLoader ? m_documentLoader->request().httpReferrer() : emptyString();
}
void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
@@ -3342,8 +3550,8 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
Vector<Ref<DOMWrapperWorld>> worlds;
ScriptController::getAllWorlds(worlds);
- for (size_t i = 0; i < worlds.size(); ++i)
- dispatchDidClearWindowObjectInWorld(worlds[i].get());
+ for (auto& world : worlds)
+ dispatchDidClearWindowObjectInWorld(world);
}
void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world)
@@ -3353,20 +3561,18 @@ void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world)
m_client.dispatchDidClearWindowObjectInWorld(world);
-#if ENABLE(INSPECTOR)
if (Page* page = m_frame.page())
- page->inspectorController().didClearWindowObjectInWorld(&m_frame, world);
-#endif
+ page->inspectorController().didClearWindowObjectInWorld(m_frame, world);
- InspectorInstrumentation::didClearWindowObjectInWorld(&m_frame, world);
+ InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world);
}
void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds()
{
Vector<Ref<DOMWrapperWorld>> worlds;
ScriptController::getAllWorlds(worlds);
- for (size_t i = 0; i < worlds.size(); ++i)
- m_client.dispatchGlobalObjectAvailable(worlds[i].get());
+ for (auto& world : worlds)
+ m_client.dispatchGlobalObjectAvailable(world);
}
SandboxFlags FrameLoader::effectiveSandboxFlags() const
@@ -3398,31 +3604,24 @@ void FrameLoader::didChangeTitle(DocumentLoader* loader)
#endif
}
-void FrameLoader::didChangeIcons(IconType type)
-{
- m_client.dispatchDidChangeIcons(type);
-}
-
-void FrameLoader::dispatchDidCommitLoad()
+void FrameLoader::dispatchDidCommitLoad(std::optional<HasInsecureContent> initialHasInsecureContent)
{
if (m_stateMachine.creatingInitialEmptyDocument())
return;
- m_client.dispatchDidCommitLoad();
+ m_client.dispatchDidCommitLoad(initialHasInsecureContent);
if (m_frame.isMainFrame()) {
m_frame.page()->resetSeenPlugins();
m_frame.page()->resetSeenMediaEngines();
}
- InspectorInstrumentation::didCommitLoad(&m_frame, m_documentLoader.get());
+ InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
- if (m_frame.isMainFrame()) {
- m_frame.page()->featureObserver()->didCommitLoad();
#if ENABLE(REMOTE_INSPECTOR)
+ if (m_frame.isMainFrame())
m_frame.page()->remoteInspectorInformationDidChange();
#endif
- }
}
void FrameLoader::tellClientAboutPastMemoryCacheLoads()
@@ -3436,9 +3635,8 @@ void FrameLoader::tellClientAboutPastMemoryCacheLoads()
Vector<ResourceRequest> pastLoads;
m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
- size_t size = pastLoads.size();
- for (size_t i = 0; i < size; ++i) {
- CachedResource* resource = memoryCache()->resourceForRequest(pastLoads[i]);
+ for (auto& pastLoad : pastLoads) {
+ CachedResource* resource = MemoryCache::singleton().resourceForRequest(pastLoad, m_frame.page()->sessionID());
// FIXME: These loads, loaded from cache, but now gone from the cache by the time
// Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
@@ -3459,12 +3657,8 @@ NetworkingContext* FrameLoader::networkingContext() const
void FrameLoader::loadProgressingStatusChanged()
{
- FrameView* view = m_frame.mainFrame().view();
- if (!view)
- return;
-
- view->updateLayerFlushThrottlingInAllFrames();
- view->adjustTiledBackingCoverage();
+ if (auto* view = m_frame.mainFrame().view())
+ view->loadProgressingStatusChanged();
}
void FrameLoader::forcePageTransitionIfNeeded()
@@ -3472,22 +3666,40 @@ void FrameLoader::forcePageTransitionIfNeeded()
m_client.forcePageTransitionIfNeeded();
}
+void FrameLoader::clearTestingOverrides()
+{
+ m_overrideCachePolicyForTesting = std::nullopt;
+ m_overrideResourceLoadPriorityForTesting = std::nullopt;
+ m_isStrictRawResourceValidationPolicyDisabledForTesting = false;
+}
+
+void FrameLoader::applyShouldOpenExternalURLsPolicyToNewDocumentLoader(DocumentLoader& documentLoader, ShouldOpenExternalURLsPolicy propagatedPolicy)
+{
+ documentLoader.setShouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicyToApply(m_frame, propagatedPolicy));
+}
+
+bool FrameLoader::isAlwaysOnLoggingAllowed() const
+{
+ return frame().isAlwaysOnLoggingAllowed();
+}
+
bool FrameLoaderClient::hasHTMLView() const
{
return true;
}
-PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
+RefPtr<Frame> createWindow(Frame& openerFrame, Frame& lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
{
ASSERT(!features.dialog || request.frameName().isEmpty());
+ created = false;
+
if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
- if (Frame* frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) {
+ if (RefPtr<Frame> frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) {
if (request.frameName() != "_self") {
if (Page* page = frame->page())
page->chrome().focus();
}
- created = false;
return frame;
}
}
@@ -3495,74 +3707,98 @@ PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const Fra
// Sandboxed frames cannot open new auxiliary browsing contexts.
if (isDocumentSandboxed(openerFrame, SandboxPopups)) {
// FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
- openerFrame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.");
- return 0;
+ openerFrame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.");
+ return nullptr;
}
// FIXME: Setting the referrer should be the caller's responsibility.
FrameLoadRequest requestWithReferrer = request;
- String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader().outgoingReferrer());
+ String referrer = SecurityPolicy::generateReferrerHeader(openerFrame.document()->referrerPolicy(), request.resourceRequest().url(), openerFrame.loader().outgoingReferrer());
if (!referrer.isEmpty())
requestWithReferrer.resourceRequest().setHTTPReferrer(referrer);
- FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader().outgoingOrigin());
+ FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame.loader().outgoingOrigin());
+ FrameLoader::addHTTPUpgradeInsecureRequestsIfNeeded(requestWithReferrer.resourceRequest());
- Page* oldPage = openerFrame->page();
+ Page* oldPage = openerFrame.page();
if (!oldPage)
- return 0;
+ return nullptr;
- NavigationAction action(requestWithReferrer.resourceRequest());
- Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, action);
+ ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicyToApply(openerFrame, request.shouldOpenExternalURLsPolicy());
+ Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest(), shouldOpenExternalURLsPolicy));
if (!page)
- return 0;
+ return nullptr;
+
+ RefPtr<Frame> frame = &page->mainFrame();
- page->mainFrame().loader().forceSandboxFlags(openerFrame->document()->sandboxFlags());
+ frame->loader().forceSandboxFlags(openerFrame.document()->sandboxFlags());
if (request.frameName() != "_blank")
- page->mainFrame().tree().setName(request.frameName());
+ frame->tree().setName(request.frameName());
page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
+
+ if (!frame->page())
+ return nullptr;
page->chrome().setStatusbarVisible(features.statusBarVisible);
+
+ if (!frame->page())
+ return nullptr;
page->chrome().setScrollbarsVisible(features.scrollbarsVisible);
+
+ if (!frame->page())
+ return nullptr;
page->chrome().setMenubarVisible(features.menuBarVisible);
+
+ if (!frame->page())
+ return nullptr;
page->chrome().setResizable(features.resizable);
// 'x' and 'y' specify the location of the window, while 'width' and 'height'
// specify the size of the viewport. We can only resize the window, so adjust
// for the difference between the window size and the viewport size.
-// FIXME: We should reconcile the initialization of viewport arguments between iOS and OpenSource.
+ // FIXME: We should reconcile the initialization of viewport arguments between iOS and non-IOS.
#if !PLATFORM(IOS)
FloatSize viewportSize = page->chrome().pageRect().size();
FloatRect windowRect = page->chrome().windowRect();
- if (features.xSet)
- windowRect.setX(features.x);
- if (features.ySet)
- windowRect.setY(features.y);
+ if (features.x)
+ windowRect.setX(*features.x);
+ if (features.y)
+ windowRect.setY(*features.y);
// Zero width and height mean using default size, not minumum one.
- if (features.widthSet && features.width)
- windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width()));
- if (features.heightSet && features.height)
- windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height()));
+ if (features.width && *features.width)
+ windowRect.setWidth(*features.width + (windowRect.width() - viewportSize.width()));
+ if (features.height && *features.height)
+ windowRect.setHeight(*features.height + (windowRect.height() - viewportSize.height()));
// Ensure non-NaN values, minimum size as well as being within valid screen area.
- FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect);
+ FloatRect newWindowRect = DOMWindow::adjustWindowRect(*page, windowRect);
+ if (!frame->page())
+ return nullptr;
page->chrome().setWindowRect(newWindowRect);
#else
// On iOS, width and height refer to the viewport dimensions.
ViewportArguments arguments;
// Zero width and height mean using default size, not minimum one.
- if (features.widthSet && features.width)
- arguments.width = features.width;
- if (features.heightSet && features.height)
- arguments.height = features.height;
- page->mainFrame().setViewportArguments(arguments);
+ if (features.width && *features.width)
+ arguments.width = *features.width;
+ if (features.height && *features.height)
+ arguments.height = *features.height;
+ frame->setViewportArguments(arguments);
#endif
+ if (!frame->page())
+ return nullptr;
page->chrome().show();
created = true;
- return &page->mainFrame();
+ return frame;
+}
+
+bool FrameLoader::shouldSuppressKeyboardInput() const
+{
+ return m_frame.settings().shouldSuppressKeyboardInputDuringProvisionalNavigation() && m_state == FrameStateProvisional;
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/FrameLoader.h b/Source/WebCore/loader/FrameLoader.h
index 4244bf30a..f956e1687 100644
--- a/Source/WebCore/loader/FrameLoader.h
+++ b/Source/WebCore/loader/FrameLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) Research In Motion Limited 2009. All rights reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
@@ -13,7 +13,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,25 +29,27 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FrameLoader_h
-#define FrameLoader_h
+#pragma once
#include "CachePolicy.h"
#include "FrameLoaderStateMachine.h"
#include "FrameLoaderTypes.h"
-#include "IconURL.h"
#include "LayoutMilestones.h"
#include "MixedContentChecker.h"
#include "ResourceHandleTypes.h"
#include "ResourceLoadNotifier.h"
+#include "ResourceLoaderOptions.h"
+#include "ResourceRequestBase.h"
#include "SecurityContext.h"
#include "Timer.h"
#include <wtf/Forward.h>
#include <wtf/HashSet.h>
+#include <wtf/Optional.h>
namespace WebCore {
class Archive;
+class CachedFrame;
class CachedFrameBase;
class CachedPage;
class CachedResource;
@@ -66,21 +68,19 @@ class IconController;
class NavigationAction;
class NetworkingContext;
class Page;
-class PageActivityAssertionToken;
class PolicyChecker;
class ResourceError;
class ResourceRequest;
class ResourceResponse;
-class SecurityOrigin;
class SerializedScriptValue;
-class StringWithDirection;
+class SharedBuffer;
class SubframeLoader;
class SubstituteData;
struct FrameLoadRequest;
struct WindowFeatures;
-bool isBackForwardLoadType(FrameLoadType);
+WEBCORE_EXPORT bool isBackForwardLoadType(FrameLoadType);
class FrameLoader {
WTF_MAKE_NONCOPYABLE(FrameLoader);
@@ -88,7 +88,7 @@ public:
FrameLoader(Frame&, FrameLoaderClient&);
~FrameLoader();
- void init();
+ WEBCORE_EXPORT void init();
#if PLATFORM(IOS)
void initForSynthesizedDocument(const URL&);
#endif
@@ -102,40 +102,38 @@ public:
IconController& icon() const { return *m_icon; }
MixedContentChecker& mixedContentChecker() const { return m_mixedContentChecker; }
- void prepareForHistoryNavigation();
void setupForReplace();
// FIXME: These are all functions which start loads. We have too many.
- void loadURLIntoChildFrame(const URL&, const String& referer, Frame*);
- void loadFrameRequest(const FrameLoadRequest&, bool lockHistory, bool lockBackForwardList, // Called by submitForm, calls loadPostRequest and loadURL.
- PassRefPtr<Event>, PassRefPtr<FormState>, ShouldSendReferrer);
+ WEBCORE_EXPORT void loadURLIntoChildFrame(const URL&, const String& referer, Frame*);
+ WEBCORE_EXPORT void loadFrameRequest(const FrameLoadRequest&, Event*, FormState*); // Called by submitForm, calls loadPostRequest and loadURL.
- void load(const FrameLoadRequest&);
+ WEBCORE_EXPORT void load(const FrameLoadRequest&);
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- void loadArchive(PassRefPtr<Archive>);
+ WEBCORE_EXPORT void loadArchive(Ref<Archive>&&);
#endif
- unsigned long loadResourceSynchronously(const ResourceRequest&, StoredCredentials, ClientCredentialPolicy, ResourceError&, ResourceResponse&, Vector<char>& data);
+ unsigned long loadResourceSynchronously(const ResourceRequest&, StoredCredentials, ClientCredentialPolicy, ResourceError&, ResourceResponse&, RefPtr<SharedBuffer>& data);
- void changeLocation(SecurityOrigin*, const URL&, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool refresh = false);
- void urlSelected(const URL&, const String& target, PassRefPtr<Event>, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer);
- void submitForm(PassRefPtr<FormSubmission>);
+ void changeLocation(const FrameLoadRequest&);
+ WEBCORE_EXPORT void urlSelected(const URL&, const String& target, Event*, LockHistory, LockBackForwardList, ShouldSendReferrer, ShouldOpenExternalURLsPolicy, std::optional<NewFrameOpenerPolicy> = std::nullopt, const AtomicString& downloadAttribute = nullAtom);
+ void submitForm(Ref<FormSubmission>&&);
- void reload(bool endToEndReload = false);
- void reloadWithOverrideEncoding(const String& overrideEncoding);
- void reloadWithOverrideURL(const URL& overrideUrl, bool endToEndReload = false);
+ WEBCORE_EXPORT void reload(bool endToEndReload = false, bool contentBlockersEnabled = true);
+ WEBCORE_EXPORT void reloadWithOverrideEncoding(const String& overrideEncoding);
void open(CachedFrameBase&);
- void loadItem(HistoryItem*, FrameLoadType);
+ void loadItem(HistoryItem&, FrameLoadType);
HistoryItem* requestedHistoryItem() const { return m_requestedHistoryItem.get(); }
void retryAfterFailedCacheOnlyMainResourceLoad();
static void reportLocalLoadFailed(Frame*, const String& url);
+ static void reportBlockedPortFailed(Frame*, const String& url);
// FIXME: These are all functions which stop loads. We have too many.
- void stopAllLoaders(ClearProvisionalItemPolicy = ShouldClearProvisionalItem);
- void stopForUserCancel(bool deferCheckLoadComplete = false);
+ WEBCORE_EXPORT void stopAllLoaders(ClearProvisionalItemPolicy = ShouldClearProvisionalItem);
+ WEBCORE_EXPORT void stopForUserCancel(bool deferCheckLoadComplete = false);
void stop();
void stopLoading(UnloadEventPolicy);
bool closeURL();
@@ -144,14 +142,14 @@ public:
void clear(Document* newDocument, bool clearWindowProperties = true, bool clearScriptObjects = true, bool clearFrameView = true);
bool isLoading() const;
- bool frameHasLoaded() const;
+ WEBCORE_EXPORT bool frameHasLoaded() const;
- int numPendingOrLoadingRequests(bool recurse) const;
+ WEBCORE_EXPORT int numPendingOrLoadingRequests(bool recurse) const;
String referrer() const;
- String outgoingReferrer() const;
+ WEBCORE_EXPORT String outgoingReferrer() const;
String outgoingOrigin() const;
- DocumentLoader* activeDocumentLoader() const;
+ WEBCORE_EXPORT DocumentLoader* activeDocumentLoader() const;
DocumentLoader* documentLoader() const { return m_documentLoader.get(); }
DocumentLoader* policyDocumentLoader() const { return m_policyDocumentLoader.get(); }
DocumentLoader* provisionalDocumentLoader() const { return m_provisionalDocumentLoader.get(); }
@@ -168,7 +166,12 @@ public:
void handleFallbackContent();
- ResourceError cancelledError(const ResourceRequest&) const;
+ WEBCORE_EXPORT ResourceError cancelledError(const ResourceRequest&) const;
+ WEBCORE_EXPORT ResourceError blockedByContentBlockerError(const ResourceRequest&) const;
+ ResourceError blockedError(const ResourceRequest&) const;
+#if ENABLE(CONTENT_FILTERING)
+ ResourceError blockedByContentFilterError(const ResourceRequest&) const;
+#endif
bool isHostedByObjectElement() const;
@@ -177,28 +180,28 @@ public:
bool subframeIsLoading() const;
void willChangeTitle(DocumentLoader*);
void didChangeTitle(DocumentLoader*);
- void didChangeIcons(IconType);
bool shouldTreatURLAsSrcdocDocument(const URL&) const;
- FrameLoadType loadType() const;
+ WEBCORE_EXPORT FrameLoadType loadType() const;
CachePolicy subresourceCachePolicy() const;
- void didLayout(LayoutMilestones);
+ void didReachLayoutMilestone(LayoutMilestones);
void didFirstLayout();
void loadedResourceFromMemoryCache(CachedResource*, ResourceRequest& newRequest);
void tellClientAboutPastMemoryCacheLoads();
void checkLoadComplete();
- void detachFromParent();
+ WEBCORE_EXPORT void detachFromParent();
void detachViewsAndDocumentLoader();
void addExtraFieldsToSubresourceRequest(ResourceRequest&);
void addExtraFieldsToMainResourceRequest(ResourceRequest&);
static void addHTTPOriginIfNeeded(ResourceRequest&, const String& origin);
+ static void addHTTPUpgradeInsecureRequestsIfNeeded(ResourceRequest&);
FrameLoaderClient& client() const { return m_client; }
@@ -211,7 +214,7 @@ public:
void receivedFirstData();
- void handledOnloadEvents();
+ void dispatchOnloadEvents();
String userAgent(const URL&) const;
void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&);
@@ -222,10 +225,10 @@ public:
void forceSandboxFlags(SandboxFlags flags) { m_forcedSandboxFlags |= flags; }
SandboxFlags effectiveSandboxFlags() const;
- bool checkIfFormActionAllowedByCSP(const URL&) const;
+ bool checkIfFormActionAllowedByCSP(const URL&, bool didReceiveRedirectResponse) const;
- Frame* opener();
- void setOpener(Frame*);
+ WEBCORE_EXPORT Frame* opener();
+ WEBCORE_EXPORT void setOpener(Frame*);
void resetMultipleFormSubmissionProtection();
@@ -239,16 +242,16 @@ public:
void finishedParsing();
void checkCompleted();
- bool isComplete() const;
+ WEBCORE_EXPORT bool isComplete() const;
void commitProvisionalLoad();
void setLoadsSynchronously(bool loadsSynchronously) { m_loadsSynchronously = loadsSynchronously; }
bool loadsSynchronously() const { return m_loadsSynchronously; }
- FrameLoaderStateMachine* stateMachine() const { return &m_stateMachine; }
+ FrameLoaderStateMachine& stateMachine() { return m_stateMachine; }
- Frame* findFrameForNavigation(const AtomicString& name, Document* activeDocument = 0);
+ WEBCORE_EXPORT Frame* findFrameForNavigation(const AtomicString& name, Document* activeDocument = nullptr);
void applyUserAgent(ResourceRequest&);
@@ -256,7 +259,7 @@ public:
void completed();
bool allAncestorsAreComplete() const; // including this
- void clientRedirected(const URL&, double delay, double fireDate, bool lockBackForwardList);
+ void clientRedirected(const URL&, double delay, double fireDate, LockBackForwardList);
void clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress);
// FIXME: This is public because this asynchronous callback from the FrameLoaderClient
@@ -264,27 +267,18 @@ public:
// introduce a proper callback type for this function, we should make it private again.
void continueLoadAfterWillSubmitForm();
- void setOriginalURLForDownloadRequest(ResourceRequest&);
-
- bool suppressOpenerInNewFrame() const { return m_suppressOpenerInNewFrame; }
-
- static ObjectContentType defaultObjectContentType(const URL&, const String& mimeType, bool shouldPreferPlugInsForImages);
+ WEBCORE_EXPORT void setOriginalURLForDownloadRequest(ResourceRequest&);
bool quickRedirectComing() const { return m_quickRedirectComing; }
- bool shouldClose();
+ WEBCORE_EXPORT bool shouldClose();
void started();
- enum PageDismissalType {
- NoDismissal = 0,
- BeforeUnloadDismissal = 1,
- PageHideDismissal = 2,
- UnloadDismissal = 3
- };
+ enum class PageDismissalType { None, BeforeUnload, PageHide, Unload };
PageDismissalType pageDismissalEventBeingDispatched() const { return m_pageDismissalEventBeingDispatched; }
- NetworkingContext* networkingContext() const;
+ WEBCORE_EXPORT NetworkingContext* networkingContext() const;
void loadProgressingStatusChanged();
@@ -292,6 +286,19 @@ public:
void forcePageTransitionIfNeeded();
+ void setOverrideCachePolicyForTesting(ResourceRequestCachePolicy policy) { m_overrideCachePolicyForTesting = policy; }
+ void setOverrideResourceLoadPriorityForTesting(ResourceLoadPriority priority) { m_overrideResourceLoadPriorityForTesting = priority; }
+ void setStrictRawResourceValidationPolicyDisabledForTesting(bool disabled) { m_isStrictRawResourceValidationPolicyDisabledForTesting = disabled; }
+ bool isStrictRawResourceValidationPolicyDisabledForTesting() { return m_isStrictRawResourceValidationPolicyDisabledForTesting; }
+
+ WEBCORE_EXPORT void clearTestingOverrides();
+
+ const URL& provisionalLoadErrorBeingHandledURL() const { return m_provisionalLoadErrorBeingHandledURL; }
+ void setProvisionalLoadErrorBeingHandledURL(const URL& url) { m_provisionalLoadErrorBeingHandledURL = url; }
+
+ bool isAlwaysOnLoggingAllowed() const;
+ bool shouldSuppressKeyboardInput() const;
+
private:
enum FormSubmissionCacheLoadPolicy {
MayAttemptCacheOnlyLoadForFormSubmissionItem,
@@ -300,17 +307,18 @@ private:
bool allChildrenAreComplete() const; // immediate children, not all descendants
- void checkTimerFired(Timer<FrameLoader>&);
-
- void loadSameDocumentItem(HistoryItem*);
- void loadDifferentDocumentItem(HistoryItem*, FrameLoadType, FormSubmissionCacheLoadPolicy);
-
+ void checkTimerFired();
+
+ void loadSameDocumentItem(HistoryItem&);
+ void loadDifferentDocumentItem(HistoryItem&, FrameLoadType, FormSubmissionCacheLoadPolicy);
+
void loadProvisionalItemFromCachedPage();
void updateFirstPartyForCookies();
void setFirstPartyForCookies(const URL&);
-
+
void addExtraFieldsToRequest(ResourceRequest&, FrameLoadType, bool isMainResource);
+ ResourceRequestCachePolicy defaultRequestCachingPolicy(const ResourceRequest&, FrameLoadType, bool isMainResource);
void clearProvisionalLoad();
void transitionToCommitted(CachedPage*);
@@ -318,10 +326,11 @@ private:
SubstituteData defaultSubstituteDataForURL(const URL&);
- bool handleBeforeUnloadEvent(Chrome&, FrameLoader* frameLoaderBeingNavigated);
+ bool dispatchBeforeUnloadEvent(Chrome&, FrameLoader* frameLoaderBeingNavigated);
+ void dispatchUnloadEvents(UnloadEventPolicy);
- void continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
- void continueLoadAfterNewWindowPolicy(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, bool shouldContinue);
+ void continueLoadAfterNavigationPolicy(const ResourceRequest&, FormState*, bool shouldContinue, AllowNavigationToInvalidURL);
+ void continueLoadAfterNewWindowPolicy(const ResourceRequest&, FormState*, const String& frameName, const NavigationAction&, bool shouldContinue, AllowNavigationToInvalidURL, NewFrameOpenerPolicy);
void continueFragmentScrollAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue);
bool shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType, const URL&);
@@ -336,35 +345,31 @@ private:
void setState(FrameState);
void closeOldDataSources();
- void prepareForCachedPageRestore();
+ void willRestoreFromCachedPage();
+ void didRestoreFromCachedPage();
bool shouldReloadToHandleUnreachableURL(DocumentLoader*);
- void dispatchDidCommitLoad();
-
- void urlSelected(const FrameLoadRequest&, PassRefPtr<Event>, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL);
+ void dispatchDidCommitLoad(std::optional<HasInsecureContent> initialHasInsecureContent);
- void loadWithDocumentLoader(DocumentLoader*, FrameLoadType, PassRefPtr<FormState>); // Calls continueLoadAfterNavigationPolicy
- void load(DocumentLoader*); // Calls loadWithDocumentLoader
+ void urlSelected(const FrameLoadRequest&, Event*);
- void loadWithNavigationAction(const ResourceRequest&, const NavigationAction&, // Calls loadWithDocumentLoader
- bool lockHistory, FrameLoadType, PassRefPtr<FormState>);
+ void loadWithDocumentLoader(DocumentLoader*, FrameLoadType, FormState*, AllowNavigationToInvalidURL); // Calls continueLoadAfterNavigationPolicy
+ void load(DocumentLoader*); // Calls loadWithDocumentLoader
- void loadPostRequest(const ResourceRequest&, const String& referrer, // Called by loadFrameRequest, calls loadWithNavigationAction
- const String& frameName, bool lockHistory, FrameLoadType, PassRefPtr<Event>, PassRefPtr<FormState>);
- void loadURL(const URL&, const String& referrer, const String& frameName, // Called by loadFrameRequest, calls loadWithNavigationAction or dispatches to navigation policy delegate
- bool lockHistory, FrameLoadType, PassRefPtr<Event>, PassRefPtr<FormState>);
+ void loadWithNavigationAction(const ResourceRequest&, const NavigationAction&, LockHistory, FrameLoadType, FormState*, AllowNavigationToInvalidURL); // Calls loadWithDocumentLoader
- void reloadWithRequest(const ResourceRequest&, bool endToEndReload);
+ void loadPostRequest(const FrameLoadRequest&, const String& referrer, FrameLoadType, Event*, FormState*);
+ void loadURL(const FrameLoadRequest&, const String& referrer, FrameLoadType, Event*, FormState*);
bool shouldReload(const URL& currentURL, const URL& destinationURL);
void requestFromDelegate(ResourceRequest&, unsigned long& identifier, ResourceError&);
- void detachChildren();
- void closeAndRemoveChild(Frame*);
+ WEBCORE_EXPORT void detachChildren();
+ void closeAndRemoveChild(Frame&);
- void loadInSameDocument(const URL&, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation);
+ void loadInSameDocument(const URL&, SerializedScriptValue* stateObject, bool isNewNavigation);
void prepareForLoadStart();
void provisionalLoadStarted();
@@ -380,6 +385,10 @@ private:
void dispatchGlobalObjectAvailableInAllWorlds();
+ void applyShouldOpenExternalURLsPolicyToNewDocumentLoader(DocumentLoader&, ShouldOpenExternalURLsPolicy propagatedPolicy);
+
+ bool isNavigationAllowed() const;
+
Frame& m_frame;
FrameLoaderClient& m_client;
@@ -405,7 +414,7 @@ private:
RefPtr<DocumentLoader> m_provisionalDocumentLoader;
RefPtr<DocumentLoader> m_policyDocumentLoader;
- bool m_delegateIsHandlingProvisionalLoadError;
+ URL m_provisionalLoadErrorBeingHandledURL;
bool m_quickRedirectComing;
bool m_sentRedirectNotification;
@@ -417,7 +426,8 @@ private:
bool m_didCallImplicitClose;
bool m_wasUnloadEventEmitted;
- PageDismissalType m_pageDismissalEventBeingDispatched;
+
+ PageDismissalType m_pageDismissalEventBeingDispatched { PageDismissalType::None };
bool m_isComplete;
RefPtr<SerializedScriptValue> m_pendingStateObject;
@@ -426,7 +436,7 @@ private:
URL m_submittedFormURL;
- Timer<FrameLoader> m_checkTimer;
+ Timer m_checkTimer;
bool m_shouldCallCheckCompleted;
bool m_shouldCallCheckLoadComplete;
@@ -434,7 +444,6 @@ private:
HashSet<Frame*> m_openedFrames;
bool m_loadingFromCachedPage;
- bool m_suppressOpenerInNewFrame;
bool m_currentNavigationHasShownBeforeUnloadConfirmPanel;
@@ -444,9 +453,12 @@ private:
RefPtr<FrameNetworkingContext> m_networkingContext;
+ std::optional<ResourceRequestCachePolicy> m_overrideCachePolicyForTesting;
+ std::optional<ResourceLoadPriority> m_overrideResourceLoadPriorityForTesting;
+ bool m_isStrictRawResourceValidationPolicyDisabledForTesting { false };
+
URL m_previousURL;
RefPtr<HistoryItem> m_requestedHistoryItem;
- std::unique_ptr<PageActivityAssertionToken> m_activityAssertion;
};
// This function is called by createWindow() in JSDOMWindowBase.cpp, for example, for
@@ -456,8 +468,6 @@ private:
//
// FIXME: Consider making this function part of an appropriate class (not FrameLoader)
// and moving it to a more appropriate location.
-PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest&, const WindowFeatures&, bool& created);
+RefPtr<Frame> createWindow(Frame& openerFrame, Frame& lookupFrame, const FrameLoadRequest&, const WindowFeatures&, bool& created);
} // namespace WebCore
-
-#endif // FrameLoader_h
diff --git a/Source/WebCore/loader/FrameLoaderClient.h b/Source/WebCore/loader/FrameLoaderClient.h
index c81bdba41..66e386e52 100644
--- a/Source/WebCore/loader/FrameLoaderClient.h
+++ b/Source/WebCore/loader/FrameLoaderClient.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,18 +27,22 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FrameLoaderClient_h
-#define FrameLoaderClient_h
+#pragma once
#include "FrameLoaderTypes.h"
-#include "IconURL.h"
#include "LayoutMilestones.h"
+#include "LinkIcon.h"
#include "ResourceLoadPriority.h"
#include <functional>
#include <wtf/Forward.h>
#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
-#if PLATFORM(MAC)
+#if ENABLE(CONTENT_FILTERING)
+#include "ContentFilterUnblockHandler.h"
+#endif
+
+#if PLATFORM(COCOA)
#ifdef __OBJC__
#import <Foundation/Foundation.h>
typedef id RemoteAXObjectRef;
@@ -47,296 +51,311 @@ typedef void* RemoteAXObjectRef;
#endif
#endif
-typedef class _jobject* jobject;
-
-#if PLATFORM(MAC) && !defined(__OBJC__)
-class NSCachedURLResponse;
-class NSView;
+#if PLATFORM(COCOA)
+OBJC_CLASS NSArray;
+OBJC_CLASS NSCachedURLResponse;
+OBJC_CLASS NSDictionary;
+OBJC_CLASS NSView;
#endif
namespace WebCore {
- class AuthenticationChallenge;
- class CachedFrame;
- class CachedResourceRequest;
- class Color;
- class DOMWindowExtension;
- class DOMWrapperWorld;
- class DocumentLoader;
- class Element;
- class FormState;
- class Frame;
- class FrameLoader;
- class FrameNetworkingContext;
- class HistoryItem;
- class HTMLAppletElement;
- class HTMLFormElement;
- class HTMLFrameOwnerElement;
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- class HTMLMediaElement;
-#endif
- class HTMLPlugInElement;
- class IntSize;
- class URL;
- class MessageEvent;
- class NavigationAction;
- class Page;
- class ProtectionSpace;
- class PluginView;
- class PolicyChecker;
- class ResourceError;
- class ResourceHandle;
- class ResourceRequest;
- class ResourceResponse;
-#if ENABLE(MEDIA_STREAM)
- class RTCPeerConnectionHandler;
+class AuthenticationChallenge;
+class CachedFrame;
+class CachedResourceRequest;
+class Color;
+class DOMWindowExtension;
+class DOMWrapperWorld;
+class DocumentLoader;
+class Element;
+class FormState;
+class Frame;
+class FrameLoader;
+class FrameNetworkingContext;
+class HTMLAppletElement;
+class HTMLFormElement;
+class HTMLFrameOwnerElement;
+class HTMLPlugInElement;
+class HistoryItem;
+class IntSize;
+class MessageEvent;
+class NavigationAction;
+class Page;
+class PluginViewBase;
+class PolicyChecker;
+class ProtectionSpace;
+class QuickLookHandleClient;
+class RTCPeerConnectionHandler;
+class ResourceError;
+class ResourceHandle;
+class ResourceRequest;
+class ResourceResponse;
+class SecurityOrigin;
+class SessionID;
+class SharedBuffer;
+class SubstituteData;
+class URL;
+class Widget;
+
+struct StringWithDirection;
+
+typedef std::function<void (PolicyAction)> FramePolicyFunction;
+
+class WEBCORE_EXPORT FrameLoaderClient {
+public:
+ // An inline function cannot be the first non-abstract virtual function declared
+ // in the class as it results in the vtable being generated as a weak symbol.
+ // This hurts performance (in Mac OS X at least, when loadig frameworks), so we
+ // don't want to do it in WebKit.
+ virtual bool hasHTMLView() const;
+
+ virtual ~FrameLoaderClient() { }
+
+ virtual void frameLoaderDestroyed() = 0;
+
+ virtual bool hasWebView() const = 0; // mainly for assertions
+
+ virtual void makeRepresentation(DocumentLoader*) = 0;
+
+#if PLATFORM(IOS)
+ // Returns true if the client forced the layout.
+ virtual bool forceLayoutOnRestoreFromPageCache() = 0;
#endif
- class SecurityOrigin;
- class SharedBuffer;
- class SocketStreamHandle;
- class StringWithDirection;
- class SubstituteData;
- class Widget;
-
- typedef std::function<void (PolicyAction)> FramePolicyFunction;
+ virtual void forceLayoutForNonHTML() = 0;
- class FrameLoaderClient {
- public:
- // An inline function cannot be the first non-abstract virtual function declared
- // in the class as it results in the vtable being generated as a weak symbol.
- // This hurts performance (in Mac OS X at least, when loadig frameworks), so we
- // don't want to do it in WebKit.
- virtual bool hasHTMLView() const;
+ virtual void setCopiesOnScroll() = 0;
- virtual ~FrameLoaderClient() { }
+ virtual void detachedFromParent2() = 0;
+ virtual void detachedFromParent3() = 0;
- virtual void frameLoaderDestroyed() = 0;
+ virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&) = 0;
- virtual bool hasWebView() const = 0; // mainly for assertions
+ virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse) = 0;
+ virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) = 0;
+ virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ virtual bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long identifier, const ProtectionSpace&) = 0;
+#endif
- virtual void makeRepresentation(DocumentLoader*) = 0;
- virtual void forceLayout() = 0;
#if PLATFORM(IOS)
- virtual void forceLayoutWithoutRecalculatingStyles() = 0;
+ virtual RetainPtr<CFDictionaryRef> connectionProperties(DocumentLoader*, unsigned long identifier) = 0;
#endif
- virtual void forceLayoutForNonHTML() = 0;
- virtual void setCopiesOnScroll() = 0;
+ virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) = 0;
+ virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int dataLength) = 0;
+ virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier) = 0;
+ virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&) = 0;
+ virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length) = 0;
+
+ virtual void dispatchDidDispatchOnloadEvents() = 0;
+ virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() = 0;
+ virtual void dispatchDidChangeProvisionalURL() { }
+ virtual void dispatchDidCancelClientRedirect() = 0;
+ virtual void dispatchWillPerformClientRedirect(const URL&, double interval, double fireDate) = 0;
+ virtual void dispatchDidNavigateWithinPage() { }
+ virtual void dispatchDidChangeLocationWithinPage() = 0;
+ virtual void dispatchDidPushStateWithinPage() = 0;
+ virtual void dispatchDidReplaceStateWithinPage() = 0;
+ virtual void dispatchDidPopStateWithinPage() = 0;
+ virtual void dispatchWillClose() = 0;
+ virtual void dispatchDidReceiveIcon() = 0;
+ virtual void dispatchDidStartProvisionalLoad() = 0;
+ virtual void dispatchDidReceiveTitle(const StringWithDirection&) = 0;
+ virtual void dispatchDidCommitLoad(std::optional<HasInsecureContent>) = 0;
+ virtual void dispatchDidFailProvisionalLoad(const ResourceError&) = 0;
+ virtual void dispatchDidFailLoad(const ResourceError&) = 0;
+ virtual void dispatchDidFinishDocumentLoad() = 0;
+ virtual void dispatchDidFinishLoad() = 0;
+#if ENABLE(DATA_DETECTION)
+ virtual void dispatchDidFinishDataDetection(NSArray *detectionResults) = 0;
+#endif
- virtual void detachedFromParent2() = 0;
- virtual void detachedFromParent3() = 0;
+ virtual void dispatchDidLayout() { }
+ virtual void dispatchDidReachLayoutMilestone(LayoutMilestones) { }
- virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&) = 0;
+ virtual Frame* dispatchCreatePage(const NavigationAction&) = 0;
+ virtual void dispatchShow() = 0;
- virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse) = 0;
- virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) = 0;
- virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
- virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
- virtual bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long identifier, const ProtectionSpace&) = 0;
-#endif
+ virtual void dispatchDecidePolicyForResponse(const ResourceResponse&, const ResourceRequest&, FramePolicyFunction) = 0;
+ virtual void dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, FormState*, const String& frameName, FramePolicyFunction) = 0;
+ virtual void dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, FormState*, FramePolicyFunction) = 0;
+ virtual void cancelPolicyCheck() = 0;
-#if PLATFORM(IOS)
- virtual RetainPtr<CFDictionaryRef> connectionProperties(DocumentLoader*, unsigned long identifier) = 0;
-#endif
+ virtual void dispatchUnableToImplementPolicy(const ResourceError&) = 0;
- virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) = 0;
- virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int dataLength) = 0;
- virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier) = 0;
- virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&) = 0;
- virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length) = 0;
-
- virtual void dispatchDidHandleOnloadEvents() = 0;
- virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() = 0;
- virtual void dispatchDidCancelClientRedirect() = 0;
- virtual void dispatchWillPerformClientRedirect(const URL&, double interval, double fireDate) = 0;
- virtual void dispatchDidNavigateWithinPage() { }
- virtual void dispatchDidChangeLocationWithinPage() = 0;
- virtual void dispatchDidPushStateWithinPage() = 0;
- virtual void dispatchDidReplaceStateWithinPage() = 0;
- virtual void dispatchDidPopStateWithinPage() = 0;
- virtual void dispatchWillClose() = 0;
- virtual void dispatchDidReceiveIcon() = 0;
- virtual void dispatchDidStartProvisionalLoad() = 0;
- virtual void dispatchDidReceiveTitle(const StringWithDirection&) = 0;
- virtual void dispatchDidChangeIcons(IconType) = 0;
- virtual void dispatchDidCommitLoad() = 0;
- virtual void dispatchDidFailProvisionalLoad(const ResourceError&) = 0;
- virtual void dispatchDidFailLoad(const ResourceError&) = 0;
- virtual void dispatchDidFinishDocumentLoad() = 0;
- virtual void dispatchDidFinishLoad() = 0;
-
- virtual void dispatchDidLayout() { }
- virtual void dispatchDidLayout(LayoutMilestones) { }
-
- virtual Frame* dispatchCreatePage(const NavigationAction&) = 0;
- virtual void dispatchShow() = 0;
-
- virtual void dispatchDecidePolicyForResponse(const ResourceResponse&, const ResourceRequest&, FramePolicyFunction) = 0;
- virtual void dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, FramePolicyFunction) = 0;
- virtual void dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, FramePolicyFunction) = 0;
- virtual void cancelPolicyCheck() = 0;
-
- virtual void dispatchUnableToImplementPolicy(const ResourceError&) = 0;
-
- virtual void dispatchWillRequestResource(CachedResourceRequest*) { }
-
- virtual void dispatchWillSendSubmitEvent(PassRefPtr<FormState>) = 0;
- virtual void dispatchWillSubmitForm(PassRefPtr<FormState>, FramePolicyFunction) = 0;
-
- virtual void revertToProvisionalState(DocumentLoader*) = 0;
- virtual void setMainDocumentError(DocumentLoader*, const ResourceError&) = 0;
-
- virtual void setMainFrameDocumentReady(bool) = 0;
-
- virtual void startDownload(const ResourceRequest&, const String& suggestedName = String()) = 0;
-
- virtual void willChangeTitle(DocumentLoader*) = 0;
- virtual void didChangeTitle(DocumentLoader*) = 0;
-
- virtual void committedLoad(DocumentLoader*, const char*, int) = 0;
- virtual void finishedLoading(DocumentLoader*) = 0;
-
- virtual void updateGlobalHistory() = 0;
- virtual void updateGlobalHistoryRedirectLinks() = 0;
-
- virtual bool shouldGoToHistoryItem(HistoryItem*) const = 0;
- virtual void updateGlobalHistoryItemForPage() { }
-
- // This frame has set its opener to null, disowning it for the lifetime of the frame.
- // See http://html.spec.whatwg.org/#dom-opener.
- // FIXME: JSC should allow disowning opener. - <https://bugs.webkit.org/show_bug.cgi?id=103913>.
- virtual void didDisownOpener() { }
-
- // This frame has displayed inactive content (such as an image) from an
- // insecure source. Inactive content cannot spread to other frames.
- virtual void didDisplayInsecureContent() = 0;
-
- // The indicated security origin has run active content (such as a
- // script) from an insecure source. Note that the insecure content can
- // spread to other frames in the same origin.
- virtual void didRunInsecureContent(SecurityOrigin*, const URL&) = 0;
- virtual void didDetectXSS(const URL&, bool didBlockEntirePage) = 0;
-
- virtual ResourceError cancelledError(const ResourceRequest&) = 0;
- virtual ResourceError blockedError(const ResourceRequest&) = 0;
- virtual ResourceError cannotShowURLError(const ResourceRequest&) = 0;
- virtual ResourceError interruptedForPolicyChangeError(const ResourceRequest&) = 0;
-
- virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&) = 0;
- virtual ResourceError fileDoesNotExistError(const ResourceResponse&) = 0;
- virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&) = 0;
-
- virtual bool shouldFallBack(const ResourceError&) = 0;
-
- virtual bool canHandleRequest(const ResourceRequest&) const = 0;
- virtual bool canShowMIMEType(const String& MIMEType) const = 0;
- virtual bool canShowMIMETypeAsHTML(const String& MIMEType) const = 0;
- virtual bool representationExistsForURLScheme(const String& URLScheme) const = 0;
- virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const = 0;
-
- virtual void frameLoadCompleted() = 0;
- virtual void saveViewStateToItem(HistoryItem*) = 0;
- virtual void restoreViewState() = 0;
- virtual void provisionalLoadStarted() = 0;
- virtual void didFinishLoad() = 0;
- virtual void prepareForDataSourceReplacement() = 0;
-
- virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) = 0;
- virtual void setTitle(const StringWithDirection&, const URL&) = 0;
-
- virtual String userAgent(const URL&) = 0;
-
- virtual void savePlatformDataToCachedFrame(CachedFrame*) = 0;
- virtual void transitionToCommittedFromCachedFrame(CachedFrame*) = 0;
-#if PLATFORM(IOS)
- virtual void didRestoreFrameHierarchyForCachedFrame() = 0;
+ virtual void dispatchWillSendSubmitEvent(Ref<FormState>&&) = 0;
+ virtual void dispatchWillSubmitForm(FormState&, FramePolicyFunction) = 0;
+
+ virtual void revertToProvisionalState(DocumentLoader*) = 0;
+ virtual void setMainDocumentError(DocumentLoader*, const ResourceError&) = 0;
+
+ virtual void setMainFrameDocumentReady(bool) = 0;
+
+ virtual void startDownload(const ResourceRequest&, const String& suggestedName = String()) = 0;
+
+ virtual void willChangeTitle(DocumentLoader*) = 0;
+ virtual void didChangeTitle(DocumentLoader*) = 0;
+
+ virtual void willReplaceMultipartContent() = 0;
+ virtual void didReplaceMultipartContent() = 0;
+
+ virtual void committedLoad(DocumentLoader*, const char*, int) = 0;
+ virtual void finishedLoading(DocumentLoader*) = 0;
+
+ virtual void updateGlobalHistory() = 0;
+ virtual void updateGlobalHistoryRedirectLinks() = 0;
+
+ virtual bool shouldGoToHistoryItem(HistoryItem*) const = 0;
+ virtual void updateGlobalHistoryItemForPage() { }
+
+ // This frame has set its opener to null, disowning it for the lifetime of the frame.
+ // See http://html.spec.whatwg.org/#dom-opener.
+ // FIXME: JSC should allow disowning opener. - <https://bugs.webkit.org/show_bug.cgi?id=103913>.
+ virtual void didDisownOpener() { }
+
+ // This frame has displayed inactive content (such as an image) from an
+ // insecure source. Inactive content cannot spread to other frames.
+ virtual void didDisplayInsecureContent() = 0;
+
+ // The indicated security origin has run active content (such as a
+ // script) from an insecure source. Note that the insecure content can
+ // spread to other frames in the same origin.
+ virtual void didRunInsecureContent(SecurityOrigin&, const URL&) = 0;
+ virtual void didDetectXSS(const URL&, bool didBlockEntirePage) = 0;
+
+ virtual ResourceError cancelledError(const ResourceRequest&) = 0;
+ virtual ResourceError blockedError(const ResourceRequest&) = 0;
+ virtual ResourceError blockedByContentBlockerError(const ResourceRequest&) = 0;
+ virtual ResourceError cannotShowURLError(const ResourceRequest&) = 0;
+ virtual ResourceError interruptedForPolicyChangeError(const ResourceRequest&) = 0;
+#if ENABLE(CONTENT_FILTERING)
+ virtual ResourceError blockedByContentFilterError(const ResourceRequest&) = 0;
#endif
- virtual void transitionToCommittedForNewPage() = 0;
- virtual void didSaveToPageCache() = 0;
- virtual void didRestoreFromPageCache() = 0;
+ virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&) = 0;
+ virtual ResourceError fileDoesNotExistError(const ResourceResponse&) = 0;
+ virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&) = 0;
+
+ virtual bool shouldFallBack(const ResourceError&) = 0;
- virtual void dispatchDidBecomeFrameset(bool) = 0; // Can change due to navigation or DOM modification.
+ virtual bool canHandleRequest(const ResourceRequest&) const = 0;
+ virtual bool canShowMIMEType(const String& MIMEType) const = 0;
+ virtual bool canShowMIMETypeAsHTML(const String& MIMEType) const = 0;
+ virtual bool representationExistsForURLScheme(const String& URLScheme) const = 0;
+ virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const = 0;
- virtual bool canCachePage() const = 0;
- virtual void convertMainResourceLoadToDownload(DocumentLoader*, const ResourceRequest&, const ResourceResponse&) = 0;
+ virtual void frameLoadCompleted() = 0;
+ virtual void saveViewStateToItem(HistoryItem&) = 0;
+ virtual void restoreViewState() = 0;
+ virtual void provisionalLoadStarted() = 0;
+ virtual void didFinishLoad() = 0;
+ virtual void prepareForDataSourceReplacement() = 0;
- virtual PassRefPtr<Frame> createFrame(const URL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0;
- virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually) = 0;
- virtual void recreatePlugin(Widget*) = 0;
- virtual void redirectDataToPlugin(Widget* pluginWidget) = 0;
+ virtual Ref<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) = 0;
+ virtual void updateCachedDocumentLoader(DocumentLoader&) = 0;
+ virtual void setTitle(const StringWithDirection&, const URL&) = 0;
- virtual PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const URL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues) = 0;
+ virtual String userAgent(const URL&) = 0;
- virtual void dispatchDidFailToStartPlugin(const PluginView*) const { }
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- virtual PassRefPtr<Widget> createMediaPlayerProxyPlugin(const IntSize&, HTMLMediaElement*, const URL&, const Vector<String>&, const Vector<String>&, const String&) = 0;
- virtual void hideMediaPlayerProxyPlugin(Widget*) = 0;
- virtual void showMediaPlayerProxyPlugin(Widget*) = 0;
+ virtual String overrideContentSecurityPolicy() const { return String(); }
+
+ virtual void savePlatformDataToCachedFrame(CachedFrame*) = 0;
+ virtual void transitionToCommittedFromCachedFrame(CachedFrame*) = 0;
+#if PLATFORM(IOS)
+ virtual void didRestoreFrameHierarchyForCachedFrame() = 0;
#endif
+ virtual void transitionToCommittedForNewPage() = 0;
+
+ virtual void didSaveToPageCache() = 0;
+ virtual void didRestoreFromPageCache() = 0;
+
+ virtual void dispatchDidBecomeFrameset(bool) = 0; // Can change due to navigation or DOM modification.
+
+ virtual bool canCachePage() const = 0;
+ virtual void convertMainResourceLoadToDownload(DocumentLoader*, SessionID, const ResourceRequest&, const ResourceResponse&) = 0;
+
+ virtual RefPtr<Frame> createFrame(const URL&, const String& name, HTMLFrameOwnerElement&, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0;
+ virtual RefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement&, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually) = 0;
+ virtual void recreatePlugin(Widget*) = 0;
+ virtual void redirectDataToPlugin(Widget&) = 0;
+
+ virtual RefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement&, const URL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues) = 0;
- virtual ObjectContentType objectContentType(const URL&, const String& mimeType, bool shouldPreferPlugInsForImages) = 0;
- virtual String overrideMediaType() const = 0;
+ virtual ObjectContentType objectContentType(const URL&, const String& mimeType) = 0;
+ virtual String overrideMediaType() const = 0;
- virtual void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&) = 0;
+ virtual void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&) = 0;
- virtual void registerForIconNotification(bool listen = true) = 0;
+ virtual void registerForIconNotification(bool listen = true) = 0;
-#if PLATFORM(MAC)
- // Allow an accessibility object to retrieve a Frame parent if there's no PlatformWidget.
- virtual RemoteAXObjectRef accessibilityRemoteObject() = 0;
- virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse*) const = 0;
+#if PLATFORM(COCOA)
+ // Allow an accessibility object to retrieve a Frame parent if there's no PlatformWidget.
+ virtual RemoteAXObjectRef accessibilityRemoteObject() = 0;
+ virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse*) const = 0;
+ virtual NSDictionary *dataDetectionContext() { return nullptr; }
#endif
-#if PLATFORM(WIN) && USE(CFNETWORK)
- // FIXME: Windows should use willCacheResponse - <https://bugs.webkit.org/show_bug.cgi?id=57257>.
- virtual bool shouldCacheResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&, const unsigned char* data, unsigned long long length) = 0;
+
+#if PLATFORM(WIN) && USE(CFURLCONNECTION)
+ // FIXME: Windows should use willCacheResponse - <https://bugs.webkit.org/show_bug.cgi?id=57257>.
+ virtual bool shouldCacheResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&, const unsigned char* data, unsigned long long length) = 0;
#endif
- virtual bool shouldAlwaysUsePluginDocument(const String& /*mimeType*/) const { return false; }
- virtual bool shouldLoadMediaElementURL(const URL&) const { return true; }
+ virtual bool shouldAlwaysUsePluginDocument(const String& /*mimeType*/) const { return false; }
+ virtual bool shouldLoadMediaElementURL(const URL&) const { return true; }
- virtual void didChangeScrollOffset() { }
+ virtual void didChangeScrollOffset() { }
- virtual bool allowScript(bool enabledPerSettings) { return enabledPerSettings; }
- virtual bool allowScriptFromSource(bool enabledPerSettings, const URL&) { return enabledPerSettings; }
- virtual bool allowPlugins(bool enabledPerSettings) { return enabledPerSettings; }
- virtual bool allowImage(bool enabledPerSettings, const URL&) { return enabledPerSettings; }
- virtual bool allowDisplayingInsecureContent(bool enabledPerSettings, SecurityOrigin*, const URL&) { return enabledPerSettings; }
- virtual bool allowRunningInsecureContent(bool enabledPerSettings, SecurityOrigin*, const URL&) { return enabledPerSettings; }
+ virtual bool allowScript(bool enabledPerSettings) { return enabledPerSettings; }
- // Clients that generally disallow universal access can make exceptions for particular URLs.
- virtual bool shouldForceUniversalAccessFromLocalURL(const URL&) { return false; }
+ // Clients that generally disallow universal access can make exceptions for particular URLs.
+ virtual bool shouldForceUniversalAccessFromLocalURL(const URL&) { return false; }
- virtual PassRefPtr<FrameNetworkingContext> createNetworkingContext() = 0;
+ virtual Ref<FrameNetworkingContext> createNetworkingContext() = 0;
- virtual bool shouldPaintBrokenImage(const URL&) const { return true; }
+#if ENABLE(REQUEST_AUTOCOMPLETE)
+ virtual void didRequestAutocomplete(Ref<FormState>&&) = 0;
+#endif
- virtual void dispatchWillOpenSocketStream(SocketStreamHandle*) { }
+ virtual bool shouldPaintBrokenImage(const URL&) const { return true; }
- virtual void dispatchGlobalObjectAvailable(DOMWrapperWorld&) { }
- virtual void dispatchWillDisconnectDOMWindowExtensionFromGlobalObject(DOMWindowExtension*) { }
- virtual void dispatchDidReconnectDOMWindowExtensionToGlobalObject(DOMWindowExtension*) { }
- virtual void dispatchWillDestroyGlobalObjectForDOMWindowExtension(DOMWindowExtension*) { }
+ virtual void dispatchGlobalObjectAvailable(DOMWrapperWorld&) { }
+ virtual void dispatchWillDisconnectDOMWindowExtensionFromGlobalObject(DOMWindowExtension*) { }
+ virtual void dispatchDidReconnectDOMWindowExtensionToGlobalObject(DOMWindowExtension*) { }
+ virtual void dispatchWillDestroyGlobalObjectForDOMWindowExtension(DOMWindowExtension*) { }
-#if ENABLE(MEDIA_STREAM)
- virtual void dispatchWillStartUsingPeerConnectionHandler(RTCPeerConnectionHandler*) { }
+#if ENABLE(WEB_RTC)
+ virtual void dispatchWillStartUsingPeerConnectionHandler(RTCPeerConnectionHandler*) { }
#endif
#if ENABLE(WEBGL)
- virtual bool allowWebGL(bool enabledPerSettings) { return enabledPerSettings; }
- // Informs the embedder that a WebGL canvas inside this frame received a lost context
- // notification with the given GL_ARB_robustness guilt/innocence code (see Extensions3D.h).
- virtual void didLoseWebGLContext(int) { }
- virtual WebGLLoadPolicy webGLPolicyForURL(const String&) const { return WebGLAllow; }
+ virtual bool allowWebGL(bool enabledPerSettings) { return enabledPerSettings; }
+ // Informs the embedder that a WebGL canvas inside this frame received a lost context
+ // notification with the given GL_ARB_robustness guilt/innocence code (see Extensions3D.h).
+ virtual void didLoseWebGLContext(int) { }
+ virtual WebGLLoadPolicy webGLPolicyForURL(const String&) const { return WebGLAllowCreation; }
+ virtual WebGLLoadPolicy resolveWebGLPolicyForURL(const String&) const { return WebGLAllowCreation; }
#endif
- virtual void forcePageTransitionIfNeeded() { }
+ virtual void forcePageTransitionIfNeeded() { }
- // FIXME (bug 116233): We need to get rid of EmptyFrameLoaderClient completely, then this will no longer be needed.
- virtual bool isEmptyFrameLoaderClient() { return false; }
- };
+ // FIXME (bug 116233): We need to get rid of EmptyFrameLoaderClient completely, then this will no longer be needed.
+ virtual bool isEmptyFrameLoaderClient() { return false; }
-} // namespace WebCore
+#if USE(QUICK_LOOK)
+ virtual RefPtr<QuickLookHandleClient> createQuickLookHandleClient(const String&, const String&) = 0;
+#endif
+
+#if ENABLE(CONTENT_FILTERING)
+ virtual void contentFilterDidBlockLoad(ContentFilterUnblockHandler) { }
+#endif
+
+ virtual void prefetchDNS(const String&) = 0;
+
+ virtual void didRestoreScrollPosition() { }
-#endif // FrameLoaderClient_h
+ virtual bool useIconLoadingClient() { return false; }
+ virtual void getLoadDecisionForIcon(const LinkIcon&, uint64_t) { }
+ virtual void finishedLoadingIcon(uint64_t, SharedBuffer*) { }
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/FrameLoaderStateMachine.h b/Source/WebCore/loader/FrameLoaderStateMachine.h
index 8bce923e8..714e5d6fa 100644
--- a/Source/WebCore/loader/FrameLoaderStateMachine.h
+++ b/Source/WebCore/loader/FrameLoaderStateMachine.h
@@ -26,9 +26,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FrameLoaderStateMachine_h
-#define FrameLoaderStateMachine_h
+#pragma once
+#include "PlatformExportMacros.h"
#include <wtf/Noncopyable.h>
namespace WebCore {
@@ -51,11 +51,11 @@ public:
FirstLayoutDone
};
- bool committingFirstRealLoad() const;
+ WEBCORE_EXPORT bool committingFirstRealLoad() const;
bool committedFirstRealDocumentLoad() const;
bool creatingInitialEmptyDocument() const;
- bool isDisplayingInitialEmptyDocument() const;
- bool firstLayoutDone() const;
+ WEBCORE_EXPORT bool isDisplayingInitialEmptyDocument() const;
+ WEBCORE_EXPORT bool firstLayoutDone() const;
void advanceTo(State);
private:
@@ -63,5 +63,3 @@ private:
};
} // namespace WebCore
-
-#endif // FrameLoaderStateMachine_h
diff --git a/Source/WebCore/loader/FrameLoaderTypes.h b/Source/WebCore/loader/FrameLoaderTypes.h
index 6385f6d70..a8b03341d 100644
--- a/Source/WebCore/loader/FrameLoaderTypes.h
+++ b/Source/WebCore/loader/FrameLoaderTypes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,91 +26,112 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FrameLoaderTypes_h
-#define FrameLoaderTypes_h
+#pragma once
namespace WebCore {
- enum FrameState {
- FrameStateProvisional,
- // This state indicates we are ready to commit to a page,
- // which means the view will transition to use the new data source.
- FrameStateCommittedPage,
- FrameStateComplete
- };
-
- enum PolicyAction {
- PolicyUse,
- PolicyDownload,
- PolicyIgnore
- };
-
- // NOTE: Keep in sync with WebKit/mac/WebView/WebFramePrivate.h and WebKit/win/Interfaces/IWebFramePrivate.idl
- enum FrameLoadType {
- FrameLoadTypeStandard,
- FrameLoadTypeBack,
- FrameLoadTypeForward,
- FrameLoadTypeIndexedBackForward, // a multi-item hop in the backforward list
- FrameLoadTypeReload,
- // Skipped value: 'FrameLoadTypeReloadAllowingStaleData', still present in mac/win public API. Ready to be reused
- FrameLoadTypeSame = FrameLoadTypeReload + 2, // user loads same URL again (but not reload button)
- FrameLoadTypeRedirectWithLockedBackForwardList, // FIXME: Merge "lockBackForwardList", "lockHistory", "quickRedirect" and "clientRedirect" into a single concept of redirect.
- FrameLoadTypeReplace,
- FrameLoadTypeReloadFromOrigin,
- };
-
- enum NavigationType {
- NavigationTypeLinkClicked,
- NavigationTypeFormSubmitted,
- NavigationTypeBackForward,
- NavigationTypeReload,
- NavigationTypeFormResubmitted,
- NavigationTypeOther
- };
-
- enum ClearProvisionalItemPolicy {
- ShouldClearProvisionalItem,
- ShouldNotClearProvisionalItem
- };
-
- enum ObjectContentType {
- ObjectContentNone,
- ObjectContentImage,
- ObjectContentFrame,
- ObjectContentNetscapePlugin,
- ObjectContentOtherPlugin
- };
-
- enum UnloadEventPolicy {
- UnloadEventPolicyNone,
- UnloadEventPolicyUnloadOnly,
- UnloadEventPolicyUnloadAndPageHide
- };
-
- enum ShouldSendReferrer {
- MaybeSendReferrer,
- NeverSendReferrer
- };
-
- // Passed to FrameLoader::urlSelected() and ScriptController::executeIfJavaScriptURL()
- // to control whether, in the case of a JavaScript URL, executeIfJavaScriptURL() should
- // replace the document. It is a FIXME to eliminate this extra parameter from
- // executeIfJavaScriptURL(), in which case this enum can go away.
- enum ShouldReplaceDocumentIfJavaScriptURL {
- ReplaceDocumentIfJavaScriptURL,
- DoNotReplaceDocumentIfJavaScriptURL
- };
-
- enum ReasonForCallingAllowPlugins {
- AboutToInstantiatePlugin,
- NotAboutToInstantiatePlugin
- };
-
- enum WebGLLoadPolicy {
- WebGLBlock = 0,
- WebGLAllow
- };
-
-}
-
-#endif
+enum FrameState {
+ FrameStateProvisional,
+ // This state indicates we are ready to commit to a page,
+ // which means the view will transition to use the new data source.
+ FrameStateCommittedPage,
+ FrameStateComplete
+};
+
+enum PolicyAction {
+ PolicyUse,
+ PolicyDownload,
+ PolicyIgnore
+};
+
+enum class FrameLoadType {
+ Standard,
+ Back,
+ Forward,
+ IndexedBackForward, // a multi-item hop in the backforward list
+ Reload,
+ Same, // user loads same URL again (but not reload button)
+ RedirectWithLockedBackForwardList, // FIXME: Merge "lockBackForwardList", "lockHistory", "quickRedirect" and "clientRedirect" into a single concept of redirect.
+ Replace,
+ ReloadFromOrigin,
+};
+
+enum class NewFrameOpenerPolicy {
+ Suppress,
+ Allow
+};
+
+enum class NavigationType {
+ LinkClicked,
+ FormSubmitted,
+ BackForward,
+ Reload,
+ FormResubmitted,
+ Other
+};
+
+enum class ShouldOpenExternalURLsPolicy {
+ ShouldNotAllow,
+ ShouldAllowExternalSchemes,
+ ShouldAllow,
+};
+
+enum ClearProvisionalItemPolicy {
+ ShouldClearProvisionalItem,
+ ShouldNotClearProvisionalItem
+};
+
+enum class ObjectContentType {
+ None,
+ Image,
+ Frame,
+ PlugIn,
+};
+
+enum UnloadEventPolicy {
+ UnloadEventPolicyNone,
+ UnloadEventPolicyUnloadOnly,
+ UnloadEventPolicyUnloadAndPageHide
+};
+
+enum ShouldSendReferrer {
+ MaybeSendReferrer,
+ NeverSendReferrer
+};
+
+// Passed to FrameLoader::urlSelected() and ScriptController::executeIfJavaScriptURL()
+// to control whether, in the case of a JavaScript URL, executeIfJavaScriptURL() should
+// replace the document. It is a FIXME to eliminate this extra parameter from
+// executeIfJavaScriptURL(), in which case this enum can go away.
+enum ShouldReplaceDocumentIfJavaScriptURL {
+ ReplaceDocumentIfJavaScriptURL,
+ DoNotReplaceDocumentIfJavaScriptURL
+};
+
+enum WebGLLoadPolicy {
+ WebGLBlockCreation,
+ WebGLAllowCreation,
+ WebGLPendingCreation
+};
+
+enum class LockHistory {
+ Yes,
+ No
+};
+
+enum class LockBackForwardList {
+ Yes,
+ No
+};
+
+enum class AllowNavigationToInvalidURL {
+ Yes,
+ No
+};
+
+enum class HasInsecureContent {
+ Yes,
+ No,
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/FrameNetworkingContext.h b/Source/WebCore/loader/FrameNetworkingContext.h
index 72415abd3..d87cf9e1f 100644
--- a/Source/WebCore/loader/FrameNetworkingContext.h
+++ b/Source/WebCore/loader/FrameNetworkingContext.h
@@ -17,8 +17,7 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef FrameNetworkingContext_h
-#define FrameNetworkingContext_h
+#pragma once
#include "Document.h"
#include "Frame.h"
@@ -31,16 +30,16 @@ class FrameNetworkingContext : public NetworkingContext {
public:
void invalidate()
{
- m_frame = 0;
+ m_frame = nullptr;
}
- virtual bool shouldClearReferrerOnHTTPSToHTTPRedirect() const
+ bool shouldClearReferrerOnHTTPSToHTTPRedirect() const override
{
// FIXME: PingLoader finishes without a frame, but it should use its document's referrer policy.
if (!m_frame)
return true;
- return m_frame->document()->referrerPolicy() == ReferrerPolicyDefault;
+ return m_frame->document()->referrerPolicy() == ReferrerPolicy::Default;
}
protected:
@@ -52,11 +51,9 @@ protected:
Frame* frame() const { return m_frame; }
private:
- virtual bool isValid() const override { return m_frame; }
+ bool isValid() const override { return m_frame; }
Frame* m_frame;
};
}
-
-#endif // FrameNetworkingContext_h
diff --git a/Source/WebCore/loader/HistoryController.cpp b/Source/WebCore/loader/HistoryController.cpp
index ffd9d32c1..417446ef7 100644
--- a/Source/WebCore/loader/HistoryController.cpp
+++ b/Source/WebCore/loader/HistoryController.cpp
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -41,22 +41,21 @@
#include "FrameTree.h"
#include "FrameView.h"
#include "HistoryItem.h"
+#include "LinkHash.h"
#include "Logging.h"
#include "MainFrame.h"
#include "Page.h"
#include "PageCache.h"
-#include "PageGroup.h"
-#include "PlatformStrategies.h"
#include "ScrollingCoordinator.h"
-#include "Settings.h"
-#include "VisitedLinkStrategy.h"
+#include "SerializedScriptValue.h"
+#include "VisitedLinkStore.h"
#include <wtf/text/CString.h>
namespace WebCore {
-static inline void addVisitedLink(Page* page, const URL& url)
+static inline void addVisitedLink(Page& page, const URL& url)
{
- platformStrategies()->visitedLinkStrategy()->addVisitedLink(page, visitedLinkHash(url.string()));
+ page.visitedLinkStore().addVisitedLink(page, visitedLinkHash(url.string()));
}
HistoryController::HistoryController(Frame& frame)
@@ -72,20 +71,33 @@ HistoryController::~HistoryController()
void HistoryController::saveScrollPositionAndViewStateToItem(HistoryItem* item)
{
- if (!item || !m_frame.view())
+ FrameView* frameView = m_frame.view();
+ if (!item || !frameView)
return;
- if (m_frame.document()->inPageCache())
- item->setScrollPoint(m_frame.view()->cachedScrollPosition());
+ if (m_frame.document()->pageCacheState() != Document::NotInPageCache)
+ item->setScrollPosition(frameView->cachedScrollPosition());
else
- item->setScrollPoint(m_frame.view()->scrollPosition());
+ item->setScrollPosition(frameView->scrollPosition());
+
+#if PLATFORM(IOS)
+ item->setExposedContentRect(frameView->exposedContentRect());
+ item->setUnobscuredContentRect(frameView->unobscuredContentRect());
+#endif
Page* page = m_frame.page();
- if (page && m_frame.isMainFrame())
- item->setPageScaleFactor(page->pageScaleFactor());
+ if (page && m_frame.isMainFrame()) {
+ item->setPageScaleFactor(page->pageScaleFactor() / page->viewScaleFactor());
+#if PLATFORM(IOS)
+ item->setObscuredInset(page->obscuredInset());
+#endif
+ }
// FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client.
- m_frame.loader().client().saveViewStateToItem(item);
+ m_frame.loader().client().saveViewStateToItem(*item);
+
+ // Notify clients that the HistoryItem has changed.
+ item->notifyChanged();
}
void HistoryController::clearScrollPositionAndViewState()
@@ -93,7 +105,7 @@ void HistoryController::clearScrollPositionAndViewState()
if (!m_currentItem)
return;
- m_currentItem->clearScrollPoint();
+ m_currentItem->clearScrollPosition();
m_currentItem->setPageScaleFactor(0);
}
@@ -110,7 +122,7 @@ void HistoryController::clearScrollPositionAndViewState()
*/
void HistoryController::restoreScrollPositionAndViewState()
{
- if (!m_frame.loader().stateMachine()->committedFirstRealDocumentLoad())
+ if (!m_frame.loader().stateMachine().committedFirstRealDocumentLoad())
return;
ASSERT(m_currentItem);
@@ -122,31 +134,44 @@ void HistoryController::restoreScrollPositionAndViewState()
// so there *is* no scroll or view state to restore!
if (!m_currentItem)
return;
-
- // FIXME: It would be great to work out a way to put this code in WebCore instead of calling
- // through to the client. It's currently used only for the PDF view on Mac.
- m_frame.loader().client().restoreViewState();
- // Don't restore scroll point on iOS as FrameLoaderClient::restoreViewState() does that.
-#if !PLATFORM(IOS)
+ FrameView* view = m_frame.view();
+
// FIXME: There is some scrolling related work that needs to happen whenever a page goes into the
// page cache and similar work that needs to occur when it comes out. This is where we do the work
// that needs to happen when we exit, and the work that needs to happen when we enter is in
// Document::setIsInPageCache(bool). It would be nice if there was more symmetry in these spots.
// https://bugs.webkit.org/show_bug.cgi?id=98698
- if (FrameView* view = m_frame.view()) {
+ if (view) {
Page* page = m_frame.page();
if (page && m_frame.isMainFrame()) {
if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
- scrollingCoordinator->frameViewRootLayerDidChange(view);
+ scrollingCoordinator->frameViewRootLayerDidChange(*view);
}
+ }
+
+ // FIXME: It would be great to work out a way to put this code in WebCore instead of calling
+ // through to the client.
+ m_frame.loader().client().restoreViewState();
- if (!view->wasScrolledByUser()) {
- if (page && m_frame.isMainFrame() && m_currentItem->pageScaleFactor())
- page->setPageScaleFactor(m_currentItem->pageScaleFactor(), m_currentItem->scrollPoint());
- else
- view->setScrollPosition(m_currentItem->scrollPoint());
+#if !PLATFORM(IOS)
+ // Don't restore scroll point on iOS as FrameLoaderClient::restoreViewState() does that.
+ if (view && !view->wasScrolledByUser()) {
+ Page* page = m_frame.page();
+ auto desiredScrollPosition = m_currentItem->scrollPosition();
+ LOG(Scrolling, "HistoryController::restoreScrollPositionAndViewState scrolling to %d,%d", desiredScrollPosition.x(), desiredScrollPosition.y());
+ if (page && m_frame.isMainFrame() && m_currentItem->pageScaleFactor())
+ page->setPageScaleFactor(m_currentItem->pageScaleFactor() * page->viewScaleFactor(), desiredScrollPosition);
+ else
+ view->setScrollPosition(desiredScrollPosition);
+
+ // If the scroll position doesn't have to be clamped, consider it successfully restored.
+ if (m_frame.isMainFrame()) {
+ auto adjustedDesiredScrollPosition = view->adjustScrollPositionWithinRange(desiredScrollPosition);
+ if (desiredScrollPosition == adjustedDesiredScrollPosition)
+ m_frame.loader().client().didRestoreScrollPosition();
}
+
}
#endif
}
@@ -160,7 +185,7 @@ void HistoryController::saveDocumentState()
{
// FIXME: Reading this bit of FrameLoader state here is unfortunate. I need to study
// this more to see if we can remove this dependency.
- if (m_frame.loader().stateMachine()->creatingInitialEmptyDocument())
+ if (m_frame.loader().stateMachine().creatingInitialEmptyDocument())
return;
// For a standard page load, we will have a previous item set, which will be used to
@@ -178,12 +203,14 @@ void HistoryController::saveDocumentState()
if (!item)
return;
- Document* document = m_frame.document();
- ASSERT(document);
-
- if (item->isCurrentDocument(document) && document->hasLivingRenderTree()) {
+ ASSERT(m_frame.document());
+ Document& document = *m_frame.document();
+ if (item->isCurrentDocument(document) && document.hasLivingRenderTree()) {
+ if (DocumentLoader* documentLoader = document.loader())
+ item->setShouldOpenExternalURLsPolicy(documentLoader->shouldOpenExternalURLsPolicyToPropagate());
+
LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame.tree().uniqueName().string().utf8().data(), item);
- item->setDocumentState(document->formElementsState());
+ item->setDocumentState(document.formElementsState());
}
}
@@ -200,18 +227,18 @@ void HistoryController::saveDocumentAndScrollState()
void HistoryController::restoreDocumentState()
{
switch (m_frame.loader().loadType()) {
- case FrameLoadTypeReload:
- case FrameLoadTypeReloadFromOrigin:
- case FrameLoadTypeSame:
- case FrameLoadTypeReplace:
- // Not restoring the document state.
- return;
- case FrameLoadTypeBack:
- case FrameLoadTypeForward:
- case FrameLoadTypeIndexedBackForward:
- case FrameLoadTypeRedirectWithLockedBackForwardList:
- case FrameLoadTypeStandard:
- break;
+ case FrameLoadType::Reload:
+ case FrameLoadType::ReloadFromOrigin:
+ case FrameLoadType::Same:
+ case FrameLoadType::Replace:
+ // Not restoring the document state.
+ return;
+ case FrameLoadType::Back:
+ case FrameLoadType::Forward:
+ case FrameLoadType::IndexedBackForward:
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ case FrameLoadType::Standard:
+ break;
}
if (!m_currentItem)
@@ -221,17 +248,21 @@ void HistoryController::restoreDocumentState()
if (m_frame.loader().documentLoader()->isClientRedirect())
return;
+ m_frame.loader().documentLoader()->setShouldOpenExternalURLsPolicy(m_currentItem->shouldOpenExternalURLsPolicy());
+
LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame.tree().uniqueName().string().utf8().data(), m_currentItem.get());
m_frame.document()->setStateForNewFormElements(m_currentItem->documentState());
}
void HistoryController::invalidateCurrentItemCachedPage()
{
- // When we are pre-commit, the currentItem is where any page cache data resides.
- if (!pageCache()->get(currentItem()))
+ if (!currentItem())
return;
- std::unique_ptr<CachedPage> cachedPage = pageCache()->take(currentItem());
+ // When we are pre-commit, the currentItem is where any page cache data resides.
+ std::unique_ptr<CachedPage> cachedPage = PageCache::singleton().take(*currentItem(), m_frame.page());
+ if (!cachedPage)
+ return;
// FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in RenderFlow::detach
// Somehow the PageState object is not properly updated, and is holding onto a stale document.
@@ -239,12 +270,12 @@ void HistoryController::invalidateCurrentItemCachedPage()
ASSERT(cachedPage->document() == m_frame.document());
if (cachedPage->document() == m_frame.document()) {
- cachedPage->document()->setInPageCache(false);
+ cachedPage->document()->setPageCacheState(Document::NotInPageCache);
cachedPage->clear();
}
}
-bool HistoryController::shouldStopLoadingForHistoryItem(HistoryItem* targetItem) const
+bool HistoryController::shouldStopLoadingForHistoryItem(HistoryItem& targetItem) const
{
if (!m_currentItem)
return false;
@@ -258,7 +289,7 @@ bool HistoryController::shouldStopLoadingForHistoryItem(HistoryItem* targetItem)
// Main funnel for navigating to a previous location (back/forward, non-search snap-back)
// This includes recursion to handle loading into framesets properly
-void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type)
+void HistoryController::goToItem(HistoryItem& targetItem, FrameLoadType type)
{
ASSERT(!m_frame.tree().parent());
@@ -269,26 +300,27 @@ void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type)
Page* page = m_frame.page();
if (!page)
return;
- if (!m_frame.loader().client().shouldGoToHistoryItem(targetItem))
+ if (!m_frame.loader().client().shouldGoToHistoryItem(&targetItem))
return;
if (m_defersLoading) {
- m_deferredItem = targetItem;
+ m_deferredItem = &targetItem;
m_deferredFrameLoadType = type;
return;
}
// Set the BF cursor before commit, which lets the user quickly click back/forward again.
- // - plus, it only makes sense for the top level of the operation through the frametree,
+ // - plus, it only makes sense for the top level of the operation through the frame tree,
// as opposed to happening for some/one of the page commits that might happen soon
RefPtr<HistoryItem> currentItem = page->backForward().currentItem();
- page->backForward().setCurrentItem(targetItem);
+ page->backForward().setCurrentItem(&targetItem);
m_frame.loader().client().updateGlobalHistoryItemForPage();
// First set the provisional item of any frames that are not actually navigating.
// This must be done before trying to navigate the desired frame, because some
// navigations can commit immediately (such as about:blank). We must be sure that
// all frames have provisional items set before the commit.
- recursiveSetProvisionalItem(targetItem, currentItem.get(), type);
+ recursiveSetProvisionalItem(targetItem, currentItem.get());
+
// Now that all other frames have provisional items, do the actual navigation.
recursiveGoToItem(targetItem, currentItem.get(), type);
}
@@ -297,17 +329,14 @@ void HistoryController::setDefersLoading(bool defer)
{
m_defersLoading = defer;
if (!defer && m_deferredItem) {
- goToItem(m_deferredItem.get(), m_deferredFrameLoadType);
- m_deferredItem = 0;
+ goToItem(*m_deferredItem, m_deferredFrameLoadType);
+ m_deferredItem = nullptr;
}
}
void HistoryController::updateForBackForwardNavigation()
{
-#if !LOG_DISABLED
- if (m_frame.loader().documentLoader())
- LOG(History, "WebCoreHistory: Updating History for back/forward navigation in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data());
-#endif
+ LOG(History, "HistoryController %p updateForBackForwardNavigation: Updating History for back/forward navigation in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : "");
// Must grab the current scroll position before disturbing it
if (!m_frameLoadComplete)
@@ -320,16 +349,16 @@ void HistoryController::updateForBackForwardNavigation()
void HistoryController::updateForReload()
{
-#if !LOG_DISABLED
- if (m_frame.loader().documentLoader())
- LOG(History, "WebCoreHistory: Updating History for reload in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data());
-#endif
+ LOG(History, "HistoryController %p updateForReload: Updating History for reload in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : "");
if (m_currentItem) {
- pageCache()->remove(m_currentItem.get());
+ PageCache::singleton().remove(*m_currentItem);
- if (m_frame.loader().loadType() == FrameLoadTypeReload || m_frame.loader().loadType() == FrameLoadTypeReloadFromOrigin)
+ if (m_frame.loader().loadType() == FrameLoadType::Reload || m_frame.loader().loadType() == FrameLoadType::ReloadFromOrigin)
saveScrollPositionAndViewStateToItem(m_currentItem.get());
+
+ // Rebuild the history item tree when reloading as trying to re-associate everything is too error-prone.
+ m_currentItem->clearChildren();
}
// When reloading the page, we may end up redirecting to a different URL
@@ -345,11 +374,11 @@ void HistoryController::updateForReload()
void HistoryController::updateForStandardLoad(HistoryUpdateType updateType)
{
- LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s", m_frame.loader().documentLoader()->url().string().ascii().data());
+ LOG(History, "HistoryController %p updateForStandardLoad: Updating History for standard load in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader()->url().string().ascii().data());
FrameLoader& frameLoader = m_frame.loader();
- bool needPrivacy = m_frame.settings().privateBrowsingEnabled();
+ bool needPrivacy = m_frame.page()->usesEphemeralSession();
const URL& historyURL = frameLoader.documentLoader()->urlForHistory();
if (!frameLoader.documentLoader()->isClientRedirect()) {
@@ -372,7 +401,7 @@ void HistoryController::updateForStandardLoad(HistoryUpdateType updateType)
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame.page())
- addVisitedLink(page, historyURL);
+ addVisitedLink(*page, historyURL);
if (!frameLoader.documentLoader()->didCreateGlobalHistoryEntry() && frameLoader.documentLoader()->unreachableURL().isEmpty() && !m_frame.document()->url().isEmpty())
frameLoader.client().updateGlobalHistoryRedirectLinks();
@@ -381,12 +410,9 @@ void HistoryController::updateForStandardLoad(HistoryUpdateType updateType)
void HistoryController::updateForRedirectWithLockedBackForwardList()
{
-#if !LOG_DISABLED
- if (m_frame.loader().documentLoader())
- LOG(History, "WebCoreHistory: Updating History for redirect load in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data());
-#endif
+ LOG(History, "HistoryController %p updateForRedirectWithLockedBackForwardList: Updating History for redirect load in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : "");
- bool needPrivacy = m_frame.settings().privateBrowsingEnabled();
+ bool needPrivacy = m_frame.page()->usesEphemeralSession();
const URL& historyURL = m_frame.loader().documentLoader()->urlForHistory();
if (m_frame.loader().documentLoader()->isClientRedirect()) {
@@ -413,7 +439,7 @@ void HistoryController::updateForRedirectWithLockedBackForwardList()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame.page())
- addVisitedLink(page, historyURL);
+ addVisitedLink(*page, historyURL);
if (!m_frame.loader().documentLoader()->didCreateGlobalHistoryEntry() && m_frame.loader().documentLoader()->unreachableURL().isEmpty() && !m_frame.document()->url().isEmpty())
m_frame.loader().client().updateGlobalHistoryRedirectLinks();
@@ -422,34 +448,29 @@ void HistoryController::updateForRedirectWithLockedBackForwardList()
void HistoryController::updateForClientRedirect()
{
-#if !LOG_DISABLED
- if (m_frame.loader().documentLoader())
- LOG(History, "WebCoreHistory: Updating History for client redirect in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data());
-#endif
+ LOG(History, "HistoryController %p updateForClientRedirect: Updating History for client redirect in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : "");
// Clear out form data so we don't try to restore it into the incoming page. Must happen after
// webcore has closed the URL and saved away the form state.
if (m_currentItem) {
m_currentItem->clearDocumentState();
- m_currentItem->clearScrollPoint();
+ m_currentItem->clearScrollPosition();
}
- bool needPrivacy = m_frame.settings().privateBrowsingEnabled();
+ bool needPrivacy = m_frame.page()->usesEphemeralSession();
const URL& historyURL = m_frame.loader().documentLoader()->urlForHistory();
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame.page())
- addVisitedLink(page, historyURL);
+ addVisitedLink(*page, historyURL);
}
}
void HistoryController::updateForCommit()
{
FrameLoader& frameLoader = m_frame.loader();
-#if !LOG_DISABLED
- if (frameLoader.documentLoader())
- LOG(History, "WebCoreHistory: Updating History for commit in frame %s", frameLoader.documentLoader()->title().string().utf8().data());
-#endif
+ LOG(History, "HistoryController %p updateForCommit: Updating History for commit in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : "");
+
FrameLoadType type = frameLoader.loadType();
if (isBackForwardLoadType(type)
|| isReplaceLoadTypeWithProvisionalItem(type)
@@ -458,11 +479,14 @@ void HistoryController::updateForCommit()
// the provisional item for restoring state.
// Note previousItem must be set before we close the URL, which will
// happen when the data source is made non-provisional below
- m_frameLoadComplete = false;
- m_previousItem = m_currentItem;
+
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=146842
+ // We should always have a provisional item when committing, but we sometimes don't.
+ // Not having one leads to us not having a m_currentItem later, which is also a terrible known issue.
+ // We should get to the bottom of this.
ASSERT(m_provisionalItem);
- m_currentItem = m_provisionalItem;
- m_provisionalItem = 0;
+ setCurrentItem(m_provisionalItem.get());
+ m_provisionalItem = nullptr;
// Tell all other frames in the tree to commit their provisional items and
// restore their scroll position. We'll avoid this frame (which has already
@@ -473,14 +497,14 @@ void HistoryController::updateForCommit()
bool HistoryController::isReplaceLoadTypeWithProvisionalItem(FrameLoadType type)
{
- // Going back to an error page in a subframe can trigger a FrameLoadTypeReplace
+ // Going back to an error page in a subframe can trigger a FrameLoadType::Replace
// while m_provisionalItem is set, so we need to commit it.
- return type == FrameLoadTypeReplace && m_provisionalItem;
+ return type == FrameLoadType::Replace && m_provisionalItem;
}
bool HistoryController::isReloadTypeWithProvisionalItem(FrameLoadType type)
{
- return (type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin) && m_provisionalItem;
+ return (type == FrameLoadType::Reload || type == FrameLoadType::ReloadFromOrigin) && m_provisionalItem;
}
void HistoryController::recursiveUpdateForCommit()
@@ -493,7 +517,7 @@ void HistoryController::recursiveUpdateForCommit()
// For each frame that already had the content the item requested (based on
// (a matching URL and frame tree snapshot), just restore the scroll position.
// Save form state (works from currentItem, since m_frameLoadComplete is true)
- if (m_currentItem && itemsAreClones(m_currentItem.get(), m_provisionalItem.get())) {
+ if (m_currentItem && itemsAreClones(*m_currentItem, m_provisionalItem.get())) {
ASSERT(m_frameLoadComplete);
saveDocumentState();
saveScrollPositionAndViewStateToItem(m_currentItem.get());
@@ -502,10 +526,8 @@ void HistoryController::recursiveUpdateForCommit()
view->setWasScrolledByUser(false);
// Now commit the provisional item
- m_frameLoadComplete = false;
- m_previousItem = m_currentItem;
- m_currentItem = m_provisionalItem;
- m_provisionalItem = 0;
+ setCurrentItem(m_provisionalItem.get());
+ m_provisionalItem = nullptr;
// Restore form state (works from currentItem)
restoreDocumentState();
@@ -524,14 +546,14 @@ void HistoryController::updateForSameDocumentNavigation()
if (m_frame.document()->url().isEmpty())
return;
- if (m_frame.settings().privateBrowsingEnabled())
+ if (m_frame.page()->usesEphemeralSession())
return;
Page* page = m_frame.page();
if (!page)
return;
- addVisitedLink(page, m_frame.document()->url());
+ addVisitedLink(*page, m_frame.document()->url());
m_frame.mainFrame().loader().history().recursiveUpdateForSameDocumentNavigation();
if (m_currentItem) {
@@ -549,14 +571,12 @@ void HistoryController::recursiveUpdateForSameDocumentNavigation()
// The provisional item may represent a different pending navigation.
// Don't commit it if it isn't a same document navigation.
- if (m_currentItem && !m_currentItem->shouldDoSameDocumentNavigationTo(m_provisionalItem.get()))
+ if (m_currentItem && !m_currentItem->shouldDoSameDocumentNavigationTo(*m_provisionalItem))
return;
// Commit the provisional item.
- m_frameLoadComplete = false;
- m_previousItem = m_currentItem;
- m_currentItem = m_provisionalItem;
- m_provisionalItem = 0;
+ setCurrentItem(m_provisionalItem.get());
+ m_provisionalItem = nullptr;
// Iterate over the rest of the tree.
for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
@@ -580,9 +600,9 @@ void HistoryController::setCurrentItem(HistoryItem* item)
void HistoryController::setCurrentItemTitle(const StringWithDirection& title)
{
+ // FIXME: This ignores the title's direction.
if (m_currentItem)
- // FIXME: make use of title.direction() as well.
- m_currentItem->setTitle(title.string());
+ m_currentItem->setTitle(title.string);
}
bool HistoryController::currentItemShouldBeReplaced() const
@@ -591,7 +611,14 @@ bool HistoryController::currentItemShouldBeReplaced() const
// "If the browsing context's session history contains only one Document,
// and that was the about:blank Document created when the browsing context
// was created, then the navigation must be done with replacement enabled."
- return m_currentItem && !m_previousItem && equalIgnoringCase(m_currentItem->urlString(), blankURL());
+ return m_currentItem && !m_previousItem && equalIgnoringASCIICase(m_currentItem->urlString(), blankURL());
+}
+
+void HistoryController::clearPreviousItem()
+{
+ m_previousItem = nullptr;
+ for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
+ child->loader().history().clearPreviousItem();
}
void HistoryController::setProvisionalItem(HistoryItem* item)
@@ -599,7 +626,7 @@ void HistoryController::setProvisionalItem(HistoryItem* item)
m_provisionalItem = item;
}
-void HistoryController::initializeItem(HistoryItem* item)
+void HistoryController::initializeItem(HistoryItem& item)
{
DocumentLoader* documentLoader = m_frame.loader().documentLoader();
ASSERT(documentLoader);
@@ -627,40 +654,37 @@ void HistoryController::initializeItem(HistoryItem* item)
if (originalURL.isEmpty())
originalURL = blankURL();
- Frame* parentFrame = m_frame.tree().parent();
- String parent = parentFrame ? parentFrame->tree().uniqueName() : "";
StringWithDirection title = documentLoader->title();
- item->setURL(url);
- item->setTarget(m_frame.tree().uniqueName());
- item->setParent(parent);
- // FIXME: should store title directionality in history as well.
- item->setTitle(title.string());
- item->setOriginalURLString(originalURL.string());
+ item.setURL(url);
+ item.setTarget(m_frame.tree().uniqueName());
+ // FIXME: Should store the title direction as well.
+ item.setTitle(title.string);
+ item.setOriginalURLString(originalURL.string());
if (!unreachableURL.isEmpty() || documentLoader->response().httpStatusCode() >= 400)
- item->setLastVisitWasFailure(true);
+ item.setLastVisitWasFailure(true);
+
+ item.setShouldOpenExternalURLsPolicy(documentLoader->shouldOpenExternalURLsPolicyToPropagate());
// Save form state if this is a POST
- item->setFormInfoFromRequest(documentLoader->request());
+ item.setFormInfoFromRequest(documentLoader->request());
}
-PassRefPtr<HistoryItem> HistoryController::createItem()
+Ref<HistoryItem> HistoryController::createItem()
{
- RefPtr<HistoryItem> item = HistoryItem::create();
- initializeItem(item.get());
+ Ref<HistoryItem> item = HistoryItem::create();
+ initializeItem(item);
// Set the item for which we will save document state
- m_frameLoadComplete = false;
- m_previousItem = m_currentItem;
- m_currentItem = item;
+ setCurrentItem(item.ptr());
- return item.release();
+ return item;
}
-PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame& targetFrame, bool clipAtTarget)
+Ref<HistoryItem> HistoryController::createItemTree(Frame& targetFrame, bool clipAtTarget)
{
- RefPtr<HistoryItem> bfItem = createItem();
+ Ref<HistoryItem> bfItem = createItem();
if (!m_frameLoadComplete)
saveScrollPositionAndViewStateToItem(m_previousItem.get());
@@ -700,54 +724,47 @@ PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame& targetFrame, bo
// tracking whether each frame already has the content the item requests. If there is
// a match, we set the provisional item and recurse. Otherwise we will reload that
// frame and all its kids in recursiveGoToItem.
-void HistoryController::recursiveSetProvisionalItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type)
+void HistoryController::recursiveSetProvisionalItem(HistoryItem& item, HistoryItem* fromItem)
{
- ASSERT(item);
+ if (!itemsAreClones(item, fromItem))
+ return;
- if (itemsAreClones(item, fromItem)) {
- // Set provisional item, which will be committed in recursiveUpdateForCommit.
- m_provisionalItem = item;
+ // Set provisional item, which will be committed in recursiveUpdateForCommit.
+ m_provisionalItem = &item;
- const HistoryItemVector& childItems = item->children();
+ for (auto& childItem : item.children()) {
+ const String& childFrameName = childItem->target();
- int size = childItems.size();
+ HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName);
+ ASSERT(fromChildItem);
+ Frame* childFrame = m_frame.tree().child(childFrameName);
+ ASSERT(childFrame);
- for (int i = 0; i < size; ++i) {
- String childFrameName = childItems[i]->target();
- HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName);
- ASSERT(fromChildItem);
- Frame* childFrame = m_frame.tree().child(childFrameName);
- ASSERT(childFrame);
- childFrame->loader().history().recursiveSetProvisionalItem(childItems[i].get(), fromChildItem, type);
- }
+ childFrame->loader().history().recursiveSetProvisionalItem(childItem, fromChildItem);
}
}
// We now traverse the frame tree and item tree a second time, loading frames that
// do have the content the item requests.
-void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type)
-{
- ASSERT(item);
-
- if (itemsAreClones(item, fromItem)) {
- // Just iterate over the rest, looking for frames to navigate.
- const HistoryItemVector& childItems = item->children();
-
- int size = childItems.size();
- for (int i = 0; i < size; ++i) {
- String childFrameName = childItems[i]->target();
- HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName);
- ASSERT(fromChildItem);
- Frame* childFrame = m_frame.tree().child(childFrameName);
- ASSERT(childFrame);
- childFrame->loader().history().recursiveGoToItem(childItems[i].get(), fromChildItem, type);
- }
- } else {
+void HistoryController::recursiveGoToItem(HistoryItem& item, HistoryItem* fromItem, FrameLoadType type)
+{
+ if (!itemsAreClones(item, fromItem)) {
m_frame.loader().loadItem(item, type);
+ return;
+ }
+
+ // Just iterate over the rest, looking for frames to navigate.
+ for (auto& childItem : item.children()) {
+ const String& childFrameName = childItem->target();
+
+ HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName);
+ ASSERT(fromChildItem);
+ if (Frame* childFrame = m_frame.tree().child(childFrameName))
+ childFrame->loader().history().recursiveGoToItem(childItem, fromChildItem, type);
}
}
-bool HistoryController::itemsAreClones(HistoryItem* item1, HistoryItem* item2) const
+bool HistoryController::itemsAreClones(HistoryItem& item1, HistoryItem* item2) const
{
// If the item we're going to is a clone of the item we're at, then we do
// not need to load it again. The current frame tree and the frame tree
@@ -756,11 +773,10 @@ bool HistoryController::itemsAreClones(HistoryItem* item1, HistoryItem* item2) c
// a reload. Thus, if item1 and item2 are the same, we need to create a
// new document and should not consider them clones.
// (See http://webkit.org/b/35532 for details.)
- return item1
- && item2
- && item1 != item2
- && item1->itemSequenceNumber() == item2->itemSequenceNumber()
- && currentFramesMatchItem(item1)
+ return item2
+ && &item1 != item2
+ && item1.itemSequenceNumber() == item2->itemSequenceNumber()
+ && currentFramesMatchItem(&item1)
&& item2->hasSameFrames(item1);
}
@@ -770,13 +786,12 @@ bool HistoryController::currentFramesMatchItem(HistoryItem* item) const
if ((!m_frame.tree().uniqueName().isEmpty() || !item->target().isEmpty()) && m_frame.tree().uniqueName() != item->target())
return false;
- const HistoryItemVector& childItems = item->children();
+ const auto& childItems = item->children();
if (childItems.size() != m_frame.tree().childCount())
return false;
- unsigned size = childItems.size();
- for (unsigned i = 0; i < size; ++i) {
- if (!m_frame.tree().child(childItems[i]->target()))
+ for (auto& item : childItems) {
+ if (!m_frame.tree().child(item->target()))
return false;
}
@@ -799,9 +814,10 @@ void HistoryController::updateBackForwardListClippedAtTarget(bool doClip)
FrameLoader& frameLoader = m_frame.mainFrame().loader();
- RefPtr<HistoryItem> topItem = frameLoader.history().createItemTree(m_frame, doClip);
- LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", topItem.get(), m_frame.loader().documentLoader()->url().string().ascii().data());
- page->backForward().addItem(topItem.release());
+ Ref<HistoryItem> topItem = frameLoader.history().createItemTree(m_frame, doClip);
+ LOG(History, "HistoryController %p updateBackForwardListClippedAtTarget: Adding backforward item %p in frame %p (main frame %d) %s", this, topItem.ptr(), &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader()->url().string().utf8().data());
+
+ page->backForward().addItem(WTFMove(topItem));
}
void HistoryController::updateCurrentItem()
@@ -821,7 +837,7 @@ void HistoryController::updateCurrentItem()
// dependent on the document.
bool isTargetItem = m_currentItem->isTargetItem();
m_currentItem->reset();
- initializeItem(m_currentItem.get());
+ initializeItem(*m_currentItem);
m_currentItem->setIsTargetItem(isTargetItem);
} else {
// Even if the final URL didn't change, the form data may have changed.
@@ -829,7 +845,7 @@ void HistoryController::updateCurrentItem()
}
}
-void HistoryController::pushState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
+void HistoryController::pushState(RefPtr<SerializedScriptValue>&& stateObject, const String& title, const String& urlString)
{
if (!m_currentItem)
return;
@@ -838,40 +854,44 @@ void HistoryController::pushState(PassRefPtr<SerializedScriptValue> stateObject,
ASSERT(page);
// Get a HistoryItem tree for the current frame tree.
- RefPtr<HistoryItem> topItem = m_frame.mainFrame().loader().history().createItemTree(m_frame, false);
+ Ref<HistoryItem> topItem = m_frame.mainFrame().loader().history().createItemTree(m_frame, false);
// Override data in the current item (created by createItemTree) to reflect
// the pushState() arguments.
m_currentItem->setTitle(title);
- m_currentItem->setStateObject(stateObject);
+ m_currentItem->setStateObject(WTFMove(stateObject));
m_currentItem->setURLString(urlString);
- page->backForward().addItem(topItem.release());
+ LOG(History, "HistoryController %p pushState: Adding top item %p, setting url of current item %p to %s", this, topItem.ptr(), m_currentItem.get(), urlString.ascii().data());
+
+ page->backForward().addItem(WTFMove(topItem));
- if (m_frame.settings().privateBrowsingEnabled())
+ if (m_frame.page()->usesEphemeralSession())
return;
- addVisitedLink(page, URL(ParsedURLString, urlString));
+ addVisitedLink(*page, URL(ParsedURLString, urlString));
m_frame.loader().client().updateGlobalHistory();
}
-void HistoryController::replaceState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
+void HistoryController::replaceState(RefPtr<SerializedScriptValue>&& stateObject, const String& title, const String& urlString)
{
if (!m_currentItem)
return;
+ LOG(History, "HistoryController %p replaceState: Setting url of current item %p to %s", this, m_currentItem.get(), urlString.ascii().data());
+
if (!urlString.isEmpty())
m_currentItem->setURLString(urlString);
m_currentItem->setTitle(title);
- m_currentItem->setStateObject(stateObject);
- m_currentItem->setFormData(0);
+ m_currentItem->setStateObject(WTFMove(stateObject));
+ m_currentItem->setFormData(nullptr);
m_currentItem->setFormContentType(String());
- if (m_frame.settings().privateBrowsingEnabled())
+ if (m_frame.page()->usesEphemeralSession())
return;
ASSERT(m_frame.page());
- addVisitedLink(m_frame.page(), URL(ParsedURLString, urlString));
+ addVisitedLink(*m_frame.page(), URL(ParsedURLString, urlString));
m_frame.loader().client().updateGlobalHistory();
}
diff --git a/Source/WebCore/loader/HistoryController.h b/Source/WebCore/loader/HistoryController.h
index 5d6c01cb6..3d25e289b 100644
--- a/Source/WebCore/loader/HistoryController.h
+++ b/Source/WebCore/loader/HistoryController.h
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,11 +27,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HistoryController_h
-#define HistoryController_h
+#pragma once
#include "FrameLoaderTypes.h"
-#include "SerializedScriptValue.h"
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
#include <wtf/text/WTFString.h>
@@ -41,24 +39,26 @@ namespace WebCore {
class Frame;
class HistoryItem;
class SerializedScriptValue;
-class StringWithDirection;
+
+struct StringWithDirection;
class HistoryController {
WTF_MAKE_NONCOPYABLE(HistoryController);
+ WTF_MAKE_FAST_ALLOCATED;
public:
enum HistoryUpdateType { UpdateAll, UpdateAllExceptBackForwardList };
explicit HistoryController(Frame&);
~HistoryController();
- void saveScrollPositionAndViewStateToItem(HistoryItem*);
+ WEBCORE_EXPORT void saveScrollPositionAndViewStateToItem(HistoryItem*);
void clearScrollPositionAndViewState();
- void restoreScrollPositionAndViewState();
+ WEBCORE_EXPORT void restoreScrollPositionAndViewState();
void updateBackForwardListForFragmentScroll();
void saveDocumentState();
- void saveDocumentAndScrollState();
+ WEBCORE_EXPORT void saveDocumentAndScrollState();
void restoreDocumentState();
void invalidateCurrentItemCachedPage();
@@ -76,34 +76,35 @@ public:
void setCurrentItem(HistoryItem*);
void setCurrentItemTitle(const StringWithDirection&);
bool currentItemShouldBeReplaced() const;
- void replaceCurrentItem(HistoryItem*);
+ WEBCORE_EXPORT void replaceCurrentItem(HistoryItem*);
HistoryItem* previousItem() const { return m_previousItem.get(); }
+ void clearPreviousItem();
HistoryItem* provisionalItem() const { return m_provisionalItem.get(); }
void setProvisionalItem(HistoryItem*);
- void pushState(PassRefPtr<SerializedScriptValue>, const String& title, const String& url);
- void replaceState(PassRefPtr<SerializedScriptValue>, const String& title, const String& url);
+ void pushState(RefPtr<SerializedScriptValue>&&, const String& title, const String& url);
+ void replaceState(RefPtr<SerializedScriptValue>&&, const String& title, const String& url);
void setDefersLoading(bool);
private:
friend class Page;
- bool shouldStopLoadingForHistoryItem(HistoryItem*) const;
- void goToItem(HistoryItem*, FrameLoadType);
+ bool shouldStopLoadingForHistoryItem(HistoryItem&) const;
+ void goToItem(HistoryItem&, FrameLoadType);
- void initializeItem(HistoryItem*);
- PassRefPtr<HistoryItem> createItem();
- PassRefPtr<HistoryItem> createItemTree(Frame& targetFrame, bool clipAtTarget);
+ void initializeItem(HistoryItem&);
+ Ref<HistoryItem> createItem();
+ Ref<HistoryItem> createItemTree(Frame& targetFrame, bool clipAtTarget);
- void recursiveSetProvisionalItem(HistoryItem*, HistoryItem*, FrameLoadType);
- void recursiveGoToItem(HistoryItem*, HistoryItem*, FrameLoadType);
+ void recursiveSetProvisionalItem(HistoryItem&, HistoryItem*);
+ void recursiveGoToItem(HistoryItem&, HistoryItem*, FrameLoadType);
bool isReplaceLoadTypeWithProvisionalItem(FrameLoadType);
bool isReloadTypeWithProvisionalItem(FrameLoadType);
void recursiveUpdateForCommit();
void recursiveUpdateForSameDocumentNavigation();
- bool itemsAreClones(HistoryItem*, HistoryItem*) const;
+ bool itemsAreClones(HistoryItem&, HistoryItem*) const;
bool currentFramesMatchItem(HistoryItem*) const;
void updateBackForwardListClippedAtTarget(bool doClip);
void updateCurrentItem();
@@ -122,5 +123,3 @@ private:
};
} // namespace WebCore
-
-#endif // HistoryController_h
diff --git a/Source/WebCore/loader/ImageLoader.cpp b/Source/WebCore/loader/ImageLoader.cpp
index 13c32ffa8..b992343ff 100644
--- a/Source/WebCore/loader/ImageLoader.cpp
+++ b/Source/WebCore/loader/ImageLoader.cpp
@@ -29,18 +29,17 @@
#include "Document.h"
#include "Element.h"
#include "Event.h"
+#include "EventNames.h"
#include "EventSender.h"
#include "Frame.h"
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTMLParserIdioms.h"
+#include "Page.h"
#include "RenderImage.h"
-#include "ScriptCallStack.h"
-#include "SecurityOrigin.h"
-
-#if ENABLE(SVG)
#include "RenderSVGImage.h"
-#endif
+#include <wtf/NeverDestroyed.h>
+
#if ENABLE(VIDEO)
#include "RenderVideo.h"
#endif
@@ -55,8 +54,7 @@ template<> struct ValueCheck<WebCore::ImageLoader*> {
{
if (!p)
return;
- ASSERT(p->element());
- ValueCheck<WebCore::Element*>::checkConsistency(p->element());
+ ValueCheck<WebCore::Element*>::checkConsistency(&p->element());
}
};
@@ -67,32 +65,32 @@ namespace WebCore {
static ImageEventSender& beforeLoadEventSender()
{
- DEFINE_STATIC_LOCAL(ImageEventSender, sender, (eventNames().beforeloadEvent));
+ static NeverDestroyed<ImageEventSender> sender(eventNames().beforeloadEvent);
return sender;
}
static ImageEventSender& loadEventSender()
{
- DEFINE_STATIC_LOCAL(ImageEventSender, sender, (eventNames().loadEvent));
+ static NeverDestroyed<ImageEventSender> sender(eventNames().loadEvent);
return sender;
}
static ImageEventSender& errorEventSender()
{
- DEFINE_STATIC_LOCAL(ImageEventSender, sender, (eventNames().errorEvent));
+ static NeverDestroyed<ImageEventSender> sender(eventNames().errorEvent);
return sender;
}
static inline bool pageIsBeingDismissed(Document& document)
{
Frame* frame = document.frame();
- return frame && frame->loader().pageDismissalEventBeingDispatched() != FrameLoader::NoDismissal;
+ return frame && frame->loader().pageDismissalEventBeingDispatched() != FrameLoader::PageDismissalType::None;
}
-ImageLoader::ImageLoader(Element* element)
+ImageLoader::ImageLoader(Element& element)
: m_element(element)
- , m_image(0)
- , m_derefElementTimer(this, &ImageLoader::timerFired)
+ , m_image(nullptr)
+ , m_derefElementTimer(*this, &ImageLoader::timerFired)
, m_hasPendingBeforeLoadEvent(false)
, m_hasPendingLoadEvent(false)
, m_hasPendingErrorEvent(false)
@@ -105,58 +103,51 @@ ImageLoader::ImageLoader(Element* element)
ImageLoader::~ImageLoader()
{
if (m_image)
- m_image->removeClient(this);
+ m_image->removeClient(*this);
- ASSERT(m_hasPendingBeforeLoadEvent || !beforeLoadEventSender().hasPendingEvents(this));
+ ASSERT(m_hasPendingBeforeLoadEvent || !beforeLoadEventSender().hasPendingEvents(*this));
if (m_hasPendingBeforeLoadEvent)
- beforeLoadEventSender().cancelEvent(this);
+ beforeLoadEventSender().cancelEvent(*this);
- ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(this));
+ ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(*this));
if (m_hasPendingLoadEvent)
- loadEventSender().cancelEvent(this);
+ loadEventSender().cancelEvent(*this);
- ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(this));
+ ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(*this));
if (m_hasPendingErrorEvent)
- errorEventSender().cancelEvent(this);
-
- // If the ImageLoader is being destroyed but it is still protecting its image-loading Element,
- // remove that protection here.
- if (m_elementIsProtected)
- m_element->deref();
+ errorEventSender().cancelEvent(*this);
}
-void ImageLoader::setImage(CachedImage* newImage)
+void ImageLoader::clearImage()
{
- setImageWithoutConsideringPendingLoadEvent(newImage);
+ clearImageWithoutConsideringPendingLoadEvent();
// Only consider updating the protection ref-count of the Element immediately before returning
// from this function as doing so might result in the destruction of this ImageLoader.
updatedHasPendingEvent();
}
-void ImageLoader::setImageWithoutConsideringPendingLoadEvent(CachedImage* newImage)
+void ImageLoader::clearImageWithoutConsideringPendingLoadEvent()
{
ASSERT(m_failedLoadURL.isEmpty());
CachedImage* oldImage = m_image.get();
- if (newImage != oldImage) {
- m_image = newImage;
+ if (oldImage) {
+ m_image = nullptr;
if (m_hasPendingBeforeLoadEvent) {
- beforeLoadEventSender().cancelEvent(this);
+ beforeLoadEventSender().cancelEvent(*this);
m_hasPendingBeforeLoadEvent = false;
}
if (m_hasPendingLoadEvent) {
- loadEventSender().cancelEvent(this);
+ loadEventSender().cancelEvent(*this);
m_hasPendingLoadEvent = false;
}
if (m_hasPendingErrorEvent) {
- errorEventSender().cancelEvent(this);
+ errorEventSender().cancelEvent(*this);
m_hasPendingErrorEvent = false;
}
m_imageComplete = true;
- if (newImage)
- newImage->addClient(this);
if (oldImage)
- oldImage->removeClient(this);
+ oldImage->removeClient(*this);
}
if (RenderImageResource* imageResource = renderImageResource())
@@ -165,40 +156,42 @@ void ImageLoader::setImageWithoutConsideringPendingLoadEvent(CachedImage* newIma
void ImageLoader::updateFromElement()
{
- // If we're not making renderers for the page, then don't load images. We don't want to slow
+ // If we're not making renderers for the page, then don't load images. We don't want to slow
// down the raw HTML parsing case by loading images we don't intend to display.
- Document& document = m_element->document();
+ Document& document = element().document();
if (!document.hasLivingRenderTree())
return;
- AtomicString attr = m_element->imageSourceURL();
+ AtomicString attr = element().imageSourceURL();
- if (attr == m_failedLoadURL)
+ // Avoid loading a URL we already failed to load.
+ if (!m_failedLoadURL.isEmpty() && attr == m_failedLoadURL)
return;
// Do not load any image if the 'src' attribute is missing or if it is
// an empty string.
- CachedResourceHandle<CachedImage> newImage = 0;
+ CachedResourceHandle<CachedImage> newImage = nullptr;
if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
- CachedResourceRequest request(ResourceRequest(document.completeURL(sourceURI(attr))));
+ ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
+ options.contentSecurityPolicyImposition = element().isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck;
+ options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set;
+
+ CachedResourceRequest request(ResourceRequest(document.completeURL(sourceURI(attr))), options);
request.setInitiator(element());
- String crossOriginMode = m_element->fastGetAttribute(HTMLNames::crossoriginAttr);
- if (!crossOriginMode.isNull()) {
- StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
- updateRequestForAccessControl(request.mutableResourceRequest(), document.securityOrigin(), allowCredentials);
- }
+ request.setAsPotentiallyCrossOrigin(element().attributeWithoutSynchronization(HTMLNames::crossoriginAttr), document);
if (m_loadManually) {
- bool autoLoadOtherImages = document.cachedResourceLoader()->autoLoadImages();
- document.cachedResourceLoader()->setAutoLoadImages(false);
- newImage = new CachedImage(request.resourceRequest());
+ bool autoLoadOtherImages = document.cachedResourceLoader().autoLoadImages();
+ document.cachedResourceLoader().setAutoLoadImages(false);
+ newImage = new CachedImage(WTFMove(request), m_element.document().page()->sessionID());
+ newImage->setStatus(CachedResource::Pending);
newImage->setLoading(true);
- newImage->setOwningCachedResourceLoader(document.cachedResourceLoader());
- document.cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage.get());
- document.cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages);
+ newImage->setOwningCachedResourceLoader(&document.cachedResourceLoader());
+ document.cachedResourceLoader().m_documentResources.set(newImage->url(), newImage.get());
+ document.cachedResourceLoader().setAutoLoadImages(autoLoadOtherImages);
} else
- newImage = document.cachedResourceLoader()->requestImage(request);
+ newImage = document.cachedResourceLoader().requestImage(WTFMove(request));
// If we do not have an image here, it means that a cross-site
// violation occurred, or that the image was blocked via Content
@@ -207,24 +200,24 @@ void ImageLoader::updateFromElement()
if (!newImage && !pageIsBeingDismissed(document)) {
m_failedLoadURL = attr;
m_hasPendingErrorEvent = true;
- errorEventSender().dispatchEventSoon(this);
+ errorEventSender().dispatchEventSoon(*this);
} else
clearFailedLoadURL();
} else if (!attr.isNull()) {
// Fire an error event if the url is empty.
m_failedLoadURL = attr;
m_hasPendingErrorEvent = true;
- errorEventSender().dispatchEventSoon(this);
+ errorEventSender().dispatchEventSoon(*this);
}
-
+
CachedImage* oldImage = m_image.get();
if (newImage != oldImage) {
if (m_hasPendingBeforeLoadEvent) {
- beforeLoadEventSender().cancelEvent(this);
+ beforeLoadEventSender().cancelEvent(*this);
m_hasPendingBeforeLoadEvent = false;
}
if (m_hasPendingLoadEvent) {
- loadEventSender().cancelEvent(this);
+ loadEventSender().cancelEvent(*this);
m_hasPendingLoadEvent = false;
}
@@ -233,7 +226,7 @@ void ImageLoader::updateFromElement()
// this load and we should not cancel the event.
// FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
if (m_hasPendingErrorEvent && newImage) {
- errorEventSender().cancelEvent(this);
+ errorEventSender().cancelEvent(*this);
m_hasPendingErrorEvent = false;
}
@@ -247,17 +240,19 @@ void ImageLoader::updateFromElement()
if (!document.hasListenerType(Document::BEFORELOAD_LISTENER))
dispatchPendingBeforeLoadEvent();
else
- beforeLoadEventSender().dispatchEventSoon(this);
+ beforeLoadEventSender().dispatchEventSoon(*this);
} else
updateRenderer();
// If newImage is cached, addClient() will result in the load event
// being queued to fire. Ensure this happens after beforeload is
// dispatched.
- newImage->addClient(this);
+ newImage->addClient(*this);
+ }
+ if (oldImage) {
+ oldImage->removeClient(*this);
+ updateRenderer();
}
- if (oldImage)
- oldImage->removeClient(this);
}
if (RenderImageResource* imageResource = renderImageResource())
@@ -274,10 +269,10 @@ void ImageLoader::updateFromElementIgnoringPreviousError()
updateFromElement();
}
-void ImageLoader::notifyFinished(CachedResource* resource)
+void ImageLoader::notifyFinished(CachedResource& resource)
{
ASSERT(m_failedLoadURL.isEmpty());
- ASSERT(resource == m_image.get());
+ ASSERT_UNUSED(resource, &resource == m_image.get());
m_imageComplete = true;
if (!hasPendingBeforeLoadEvent())
@@ -286,17 +281,14 @@ void ImageLoader::notifyFinished(CachedResource* resource)
if (!m_hasPendingLoadEvent)
return;
- if (m_element->fastHasAttribute(HTMLNames::crossoriginAttr)
- && !m_element->document().securityOrigin()->canRequest(image()->response().url())
- && !resource->passesAccessControlCheck(m_element->document().securityOrigin())) {
-
- setImageWithoutConsideringPendingLoadEvent(0);
+ if (m_image->resourceError().isAccessControl()) {
+ clearImageWithoutConsideringPendingLoadEvent();
m_hasPendingErrorEvent = true;
- errorEventSender().dispatchEventSoon(this);
+ errorEventSender().dispatchEventSoon(*this);
- DEFINE_STATIC_LOCAL(String, consoleMessage, (ASCIILiteral("Cross-origin image load denied by Cross-Origin Resource Sharing policy.")));
- m_element->document().addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, consoleMessage);
+ static NeverDestroyed<String> consoleMessage(ASCIILiteral("Cross-origin image load denied by Cross-Origin Resource Sharing policy."));
+ element().document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
ASSERT(!m_hasPendingLoadEvent);
@@ -306,7 +298,7 @@ void ImageLoader::notifyFinished(CachedResource* resource)
return;
}
- if (resource->wasCanceled()) {
+ if (m_image->wasCanceled()) {
m_hasPendingLoadEvent = false;
// Only consider updating the protection ref-count of the Element immediately before returning
// from this function as doing so might result in the destruction of this ImageLoader.
@@ -314,28 +306,26 @@ void ImageLoader::notifyFinished(CachedResource* resource)
return;
}
- loadEventSender().dispatchEventSoon(this);
+ loadEventSender().dispatchEventSoon(*this);
}
RenderImageResource* ImageLoader::renderImageResource()
{
- auto renderer = m_element->renderer();
+ auto* renderer = element().renderer();
if (!renderer)
return nullptr;
// We don't return style generated image because it doesn't belong to the ImageLoader.
// See <https://bugs.webkit.org/show_bug.cgi?id=42840>
- if (renderer->isRenderImage() && !toRenderImage(*renderer).isGeneratedContent())
- return &toRenderImage(*renderer).imageResource();
+ if (is<RenderImage>(*renderer) && !downcast<RenderImage>(*renderer).isGeneratedContent())
+ return &downcast<RenderImage>(*renderer).imageResource();
-#if ENABLE(SVG)
- if (renderer->isSVGImage())
- return &toRenderSVGImage(renderer)->imageResource();
-#endif
+ if (is<RenderSVGImage>(*renderer))
+ return &downcast<RenderSVGImage>(*renderer).imageResource();
#if ENABLE(VIDEO)
- if (renderer->isVideo())
- return &toRenderVideo(*renderer).imageResource();
+ if (is<RenderVideo>(*renderer))
+ return &downcast<RenderVideo>(*renderer).imageResource();
#endif
return nullptr;
@@ -349,7 +339,7 @@ void ImageLoader::updateRenderer()
return;
// Only update the renderer if it doesn't have an image or if what we have
- // is a complete image. This prevents flickering in the case where a dynamic
+ // is a complete image. This prevents flickering in the case where a dynamic
// change is happening between two images.
CachedImage* cachedImage = imageResource->cachedImage();
if (m_image != cachedImage && (m_imageComplete || !cachedImage))
@@ -371,16 +361,16 @@ void ImageLoader::updatedHasPendingEvent()
if (m_derefElementTimer.isActive())
m_derefElementTimer.stop();
else
- m_element->ref();
+ m_protectedElement = &element();
} else {
ASSERT(!m_derefElementTimer.isActive());
m_derefElementTimer.startOneShot(0);
}
}
-void ImageLoader::timerFired(Timer<ImageLoader>&)
+void ImageLoader::timerFired()
{
- m_element->deref();
+ m_protectedElement = nullptr;
}
void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender)
@@ -401,23 +391,28 @@ void ImageLoader::dispatchPendingBeforeLoadEvent()
return;
if (!m_image)
return;
- if (!m_element->document().hasLivingRenderTree())
+ if (!element().document().hasLivingRenderTree())
return;
m_hasPendingBeforeLoadEvent = false;
- if (m_element->dispatchBeforeLoadEvent(m_image->url())) {
+ Ref<Document> originalDocument = element().document();
+ if (element().dispatchBeforeLoadEvent(m_image->url())) {
+ bool didEventListenerDisconnectThisElement = !element().isConnected() || &element().document() != originalDocument.ptr();
+ if (didEventListenerDisconnectThisElement)
+ return;
+
updateRenderer();
return;
}
if (m_image) {
- m_image->removeClient(this);
- m_image = 0;
+ m_image->removeClient(*this);
+ m_image = nullptr;
}
- loadEventSender().cancelEvent(this);
+ loadEventSender().cancelEvent(*this);
m_hasPendingLoadEvent = false;
- if (isHTMLObjectElement(m_element))
- toHTMLObjectElement(m_element)->renderFallbackContent();
+ if (is<HTMLObjectElement>(element()))
+ downcast<HTMLObjectElement>(element()).renderFallbackContent();
// Only consider updating the protection ref-count of the Element immediately before returning
// from this function as doing so might result in the destruction of this ImageLoader.
@@ -431,7 +426,7 @@ void ImageLoader::dispatchPendingLoadEvent()
if (!m_image)
return;
m_hasPendingLoadEvent = false;
- if (m_element->document().hasLivingRenderTree())
+ if (element().document().hasLivingRenderTree())
dispatchLoadEvent();
// Only consider updating the protection ref-count of the Element immediately before returning
@@ -444,8 +439,8 @@ void ImageLoader::dispatchPendingErrorEvent()
if (!m_hasPendingErrorEvent)
return;
m_hasPendingErrorEvent = false;
- if (m_element->document().hasLivingRenderTree())
- m_element->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+ if (element().document().hasLivingRenderTree())
+ element().dispatchEvent(Event::create(eventNames().errorEvent, false, false));
// Only consider updating the protection ref-count of the Element immediately before returning
// from this function as doing so might result in the destruction of this ImageLoader.
@@ -470,12 +465,12 @@ void ImageLoader::dispatchPendingErrorEvents()
void ImageLoader::elementDidMoveToNewDocument()
{
clearFailedLoadURL();
- setImage(0);
+ clearImage();
}
inline void ImageLoader::clearFailedLoadURL()
{
- m_failedLoadURL = AtomicString();
+ m_failedLoadURL = nullAtom;
}
}
diff --git a/Source/WebCore/loader/ImageLoader.h b/Source/WebCore/loader/ImageLoader.h
index d76fa3a85..7717667f6 100644
--- a/Source/WebCore/loader/ImageLoader.h
+++ b/Source/WebCore/loader/ImageLoader.h
@@ -20,8 +20,7 @@
*
*/
-#ifndef ImageLoader_h
-#define ImageLoader_h
+#pragma once
#include "CachedImageClient.h"
#include "CachedResourceHandle.h"
@@ -38,8 +37,8 @@ template<typename T> class EventSender;
typedef EventSender<ImageLoader> ImageEventSender;
class ImageLoader : public CachedImageClient {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- explicit ImageLoader(Element*);
virtual ~ImageLoader();
// This function should be called when the element is attached to a document; starts
@@ -52,11 +51,13 @@ public:
void elementDidMoveToNewDocument();
- Element* element() const { return m_element; }
+ Element& element() { return m_element; }
+ const Element& element() const { return m_element; }
+
bool imageComplete() const { return m_imageComplete; }
CachedImage* image() const { return m_image.get(); }
- void setImage(CachedImage*); // Cancels pending beforeload and load events, and doesn't dispatch new ones.
+ void clearImage(); // Cancels pending beforeload and load events, and doesn't dispatch new ones.
void setLoadManually(bool loadManually) { m_loadManually = loadManually; }
@@ -70,7 +71,8 @@ public:
static void dispatchPendingErrorEvents();
protected:
- virtual void notifyFinished(CachedResource*) override;
+ explicit ImageLoader(Element&);
+ void notifyFinished(CachedResource&) override;
private:
virtual void dispatchLoadEvent() = 0;
@@ -85,14 +87,15 @@ private:
RenderImageResource* renderImageResource();
void updateRenderer();
- void setImageWithoutConsideringPendingLoadEvent(CachedImage*);
+ void clearImageWithoutConsideringPendingLoadEvent();
void clearFailedLoadURL();
- void timerFired(Timer<ImageLoader>&);
+ void timerFired();
- Element* m_element;
+ Element& m_element;
CachedResourceHandle<CachedImage> m_image;
- Timer<ImageLoader> m_derefElementTimer;
+ Timer m_derefElementTimer;
+ RefPtr<Element> m_protectedElement;
AtomicString m_failedLoadURL;
bool m_hasPendingBeforeLoadEvent : 1;
bool m_hasPendingLoadEvent : 1;
@@ -103,5 +106,3 @@ private:
};
}
-
-#endif
diff --git a/Source/WebCore/loader/LinkHeader.cpp b/Source/WebCore/loader/LinkHeader.cpp
new file mode 100644
index 000000000..e2546d688
--- /dev/null
+++ b/Source/WebCore/loader/LinkHeader.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2015 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LinkHeader.h"
+
+#include "ParsingUtilities.h"
+
+namespace WebCore {
+
+// LWSP definition in https://www.ietf.org/rfc/rfc0822.txt
+template <typename CharacterType>
+static bool isSpaceOrTab(CharacterType chr)
+{
+ return (chr == ' ') || (chr == '\t');
+}
+
+template <typename CharacterType>
+static bool isNotURLTerminatingChar(CharacterType chr)
+{
+ return (chr != '>');
+}
+
+template <typename CharacterType>
+static bool isValidParameterNameChar(CharacterType chr)
+{
+ // A separator, CTL or '%', '*' or '\'' means the char is not valid.
+ // Definition as attr-char at https://tools.ietf.org/html/rfc5987
+ // CTL and separators are defined in https://tools.ietf.org/html/rfc2616#section-2.2
+ // Valid chars are alpha-numeric and any of !#$&+-.^_`|~"
+ if ((chr >= '^' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || (chr >= '!' && chr <= '$') || chr == '&' || chr == '+' || chr == '-' || chr == '.')
+ return true;
+ return false;
+}
+
+template <typename CharacterType>
+static bool isParameterValueEnd(CharacterType chr)
+{
+ return chr == ';' || chr == ',';
+}
+
+template <typename CharacterType>
+static bool isParameterValueChar(CharacterType chr)
+{
+ return !isSpaceOrTab(chr) && !isParameterValueEnd(chr);
+}
+
+// Verify that the parameter is a link-extension which according to spec doesn't have to have a value.
+static bool isExtensionParameter(LinkHeader::LinkParameterName name)
+{
+ return name >= LinkHeader::LinkParameterUnknown;
+}
+
+// Before:
+//
+// <cat.jpg>; rel=preload
+// ^ ^
+// position end
+//
+// After (if successful: otherwise the method returns false)
+//
+// <cat.jpg>; rel=preload
+// ^ ^
+// position end
+template <typename CharacterType>
+static std::optional<String> findURLBoundaries(CharacterType*& position, CharacterType* const end)
+{
+ ASSERT(position <= end);
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+ if (!skipExactly<CharacterType>(position, end, '<'))
+ return std::nullopt;
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+
+ CharacterType* urlStart = position;
+ skipWhile<CharacterType, isNotURLTerminatingChar>(position, end);
+ CharacterType* urlEnd = position;
+ skipUntil<CharacterType>(position, end, '>');
+ if (!skipExactly<CharacterType>(position, end, '>'))
+ return std::nullopt;
+
+ return String(urlStart, urlEnd - urlStart);
+}
+
+template <typename CharacterType>
+static bool invalidParameterDelimiter(CharacterType*& position, CharacterType* const end)
+{
+ ASSERT(position <= end);
+ return (!skipExactly<CharacterType>(position, end, ';') && (position < end) && (*position != ','));
+}
+
+template <typename CharacterType>
+static bool validFieldEnd(CharacterType*& position, CharacterType* const end)
+{
+ ASSERT(position <= end);
+ return (position == end || *position == ',');
+}
+
+// Before:
+//
+// <cat.jpg>; rel=preload
+// ^ ^
+// position end
+//
+// After (if successful: otherwise the method returns false, and modifies the isValid boolean accordingly)
+//
+// <cat.jpg>; rel=preload
+// ^ ^
+// position end
+template <typename CharacterType>
+static bool parseParameterDelimiter(CharacterType*& position, CharacterType* const end, bool& isValid)
+{
+ ASSERT(position <= end);
+ isValid = true;
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+ if (invalidParameterDelimiter(position, end)) {
+ isValid = false;
+ return false;
+ }
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+ if (validFieldEnd(position, end))
+ return false;
+ return true;
+}
+
+static LinkHeader::LinkParameterName paramterNameFromString(String name)
+{
+ if (equalLettersIgnoringASCIICase(name, "rel"))
+ return LinkHeader::LinkParameterRel;
+ if (equalLettersIgnoringASCIICase(name, "anchor"))
+ return LinkHeader::LinkParameterAnchor;
+ if (equalLettersIgnoringASCIICase(name, "crossorigin"))
+ return LinkHeader::LinkParameterCrossOrigin;
+ if (equalLettersIgnoringASCIICase(name, "title"))
+ return LinkHeader::LinkParameterTitle;
+ if (equalLettersIgnoringASCIICase(name, "media"))
+ return LinkHeader::LinkParameterMedia;
+ if (equalLettersIgnoringASCIICase(name, "type"))
+ return LinkHeader::LinkParameterType;
+ if (equalLettersIgnoringASCIICase(name, "rev"))
+ return LinkHeader::LinkParameterRev;
+ if (equalLettersIgnoringASCIICase(name, "hreflang"))
+ return LinkHeader::LinkParameterHreflang;
+ if (equalLettersIgnoringASCIICase(name, "as"))
+ return LinkHeader::LinkParameterAs;
+ return LinkHeader::LinkParameterUnknown;
+}
+
+// Before:
+//
+// <cat.jpg>; rel=preload
+// ^ ^
+// position end
+//
+// After (if successful: otherwise the method returns false)
+//
+// <cat.jpg>; rel=preload
+// ^ ^
+// position end
+template <typename CharacterType>
+static bool parseParameterName(CharacterType*& position, CharacterType* const end, LinkHeader::LinkParameterName& name)
+{
+ ASSERT(position <= end);
+ CharacterType* nameStart = position;
+ skipWhile<CharacterType, isValidParameterNameChar>(position, end);
+ CharacterType* nameEnd = position;
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+ bool hasEqual = skipExactly<CharacterType>(position, end, '=');
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+ name = paramterNameFromString(String(nameStart, nameEnd - nameStart));
+ if (hasEqual)
+ return true;
+ bool validParameterValueEnd = (position == end) || isParameterValueEnd(*position);
+ return validParameterValueEnd && isExtensionParameter(name);
+}
+
+// Before:
+//
+// <cat.jpg>; rel="preload"; type="image/jpeg";
+// ^ ^
+// position end
+//
+// After (if the parameter starts with a quote, otherwise the method returns false)
+//
+// <cat.jpg>; rel="preload"; type="image/jpeg";
+// ^ ^
+// position end
+template <typename CharacterType>
+static bool skipQuotesIfNeeded(CharacterType*& position, CharacterType* const end, bool& completeQuotes)
+{
+ ASSERT(position <= end);
+ unsigned char quote;
+ if (skipExactly<CharacterType>(position, end, '\''))
+ quote = '\'';
+ else if (skipExactly<CharacterType>(position, end, '"'))
+ quote = '"';
+ else
+ return false;
+
+ while (!completeQuotes && position < end) {
+ skipUntil(position, end, static_cast<CharacterType>(quote));
+ if (*(position - 1) != '\\')
+ completeQuotes = true;
+ completeQuotes = skipExactly(position, end, static_cast<CharacterType>(quote)) && completeQuotes;
+ }
+ return true;
+}
+
+// Before:
+//
+// <cat.jpg>; rel=preload; foo=bar
+// ^ ^
+// position end
+//
+// After (if successful: otherwise the method returns false)
+//
+// <cat.jpg>; rel=preload; foo=bar
+// ^ ^
+// position end
+template <typename CharacterType>
+static bool parseParameterValue(CharacterType*& position, CharacterType* const end, String& value)
+{
+ ASSERT(position <= end);
+ CharacterType* valueStart = position;
+ CharacterType* valueEnd = position;
+ bool completeQuotes = false;
+ bool hasQuotes = skipQuotesIfNeeded(position, end, completeQuotes);
+ if (!hasQuotes)
+ skipWhile<CharacterType, isParameterValueChar>(position, end);
+ valueEnd = position;
+ skipWhile<CharacterType, isSpaceOrTab>(position, end);
+ if ((!completeQuotes && valueStart == valueEnd) || (position != end && !isParameterValueEnd(*position))) {
+ value = String("");
+ return false;
+ }
+ if (hasQuotes)
+ ++valueStart;
+ if (completeQuotes)
+ --valueEnd;
+ ASSERT(valueEnd >= valueStart);
+ value = String(valueStart, valueEnd - valueStart);
+ return !hasQuotes || completeQuotes;
+}
+
+void LinkHeader::setValue(LinkParameterName name, String value)
+{
+ switch (name) {
+ case LinkParameterRel:
+ if (!m_rel)
+ m_rel = value;
+ break;
+ case LinkParameterAnchor:
+ m_isValid = false;
+ break;
+ case LinkParameterCrossOrigin:
+ m_crossOrigin = value;
+ break;
+ case LinkParameterAs:
+ m_as = value;
+ break;
+ case LinkParameterType:
+ m_mimeType = value;
+ break;
+ case LinkParameterMedia:
+ m_media = value;
+ break;
+ case LinkParameterTitle:
+ case LinkParameterRev:
+ case LinkParameterHreflang:
+ case LinkParameterUnknown:
+ // These parameters are not yet supported, so they are currently ignored.
+ break;
+ }
+ // FIXME: Add support for more header parameters as neccessary.
+}
+
+template <typename CharacterType>
+static void findNextHeader(CharacterType*& position, CharacterType* const end)
+{
+ ASSERT(position <= end);
+ skipUntil<CharacterType>(position, end, ',');
+ skipExactly<CharacterType>(position, end, ',');
+}
+
+template <typename CharacterType>
+LinkHeader::LinkHeader(CharacterType*& position, CharacterType* const end)
+{
+ ASSERT(position <= end);
+ auto urlResult = findURLBoundaries(position, end);
+ if (urlResult == std::nullopt) {
+ m_isValid = false;
+ findNextHeader(position, end);
+ return;
+ }
+ m_url = urlResult.value();
+
+ while (m_isValid && position < end) {
+ if (!parseParameterDelimiter(position, end, m_isValid)) {
+ findNextHeader(position, end);
+ return;
+ }
+
+ LinkParameterName parameterName;
+ if (!parseParameterName(position, end, parameterName)) {
+ findNextHeader(position, end);
+ m_isValid = false;
+ return;
+ }
+
+ String parameterValue;
+ if (!parseParameterValue(position, end, parameterValue) && !isExtensionParameter(parameterName)) {
+ findNextHeader(position, end);
+ m_isValid = false;
+ return;
+ }
+
+ setValue(parameterName, parameterValue);
+ }
+ findNextHeader(position, end);
+}
+
+LinkHeaderSet::LinkHeaderSet(const String& header)
+{
+ if (header.isNull())
+ return;
+
+ if (header.is8Bit())
+ init(header.characters8(), header.length());
+ else
+ init(header.characters16(), header.length());
+}
+
+template <typename CharacterType>
+void LinkHeaderSet::init(CharacterType* headerValue, size_t length)
+{
+ CharacterType* position = headerValue;
+ CharacterType* const end = headerValue + length;
+ while (position < end)
+ m_headerSet.append(LinkHeader(position, end));
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/loader/LinkHeader.h b/Source/WebCore/loader/LinkHeader.h
new file mode 100644
index 000000000..8e3547419
--- /dev/null
+++ b/Source/WebCore/loader/LinkHeader.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class LinkHeader {
+public:
+ template <typename CharacterType>
+ LinkHeader(CharacterType*& position, CharacterType* const end);
+
+ const String& url() const { return m_url; }
+ const String& rel() const { return m_rel; }
+ const String& as() const { return m_as; }
+ const String& mimeType() const { return m_mimeType; }
+ const String& media() const { return m_media; }
+ const String& crossOrigin() const { return m_crossOrigin; }
+ bool valid() const { return m_isValid; }
+
+ enum LinkParameterName {
+ LinkParameterRel,
+ LinkParameterAnchor,
+ LinkParameterTitle,
+ LinkParameterMedia,
+ LinkParameterType,
+ LinkParameterRev,
+ LinkParameterHreflang,
+ // Beyond this point, only link-extension parameters
+ LinkParameterUnknown,
+ LinkParameterCrossOrigin,
+ LinkParameterAs,
+ };
+
+private:
+ void setValue(LinkParameterName, String value);
+
+ String m_url;
+ String m_rel;
+ String m_as;
+ String m_mimeType;
+ String m_media;
+ String m_crossOrigin;
+ bool m_isValid { true };
+};
+
+class LinkHeaderSet {
+public:
+ LinkHeaderSet(const String& header);
+
+ Vector<LinkHeader>::const_iterator begin() const { return m_headerSet.begin(); }
+ Vector<LinkHeader>::const_iterator end() const { return m_headerSet.end(); }
+
+private:
+ template <typename CharacterType>
+ void init(CharacterType* headerValue, size_t length);
+
+ Vector<LinkHeader> m_headerSet;
+};
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/loader/LinkLoader.cpp b/Source/WebCore/loader/LinkLoader.cpp
index e63bbf0c2..9b53ce87d 100644
--- a/Source/WebCore/loader/LinkLoader.cpp
+++ b/Source/WebCore/loader/LinkLoader.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -37,101 +38,208 @@
#include "CachedResourceLoader.h"
#include "CachedResourceRequest.h"
#include "ContainerNode.h"
-#include "DNS.h"
+#include "CrossOriginAccessControl.h"
#include "Document.h"
#include "Frame.h"
+#include "FrameLoaderClient.h"
#include "FrameView.h"
+#include "LinkHeader.h"
+#include "LinkPreloadResourceClients.h"
#include "LinkRelAttribute.h"
+#include "RuntimeEnabledFeatures.h"
#include "Settings.h"
#include "StyleResolver.h"
namespace WebCore {
-LinkLoader::LinkLoader(LinkLoaderClient* client)
+LinkLoader::LinkLoader(LinkLoaderClient& client)
: m_client(client)
- , m_linkLoadTimer(this, &LinkLoader::linkLoadTimerFired)
- , m_linkLoadingErrorTimer(this, &LinkLoader::linkLoadingErrorTimerFired)
+ , m_weakPtrFactory(this)
{
}
LinkLoader::~LinkLoader()
{
if (m_cachedLinkResource)
- m_cachedLinkResource->removeClient(this);
+ m_cachedLinkResource->removeClient(*this);
+ if (m_preloadResourceClient)
+ m_preloadResourceClient->clear();
}
-void LinkLoader::linkLoadTimerFired(Timer<LinkLoader>& timer)
+void LinkLoader::triggerEvents(const CachedResource& resource)
{
- ASSERT_UNUSED(timer, &timer == &m_linkLoadTimer);
- m_client->linkLoaded();
+ if (resource.errorOccurred())
+ m_client.linkLoadingErrored();
+ else
+ m_client.linkLoaded();
}
-void LinkLoader::linkLoadingErrorTimerFired(Timer<LinkLoader>& timer)
+void LinkLoader::notifyFinished(CachedResource& resource)
{
- ASSERT_UNUSED(timer, &timer == &m_linkLoadingErrorTimer);
- m_client->linkLoadingErrored();
+ ASSERT_UNUSED(resource, m_cachedLinkResource.get() == &resource);
+
+ triggerEvents(*m_cachedLinkResource);
+
+ m_cachedLinkResource->removeClient(*this);
+ m_cachedLinkResource = nullptr;
}
-void LinkLoader::notifyFinished(CachedResource* resource)
+void LinkLoader::loadLinksFromHeader(const String& headerValue, const URL& baseURL, Document& document)
{
- ASSERT_UNUSED(resource, m_cachedLinkResource.get() == resource);
+ if (headerValue.isEmpty())
+ return;
+ LinkHeaderSet headerSet(headerValue);
+ for (auto& header : headerSet) {
+ if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty())
+ continue;
+
+ LinkRelAttribute relAttribute(header.rel());
+ URL url(baseURL, header.url());
+ // Sanity check to avoid re-entrancy here.
+ if (equalIgnoringFragmentIdentifier(url, baseURL))
+ continue;
+ preloadIfNeeded(relAttribute, url, document, header.as(), header.crossOrigin(), nullptr, nullptr);
+ }
+}
- if (m_cachedLinkResource->errorOccurred())
- m_linkLoadingErrorTimer.startOneShot(0);
- else
- m_linkLoadTimer.startOneShot(0);
+std::optional<CachedResource::Type> LinkLoader::resourceTypeFromAsAttribute(const String& as)
+{
+ if (as.isEmpty())
+ return CachedResource::RawResource;
+ if (equalLettersIgnoringASCIICase(as, "image"))
+ return CachedResource::ImageResource;
+ if (equalLettersIgnoringASCIICase(as, "script"))
+ return CachedResource::Script;
+ if (equalLettersIgnoringASCIICase(as, "style"))
+ return CachedResource::CSSStyleSheet;
+ if (equalLettersIgnoringASCIICase(as, "media"))
+ return CachedResource::MediaResource;
+ if (equalLettersIgnoringASCIICase(as, "font"))
+ return CachedResource::FontResource;
+#if ENABLE(VIDEO_TRACK)
+ if (equalLettersIgnoringASCIICase(as, "track"))
+ return CachedResource::TextTrackResource;
+#endif
+ return std::nullopt;
+}
- m_cachedLinkResource->removeClient(this);
- m_cachedLinkResource = 0;
+static std::unique_ptr<LinkPreloadResourceClient> createLinkPreloadResourceClient(CachedResource& resource, LinkLoader& loader, CachedResource::Type type)
+{
+ switch (type) {
+ case CachedResource::ImageResource:
+ return LinkPreloadImageResourceClient::create(loader, static_cast<CachedImage&>(resource));
+ case CachedResource::Script:
+ return LinkPreloadScriptResourceClient::create(loader, static_cast<CachedScript&>(resource));
+ case CachedResource::CSSStyleSheet:
+ return LinkPreloadStyleResourceClient::create(loader, static_cast<CachedCSSStyleSheet&>(resource));
+ case CachedResource::FontResource:
+ return LinkPreloadFontResourceClient::create(loader, static_cast<CachedFont&>(resource));
+ case CachedResource::MediaResource:
+#if ENABLE(VIDEO_TRACK)
+ case CachedResource::TextTrackResource:
+#endif
+ case CachedResource::RawResource:
+ return LinkPreloadRawResourceClient::create(loader, static_cast<CachedRawResource&>(resource));
+ case CachedResource::MainResource:
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
+ case CachedResource::SVGDocumentResource:
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+#endif
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkSubresource:
+ case CachedResource::LinkPrefetch:
+#endif
+ // None of these values is currently supported as an `as` value.
+ ASSERT_NOT_REACHED();
+ }
+ return nullptr;
}
-bool LinkLoader::loadLink(const LinkRelAttribute& relAttribute, const String& type,
- const String& sizes, const URL& href, Document* document)
+std::unique_ptr<LinkPreloadResourceClient> LinkLoader::preloadIfNeeded(const LinkRelAttribute& relAttribute, const URL& href, Document& document, const String& as, const String& crossOriginMode, LinkLoader* loader, LinkLoaderClient* client)
{
- // We'll record this URL per document, even if we later only use it in top level frames
- if (relAttribute.m_iconType != InvalidIcon && href.isValid() && !href.isEmpty()) {
- if (!m_client->shouldLoadLink())
- return false;
- document->addIconURL(href.string(), type, sizes, relAttribute.m_iconType);
+ if (!document.loader() || !relAttribute.isLinkPreload)
+ return nullptr;
+
+ ASSERT(RuntimeEnabledFeatures::sharedFeatures().linkPreloadEnabled());
+ if (!href.isValid()) {
+ document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, String("<link rel=preload> has an invalid `href` value"));
+ return nullptr;
}
+ auto type = LinkLoader::resourceTypeFromAsAttribute(as);
+ if (!type) {
+ document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, String("<link rel=preload> must have a valid `as` value"));
+ if (client)
+ client->linkLoadingErrored();
+ return nullptr;
+ }
+
+ ResourceRequest resourceRequest(document.completeURL(href));
+ resourceRequest.setIgnoreForRequestCount(true);
+ CachedResourceRequest linkRequest(WTFMove(resourceRequest), CachedResourceLoader::defaultCachedResourceOptions(), CachedResource::defaultPriorityForResourceType(type.value()));
+ linkRequest.setInitiator("link");
+ linkRequest.setIsLinkPreload();
+
+ linkRequest.setAsPotentiallyCrossOrigin(crossOriginMode, document);
+ CachedResourceHandle<CachedResource> cachedLinkResource = document.cachedResourceLoader().preload(type.value(), WTFMove(linkRequest));
+
+ if (cachedLinkResource && loader)
+ return createLinkPreloadResourceClient(*cachedLinkResource, *loader, type.value());
+ return nullptr;
+}
+
+void LinkLoader::cancelLoad()
+{
+ if (m_preloadResourceClient)
+ m_preloadResourceClient->clear();
+}
- if (relAttribute.m_isDNSPrefetch) {
- Settings* settings = document->settings();
+bool LinkLoader::loadLink(const LinkRelAttribute& relAttribute, const URL& href, const String& as, const String& crossOrigin, Document& document)
+{
+ if (relAttribute.isDNSPrefetch) {
// FIXME: The href attribute of the link element can be in "//hostname" form, and we shouldn't attempt
// to complete that as URL <https://bugs.webkit.org/show_bug.cgi?id=48857>.
- if (settings && settings->dnsPrefetchingEnabled() && href.isValid() && !href.isEmpty())
- prefetchDNS(href.host());
+ if (document.settings().dnsPrefetchingEnabled() && href.isValid() && !href.isEmpty() && document.frame())
+ document.frame()->loader().client().prefetchDNS(href.host());
+ }
+
+ if (m_client.shouldLoadLink()) {
+ auto resourceClient = preloadIfNeeded(relAttribute, href, document, as, crossOrigin, this, &m_client);
+ if (resourceClient)
+ m_preloadResourceClient = WTFMove(resourceClient);
+ else if (m_preloadResourceClient)
+ m_preloadResourceClient->clear();
}
#if ENABLE(LINK_PREFETCH)
- if ((relAttribute.m_isLinkPrefetch || relAttribute.m_isLinkSubresource) && href.isValid() && document->frame()) {
- if (!m_client->shouldLoadLink())
+ if ((relAttribute.isLinkPrefetch || relAttribute.isLinkSubresource) && href.isValid() && document.frame()) {
+ if (!m_client.shouldLoadLink())
return false;
- ResourceLoadPriority priority = ResourceLoadPriorityUnresolved;
+
+ std::optional<ResourceLoadPriority> priority;
CachedResource::Type type = CachedResource::LinkPrefetch;
- // We only make one request to the cachedresourcelodaer if multiple rel types are
- // specified,
- if (relAttribute.m_isLinkSubresource) {
- priority = ResourceLoadPriorityLow;
+ if (relAttribute.isLinkSubresource) {
+ // We only make one request to the cached resource loader if multiple rel types are specified;
+ // this is the higher priority, which should overwrite the lower priority.
+ priority = ResourceLoadPriority::Low;
type = CachedResource::LinkSubresource;
}
- CachedResourceRequest linkRequest(ResourceRequest(document->completeURL(href)), priority);
-
+
if (m_cachedLinkResource) {
- m_cachedLinkResource->removeClient(this);
- m_cachedLinkResource = 0;
+ m_cachedLinkResource->removeClient(*this);
+ m_cachedLinkResource = nullptr;
}
- m_cachedLinkResource = document->cachedResourceLoader()->requestLinkResource(type, linkRequest);
+ ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
+ options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
+ m_cachedLinkResource = document.cachedResourceLoader().requestLinkResource(type, CachedResourceRequest(ResourceRequest(document.completeURL(href)), options, priority));
if (m_cachedLinkResource)
- m_cachedLinkResource->addClient(this);
+ m_cachedLinkResource->addClient(*this);
}
#endif
return true;
}
-void LinkLoader::released()
-{
-}
-
}
diff --git a/Source/WebCore/loader/LinkLoader.h b/Source/WebCore/loader/LinkLoader.h
index 9b5d8cb76..9c714729d 100644
--- a/Source/WebCore/loader/LinkLoader.h
+++ b/Source/WebCore/loader/LinkLoader.h
@@ -29,46 +29,44 @@
*
*/
-#ifndef LinkLoader_h
-#define LinkLoader_h
+#pragma once
+#include "CachedResource.h"
#include "CachedResourceClient.h"
#include "CachedResourceHandle.h"
#include "LinkLoaderClient.h"
-#include "Timer.h"
-#include <wtf/RefPtr.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
class Document;
class URL;
-struct LinkRelAttribute;
+class LinkPreloadResourceClient;
-// The LinkLoader can load link rel types icon, dns-prefetch, subresource and prefetch.
-class LinkLoader : public CachedResourceClient {
+struct LinkRelAttribute;
+class LinkLoader : private CachedResourceClient {
public:
- explicit LinkLoader(LinkLoaderClient*);
+ explicit LinkLoader(LinkLoaderClient&);
virtual ~LinkLoader();
- // from CachedResourceClient
- virtual void notifyFinished(CachedResource*);
+ bool loadLink(const LinkRelAttribute&, const URL&, const String& as, const String& crossOrigin, Document&);
+ static std::optional<CachedResource::Type> resourceTypeFromAsAttribute(const String& as);
+ static void loadLinksFromHeader(const String& headerValue, const URL& baseURL, Document&);
- void released();
- bool loadLink(const LinkRelAttribute&, const String& type, const String& sizes, const URL&, Document*);
+ WeakPtr<LinkLoader> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
+ void triggerEvents(const CachedResource&);
+ void cancelLoad();
private:
- void linkLoadTimerFired(Timer<LinkLoader>&);
- void linkLoadingErrorTimerFired(Timer<LinkLoader>&);
-
- LinkLoaderClient* m_client;
+ void notifyFinished(CachedResource&) override;
+ static std::unique_ptr<LinkPreloadResourceClient> preloadIfNeeded(const LinkRelAttribute&, const URL& href, Document&, const String& as, const String& crossOriginMode, LinkLoader*, LinkLoaderClient*);
+ LinkLoaderClient& m_client;
CachedResourceHandle<CachedResource> m_cachedLinkResource;
- Timer<LinkLoader> m_linkLoadTimer;
- Timer<LinkLoader> m_linkLoadingErrorTimer;
+ std::unique_ptr<LinkPreloadResourceClient> m_preloadResourceClient;
+ WeakPtrFactory<LinkLoader> m_weakPtrFactory;
};
-
-}
-#endif
+}
diff --git a/Source/WebCore/loader/LinkLoaderClient.h b/Source/WebCore/loader/LinkLoaderClient.h
index 4350ee78c..f2f18e238 100644
--- a/Source/WebCore/loader/LinkLoaderClient.h
+++ b/Source/WebCore/loader/LinkLoaderClient.h
@@ -28,8 +28,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-#ifndef LinkLoaderClient_h
-#define LinkLoaderClient_h
+
+#pragma once
namespace WebCore {
@@ -44,6 +44,4 @@ public:
// There is no notification for cancellation.
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/LinkPreloadResourceClients.cpp b/Source/WebCore/loader/LinkPreloadResourceClients.cpp
new file mode 100644
index 000000000..1cd744300
--- /dev/null
+++ b/Source/WebCore/loader/LinkPreloadResourceClients.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LinkPreloadResourceClients.h"
+
+#include "LinkLoader.h"
+
+namespace WebCore {
+
+LinkPreloadResourceClient::LinkPreloadResourceClient(LinkLoader& loader, CachedResource& resource)
+{
+ m_loader = loader.createWeakPtr();
+ m_resource = &resource;
+}
+
+void LinkPreloadResourceClient::triggerEvents(const CachedResource& resource)
+{
+ if (m_loader)
+ m_loader->triggerEvents(resource);
+}
+
+}
diff --git a/Source/WebCore/loader/LinkPreloadResourceClients.h b/Source/WebCore/loader/LinkPreloadResourceClients.h
new file mode 100644
index 000000000..2c3a7a4dd
--- /dev/null
+++ b/Source/WebCore/loader/LinkPreloadResourceClients.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2016 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CachedCSSStyleSheet.h"
+#include "CachedFont.h"
+#include "CachedFontClient.h"
+#include "CachedImage.h"
+#include "CachedImageClient.h"
+#include "CachedRawResource.h"
+#include "CachedResourceLoader.h"
+#include "CachedScript.h"
+#include "CachedStyleSheetClient.h"
+
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class LinkLoader;
+
+class LinkPreloadResourceClient {
+public:
+ virtual ~LinkPreloadResourceClient() { }
+
+ void triggerEvents(const CachedResource&);
+
+ virtual void clear() = 0;
+
+protected:
+
+ LinkPreloadResourceClient(LinkLoader&, CachedResource&);
+
+ void addResource(CachedResourceClient& client)
+ {
+ m_resource->addClient(client);
+ }
+
+ void clearResource(CachedResourceClient& client)
+ {
+ if (m_resource) {
+ m_resource->cancelLoad();
+ m_resource->removeClient(client);
+ }
+ m_resource = nullptr;
+ }
+
+ CachedResource* ownedResource() { return m_resource.get(); }
+
+private:
+ WeakPtr<LinkLoader> m_loader;
+ CachedResourceHandle<CachedResource> m_resource;
+};
+
+class LinkPreloadScriptResourceClient: public LinkPreloadResourceClient, CachedResourceClient {
+public:
+ static std::unique_ptr<LinkPreloadScriptResourceClient> create(LinkLoader& loader, CachedScript& resource)
+ {
+ return std::unique_ptr<LinkPreloadScriptResourceClient>(new LinkPreloadScriptResourceClient(loader, resource));
+ }
+
+ virtual ~LinkPreloadScriptResourceClient() { }
+
+
+ void notifyFinished(CachedResource& resource) override { triggerEvents(resource); }
+
+ void clear() override { clearResource(*this); }
+
+private:
+ LinkPreloadScriptResourceClient(LinkLoader& loader, CachedScript& resource)
+ : LinkPreloadResourceClient(loader, resource)
+ {
+ addResource(*this);
+ }
+};
+
+class LinkPreloadStyleResourceClient: public LinkPreloadResourceClient, public CachedStyleSheetClient {
+public:
+ static std::unique_ptr<LinkPreloadStyleResourceClient> create(LinkLoader& loader, CachedCSSStyleSheet& resource)
+ {
+ return std::unique_ptr<LinkPreloadStyleResourceClient>(new LinkPreloadStyleResourceClient(loader, resource));
+ }
+
+ virtual ~LinkPreloadStyleResourceClient() { }
+
+ void setCSSStyleSheet(const String&, const URL&, const String&, const CachedCSSStyleSheet* resource) override
+ {
+ ASSERT(resource);
+ ASSERT(ownedResource() == resource);
+ triggerEvents(*resource);
+ }
+
+ void clear() override { clearResource(*this); }
+
+private:
+ LinkPreloadStyleResourceClient(LinkLoader& loader, CachedCSSStyleSheet& resource)
+ : LinkPreloadResourceClient(loader, resource)
+ {
+ addResource(*this);
+ }
+};
+
+class LinkPreloadImageResourceClient: public LinkPreloadResourceClient, public CachedImageClient {
+public:
+ static std::unique_ptr<LinkPreloadImageResourceClient> create(LinkLoader& loader, CachedImage& resource)
+ {
+ return std::unique_ptr<LinkPreloadImageResourceClient>(new LinkPreloadImageResourceClient(loader, resource));
+ }
+
+ virtual ~LinkPreloadImageResourceClient() { }
+
+ void notifyFinished(CachedResource& resource) override { triggerEvents(resource); }
+
+ void clear() override { clearResource(*this); }
+
+private:
+ LinkPreloadImageResourceClient(LinkLoader& loader, CachedImage& resource)
+ : LinkPreloadResourceClient(loader, dynamic_cast<CachedResource&>(resource))
+ {
+ addResource(*this);
+ }
+};
+
+class LinkPreloadFontResourceClient: public LinkPreloadResourceClient, public CachedFontClient {
+public:
+ static std::unique_ptr<LinkPreloadFontResourceClient> create(LinkLoader& loader, CachedFont& resource)
+ {
+ return std::unique_ptr<LinkPreloadFontResourceClient>(new LinkPreloadFontResourceClient(loader, resource));
+ }
+
+ virtual ~LinkPreloadFontResourceClient() { }
+
+ void fontLoaded(CachedFont& resource) override
+ {
+ ASSERT(ownedResource() == &resource);
+ triggerEvents(resource);
+ }
+
+ void clear() override { clearResource(*this); }
+
+private:
+ LinkPreloadFontResourceClient(LinkLoader& loader, CachedFont& resource)
+ : LinkPreloadResourceClient(loader, resource)
+ {
+ addResource(*this);
+ }
+};
+
+class LinkPreloadRawResourceClient: public LinkPreloadResourceClient, public CachedRawResourceClient {
+public:
+ static std::unique_ptr<LinkPreloadRawResourceClient> create(LinkLoader& loader, CachedRawResource& resource)
+ {
+ return std::unique_ptr<LinkPreloadRawResourceClient>(new LinkPreloadRawResourceClient(loader, resource));
+ }
+
+ virtual ~LinkPreloadRawResourceClient() { }
+
+ void notifyFinished(CachedResource& resource) override { triggerEvents(resource); }
+
+ void clear() override { clearResource(*this); }
+
+private:
+ LinkPreloadRawResourceClient(LinkLoader& loader, CachedRawResource& resource)
+ : LinkPreloadResourceClient(loader, resource)
+ {
+ addResource(*this);
+ }
+};
+
+}
diff --git a/Source/WebCore/loader/DocumentLoadTiming.cpp b/Source/WebCore/loader/LoadTiming.cpp
index 3a02b2310..feb0a9b4e 100644
--- a/Source/WebCore/loader/DocumentLoadTiming.cpp
+++ b/Source/WebCore/loader/LoadTiming.cpp
@@ -24,73 +24,72 @@
*/
#include "config.h"
-#include "DocumentLoadTiming.h"
+#include "LoadTiming.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Frame.h"
-#include "Page.h"
#include "SecurityOrigin.h"
#include <wtf/CurrentTime.h>
#include <wtf/RefPtr.h>
namespace WebCore {
-DocumentLoadTiming::DocumentLoadTiming()
- : m_referenceMonotonicTime(0.0)
- , m_referenceWallTime(0.0)
- , m_navigationStart(0.0)
- , m_unloadEventStart(0.0)
- , m_unloadEventEnd(0.0)
- , m_redirectStart(0.0)
- , m_redirectEnd(0.0)
- , m_redirectCount(0)
- , m_fetchStart(0.0)
- , m_responseEnd(0.0)
- , m_loadEventStart(0.0)
- , m_loadEventEnd(0.0)
- , m_hasCrossOriginRedirect(false)
- , m_hasSameOriginAsPreviousDocument(false)
+Seconds LoadTiming::secondsSinceStartTime(MonotonicTime timeStamp) const
{
-}
-
-double DocumentLoadTiming::monotonicTimeToZeroBasedDocumentTime(double monotonicTime) const
-{
- if (!monotonicTime)
- return 0.0;
- return monotonicTime - m_referenceMonotonicTime;
-}
+ if (!timeStamp)
+ return Seconds(0);
-double DocumentLoadTiming::monotonicTimeToPseudoWallTime(double monotonicTime) const
-{
- if (!monotonicTime)
- return 0.0;
- return m_referenceWallTime + monotonicTime - m_referenceMonotonicTime;
+ return timeStamp - m_referenceMonotonicTime;
}
-void DocumentLoadTiming::markNavigationStart()
+WallTime LoadTiming::monotonicTimeToPseudoWallTime(MonotonicTime timeStamp) const
{
- ASSERT(!m_navigationStart && !m_referenceMonotonicTime && !m_referenceWallTime);
+ if (!timeStamp)
+ return WallTime::fromRawSeconds(0);
- m_navigationStart = m_referenceMonotonicTime = monotonicallyIncreasingTime();
- m_referenceWallTime = currentTime();
+ return m_referenceWallTime + (timeStamp - m_referenceMonotonicTime);
}
-void DocumentLoadTiming::setNavigationStart(double navigationStart)
+void LoadTiming::markStartTime()
{
- ASSERT(m_referenceMonotonicTime && m_referenceWallTime);
- m_navigationStart = navigationStart;
+ ASSERT(!m_startTime && !m_referenceMonotonicTime && !m_referenceWallTime);
+
+ m_referenceMonotonicTime = m_startTime = MonotonicTime::now();
+ m_referenceWallTime = WallTime::now();
}
-void DocumentLoadTiming::addRedirect(const URL& redirectingUrl, const URL& redirectedUrl)
+void LoadTiming::addRedirect(const URL& redirectingUrl, const URL& redirectedUrl)
{
m_redirectCount++;
if (!m_redirectStart)
m_redirectStart = m_fetchStart;
- m_redirectEnd = m_fetchStart = monotonicallyIncreasingTime();
+ m_redirectEnd = m_fetchStart = MonotonicTime::now();
// Check if the redirected url is allowed to access the redirecting url's timing information.
- RefPtr<SecurityOrigin> redirectedSecurityOrigin = SecurityOrigin::create(redirectedUrl);
- m_hasCrossOriginRedirect = !redirectedSecurityOrigin->canRequest(redirectingUrl);
+ Ref<SecurityOrigin> redirectedSecurityOrigin(SecurityOrigin::create(redirectedUrl));
+ m_hasCrossOriginRedirect = !redirectedSecurityOrigin.get().canRequest(redirectingUrl);
+}
+
+LoadTiming LoadTiming::isolatedCopy() const
+{
+ LoadTiming result;
+
+ result.m_referenceWallTime = m_referenceWallTime;
+ result.m_referenceMonotonicTime = m_referenceMonotonicTime;
+ result.m_startTime = m_startTime;
+ result.m_unloadEventStart = m_unloadEventStart;
+ result.m_unloadEventEnd = m_unloadEventEnd;
+ result.m_redirectStart = m_redirectStart;
+ result.m_redirectEnd = m_redirectEnd;
+ result.m_fetchStart = m_fetchStart;
+ result.m_responseEnd = m_responseEnd;
+ result.m_loadEventStart = m_loadEventStart;
+ result.m_loadEventEnd = m_loadEventEnd;
+ result.m_redirectCount = m_redirectCount;
+ result.m_hasCrossOriginRedirect = m_hasCrossOriginRedirect;
+ result.m_hasSameOriginAsPreviousDocument = m_hasSameOriginAsPreviousDocument;
+
+ return result;
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/LoadTiming.h b/Source/WebCore/loader/LoadTiming.h
new file mode 100644
index 000000000..23c41e27a
--- /dev/null
+++ b/Source/WebCore/loader/LoadTiming.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/CurrentTime.h>
+#include <wtf/MonotonicTime.h>
+#include <wtf/WallTime.h>
+
+namespace WebCore {
+
+class URL;
+
+class LoadTiming {
+public:
+ Seconds secondsSinceStartTime(MonotonicTime) const;
+ WallTime monotonicTimeToPseudoWallTime(MonotonicTime) const;
+
+ void markStartTime();
+ void addRedirect(const URL& redirectingUrl, const URL& redirectedUrl);
+
+ void markStartTimeAndFetchStart() { markStartTime(); m_fetchStart = m_startTime; }
+
+ void markUnloadEventStart() { m_unloadEventStart = MonotonicTime::now(); }
+ void markUnloadEventEnd() { m_unloadEventEnd = MonotonicTime::now(); }
+ void markRedirectStart() { m_redirectStart = MonotonicTime::now(); }
+ void markRedirectEnd() { m_redirectEnd = MonotonicTime::now(); }
+ void markFetchStart() { m_fetchStart = MonotonicTime::now(); }
+ void setResponseEnd(MonotonicTime time) { m_responseEnd = time; }
+ void markLoadEventStart() { m_loadEventStart = MonotonicTime::now(); }
+ void markLoadEventEnd() { m_loadEventEnd = MonotonicTime::now(); }
+
+ void setHasSameOriginAsPreviousDocument(bool value) { m_hasSameOriginAsPreviousDocument = value; }
+
+ MonotonicTime startTime() const { return m_startTime; }
+ MonotonicTime unloadEventStart() const { return m_unloadEventStart; }
+ MonotonicTime unloadEventEnd() const { return m_unloadEventEnd; }
+ MonotonicTime redirectStart() const { return m_redirectStart; }
+ MonotonicTime redirectEnd() const { return m_redirectEnd; }
+ MonotonicTime fetchStart() const { return m_fetchStart; }
+ MonotonicTime responseEnd() const { return m_responseEnd; }
+ MonotonicTime loadEventStart() const { return m_loadEventStart; }
+ MonotonicTime loadEventEnd() const { return m_loadEventEnd; }
+ short redirectCount() const { return m_redirectCount; }
+ bool hasCrossOriginRedirect() const { return m_hasCrossOriginRedirect; }
+ bool hasSameOriginAsPreviousDocument() const { return m_hasSameOriginAsPreviousDocument; }
+
+ MonotonicTime referenceMonotonicTime() const { return m_referenceMonotonicTime; }
+ WallTime referenceWallTime() const { return m_referenceWallTime; }
+
+ LoadTiming isolatedCopy() const;
+
+private:
+ WallTime m_referenceWallTime;
+ MonotonicTime m_referenceMonotonicTime;
+ MonotonicTime m_startTime;
+ MonotonicTime m_unloadEventStart;
+ MonotonicTime m_unloadEventEnd;
+ MonotonicTime m_redirectStart;
+ MonotonicTime m_redirectEnd;
+ MonotonicTime m_fetchStart;
+ MonotonicTime m_responseEnd;
+ MonotonicTime m_loadEventStart;
+ MonotonicTime m_loadEventEnd;
+ short m_redirectCount { 0 };
+ bool m_hasCrossOriginRedirect { false };
+ bool m_hasSameOriginAsPreviousDocument { false };
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/LoaderStrategy.cpp b/Source/WebCore/loader/LoaderStrategy.cpp
index fc4400772..75aae4285 100644
--- a/Source/WebCore/loader/LoaderStrategy.cpp
+++ b/Source/WebCore/loader/LoaderStrategy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,28 +26,14 @@
#include "config.h"
#include "LoaderStrategy.h"
-#include "BlobRegistryImpl.h"
-#include "ResourceHandle.h"
-#include "ResourceLoadScheduler.h"
+#include "PlatformStrategies.h"
namespace WebCore {
-ResourceLoadScheduler* LoaderStrategy::resourceLoadScheduler()
+LoaderStrategy::~LoaderStrategy()
{
- return WebCore::resourceLoadScheduler();
}
-void LoaderStrategy::loadResourceSynchronously(NetworkingContext* context, unsigned long, const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
-{
- ResourceHandle::loadResourceSynchronously(context, request, storedCredentials, error, response, data);
-}
-
-#if ENABLE(BLOB)
-BlobRegistry* LoaderStrategy::createBlobRegistry()
-{
- return new BlobRegistryImpl;
-}
-#endif
+} // namespace WebCore
-} // namespace WebCore
diff --git a/Source/WebCore/loader/LoaderStrategy.h b/Source/WebCore/loader/LoaderStrategy.h
index 0e625d35a..8121f0e77 100644
--- a/Source/WebCore/loader/LoaderStrategy.h
+++ b/Source/WebCore/loader/LoaderStrategy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,37 +23,48 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef LoaderStrategy_h
-#define LoaderStrategy_h
+#pragma once
#include "ResourceHandleTypes.h"
+#include "ResourceLoadPriority.h"
+#include "ResourceLoaderOptions.h"
+#include <wtf/SHA1.h>
#include <wtf/Vector.h>
namespace WebCore {
-class BlobRegistry;
+class CachedResource;
+class Frame;
+class NetscapePlugInStreamLoader;
+class NetscapePlugInStreamLoaderClient;
class NetworkingContext;
class ResourceError;
-class ResourceLoadScheduler;
+class ResourceLoader;
class ResourceRequest;
class ResourceResponse;
+class SharedBuffer;
+class SubresourceLoader;
+class URL;
-class LoaderStrategy {
+class WEBCORE_EXPORT LoaderStrategy {
public:
- virtual ResourceLoadScheduler* resourceLoadScheduler();
+ virtual RefPtr<SubresourceLoader> loadResource(Frame&, CachedResource&, const ResourceRequest&, const ResourceLoaderOptions&) = 0;
+ virtual void loadResourceSynchronously(NetworkingContext*, unsigned long identifier, const ResourceRequest&, StoredCredentials, ClientCredentialPolicy, ResourceError&, ResourceResponse&, Vector<char>& data) = 0;
- virtual void loadResourceSynchronously(NetworkingContext*, unsigned long identifier, const ResourceRequest&, StoredCredentials, ClientCredentialPolicy, ResourceError&, ResourceResponse&, Vector<char>& data);
+ virtual void remove(ResourceLoader*) = 0;
+ virtual void setDefersLoading(ResourceLoader*, bool) = 0;
+ virtual void crossOriginRedirectReceived(ResourceLoader*, const URL& redirectURL) = 0;
-#if ENABLE(BLOB)
- virtual BlobRegistry* createBlobRegistry();
-#endif
+ virtual void servePendingRequests(ResourceLoadPriority minimumPriority = ResourceLoadPriority::VeryLow) = 0;
+ virtual void suspendPendingRequests() = 0;
+ virtual void resumePendingRequests() = 0;
+
+ virtual void createPingHandle(NetworkingContext*, ResourceRequest&, bool shouldUseCredentialStorage, bool shouldFollowRedirects) = 0;
+
+ virtual void storeDerivedDataToCache(const SHA1::Digest& bodyKey, const String& type, const String& partition, WebCore::SharedBuffer&) = 0;
protected:
- virtual ~LoaderStrategy()
- {
- }
+ virtual ~LoaderStrategy();
};
} // namespace WebCore
-
-#endif // LoaderStrategy_h
diff --git a/Source/WebCore/loader/MediaResourceLoader.cpp b/Source/WebCore/loader/MediaResourceLoader.cpp
new file mode 100644
index 000000000..ac708d6bd
--- /dev/null
+++ b/Source/WebCore/loader/MediaResourceLoader.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 Igalia S.L
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MediaResourceLoader.h"
+
+#if ENABLE(VIDEO)
+
+#include "CachedRawResource.h"
+#include "CachedResourceLoader.h"
+#include "CachedResourceRequest.h"
+#include "CrossOriginAccessControl.h"
+#include "Document.h"
+#include "SecurityOrigin.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+MediaResourceLoader::MediaResourceLoader(Document& document, const String& crossOriginMode)
+ : ContextDestructionObserver(&document)
+ , m_document(&document)
+ , m_crossOriginMode(crossOriginMode)
+{
+}
+
+MediaResourceLoader::~MediaResourceLoader()
+{
+ ASSERT(m_resources.isEmpty());
+}
+
+void MediaResourceLoader::contextDestroyed()
+{
+ ContextDestructionObserver::contextDestroyed();
+ m_document = nullptr;
+}
+
+RefPtr<PlatformMediaResource> MediaResourceLoader::requestResource(ResourceRequest&& request, LoadOptions options)
+{
+ if (!m_document)
+ return nullptr;
+
+ DataBufferingPolicy bufferingPolicy = options & LoadOption::BufferData ? WebCore::BufferData : WebCore::DoNotBufferData;
+ auto cachingPolicy = options & LoadOption::DisallowCaching ? CachingPolicy::DisallowCaching : CachingPolicy::AllowCaching;
+
+ request.setRequester(ResourceRequest::Requester::Media);
+#if HAVE(AVFOUNDATION_LOADER_DELEGATE) && PLATFORM(MAC)
+ // FIXME: Workaround for <rdar://problem/26071607>. We are not able to do CORS checking on 304 responses because they are usually missing the headers we need.
+ if (!m_crossOriginMode.isNull())
+ request.makeUnconditional();
+#endif
+
+ // FIXME: Skip Content Security Policy check if the element that initiated this request is in a user-agent shadow tree. See <https://bugs.webkit.org/show_bug.cgi?id=155505>.
+ CachedResourceRequest cacheRequest(WTFMove(request), ResourceLoaderOptions(SendCallbacks, DoNotSniffContent, bufferingPolicy, AllowStoredCredentials, ClientCredentialPolicy::MayAskClientForCredentials, FetchOptions::Credentials::Include, DoSecurityCheck, FetchOptions::Mode::NoCors, DoNotIncludeCertificateInfo, ContentSecurityPolicyImposition::DoPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, cachingPolicy));
+ cacheRequest.setAsPotentiallyCrossOrigin(m_crossOriginMode, *m_document);
+
+ CachedResourceHandle<CachedRawResource> resource = m_document->cachedResourceLoader().requestMedia(WTFMove(cacheRequest));
+ if (!resource)
+ return nullptr;
+
+ Ref<MediaResource> mediaResource = MediaResource::create(*this, resource);
+ m_resources.add(mediaResource.ptr());
+
+ return WTFMove(mediaResource);
+}
+
+void MediaResourceLoader::removeResource(MediaResource& mediaResource)
+{
+ ASSERT(m_resources.contains(&mediaResource));
+ m_resources.remove(&mediaResource);
+}
+
+Ref<MediaResource> MediaResource::create(MediaResourceLoader& loader, CachedResourceHandle<CachedRawResource> resource)
+{
+ return adoptRef(*new MediaResource(loader, resource));
+}
+
+MediaResource::MediaResource(MediaResourceLoader& loader, CachedResourceHandle<CachedRawResource> resource)
+ : m_loader(loader)
+ , m_resource(resource)
+{
+ ASSERT(resource);
+ resource->addClient(*this);
+}
+
+MediaResource::~MediaResource()
+{
+ stop();
+ m_loader->removeResource(*this);
+}
+
+void MediaResource::stop()
+{
+ if (!m_resource)
+ return;
+
+ m_resource->removeClient(*this);
+ m_resource = nullptr;
+}
+
+void MediaResource::setDefersLoading(bool defersLoading)
+{
+ if (m_resource)
+ m_resource->setDefersLoading(defersLoading);
+}
+
+void MediaResource::responseReceived(CachedResource& resource, const ResourceResponse& response)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
+ if (!m_loader->document())
+ return;
+
+ RefPtr<MediaResource> protectedThis(this);
+ if (m_resource->resourceError().isAccessControl()) {
+ static NeverDestroyed<const String> consoleMessage("Cross-origin media resource load denied by Cross-Origin Resource Sharing policy.");
+ m_loader->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage.get());
+ m_didPassAccessControlCheck = false;
+ if (m_client)
+ m_client->accessControlCheckFailed(*this, ResourceError(errorDomainWebKitInternal, 0, response.url(), consoleMessage.get()));
+ stop();
+ return;
+ }
+
+ m_didPassAccessControlCheck = m_resource->options().mode == FetchOptions::Mode::Cors;
+ if (m_client)
+ m_client->responseReceived(*this, response);
+}
+
+bool MediaResource::shouldCacheResponse(CachedResource& resource, const ResourceResponse& response)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
+ RefPtr<MediaResource> protectedThis(this);
+ if (m_client)
+ return m_client->shouldCacheResponse(*this, response);
+ return true;
+}
+
+void MediaResource::redirectReceived(CachedResource& resource, ResourceRequest& request, const ResourceResponse& response)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
+ RefPtr<MediaResource> protectedThis(this);
+ if (m_client)
+ m_client->redirectReceived(*this, request, response);
+}
+
+void MediaResource::dataSent(CachedResource& resource, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
+ RefPtr<MediaResource> protectedThis(this);
+ if (m_client)
+ m_client->dataSent(*this, bytesSent, totalBytesToBeSent);
+}
+
+void MediaResource::dataReceived(CachedResource& resource, const char* data, int dataLength)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
+ RefPtr<MediaResource> protectedThis(this);
+ if (m_client)
+ m_client->dataReceived(*this, data, dataLength);
+}
+
+void MediaResource::notifyFinished(CachedResource& resource)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+
+ RefPtr<MediaResource> protectedThis(this);
+ if (m_client) {
+ if (m_resource->loadFailedOrCanceled())
+ m_client->loadFailed(*this, m_resource->resourceError());
+ else
+ m_client->loadFinished(*this);
+ }
+ stop();
+}
+
+#if USE(SOUP)
+char* MediaResource::getOrCreateReadBuffer(CachedResource& resource, size_t requestedSize, size_t& actualSize)
+{
+ ASSERT_UNUSED(resource, &resource == m_resource);
+ return m_client ? m_client->getOrCreateReadBuffer(*this, requestedSize, actualSize) : nullptr;
+}
+#endif
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/loader/MediaResourceLoader.h b/Source/WebCore/loader/MediaResourceLoader.h
new file mode 100644
index 000000000..9485d0ef1
--- /dev/null
+++ b/Source/WebCore/loader/MediaResourceLoader.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 Igalia S.L
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(VIDEO)
+
+#include "CachedRawResourceClient.h"
+#include "CachedResourceHandle.h"
+#include "ContextDestructionObserver.h"
+#include "PlatformMediaResourceLoader.h"
+#include <wtf/HashSet.h>
+#include <wtf/Ref.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class CachedRawResource;
+class Document;
+class MediaResource;
+
+class MediaResourceLoader final : public PlatformMediaResourceLoader, public ContextDestructionObserver {
+public:
+ WEBCORE_EXPORT MediaResourceLoader(Document&, const String& crossOriginMode);
+ WEBCORE_EXPORT virtual ~MediaResourceLoader();
+
+ RefPtr<PlatformMediaResource> requestResource(ResourceRequest&&, LoadOptions) final;
+ void removeResource(MediaResource&);
+
+ Document* document() { return m_document; }
+ const String& crossOriginMode() const { return m_crossOriginMode; }
+
+private:
+ void contextDestroyed() override;
+
+ Document* m_document;
+ String m_crossOriginMode;
+ HashSet<MediaResource*> m_resources;
+};
+
+class MediaResource : public PlatformMediaResource, CachedRawResourceClient {
+public:
+ static Ref<MediaResource> create(MediaResourceLoader&, CachedResourceHandle<CachedRawResource>);
+ virtual ~MediaResource();
+
+ // PlatformMediaResource
+ void stop() override;
+ void setDefersLoading(bool) override;
+ bool didPassAccessControlCheck() const override { return m_didPassAccessControlCheck; }
+
+ // CachedRawResourceClient
+ void responseReceived(CachedResource&, const ResourceResponse&) override;
+ void redirectReceived(CachedResource&, ResourceRequest&, const ResourceResponse&) override;
+ bool shouldCacheResponse(CachedResource&, const ResourceResponse&) override;
+ void dataSent(CachedResource&, unsigned long long, unsigned long long) override;
+ void dataReceived(CachedResource&, const char*, int) override;
+ void notifyFinished(CachedResource&) override;
+#if USE(SOUP)
+ char* getOrCreateReadBuffer(CachedResource&, size_t /*requestedSize*/, size_t& /*actualSize*/) override;
+#endif
+
+private:
+ MediaResource(MediaResourceLoader&, CachedResourceHandle<CachedRawResource>);
+ Ref<MediaResourceLoader> m_loader;
+ bool m_didPassAccessControlCheck { false };
+ CachedResourceHandle<CachedRawResource> m_resource;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(VIDEO)
diff --git a/Source/WebCore/loader/MixedContentChecker.cpp b/Source/WebCore/loader/MixedContentChecker.cpp
index e507aa62d..46081a722 100644
--- a/Source/WebCore/loader/MixedContentChecker.cpp
+++ b/Source/WebCore/loader/MixedContentChecker.cpp
@@ -6,13 +6,13 @@
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -29,13 +29,11 @@
#include "config.h"
#include "MixedContentChecker.h"
-#include "Console.h"
-#include "DOMWindow.h"
+#include "ContentSecurityPolicy.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
-#include "SchemeRegistry.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#include <wtf/text/CString.h>
@@ -54,47 +52,78 @@ FrameLoaderClient& MixedContentChecker::client() const
}
// static
-bool MixedContentChecker::isMixedContent(SecurityOrigin* securityOrigin, const URL& url)
+bool MixedContentChecker::isMixedContent(SecurityOrigin& securityOrigin, const URL& url)
{
- if (securityOrigin->protocol() != "https")
+ if (securityOrigin.protocol() != "https")
return false; // We only care about HTTPS security origins.
// We're in a secure context, so |url| is mixed content if it's insecure.
return !SecurityOrigin::isSecure(url);
}
-bool MixedContentChecker::canDisplayInsecureContent(SecurityOrigin* securityOrigin, const URL& url) const
+bool MixedContentChecker::canDisplayInsecureContent(SecurityOrigin& securityOrigin, ContentType type, const URL& url, AlwaysDisplayInNonStrictMode alwaysDisplayInNonStrictMode) const
{
if (!isMixedContent(securityOrigin, url))
return true;
- bool allowed = client().allowDisplayingInsecureContent(m_frame.settings().allowDisplayOfInsecureContent(), securityOrigin, url);
- logWarning(allowed, "displayed", url);
+ if (!m_frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
+ return false;
- if (allowed)
+ bool isStrictMode = m_frame.document()->isStrictMixedContentMode();
+ if (!isStrictMode && alwaysDisplayInNonStrictMode == AlwaysDisplayInNonStrictMode::Yes)
+ return true;
+
+ bool allowed = !isStrictMode && (m_frame.settings().allowDisplayOfInsecureContent() || type == ContentType::ActiveCanWarn) && !m_frame.document()->geolocationAccessed();
+ logWarning(allowed, "display", url);
+
+ if (allowed) {
+ m_frame.document()->setFoundMixedContent();
client().didDisplayInsecureContent();
+ }
return allowed;
}
-bool MixedContentChecker::canRunInsecureContent(SecurityOrigin* securityOrigin, const URL& url) const
+bool MixedContentChecker::canRunInsecureContent(SecurityOrigin& securityOrigin, const URL& url) const
{
if (!isMixedContent(securityOrigin, url))
return true;
- bool allowed = client().allowRunningInsecureContent(m_frame.settings().allowRunningOfInsecureContent(), securityOrigin, url);
- logWarning(allowed, "ran", url);
+ if (!m_frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
+ return false;
- if (allowed)
+ bool allowed = !m_frame.document()->isStrictMixedContentMode() && m_frame.settings().allowRunningOfInsecureContent() && !m_frame.document()->geolocationAccessed();
+ logWarning(allowed, "run", url);
+
+ if (allowed) {
+ m_frame.document()->setFoundMixedContent();
client().didRunInsecureContent(securityOrigin, url);
+ }
return allowed;
}
+void MixedContentChecker::checkFormForMixedContent(SecurityOrigin& securityOrigin, const URL& url) const
+{
+ // Unconditionally allow javascript: URLs as form actions as some pages do this and it does not introduce
+ // a mixed content issue.
+ if (protocolIsJavaScript(url))
+ return;
+
+ if (!isMixedContent(securityOrigin, url))
+ return;
+
+ String message = makeString("The page at ", m_frame.document()->url().stringCenterEllipsizedToLength(), " contains a form which targets an insecure URL ", url.stringCenterEllipsizedToLength(), ".\n");
+ m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
+
+ client().didDisplayInsecureContent();
+}
+
void MixedContentChecker::logWarning(bool allowed, const String& action, const URL& target) const
{
- String message = makeString((allowed ? "" : "[blocked] "), "The page at ", m_frame.document()->url().stringCenterEllipsizedToLength(), " ", action, " insecure content from ", target.stringCenterEllipsizedToLength(), ".\n");
- m_frame.document()->addConsoleMessage(SecurityMessageSource, WarningMessageLevel, message);
+ const char* errorString = allowed ? " was allowed to " : " was not allowed to ";
+ String message = makeString((allowed ? String() : "[blocked] "), "The page at ", m_frame.document()->url().stringCenterEllipsizedToLength(), errorString, action, " insecure content from ", target.stringCenterEllipsizedToLength(), ".\n");
+ m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/MixedContentChecker.h b/Source/WebCore/loader/MixedContentChecker.h
index bff9c795f..a26a85797 100644
--- a/Source/WebCore/loader/MixedContentChecker.h
+++ b/Source/WebCore/loader/MixedContentChecker.h
@@ -28,8 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MixedContentChecker_h
-#define MixedContentChecker_h
+#pragma once
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
@@ -44,11 +43,22 @@ class SecurityOrigin;
class MixedContentChecker {
WTF_MAKE_NONCOPYABLE(MixedContentChecker);
public:
+ enum class ContentType {
+ Active,
+ ActiveCanWarn,
+ };
+
MixedContentChecker(Frame&);
- bool canDisplayInsecureContent(SecurityOrigin*, const URL&) const;
- bool canRunInsecureContent(SecurityOrigin*, const URL&) const;
- static bool isMixedContent(SecurityOrigin*, const URL&);
+ enum class AlwaysDisplayInNonStrictMode {
+ No,
+ Yes,
+ };
+
+ bool canDisplayInsecureContent(SecurityOrigin&, ContentType, const URL&, AlwaysDisplayInNonStrictMode = AlwaysDisplayInNonStrictMode::No) const;
+ bool canRunInsecureContent(SecurityOrigin&, const URL&) const;
+ void checkFormForMixedContent(SecurityOrigin&, const URL&) const;
+ static bool isMixedContent(SecurityOrigin&, const URL&);
private:
// FIXME: This should probably have a separate client from FrameLoader.
@@ -60,6 +70,3 @@ private:
};
} // namespace WebCore
-
-#endif // MixedContentChecker_h
-
diff --git a/Source/WebCore/loader/NavigationAction.cpp b/Source/WebCore/loader/NavigationAction.cpp
index e840fb2a9..7ea86196c 100644
--- a/Source/WebCore/loader/NavigationAction.cpp
+++ b/Source/WebCore/loader/NavigationAction.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,59 +31,93 @@
#include "Event.h"
#include "FrameLoader.h"
+#include "ScriptController.h"
namespace WebCore {
static NavigationType navigationType(FrameLoadType frameLoadType, bool isFormSubmission, bool haveEvent)
{
if (isFormSubmission)
- return NavigationTypeFormSubmitted;
+ return NavigationType::FormSubmitted;
if (haveEvent)
- return NavigationTypeLinkClicked;
- if (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin)
- return NavigationTypeReload;
+ return NavigationType::LinkClicked;
+ if (frameLoadType == FrameLoadType::Reload || frameLoadType == FrameLoadType::ReloadFromOrigin)
+ return NavigationType::Reload;
if (isBackForwardLoadType(frameLoadType))
- return NavigationTypeBackForward;
- return NavigationTypeOther;
+ return NavigationType::BackForward;
+ return NavigationType::Other;
+}
+
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, NavigationType type, Event* event, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, const AtomicString& downloadAttribute)
+ : m_resourceRequest(resourceRequest)
+ , m_type(type)
+ , m_event(event)
+ , m_userGestureToken(UserGestureIndicator::currentUserGesture())
+ , m_shouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy)
+ , m_downloadAttribute(downloadAttribute)
+{
}
NavigationAction::NavigationAction()
- : m_type(NavigationTypeOther)
+ : NavigationAction(ResourceRequest(), NavigationType::Other, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow, nullAtom)
{
}
NavigationAction::NavigationAction(const ResourceRequest& resourceRequest)
- : m_resourceRequest(resourceRequest)
- , m_type(NavigationTypeOther)
+ : NavigationAction(resourceRequest, NavigationType::Other, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow, nullAtom)
+{
+}
+
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : NavigationAction(resourceRequest, NavigationType::Other, nullptr, shouldOpenExternalURLsPolicy, nullAtom)
{
}
NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, NavigationType type)
- : m_resourceRequest(resourceRequest)
- , m_type(type)
+ : NavigationAction(resourceRequest, type, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow, nullAtom)
{
}
-NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, FrameLoadType frameLoadType,
- bool isFormSubmission)
- : m_resourceRequest(resourceRequest)
- , m_type(navigationType(frameLoadType, isFormSubmission, 0))
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, NavigationType type, Event* event, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : NavigationAction(resourceRequest, type, event, shouldOpenExternalURLsPolicy, nullAtom)
{
}
-NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, NavigationType type, PassRefPtr<Event> event)
- : m_resourceRequest(resourceRequest)
- , m_type(type)
- , m_event(event)
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, FrameLoadType frameLoadType, bool isFormSubmission)
+ : NavigationAction(resourceRequest, navigationType(frameLoadType, isFormSubmission, 0), nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow, nullAtom)
{
}
-NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, FrameLoadType frameLoadType,
- bool isFormSubmission, PassRefPtr<Event> event)
- : m_resourceRequest(resourceRequest)
- , m_type(navigationType(frameLoadType, isFormSubmission, event))
- , m_event(event)
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, NavigationType type, Event* event)
+ : NavigationAction(resourceRequest, type, event, ShouldOpenExternalURLsPolicy::ShouldNotAllow, nullAtom)
+{
+}
+
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, NavigationType type, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : NavigationAction(resourceRequest, type, nullptr, shouldOpenExternalURLsPolicy, nullAtom)
+{
+}
+
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, FrameLoadType frameLoadType, bool isFormSubmission, Event* event)
+ : NavigationAction(resourceRequest, navigationType(frameLoadType, isFormSubmission, event), event, ShouldOpenExternalURLsPolicy::ShouldNotAllow, nullAtom)
+{
+}
+
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, FrameLoadType frameLoadType, bool isFormSubmission, Event* event, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+ : NavigationAction(resourceRequest, navigationType(frameLoadType, isFormSubmission, event), event, shouldOpenExternalURLsPolicy, nullAtom)
+{
+}
+
+NavigationAction::NavigationAction(const ResourceRequest& resourceRequest, FrameLoadType frameLoadType, bool isFormSubmission, Event* event, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, const AtomicString& downloadAttribute)
+ : NavigationAction(resourceRequest, navigationType(frameLoadType, isFormSubmission, event), event, shouldOpenExternalURLsPolicy, downloadAttribute)
+{
+}
+
+NavigationAction NavigationAction::copyWithShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy) const
{
+ NavigationAction result(*this);
+ result.m_shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
+ return result;
}
}
diff --git a/Source/WebCore/loader/NavigationAction.h b/Source/WebCore/loader/NavigationAction.h
index 5e21e0140..3702dc550 100644
--- a/Source/WebCore/loader/NavigationAction.h
+++ b/Source/WebCore/loader/NavigationAction.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,40 +26,57 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NavigationAction_h
-#define NavigationAction_h
+#pragma once
#include "Event.h"
#include "FrameLoaderTypes.h"
#include "URL.h"
#include "ResourceRequest.h"
+#include "UserGestureIndicator.h"
#include <wtf/Forward.h>
namespace WebCore {
- class NavigationAction {
- public:
- NavigationAction();
- explicit NavigationAction(const ResourceRequest&);
- NavigationAction(const ResourceRequest&, NavigationType);
- NavigationAction(const ResourceRequest&, FrameLoadType, bool isFormSubmission);
- NavigationAction(const ResourceRequest&, NavigationType, PassRefPtr<Event>);
- NavigationAction(const ResourceRequest&, FrameLoadType, bool isFormSubmission, PassRefPtr<Event>);
+class NavigationAction {
+public:
+ WEBCORE_EXPORT NavigationAction();
+ WEBCORE_EXPORT explicit NavigationAction(const ResourceRequest&);
+ WEBCORE_EXPORT NavigationAction(const ResourceRequest&, NavigationType);
+ WEBCORE_EXPORT NavigationAction(const ResourceRequest&, FrameLoadType, bool isFormSubmission);
- bool isEmpty() const { return m_resourceRequest.url().isEmpty(); }
+ NavigationAction(const ResourceRequest&, ShouldOpenExternalURLsPolicy);
+ NavigationAction(const ResourceRequest&, NavigationType, Event*);
+ NavigationAction(const ResourceRequest&, NavigationType, Event*, ShouldOpenExternalURLsPolicy);
+ NavigationAction(const ResourceRequest&, NavigationType, Event*, ShouldOpenExternalURLsPolicy, const AtomicString& downloadAttribute);
+ NavigationAction(const ResourceRequest&, NavigationType, ShouldOpenExternalURLsPolicy);
+ NavigationAction(const ResourceRequest&, FrameLoadType, bool isFormSubmission, Event*);
+ NavigationAction(const ResourceRequest&, FrameLoadType, bool isFormSubmission, Event*, ShouldOpenExternalURLsPolicy);
+ NavigationAction(const ResourceRequest&, FrameLoadType, bool isFormSubmission, Event*, ShouldOpenExternalURLsPolicy, const AtomicString& downloadAttribute);
- URL url() const { return m_resourceRequest.url(); }
- const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
+ NavigationAction copyWithShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy) const;
- NavigationType type() const { return m_type; }
- const Event* event() const { return m_event.get(); }
+ bool isEmpty() const { return m_resourceRequest.url().isEmpty(); }
- private:
- ResourceRequest m_resourceRequest;
- NavigationType m_type;
- RefPtr<Event> m_event;
- };
+ URL url() const { return m_resourceRequest.url(); }
+ const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
-}
+ NavigationType type() const { return m_type; }
+ const Event* event() const { return m_event.get(); }
-#endif
+ bool processingUserGesture() const { return m_userGestureToken ? m_userGestureToken->processingUserGesture() : false; }
+ RefPtr<UserGestureToken> userGestureToken() const { return m_userGestureToken; }
+
+ ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy() const { return m_shouldOpenExternalURLsPolicy; }
+
+ const AtomicString& downloadAttribute() const { return m_downloadAttribute; }
+
+private:
+ ResourceRequest m_resourceRequest;
+ NavigationType m_type { NavigationType::Other };
+ RefPtr<Event> m_event;
+ RefPtr<UserGestureToken> m_userGestureToken;
+ ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
+ AtomicString m_downloadAttribute;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp
index 7a6351639..0f0290c11 100644
--- a/Source/WebCore/loader/NavigationScheduler.cpp
+++ b/Source/WebCore/loader/NavigationScheduler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2009 Adam Barth. All rights reserved.
@@ -13,7 +13,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -46,6 +46,7 @@
#include "HTMLFrameOwnerElement.h"
#include "HistoryItem.h"
#include "InspectorInstrumentation.h"
+#include "Logging.h"
#include "Page.h"
#include "ScriptController.h"
#include "UserGestureIndicator.h"
@@ -54,18 +55,28 @@
namespace WebCore {
-unsigned NavigationDisablerForBeforeUnload::s_navigationDisableCount = 0;
+unsigned NavigationDisabler::s_navigationDisableCount = 0;
class ScheduledNavigation {
WTF_MAKE_NONCOPYABLE(ScheduledNavigation); WTF_MAKE_FAST_ALLOCATED;
public:
- ScheduledNavigation(double delay, bool lockHistory, bool lockBackForwardList, bool wasDuringLoad, bool isLocationChange)
+ ScheduledNavigation(double delay, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool wasDuringLoad, bool isLocationChange)
: m_delay(delay)
, m_lockHistory(lockHistory)
, m_lockBackForwardList(lockBackForwardList)
, m_wasDuringLoad(wasDuringLoad)
, m_isLocationChange(isLocationChange)
- , m_wasUserGesture(ScriptController::processingUserGesture())
+ , m_userGestureToForward(UserGestureIndicator::currentUserGesture())
+ {
+ }
+ ScheduledNavigation(double delay, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool wasDuringLoad, bool isLocationChange, ShouldOpenExternalURLsPolicy externalURLPolicy)
+ : m_delay(delay)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_wasDuringLoad(wasDuringLoad)
+ , m_isLocationChange(isLocationChange)
+ , m_userGestureToForward(UserGestureIndicator::currentUserGesture())
+ , m_shouldOpenExternalURLsPolicy(externalURLPolicy)
{
}
virtual ~ScheduledNavigation() { }
@@ -73,56 +84,61 @@ public:
virtual void fire(Frame&) = 0;
virtual bool shouldStartTimer(Frame&) { return true; }
- virtual void didStartTimer(Frame&, Timer<NavigationScheduler>&) { }
+ virtual void didStartTimer(Frame&, Timer&) { }
virtual void didStopTimer(Frame&, bool /* newLoadInProgress */) { }
double delay() const { return m_delay; }
- bool lockHistory() const { return m_lockHistory; }
- bool lockBackForwardList() const { return m_lockBackForwardList; }
+ LockHistory lockHistory() const { return m_lockHistory; }
+ LockBackForwardList lockBackForwardList() const { return m_lockBackForwardList; }
bool wasDuringLoad() const { return m_wasDuringLoad; }
bool isLocationChange() const { return m_isLocationChange; }
- bool wasUserGesture() const { return m_wasUserGesture; }
+ UserGestureToken* userGestureToForward() const { return m_userGestureToForward.get(); }
protected:
- void clearUserGesture() { m_wasUserGesture = false; }
+ void clearUserGesture() { m_userGestureToForward = nullptr; }
+ ShouldOpenExternalURLsPolicy shouldOpenExternalURLs() const { return m_shouldOpenExternalURLsPolicy; }
private:
double m_delay;
- bool m_lockHistory;
- bool m_lockBackForwardList;
+ LockHistory m_lockHistory;
+ LockBackForwardList m_lockBackForwardList;
bool m_wasDuringLoad;
bool m_isLocationChange;
- bool m_wasUserGesture;
+ RefPtr<UserGestureToken> m_userGestureToForward;
+ ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
};
class ScheduledURLNavigation : public ScheduledNavigation {
protected:
- ScheduledURLNavigation(double delay, SecurityOrigin* securityOrigin, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool duringLoad, bool isLocationChange)
- : ScheduledNavigation(delay, lockHistory, lockBackForwardList, duringLoad, isLocationChange)
+ ScheduledURLNavigation(Document& initiatingDocument, double delay, SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool duringLoad, bool isLocationChange)
+ : ScheduledNavigation(delay, lockHistory, lockBackForwardList, duringLoad, isLocationChange, initiatingDocument.shouldOpenExternalURLsPolicyToPropagate())
, m_securityOrigin(securityOrigin)
, m_url(url)
, m_referrer(referrer)
- , m_haveToldClient(false)
{
}
- virtual void fire(Frame& frame) override
+ void fire(Frame& frame) override
{
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
- frame.loader().changeLocation(m_securityOrigin.get(), URL(ParsedURLString, m_url), m_referrer, lockHistory(), lockBackForwardList(), false);
+ UserGestureIndicator gestureIndicator(userGestureToForward());
+
+ ResourceRequest resourceRequest(m_url, m_referrer, UseProtocolCachePolicy);
+ FrameLoadRequest frameRequest(*m_securityOrigin, resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs());
+
+ frame.loader().changeLocation(frameRequest);
}
- virtual void didStartTimer(Frame& frame, Timer<NavigationScheduler>& timer) override
+ void didStartTimer(Frame& frame, Timer& timer) override
{
if (m_haveToldClient)
return;
m_haveToldClient = true;
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
- frame.loader().clientRedirected(URL(ParsedURLString, m_url), delay(), currentTime() + timer.nextFireInterval(), lockBackForwardList());
+ UserGestureIndicator gestureIndicator(userGestureToForward());
+ frame.loader().clientRedirected(m_url, delay(), currentTime() + timer.nextFireInterval(), lockBackForwardList());
}
- virtual void didStopTimer(Frame& frame, bool newLoadInProgress) override
+ void didStopTimer(Frame& frame, bool newLoadInProgress) override
{
if (!m_haveToldClient)
return;
@@ -137,73 +153,88 @@ protected:
}
SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); }
- String url() const { return m_url; }
+ const URL& url() const { return m_url; }
String referrer() const { return m_referrer; }
private:
RefPtr<SecurityOrigin> m_securityOrigin;
- String m_url;
+ URL m_url;
String m_referrer;
- bool m_haveToldClient;
+ bool m_haveToldClient { false };
};
class ScheduledRedirect : public ScheduledURLNavigation {
public:
- ScheduledRedirect(double delay, SecurityOrigin* securityOrigin, const String& url, bool lockHistory, bool lockBackForwardList)
- : ScheduledURLNavigation(delay, securityOrigin, url, String(), lockHistory, lockBackForwardList, false, false)
+ ScheduledRedirect(Document& initiatingDocument, double delay, SecurityOrigin* securityOrigin, const URL& url, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
+ : ScheduledURLNavigation(initiatingDocument, delay, securityOrigin, url, String(), lockHistory, lockBackForwardList, false, false)
{
clearUserGesture();
}
- virtual bool shouldStartTimer(Frame& frame) override
+ bool shouldStartTimer(Frame& frame) override
{
return frame.loader().allAncestorsAreComplete();
}
- virtual void fire(Frame& frame) override
+ void fire(Frame& frame) override
{
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
- bool refresh = equalIgnoringFragmentIdentifier(frame.document()->url(), URL(ParsedURLString, url()));
- frame.loader().changeLocation(securityOrigin(), URL(ParsedURLString, url()), referrer(), lockHistory(), lockBackForwardList(), refresh);
+ UserGestureIndicator gestureIndicator(userGestureToForward());
+ bool refresh = equalIgnoringFragmentIdentifier(frame.document()->url(), url());
+ ResourceRequest resourceRequest(url(), referrer(), refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
+ FrameLoadRequest frameRequest(*securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs());
+
+ frame.loader().changeLocation(frameRequest);
}
};
class ScheduledLocationChange : public ScheduledURLNavigation {
public:
- ScheduledLocationChange(SecurityOrigin* securityOrigin, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool duringLoad)
- : ScheduledURLNavigation(0.0, securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad, true) { }
+ ScheduledLocationChange(Document& initiatingDocument, SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool duringLoad)
+ : ScheduledURLNavigation(initiatingDocument, 0.0, securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad, true) { }
+
+ void fire(Frame& frame) override
+ {
+ UserGestureIndicator gestureIndicator(userGestureToForward());
+
+ ResourceRequest resourceRequest(url(), referrer(), UseProtocolCachePolicy);
+ FrameLoadRequest frameRequest(*securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs());
+ frame.loader().changeLocation(frameRequest);
+ }
};
class ScheduledRefresh : public ScheduledURLNavigation {
public:
- ScheduledRefresh(SecurityOrigin* securityOrigin, const String& url, const String& referrer)
- : ScheduledURLNavigation(0.0, securityOrigin, url, referrer, true, true, false, true)
+ ScheduledRefresh(Document& initiatingDocument, SecurityOrigin* securityOrigin, const URL& url, const String& referrer)
+ : ScheduledURLNavigation(initiatingDocument, 0.0, securityOrigin, url, referrer, LockHistory::Yes, LockBackForwardList::Yes, false, true)
{
}
- virtual void fire(Frame& frame) override
+ void fire(Frame& frame) override
{
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
- frame.loader().changeLocation(securityOrigin(), URL(ParsedURLString, url()), referrer(), lockHistory(), lockBackForwardList(), true);
+ UserGestureIndicator gestureIndicator(userGestureToForward());
+
+ ResourceRequest resourceRequest(url(), referrer(), ReloadIgnoringCacheData);
+ FrameLoadRequest frameRequest(*securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs());
+ frame.loader().changeLocation(frameRequest);
}
};
class ScheduledHistoryNavigation : public ScheduledNavigation {
public:
explicit ScheduledHistoryNavigation(int historySteps)
- : ScheduledNavigation(0, false, false, false, true)
+ : ScheduledNavigation(0, LockHistory::No, LockBackForwardList::No, false, true)
, m_historySteps(historySteps)
{
}
- virtual void fire(Frame& frame) override
+ void fire(Frame& frame) override
{
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+ UserGestureIndicator gestureIndicator(userGestureToForward());
if (!m_historySteps) {
// Special case for go(0) from a frame -> reload only the frame
// To follow Firefox and IE's behavior, history reload can only navigate the self frame.
- frame.loader().urlSelected(frame.document()->url(), "_self", 0, lockHistory(), lockBackForwardList(), MaybeSendReferrer);
+ frame.loader().urlSelected(frame.document()->url(), "_self", 0, lockHistory(), lockBackForwardList(), MaybeSendReferrer, shouldOpenExternalURLs());
return;
}
@@ -218,41 +249,39 @@ private:
class ScheduledFormSubmission : public ScheduledNavigation {
public:
- ScheduledFormSubmission(PassRefPtr<FormSubmission> submission, bool lockBackForwardList, bool duringLoad)
- : ScheduledNavigation(0, submission->lockHistory(), lockBackForwardList, duringLoad, true)
- , m_submission(submission)
- , m_haveToldClient(false)
+ ScheduledFormSubmission(Ref<FormSubmission>&& submission, LockBackForwardList lockBackForwardList, bool duringLoad)
+ : ScheduledNavigation(0, submission->lockHistory(), lockBackForwardList, duringLoad, true, submission->state().sourceDocument().shouldOpenExternalURLsPolicyToPropagate())
+ , m_submission(WTFMove(submission))
{
- ASSERT(m_submission->state());
}
- virtual void fire(Frame& frame) override
+ void fire(Frame& frame) override
{
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+ UserGestureIndicator gestureIndicator(userGestureToForward());
// The submitForm function will find a target frame before using the redirection timer.
// Now that the timer has fired, we need to repeat the security check which normally is done when
// selecting a target, in case conditions have changed. Other code paths avoid this by targeting
// without leaving a time window. If we fail the check just silently drop the form submission.
- Document* requestingDocument = m_submission->state()->sourceDocument();
- if (!requestingDocument->canNavigate(&frame))
+ auto& requestingDocument = m_submission->state().sourceDocument();
+ if (!requestingDocument.canNavigate(&frame))
return;
- FrameLoadRequest frameRequest(requestingDocument->securityOrigin());
+ FrameLoadRequest frameRequest(requestingDocument.securityOrigin(), lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs());
m_submission->populateFrameLoadRequest(frameRequest);
- frame.loader().loadFrameRequest(frameRequest, lockHistory(), lockBackForwardList(), m_submission->event(), m_submission->state(), MaybeSendReferrer);
+ frame.loader().loadFrameRequest(frameRequest, m_submission->event(), &m_submission->state());
}
-
- virtual void didStartTimer(Frame& frame, Timer<NavigationScheduler>& timer) override
+
+ void didStartTimer(Frame& frame, Timer& timer) override
{
if (m_haveToldClient)
return;
m_haveToldClient = true;
- UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+ UserGestureIndicator gestureIndicator(userGestureToForward());
frame.loader().clientRedirected(m_submission->requestURL(), delay(), currentTime() + timer.nextFireInterval(), lockBackForwardList());
}
- virtual void didStopTimer(Frame& frame, bool newLoadInProgress) override
+ void didStopTimer(Frame& frame, bool newLoadInProgress) override
{
if (!m_haveToldClient)
return;
@@ -267,13 +296,38 @@ public:
}
private:
- RefPtr<FormSubmission> m_submission;
- bool m_haveToldClient;
+ Ref<FormSubmission> m_submission;
+ bool m_haveToldClient { false };
+};
+
+class ScheduledPageBlock final : public ScheduledNavigation {
+public:
+ ScheduledPageBlock(Document& originDocument)
+ : ScheduledNavigation(0, LockHistory::Yes, LockBackForwardList::Yes, false, false)
+ , m_originDocument(originDocument)
+ {
+ }
+
+ void fire(Frame& frame) override
+ {
+ UserGestureIndicator gestureIndicator(userGestureToForward());
+
+ ResourceResponse replacementResponse(m_originDocument.url(), ASCIILiteral("text/plain"), 0, ASCIILiteral("UTF-8"));
+ SubstituteData replacementData(SharedBuffer::create(), m_originDocument.url(), replacementResponse, SubstituteData::SessionHistoryVisibility::Hidden);
+
+ ResourceRequest resourceRequest(m_originDocument.url(), emptyString(), ReloadIgnoringCacheData);
+ FrameLoadRequest frameRequest(m_originDocument.securityOrigin(), resourceRequest, lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs());
+ frameRequest.setSubstituteData(replacementData);
+ frame.loader().load(frameRequest);
+ }
+
+private:
+ Document& m_originDocument;
};
NavigationScheduler::NavigationScheduler(Frame& frame)
: m_frame(frame)
- , m_timer(this, &NavigationScheduler::timerFired)
+ , m_timer(*this, &NavigationScheduler::timerFired)
{
}
@@ -304,12 +358,16 @@ inline bool NavigationScheduler::shouldScheduleNavigation() const
return m_frame.page();
}
-inline bool NavigationScheduler::shouldScheduleNavigation(const String& url) const
+inline bool NavigationScheduler::shouldScheduleNavigation(const URL& url) const
{
- return shouldScheduleNavigation() && (protocolIsJavaScript(url) || NavigationDisablerForBeforeUnload::isNavigationAllowed());
+ if (!shouldScheduleNavigation())
+ return false;
+ if (protocolIsJavaScript(url))
+ return true;
+ return NavigationDisabler::isNavigationAllowed();
}
-void NavigationScheduler::scheduleRedirect(double delay, const String& url)
+void NavigationScheduler::scheduleRedirect(Document& initiatingDocument, double delay, const URL& url)
{
if (!shouldScheduleNavigation(url))
return;
@@ -319,16 +377,18 @@ void NavigationScheduler::scheduleRedirect(double delay, const String& url)
return;
// We want a new back/forward list item if the refresh timeout is > 1 second.
- if (!m_redirect || delay <= m_redirect->delay())
- schedule(std::make_unique<ScheduledRedirect>(delay, m_frame.document()->securityOrigin(), url, true, delay <= 1));
+ if (!m_redirect || delay <= m_redirect->delay()) {
+ auto lockBackForwardList = delay <= 1 ? LockBackForwardList::Yes : LockBackForwardList::No;
+ schedule(std::make_unique<ScheduledRedirect>(initiatingDocument, delay, &m_frame.document()->securityOrigin(), url, LockHistory::Yes, lockBackForwardList));
+ }
}
-bool NavigationScheduler::mustLockBackForwardList(Frame& targetFrame)
+LockBackForwardList NavigationScheduler::mustLockBackForwardList(Frame& targetFrame)
{
// Non-user navigation before the page has finished firing onload should not create a new back/forward item.
// See https://webkit.org/b/42861 for the original motivation for this.
- if (!ScriptController::processingUserGesture() && targetFrame.loader().documentLoader() && !targetFrame.loader().documentLoader()->wasOnloadHandled())
- return true;
+ if (!UserGestureIndicator::processingUserGesture() && targetFrame.loader().documentLoader() && !targetFrame.loader().documentLoader()->wasOnloadDispatched())
+ return LockBackForwardList::Yes;
// Navigation of a subframe during loading of an ancestor frame does not create a new back/forward item.
// The definition of "during load" is any time before all handlers for the load event have been run.
@@ -336,38 +396,38 @@ bool NavigationScheduler::mustLockBackForwardList(Frame& targetFrame)
for (Frame* ancestor = targetFrame.tree().parent(); ancestor; ancestor = ancestor->tree().parent()) {
Document* document = ancestor->document();
if (!ancestor->loader().isComplete() || (document && document->processingLoadEvent()))
- return true;
+ return LockBackForwardList::Yes;
}
- return false;
+ return LockBackForwardList::No;
}
-void NavigationScheduler::scheduleLocationChange(SecurityOrigin* securityOrigin, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList)
+void NavigationScheduler::scheduleLocationChange(Document& initiatingDocument, SecurityOrigin& securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
{
if (!shouldScheduleNavigation(url))
return;
- if (url.isEmpty())
- return;
- lockBackForwardList = lockBackForwardList || mustLockBackForwardList(m_frame);
+ if (lockBackForwardList == LockBackForwardList::No)
+ lockBackForwardList = mustLockBackForwardList(m_frame);
FrameLoader& loader = m_frame.loader();
// If the URL we're going to navigate to is the same as the current one, except for the
// fragment part, we don't need to schedule the location change.
- URL parsedURL(ParsedURLString, url);
- if (parsedURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(m_frame.document()->url(), parsedURL)) {
- loader.changeLocation(securityOrigin, m_frame.document()->completeURL(url), referrer, lockHistory, lockBackForwardList);
+ if (url.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(m_frame.document()->url(), url)) {
+ ResourceRequest resourceRequest(m_frame.document()->completeURL(url), referrer, UseProtocolCachePolicy);
+ FrameLoadRequest frameRequest(securityOrigin, resourceRequest, "_self", lockHistory, lockBackForwardList, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ReplaceDocumentIfJavaScriptURL, initiatingDocument.shouldOpenExternalURLsPolicyToPropagate());
+ loader.changeLocation(frameRequest);
return;
}
// Handle a location change of a page with no document as a special case.
// This may happen when a frame changes the location of another frame.
- bool duringLoad = !loader.stateMachine()->committedFirstRealDocumentLoad();
+ bool duringLoad = !loader.stateMachine().committedFirstRealDocumentLoad();
- schedule(std::make_unique<ScheduledLocationChange>(securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad));
+ schedule(std::make_unique<ScheduledLocationChange>(initiatingDocument, &securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad));
}
-void NavigationScheduler::scheduleFormSubmission(PassRefPtr<FormSubmission> submission)
+void NavigationScheduler::scheduleFormSubmission(Ref<FormSubmission>&& submission)
{
ASSERT(m_frame.page());
@@ -376,19 +436,21 @@ void NavigationScheduler::scheduleFormSubmission(PassRefPtr<FormSubmission> subm
// Handle a location change of a page with no document as a special case.
// This may happen when a frame changes the location of another frame.
- bool duringLoad = !m_frame.loader().stateMachine()->committedFirstRealDocumentLoad();
+ bool duringLoad = !m_frame.loader().stateMachine().committedFirstRealDocumentLoad();
// If this is a child frame and the form submission was triggered by a script, lock the back/forward list
// to match IE and Opera.
// See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
- bool lockBackForwardList = mustLockBackForwardList(m_frame)
- || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript
- && m_frame.tree().parent() && !ScriptController::processingUserGesture());
-
- schedule(std::make_unique<ScheduledFormSubmission>(submission, lockBackForwardList, duringLoad));
+ LockBackForwardList lockBackForwardList = mustLockBackForwardList(m_frame);
+ if (lockBackForwardList == LockBackForwardList::No
+ && (submission->state().formSubmissionTrigger() == SubmittedByJavaScript && m_frame.tree().parent() && !UserGestureIndicator::processingUserGesture())) {
+ lockBackForwardList = LockBackForwardList::Yes;
+ }
+
+ schedule(std::make_unique<ScheduledFormSubmission>(WTFMove(submission), lockBackForwardList, duringLoad));
}
-void NavigationScheduler::scheduleRefresh()
+void NavigationScheduler::scheduleRefresh(Document& initiatingDocument)
{
if (!shouldScheduleNavigation())
return;
@@ -396,11 +458,12 @@ void NavigationScheduler::scheduleRefresh()
if (url.isEmpty())
return;
- schedule(std::make_unique<ScheduledRefresh>(m_frame.document()->securityOrigin(), url.string(), m_frame.loader().outgoingReferrer()));
+ schedule(std::make_unique<ScheduledRefresh>(initiatingDocument, &m_frame.document()->securityOrigin(), url, m_frame.loader().outgoingReferrer()));
}
void NavigationScheduler::scheduleHistoryNavigation(int steps)
{
+ LOG(History, "NavigationScheduler %p scheduleHistoryNavigation(%d) - shouldSchedule %d", this, steps, shouldScheduleNavigation());
if (!shouldScheduleNavigation())
return;
@@ -416,7 +479,13 @@ void NavigationScheduler::scheduleHistoryNavigation(int steps)
schedule(std::make_unique<ScheduledHistoryNavigation>(steps));
}
-void NavigationScheduler::timerFired(Timer<NavigationScheduler>&)
+void NavigationScheduler::schedulePageBlock(Document& originDocument)
+{
+ if (shouldScheduleNavigation())
+ schedule(std::make_unique<ScheduledPageBlock>(originDocument));
+}
+
+void NavigationScheduler::timerFired()
{
if (!m_frame.page())
return;
@@ -427,7 +496,9 @@ void NavigationScheduler::timerFired(Timer<NavigationScheduler>&)
Ref<Frame> protect(m_frame);
- std::unique_ptr<ScheduledNavigation> redirect = std::move(m_redirect);
+ std::unique_ptr<ScheduledNavigation> redirect = WTFMove(m_redirect);
+ LOG(History, "NavigationScheduler %p timerFired - firing redirect %p", this, redirect.get());
+
redirect->fire(m_frame);
InspectorInstrumentation::frameClearedScheduledNavigation(m_frame);
}
@@ -448,7 +519,7 @@ void NavigationScheduler::schedule(std::unique_ptr<ScheduledNavigation> redirect
}
cancel();
- m_redirect = std::move(redirect);
+ m_redirect = WTFMove(redirect);
if (!m_frame.loader().isComplete() && m_redirect->isLocationChange())
m_frame.loader().completed();
@@ -478,11 +549,13 @@ void NavigationScheduler::startTimer()
void NavigationScheduler::cancel(bool newLoadInProgress)
{
+ LOG(History, "NavigationScheduler %p cancel(newLoadInProgress=%d)", this, newLoadInProgress);
+
if (m_timer.isActive())
InspectorInstrumentation::frameClearedScheduledNavigation(m_frame);
m_timer.stop();
- if (std::unique_ptr<ScheduledNavigation> redirect = std::move(m_redirect))
+ if (std::unique_ptr<ScheduledNavigation> redirect = WTFMove(m_redirect))
redirect->didStopTimer(m_frame, newLoadInProgress);
}
diff --git a/Source/WebCore/loader/NavigationScheduler.h b/Source/WebCore/loader/NavigationScheduler.h
index 78756d6cf..a2a0b94d9 100644
--- a/Source/WebCore/loader/NavigationScheduler.h
+++ b/Source/WebCore/loader/NavigationScheduler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2009 Adam Barth. All rights reserved.
*
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -28,30 +28,28 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NavigationScheduler_h
-#define NavigationScheduler_h
+#pragma once
+#include "FrameLoaderTypes.h"
#include "Timer.h"
#include <wtf/Forward.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/PassRefPtr.h>
namespace WebCore {
+class Document;
class FormSubmission;
class Frame;
class ScheduledNavigation;
class SecurityOrigin;
+class URL;
-class NavigationDisablerForBeforeUnload {
- WTF_MAKE_NONCOPYABLE(NavigationDisablerForBeforeUnload);
-
+class NavigationDisabler {
public:
- NavigationDisablerForBeforeUnload()
+ NavigationDisabler()
{
s_navigationDisableCount++;
}
- ~NavigationDisablerForBeforeUnload()
+ ~NavigationDisabler()
{
ASSERT(s_navigationDisableCount);
s_navigationDisableCount--;
@@ -63,8 +61,6 @@ private:
};
class NavigationScheduler {
- WTF_MAKE_NONCOPYABLE(NavigationScheduler);
-
public:
explicit NavigationScheduler(Frame&);
~NavigationScheduler();
@@ -72,11 +68,12 @@ public:
bool redirectScheduledDuringLoad();
bool locationChangePending();
- void scheduleRedirect(double delay, const String& url);
- void scheduleLocationChange(SecurityOrigin*, const String& url, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true);
- void scheduleFormSubmission(PassRefPtr<FormSubmission>);
- void scheduleRefresh();
+ void scheduleRedirect(Document& initiatingDocument, double delay, const URL&);
+ void scheduleLocationChange(Document& initiatingDocument, SecurityOrigin&, const URL&, const String& referrer, LockHistory = LockHistory::Yes, LockBackForwardList = LockBackForwardList::Yes);
+ void scheduleFormSubmission(Ref<FormSubmission>&&);
+ void scheduleRefresh(Document& initiatingDocument);
void scheduleHistoryNavigation(int steps);
+ void schedulePageBlock(Document& originDocument);
void startTimer();
@@ -85,18 +82,16 @@ public:
private:
bool shouldScheduleNavigation() const;
- bool shouldScheduleNavigation(const String& url) const;
+ bool shouldScheduleNavigation(const URL&) const;
- void timerFired(Timer<NavigationScheduler>&);
+ void timerFired();
void schedule(std::unique_ptr<ScheduledNavigation>);
- static bool mustLockBackForwardList(Frame& targetFrame);
+ static LockBackForwardList mustLockBackForwardList(Frame& targetFrame);
Frame& m_frame;
- Timer<NavigationScheduler> m_timer;
+ Timer m_timer;
std::unique_ptr<ScheduledNavigation> m_redirect;
};
} // namespace WebCore
-
-#endif // NavigationScheduler_h
diff --git a/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp b/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp
index b8c4556fa..6b9a344ea 100644
--- a/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp
+++ b/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -34,26 +34,34 @@
#include "FrameLoaderClient.h"
#include <wtf/Ref.h>
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "ResourceLoadInfo.h"
+#endif
+
namespace WebCore {
-NetscapePlugInStreamLoader::NetscapePlugInStreamLoader(Frame* frame, NetscapePlugInStreamLoaderClient* client)
- : ResourceLoader(frame, ResourceLoaderOptions(SendCallbacks, SniffContent, DoNotBufferData, AllowStoredCredentials, AskClientForAllCredentials, SkipSecurityCheck, UseDefaultOriginRestrictionsForType))
- , m_client(client)
+// FIXME: Skip Content Security Policy check when associated plugin element is in a user agent shadow tree.
+// See <https://bugs.webkit.org/show_bug.cgi?id=146663>.
+NetscapePlugInStreamLoader::NetscapePlugInStreamLoader(Frame& frame, NetscapePlugInStreamLoaderClient& client)
+ : ResourceLoader(frame, ResourceLoaderOptions(SendCallbacks, SniffContent, DoNotBufferData, AllowStoredCredentials, ClientCredentialPolicy::MayAskClientForCredentials, FetchOptions::Credentials::Include, SkipSecurityCheck, FetchOptions::Mode::NoCors, DoNotIncludeCertificateInfo, ContentSecurityPolicyImposition::DoPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching))
+ , m_client(&client)
{
+#if ENABLE(CONTENT_EXTENSIONS)
+ m_resourceType = ResourceType::PlugInStream;
+#endif
}
NetscapePlugInStreamLoader::~NetscapePlugInStreamLoader()
{
}
-PassRefPtr<NetscapePlugInStreamLoader> NetscapePlugInStreamLoader::create(Frame* frame, NetscapePlugInStreamLoaderClient* client, const ResourceRequest& request)
+RefPtr<NetscapePlugInStreamLoader> NetscapePlugInStreamLoader::create(Frame& frame, NetscapePlugInStreamLoaderClient& client, const ResourceRequest& request)
{
- RefPtr<NetscapePlugInStreamLoader> loader(adoptRef(new NetscapePlugInStreamLoader(frame, client)));
- loader->documentLoader()->addPlugInStreamLoader(loader.get());
+ auto loader(adoptRef(new NetscapePlugInStreamLoader(frame, client)));
if (!loader->init(request))
- return 0;
+ return nullptr;
- return loader.release();
+ return loader;
}
bool NetscapePlugInStreamLoader::isDone() const
@@ -63,13 +71,38 @@ bool NetscapePlugInStreamLoader::isDone() const
void NetscapePlugInStreamLoader::releaseResources()
{
- m_client = 0;
+ m_client = nullptr;
ResourceLoader::releaseResources();
}
+bool NetscapePlugInStreamLoader::init(const ResourceRequest& request)
+{
+ if (!ResourceLoader::init(request))
+ return false;
+
+ ASSERT(!reachedTerminalState());
+
+ m_documentLoader->addPlugInStreamLoader(*this);
+ m_isInitialized = true;
+
+ return true;
+}
+
+void NetscapePlugInStreamLoader::willSendRequest(ResourceRequest&& request, const ResourceResponse& redirectResponse, std::function<void(ResourceRequest&&)>&& callback)
+{
+ RefPtr<NetscapePlugInStreamLoader> protectedThis(this);
+
+ m_client->willSendRequest(this, WTFMove(request), redirectResponse, [protectedThis, redirectResponse, callback](ResourceRequest request) {
+ if (!request.isNull())
+ protectedThis->willSendRequestInternal(request, redirectResponse);
+
+ callback(WTFMove(request));
+ });
+}
+
void NetscapePlugInStreamLoader::didReceiveResponse(const ResourceResponse& response)
{
- Ref<NetscapePlugInStreamLoader> protect(*this);
+ Ref<NetscapePlugInStreamLoader> protectedThis(*this);
m_client->didReceiveResponse(this, response);
@@ -96,37 +129,39 @@ void NetscapePlugInStreamLoader::didReceiveResponse(const ResourceResponse& resp
void NetscapePlugInStreamLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType)
{
- didReceiveDataOrBuffer(data, length, 0, encodedDataLength, dataPayloadType);
+ didReceiveDataOrBuffer(data, length, nullptr, encodedDataLength, dataPayloadType);
}
-void NetscapePlugInStreamLoader::didReceiveBuffer(PassRefPtr<SharedBuffer> buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
+void NetscapePlugInStreamLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
{
- didReceiveDataOrBuffer(0, 0, buffer, encodedDataLength, dataPayloadType);
+ didReceiveDataOrBuffer(nullptr, 0, WTFMove(buffer), encodedDataLength, dataPayloadType);
}
-void NetscapePlugInStreamLoader::didReceiveDataOrBuffer(const char* data, int length, PassRefPtr<SharedBuffer> buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
+void NetscapePlugInStreamLoader::didReceiveDataOrBuffer(const char* data, int length, RefPtr<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
{
- Ref<NetscapePlugInStreamLoader> protect(*this);
+ Ref<NetscapePlugInStreamLoader> protectedThis(*this);
m_client->didReceiveData(this, buffer ? buffer->data() : data, buffer ? buffer->size() : length);
- ResourceLoader::didReceiveDataOrBuffer(data, length, buffer, encodedDataLength, dataPayloadType);
+ ResourceLoader::didReceiveDataOrBuffer(data, length, WTFMove(buffer), encodedDataLength, dataPayloadType);
}
void NetscapePlugInStreamLoader::didFinishLoading(double finishTime)
{
- Ref<NetscapePlugInStreamLoader> protect(*this);
+ Ref<NetscapePlugInStreamLoader> protectedThis(*this);
+
+ notifyDone();
- m_documentLoader->removePlugInStreamLoader(this);
m_client->didFinishLoading(this);
ResourceLoader::didFinishLoading(finishTime);
}
void NetscapePlugInStreamLoader::didFail(const ResourceError& error)
{
- Ref<NetscapePlugInStreamLoader> protect(*this);
+ Ref<NetscapePlugInStreamLoader> protectedThis(*this);
+
+ notifyDone();
- m_documentLoader->removePlugInStreamLoader(this);
m_client->didFail(this, error);
ResourceLoader::didFail(error);
}
@@ -138,10 +173,16 @@ void NetscapePlugInStreamLoader::willCancel(const ResourceError& error)
void NetscapePlugInStreamLoader::didCancel(const ResourceError&)
{
- // We need to remove the stream loader after the call to didFail, since didFail can
- // spawn a new run loop and if the loader has been removed it won't be deferred when
- // the document loader is asked to defer loading.
- m_documentLoader->removePlugInStreamLoader(this);
+ notifyDone();
+}
+
+void NetscapePlugInStreamLoader::notifyDone()
+{
+ if (!m_isInitialized)
+ return;
+
+ m_documentLoader->removePlugInStreamLoader(*this);
}
+
}
diff --git a/Source/WebCore/loader/NetscapePlugInStreamLoader.h b/Source/WebCore/loader/NetscapePlugInStreamLoader.h
index be5ac8e01..1fe772b26 100644
--- a/Source/WebCore/loader/NetscapePlugInStreamLoader.h
+++ b/Source/WebCore/loader/NetscapePlugInStreamLoader.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NetscapePlugInStreamLoader_h
-#define NetscapePlugInStreamLoader_h
+#pragma once
#include "ResourceLoader.h"
#include <wtf/Forward.h>
@@ -38,6 +37,7 @@ class NetscapePlugInStreamLoader;
class NetscapePlugInStreamLoaderClient {
public:
+ virtual void willSendRequest(NetscapePlugInStreamLoader*, ResourceRequest&&, const ResourceResponse& redirectResponse, std::function<void (ResourceRequest&&)>&&) = 0;
virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&) = 0;
virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int) = 0;
virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&) = 0;
@@ -48,32 +48,36 @@ protected:
virtual ~NetscapePlugInStreamLoaderClient() { }
};
-class NetscapePlugInStreamLoader : public ResourceLoader {
+class NetscapePlugInStreamLoader final : public ResourceLoader {
public:
- static PassRefPtr<NetscapePlugInStreamLoader> create(Frame*, NetscapePlugInStreamLoaderClient*, const ResourceRequest&);
+ WEBCORE_EXPORT static RefPtr<NetscapePlugInStreamLoader> create(Frame&, NetscapePlugInStreamLoaderClient&, const ResourceRequest&);
virtual ~NetscapePlugInStreamLoader();
- bool isDone() const;
+ WEBCORE_EXPORT bool isDone() const;
private:
- virtual void didReceiveResponse(const ResourceResponse&) override;
- virtual void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override;
- virtual void didReceiveBuffer(PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType) override;
- virtual void didFinishLoading(double finishTime) override;
- virtual void didFail(const ResourceError&) override;
+ bool init(const ResourceRequest&) override;
- virtual void releaseResources() override;
+ void willSendRequest(ResourceRequest&&, const ResourceResponse& redirectResponse, std::function<void(ResourceRequest&&)>&& callback) override;
+ void didReceiveResponse(const ResourceResponse&) override;
+ void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override;
+ void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType) override;
+ void didFinishLoading(double finishTime) override;
+ void didFail(const ResourceError&) override;
- NetscapePlugInStreamLoader(Frame*, NetscapePlugInStreamLoaderClient*);
+ void releaseResources() override;
- virtual void willCancel(const ResourceError&) override;
- virtual void didCancel(const ResourceError&) override;
+ NetscapePlugInStreamLoader(Frame&, NetscapePlugInStreamLoaderClient&);
- void didReceiveDataOrBuffer(const char*, int, PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType);
+ void willCancel(const ResourceError&) override;
+ void didCancel(const ResourceError&) override;
+
+ void didReceiveDataOrBuffer(const char*, int, RefPtr<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
+
+ void notifyDone();
NetscapePlugInStreamLoaderClient* m_client;
+ bool m_isInitialized { false };
};
}
-
-#endif // NetscapePlugInStreamLoader_h
diff --git a/Source/WebCore/loader/PingLoader.cpp b/Source/WebCore/loader/PingLoader.cpp
index db7cde041..d5fff791f 100644
--- a/Source/WebCore/loader/PingLoader.cpp
+++ b/Source/WebCore/loader/PingLoader.cpp
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2015 Roopesh Chander (roop@roopc.net)
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -32,111 +34,166 @@
#include "config.h"
#include "PingLoader.h"
+#include "ContentSecurityPolicy.h"
#include "Document.h"
#include "FormData.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
+#include "HTTPHeaderNames.h"
#include "InspectorInstrumentation.h"
+#include "LoaderStrategy.h"
#include "Page.h"
+#include "PlatformStrategies.h"
#include "ProgressTracker.h"
#include "ResourceHandle.h"
+#include "ResourceLoadInfo.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SecurityOrigin.h"
#include "SecurityPolicy.h"
+#include "UserContentController.h"
#include <wtf/text/CString.h>
namespace WebCore {
-void PingLoader::loadImage(Frame* frame, const URL& url)
+#if !ENABLE(CONTENT_EXTENSIONS)
+
+// Returns true if we should block the load.
+static inline bool processContentExtensionRulesForLoad(const Frame&, ResourceRequest&, ResourceType)
+{
+ return false;
+}
+
+#else
+
+// Returns true if we should block the load.
+static bool processContentExtensionRulesForLoad(const Frame& frame, ResourceRequest& request, ResourceType resourceType)
+{
+ auto* documentLoader = frame.loader().documentLoader();
+ if (!documentLoader)
+ return false;
+ auto* page = frame.page();
+ if (!page)
+ return false;
+ auto status = page->userContentProvider().processContentExtensionRulesForLoad(request.url(), resourceType, *documentLoader);
+ applyBlockedStatusToRequest(status, request);
+ return status.blockedLoad;
+}
+
+#endif
+
+void PingLoader::loadImage(Frame& frame, const URL& url)
{
- if (!frame->document()->securityOrigin()->canDisplay(url)) {
- FrameLoader::reportLocalLoadFailed(frame, url);
+ ASSERT(frame.document());
+ auto& document = *frame.document();
+
+ if (!document.securityOrigin().canDisplay(url)) {
+ FrameLoader::reportLocalLoadFailed(&frame, url);
return;
}
ResourceRequest request(url);
- request.setHTTPHeaderField("Cache-Control", "max-age=0");
- String referrer = SecurityPolicy::generateReferrerHeader(frame->document()->referrerPolicy(), request.url(), frame->loader().outgoingReferrer());
+ if (processContentExtensionRulesForLoad(frame, request, ResourceType::Image))
+ return;
+
+ document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load);
+
+ request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
+ String referrer = SecurityPolicy::generateReferrerHeader(document.referrerPolicy(), request.url(), frame.loader().outgoingReferrer());
if (!referrer.isEmpty())
request.setHTTPReferrer(referrer);
- frame->loader().addExtraFieldsToSubresourceRequest(request);
+ frame.loader().addExtraFieldsToSubresourceRequest(request);
- createPingLoader(frame, request);
+ startPingLoad(frame, request, ShouldFollowRedirects::Yes);
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
-void PingLoader::sendPing(Frame* frame, const URL& pingURL, const URL& destinationURL)
+void PingLoader::sendPing(Frame& frame, const URL& pingURL, const URL& destinationURL)
{
+ ASSERT(frame.document());
+
+ if (!pingURL.protocolIsInHTTPFamily())
+ return;
+
ResourceRequest request(pingURL);
+ if (processContentExtensionRulesForLoad(frame, request, ResourceType::Raw))
+ return;
+
+ auto& document = *frame.document();
+ document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load);
+
request.setHTTPMethod("POST");
request.setHTTPContentType("text/ping");
request.setHTTPBody(FormData::create("PING"));
- request.setHTTPHeaderField("Cache-Control", "max-age=0");
- frame->loader().addExtraFieldsToSubresourceRequest(request);
-
- SecurityOrigin* sourceOrigin = frame->document()->securityOrigin();
- RefPtr<SecurityOrigin> pingOrigin = SecurityOrigin::create(pingURL);
- FrameLoader::addHTTPOriginIfNeeded(request, sourceOrigin->toString());
- request.setHTTPHeaderField("Ping-To", destinationURL);
- if (!SecurityPolicy::shouldHideReferrer(pingURL, frame->loader().outgoingReferrer())) {
- request.setHTTPHeaderField("Ping-From", frame->document()->url());
- if (!sourceOrigin->isSameSchemeHostPort(pingOrigin.get())) {
- String referrer = SecurityPolicy::generateReferrerHeader(frame->document()->referrerPolicy(), pingURL, frame->loader().outgoingReferrer());
+ request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
+ frame.loader().addExtraFieldsToSubresourceRequest(request);
+
+ auto& sourceOrigin = document.securityOrigin();
+ FrameLoader::addHTTPOriginIfNeeded(request, sourceOrigin.toString());
+ request.setHTTPHeaderField(HTTPHeaderName::PingTo, destinationURL);
+ if (!SecurityPolicy::shouldHideReferrer(pingURL, frame.loader().outgoingReferrer())) {
+ request.setHTTPHeaderField(HTTPHeaderName::PingFrom, document.url());
+ if (!sourceOrigin.isSameSchemeHostPort(SecurityOrigin::create(pingURL).get())) {
+ String referrer = SecurityPolicy::generateReferrerHeader(document.referrerPolicy(), pingURL, frame.loader().outgoingReferrer());
if (!referrer.isEmpty())
request.setHTTPReferrer(referrer);
}
}
- createPingLoader(frame, request);
+ startPingLoad(frame, request, ShouldFollowRedirects::Yes);
}
-void PingLoader::sendViolationReport(Frame* frame, const URL& reportURL, PassRefPtr<FormData> report)
+void PingLoader::sendViolationReport(Frame& frame, const URL& reportURL, Ref<FormData>&& report, ViolationReportType reportType)
{
+ ASSERT(frame.document());
+
ResourceRequest request(reportURL);
- request.setHTTPMethod("POST");
- request.setHTTPContentType("application/json");
- request.setHTTPBody(report);
- request.setAllowCookies(frame->document()->securityOrigin()->isSameSchemeHostPort(SecurityOrigin::create(reportURL).get()));
- frame->loader().addExtraFieldsToSubresourceRequest(request);
+ if (processContentExtensionRulesForLoad(frame, request, ResourceType::Raw))
+ return;
+
+ auto& document = *frame.document();
+ document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load);
+
+ request.setHTTPMethod(ASCIILiteral("POST"));
+ request.setHTTPBody(WTFMove(report));
+ switch (reportType) {
+ case ViolationReportType::ContentSecurityPolicy:
+ request.setHTTPContentType(ASCIILiteral("application/csp-report"));
+ break;
+ case ViolationReportType::XSSAuditor:
+ request.setHTTPContentType(ASCIILiteral("application/json"));
+ break;
+ }
- String referrer = SecurityPolicy::generateReferrerHeader(frame->document()->referrerPolicy(), reportURL, frame->loader().outgoingReferrer());
+ bool removeCookies = true;
+ if (document.securityOrigin().isSameSchemeHostPort(SecurityOrigin::create(reportURL).get()))
+ removeCookies = false;
+ if (removeCookies)
+ request.setAllowCookies(false);
+
+ frame.loader().addExtraFieldsToSubresourceRequest(request);
+
+ String referrer = SecurityPolicy::generateReferrerHeader(document.referrerPolicy(), reportURL, frame.loader().outgoingReferrer());
if (!referrer.isEmpty())
request.setHTTPReferrer(referrer);
- createPingLoader(frame, request);
-}
-
-void PingLoader::createPingLoader(Frame* frame, ResourceRequest& request)
-{
- // No need to free the PingLoader object or manage it via a smart pointer - it will kill itself as soon as it receives a response.
- new PingLoader(frame, request);
+ startPingLoad(frame, request, ShouldFollowRedirects::No);
}
-PingLoader::PingLoader(Frame* frame, ResourceRequest& request)
- : m_timeout(this, &PingLoader::timeoutTimerFired)
+void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, ShouldFollowRedirects shouldFollowRedirects)
{
- unsigned long identifier = frame->page()->progress().createUniqueIdentifier();
+ unsigned long identifier = frame.page()->progress().createUniqueIdentifier();
// FIXME: Why activeDocumentLoader? I would have expected documentLoader().
// Itseems like the PingLoader should be associated with the current
// Document in the Frame, but the activeDocumentLoader will be associated
// with the provisional DocumentLoader if there is a provisional
// DocumentLoader.
- m_shouldUseCredentialStorage = frame->loader().client().shouldUseCredentialStorage(frame->loader().activeDocumentLoader(), identifier);
- m_handle = ResourceHandle::create(frame->loader().networkingContext(), request, this, false, false);
-
- InspectorInstrumentation::continueAfterPingLoader(frame, identifier, frame->loader().activeDocumentLoader(), request, ResourceResponse());
+ bool shouldUseCredentialStorage = frame.loader().client().shouldUseCredentialStorage(frame.loader().activeDocumentLoader(), identifier);
- // If the server never responds, FrameLoader won't be able to cancel this load and
- // we'll sit here waiting forever. Set a very generous timeout, just in case.
- m_timeout.startOneShot(60000);
-}
+ InspectorInstrumentation::continueAfterPingLoader(frame, identifier, frame.loader().activeDocumentLoader(), request, ResourceResponse());
-PingLoader::~PingLoader()
-{
- if (m_handle)
- m_handle->cancel();
+ platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, shouldUseCredentialStorage, shouldFollowRedirects == ShouldFollowRedirects::Yes);
}
}
diff --git a/Source/WebCore/loader/PingLoader.h b/Source/WebCore/loader/PingLoader.h
index 295e2f4f2..b29e8da8f 100644
--- a/Source/WebCore/loader/PingLoader.h
+++ b/Source/WebCore/loader/PingLoader.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -29,53 +30,31 @@
*
*/
-#ifndef PingLoader_h
-#define PingLoader_h
+#pragma once
-#include "ResourceHandleClient.h"
-#include "Timer.h"
-#include <wtf/Noncopyable.h>
-#include <wtf/RefPtr.h>
+#include <wtf/Ref.h>
namespace WebCore {
class FormData;
class Frame;
class URL;
-class ResourceError;
-class ResourceHandle;
-class ResourceResponse;
+class ResourceRequest;
-// This class triggers asynchronous loads independent of Frame staying alive (i.e., auditing pingbacks).
-// Since nothing depends on resources loaded through this class, we just want
-// to allow the load to live long enough to ensure the message was actually sent.
-// Therefore, as soon as a callback is received from the ResourceHandle, this class
-// will cancel the load and delete itself.
-class PingLoader : private ResourceHandleClient {
- WTF_MAKE_NONCOPYABLE(PingLoader); WTF_MAKE_FAST_ALLOCATED;
-public:
- static void loadImage(Frame*, const URL& url);
- static void sendPing(Frame*, const URL& pingURL, const URL& destinationURL);
- static void sendViolationReport(Frame*, const URL& reportURL, PassRefPtr<FormData> report);
+enum class ViolationReportType {
+ ContentSecurityPolicy,
+ XSSAuditor,
+};
- virtual ~PingLoader();
+class PingLoader {
+public:
+ static void loadImage(Frame&, const URL&);
+ static void sendPing(Frame&, const URL& pingURL, const URL& destinationURL);
+ static void sendViolationReport(Frame&, const URL& reportURL, Ref<FormData>&& report, ViolationReportType);
private:
- static void createPingLoader(Frame*, ResourceRequest&);
- PingLoader(Frame*, ResourceRequest&);
-
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) override { delete this; }
- virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int) override { delete this; }
- virtual void didFinishLoading(ResourceHandle*, double) override { delete this; }
- virtual void didFail(ResourceHandle*, const ResourceError&) override { delete this; }
- virtual bool shouldUseCredentialStorage(ResourceHandle*) override { return m_shouldUseCredentialStorage; }
- void timeoutTimerFired(Timer<PingLoader>&) { delete this; }
-
- RefPtr<ResourceHandle> m_handle;
- Timer<PingLoader> m_timeout;
- bool m_shouldUseCredentialStorage;
+ enum class ShouldFollowRedirects { No, Yes };
+ static void startPingLoad(Frame&, ResourceRequest&, ShouldFollowRedirects);
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/PolicyCallback.cpp b/Source/WebCore/loader/PolicyCallback.cpp
index 6ffa8a8cd..f1f633102 100644
--- a/Source/WebCore/loader/PolicyCallback.cpp
+++ b/Source/WebCore/loader/PolicyCallback.cpp
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -38,14 +38,6 @@
namespace WebCore {
-PolicyCallback::PolicyCallback()
-{
-}
-
-PolicyCallback::~PolicyCallback()
-{
-}
-
void PolicyCallback::clear()
{
clearRequest();
@@ -54,19 +46,19 @@ void PolicyCallback::clear()
m_contentFunction = nullptr;
}
-void PolicyCallback::set(const ResourceRequest& request, PassRefPtr<FormState> formState,
+void PolicyCallback::set(const ResourceRequest& request, FormState* formState,
NavigationPolicyDecisionFunction function)
{
m_request = request;
m_formState = formState;
m_frameName = String();
- m_navigationFunction = std::move(function);
+ m_navigationFunction = WTFMove(function);
m_newWindowFunction = nullptr;
m_contentFunction = nullptr;
}
-void PolicyCallback::set(const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& navigationAction, NewWindowPolicyDecisionFunction function)
+void PolicyCallback::set(const ResourceRequest& request, FormState* formState, const String& frameName, const NavigationAction& navigationAction, NewWindowPolicyDecisionFunction function)
{
m_request = request;
m_formState = formState;
@@ -74,7 +66,7 @@ void PolicyCallback::set(const ResourceRequest& request, PassRefPtr<FormState> f
m_navigationAction = navigationAction;
m_navigationFunction = nullptr;
- m_newWindowFunction = std::move(function);
+ m_newWindowFunction = WTFMove(function);
m_contentFunction = nullptr;
}
@@ -86,7 +78,7 @@ void PolicyCallback::set(ContentPolicyDecisionFunction function)
m_navigationFunction = nullptr;
m_newWindowFunction = nullptr;
- m_contentFunction = std::move(function);
+ m_contentFunction = WTFMove(function);
}
void PolicyCallback::call(bool shouldContinue)
diff --git a/Source/WebCore/loader/PolicyCallback.h b/Source/WebCore/loader/PolicyCallback.h
index c70edcc38..d8bd1cc9f 100644
--- a/Source/WebCore/loader/PolicyCallback.h
+++ b/Source/WebCore/loader/PolicyCallback.h
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,8 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PolicyCallback_h
-#define PolicyCallback_h
+#pragma once
#include "FrameLoaderTypes.h"
#include "NavigationAction.h"
@@ -41,18 +40,15 @@ namespace WebCore {
class FormState;
-typedef std::function<void (const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue)> NavigationPolicyDecisionFunction;
-typedef std::function<void (const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, bool shouldContinue)> NewWindowPolicyDecisionFunction;
-typedef std::function<void (PolicyAction)> ContentPolicyDecisionFunction;
+using ContentPolicyDecisionFunction = std::function<void(PolicyAction)>;
+using NavigationPolicyDecisionFunction = std::function<void(const ResourceRequest&, FormState*, bool shouldContinue)>;
+using NewWindowPolicyDecisionFunction = std::function<void(const ResourceRequest&, FormState*, const String& frameName, const NavigationAction&, bool shouldContinue)>;
class PolicyCallback {
public:
- PolicyCallback();
- ~PolicyCallback();
-
void clear();
- void set(const ResourceRequest&, PassRefPtr<FormState>, NavigationPolicyDecisionFunction);
- void set(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, NewWindowPolicyDecisionFunction);
+ void set(const ResourceRequest&, FormState*, NavigationPolicyDecisionFunction);
+ void set(const ResourceRequest&, FormState*, const String& frameName, const NavigationAction&, NewWindowPolicyDecisionFunction);
void set(ContentPolicyDecisionFunction);
const ResourceRequest& request() const { return m_request; }
@@ -74,5 +70,3 @@ private:
};
} // namespace WebCore
-
-#endif // PolicyCallback_h
diff --git a/Source/WebCore/loader/PolicyChecker.cpp b/Source/WebCore/loader/PolicyChecker.cpp
index 8ead413cc..a01ce2929 100644
--- a/Source/WebCore/loader/PolicyChecker.cpp
+++ b/Source/WebCore/loader/PolicyChecker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,45 +31,59 @@
#include "config.h"
#include "PolicyChecker.h"
+#include "ContentFilter.h"
#include "ContentSecurityPolicy.h"
#include "DOMWindow.h"
#include "DocumentLoader.h"
+#include "EventNames.h"
#include "FormState.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "HTMLFormElement.h"
#include "HTMLFrameOwnerElement.h"
-#include "SecurityOrigin.h"
+#include "HTMLPlugInElement.h"
#if USE(QUICK_LOOK)
#include "QuickLook.h"
#endif
-#if USE(CONTENT_FILTERING)
-#include "ContentFilter.h"
-#endif
-
namespace WebCore {
+static bool isAllowedByContentSecurityPolicy(const URL& url, const Element* ownerElement, bool didReceiveRedirectResponse)
+{
+ if (!ownerElement)
+ return true;
+ // Elements in user agent show tree should load whatever the embedding document policy is.
+ if (ownerElement->isInUserAgentShadowTree())
+ return true;
+
+ auto redirectResponseReceived = didReceiveRedirectResponse ? ContentSecurityPolicy::RedirectResponseReceived::Yes : ContentSecurityPolicy::RedirectResponseReceived::No;
+
+ ASSERT(ownerElement->document().contentSecurityPolicy());
+ if (is<HTMLPlugInElement>(ownerElement))
+ return ownerElement->document().contentSecurityPolicy()->allowObjectFromSource(url, redirectResponseReceived);
+ return ownerElement->document().contentSecurityPolicy()->allowChildFrameFromSource(url, redirectResponseReceived);
+}
+
PolicyChecker::PolicyChecker(Frame& frame)
: m_frame(frame)
, m_delegateIsDecidingNavigationPolicy(false)
, m_delegateIsHandlingUnimplementablePolicy(false)
- , m_loadType(FrameLoadTypeStandard)
+ , m_loadType(FrameLoadType::Standard)
{
}
-void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function)
+void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, bool didReceiveRedirectResponse, NavigationPolicyDecisionFunction function)
{
- checkNavigationPolicy(newRequest, m_frame.loader().activeDocumentLoader(), nullptr, std::move(function));
+ checkNavigationPolicy(newRequest, didReceiveRedirectResponse, m_frame.loader().activeDocumentLoader(), nullptr, WTFMove(function));
}
-void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function)
+void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, bool didReceiveRedirectResponse, DocumentLoader* loader, FormState* formState, NavigationPolicyDecisionFunction function)
{
NavigationAction action = loader->triggeringAction();
if (action.isEmpty()) {
- action = NavigationAction(request, NavigationTypeOther);
+ action = NavigationAction(request, NavigationType::Other, loader->shouldOpenExternalURLsPolicyToPropagate());
loader->setTriggeringAction(action);
}
@@ -83,23 +97,31 @@ void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, Docume
// We are always willing to show alternate content for unreachable URLs;
// treat it like a reload so it maintains the right state for b/f list.
- if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
+ auto& substituteData = loader->substituteData();
+ if (substituteData.isValid() && !substituteData.failingURL().isEmpty()) {
+ bool shouldContinue = true;
+#if ENABLE(CONTENT_FILTERING)
+ shouldContinue = ContentFilter::continueAfterSubstituteDataRequest(*m_frame.loader().activeDocumentLoader(), substituteData);
+#endif
if (isBackForwardLoadType(m_loadType))
- m_loadType = FrameLoadTypeReload;
- function(request, 0, true);
+ m_loadType = FrameLoadType::Reload;
+ function(request, 0, shouldContinue);
return;
}
- // If we're loading content into a subframe, check against the parent's Content Security Policy
- // and kill the load if that check fails.
- if (m_frame.ownerElement() && !m_frame.ownerElement()->document().contentSecurityPolicy()->allowChildFrameFromSource(request.url())) {
+ if (!isAllowedByContentSecurityPolicy(request.url(), m_frame.ownerElement(), didReceiveRedirectResponse)) {
+ if (m_frame.ownerElement()) {
+ // Fire a load event (even though we were blocked by CSP) as timing attacks would otherwise
+ // reveal that the frame was blocked. This way, it looks like any other cross-origin page load.
+ m_frame.ownerElement()->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
+ }
function(request, 0, false);
return;
}
loader->setLastCheckedRequest(request);
- m_callback.set(request, formState.get(), std::move(function));
+ m_callback.set(request, formState, WTFMove(function));
#if USE(QUICK_LOOK)
// Always allow QuickLook-generated URLs based on the protocol scheme.
@@ -109,31 +131,36 @@ void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, Docume
}
#endif
-#if USE(CONTENT_FILTERING)
- if (DocumentLoader* documentLoader = m_frame.loader().documentLoader()) {
- if (documentLoader->handleContentFilterRequest(request)) {
- continueAfterNavigationPolicy(PolicyIgnore);
- return;
- }
+#if ENABLE(CONTENT_FILTERING)
+ if (m_contentFilterUnblockHandler.canHandleRequest(request)) {
+ RefPtr<Frame> frame { &m_frame };
+ m_contentFilterUnblockHandler.requestUnblockAsync([frame](bool unblocked) {
+ if (unblocked)
+ frame->loader().reload();
+ });
+ continueAfterNavigationPolicy(PolicyIgnore);
+ return;
}
+ m_contentFilterUnblockHandler = { };
#endif
m_delegateIsDecidingNavigationPolicy = true;
+ m_suggestedFilename = action.downloadAttribute();
m_frame.loader().client().dispatchDecidePolicyForNavigationAction(action, request, formState, [this](PolicyAction action) {
continueAfterNavigationPolicy(action);
});
m_delegateIsDecidingNavigationPolicy = false;
}
-void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, NewWindowPolicyDecisionFunction function)
+void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, FormState* formState, const String& frameName, NewWindowPolicyDecisionFunction function)
{
if (m_frame.document() && m_frame.document()->isSandboxed(SandboxPopups))
return continueAfterNavigationPolicy(PolicyIgnore);
- if (!DOMWindow::allowPopUp(&m_frame))
+ if (!DOMWindow::allowPopUp(m_frame))
return continueAfterNavigationPolicy(PolicyIgnore);
- m_callback.set(request, formState, frameName, action, std::move(function));
+ m_callback.set(request, formState, frameName, action, WTFMove(function));
m_frame.loader().client().dispatchDecidePolicyForNewWindowAction(action, request, formState, frameName, [this](PolicyAction action) {
continueAfterNewWindowPolicy(action);
});
@@ -141,7 +168,7 @@ void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, const R
void PolicyChecker::checkContentPolicy(const ResourceResponse& response, ContentPolicyDecisionFunction function)
{
- m_callback.set(std::move(function));
+ m_callback.set(WTFMove(function));
m_frame.loader().client().dispatchDecidePolicyForResponse(response, m_frame.loader().activeDocumentLoader()->request(), [this](PolicyAction action) {
continueAfterContentPolicy(action);
});
@@ -187,7 +214,7 @@ void PolicyChecker::continueAfterNavigationPolicy(PolicyAction policy)
case PolicyDownload: {
ResourceRequest request = callback.request();
m_frame.loader().setOriginalURLForDownloadRequest(request);
- m_frame.loader().client().startDownload(request);
+ m_frame.loader().client().startDownload(request, m_suggestedFilename);
callback.clearRequest();
break;
}
diff --git a/Source/WebCore/loader/PolicyChecker.h b/Source/WebCore/loader/PolicyChecker.h
index b1772e62e..16b0bed82 100644
--- a/Source/WebCore/loader/PolicyChecker.h
+++ b/Source/WebCore/loader/PolicyChecker.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,15 +27,17 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PolicyChecker_h
-#define PolicyChecker_h
+#pragma once
#include "FrameLoaderTypes.h"
#include "PolicyCallback.h"
#include "ResourceRequest.h"
-#include <wtf/PassRefPtr.h>
#include <wtf/text/WTFString.h>
+#if ENABLE(CONTENT_FILTERING)
+#include "ContentFilterUnblockHandler.h"
+#endif
+
namespace WebCore {
class DocumentLoader;
@@ -47,12 +49,13 @@ class ResourceResponse;
class PolicyChecker {
WTF_MAKE_NONCOPYABLE(PolicyChecker);
+ WTF_MAKE_FAST_ALLOCATED;
public:
explicit PolicyChecker(Frame&);
- void checkNavigationPolicy(const ResourceRequest&, DocumentLoader*, PassRefPtr<FormState>, NavigationPolicyDecisionFunction);
- void checkNavigationPolicy(const ResourceRequest&, NavigationPolicyDecisionFunction);
- void checkNewWindowPolicy(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, NewWindowPolicyDecisionFunction);
+ void checkNavigationPolicy(const ResourceRequest&, bool didReceiveRedirectResponse, DocumentLoader*, FormState*, NavigationPolicyDecisionFunction);
+ void checkNavigationPolicy(const ResourceRequest&, bool didReceiveRedirectResponse, NavigationPolicyDecisionFunction);
+ void checkNewWindowPolicy(const NavigationAction&, const ResourceRequest&, FormState*, const String& frameName, NewWindowPolicyDecisionFunction);
void checkContentPolicy(const ResourceResponse&, ContentPolicyDecisionFunction);
// FIXME: These are different. They could use better names.
@@ -64,6 +67,8 @@ public:
FrameLoadType loadType() const { return m_loadType; }
void setLoadType(FrameLoadType loadType) { m_loadType = loadType; }
+ void setSuggestedFilename(const String& suggestedFilename) { m_suggestedFilename = suggestedFilename; }
+
bool delegateIsDecidingNavigationPolicy() const { return m_delegateIsDecidingNavigationPolicy; }
bool delegateIsHandlingUnimplementablePolicy() const { return m_delegateIsHandlingUnimplementablePolicy; }
@@ -74,6 +79,10 @@ public:
// the heart to hack on all the platforms to make that happen right now.
void continueLoadAfterWillSubmitForm(PolicyAction);
+#if ENABLE(CONTENT_FILTERING)
+ void setContentFilterUnblockHandler(ContentFilterUnblockHandler unblockHandler) { m_contentFilterUnblockHandler = WTFMove(unblockHandler); }
+#endif
+
private:
void continueAfterNavigationPolicy(PolicyAction);
void continueAfterNewWindowPolicy(PolicyAction);
@@ -91,8 +100,11 @@ private:
// on navigation action delegate callbacks.
FrameLoadType m_loadType;
PolicyCallback m_callback;
+ String m_suggestedFilename;
+
+#if ENABLE(CONTENT_FILTERING)
+ ContentFilterUnblockHandler m_contentFilterUnblockHandler;
+#endif
};
} // namespace WebCore
-
-#endif // PolicyChecker_h
diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp
index 291c13643..fe0c7229e 100644
--- a/Source/WebCore/loader/ProgressTracker.cpp
+++ b/Source/WebCore/loader/ProgressTracker.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -60,6 +60,8 @@ static const unsigned loadStalledHeartbeatCount = 4;
// How many bytes are required between heartbeats to consider it progress.
static const unsigned minumumBytesPerHeartbeatForProgress = 1024;
+static const auto progressNotificationTimeInterval = 200ms;
+
struct ProgressItem {
WTF_MAKE_NONCOPYABLE(ProgressItem); WTF_MAKE_FAST_ALLOCATED;
public:
@@ -80,16 +82,12 @@ ProgressTracker::ProgressTracker(ProgressTrackerClient& client)
, m_totalPageAndResourceBytesToLoad(0)
, m_totalBytesReceived(0)
, m_lastNotifiedProgressValue(0)
- , m_lastNotifiedProgressTime(0)
- , m_progressNotificationInterval(0.02)
- , m_progressNotificationTimeInterval(0.1)
, m_finalProgressChangedSent(false)
, m_progressValue(0)
, m_numProgressTrackedFrames(0)
- , m_progressHeartbeatTimer(this, &ProgressTracker::progressHeartbeatTimerFired)
+ , m_progressHeartbeatTimer(*this, &ProgressTracker::progressHeartbeatTimerFired)
, m_heartbeatsWithNoProgress(0)
, m_totalBytesReceivedBeforePreviousHeartbeat(0)
- , m_mainLoadCompletionTimeStamp(0)
, m_isMainLoad(false)
{
}
@@ -112,10 +110,10 @@ void ProgressTracker::reset()
m_totalBytesReceived = 0;
m_progressValue = 0;
m_lastNotifiedProgressValue = 0;
- m_lastNotifiedProgressTime = 0;
+ m_lastNotifiedProgressTime = std::chrono::steady_clock::time_point();
m_finalProgressChangedSent = false;
m_numProgressTrackedFrames = 0;
- m_originatingProgressFrame = 0;
+ m_originatingProgressFrame = nullptr;
m_heartbeatsWithNoProgress = 0;
m_totalBytesReceivedBeforePreviousHeartbeat = 0;
@@ -137,9 +135,9 @@ void ProgressTracker::progressStarted(Frame& frame)
m_originatingProgressFrame->loader().loadProgressingStatusChanged();
bool isMainFrame = !m_originatingProgressFrame->tree().parent();
- double elapsedTimeSinceMainLoadComplete = monotonicallyIncreasingTime() - m_mainLoadCompletionTimeStamp;
+ auto elapsedTimeSinceMainLoadComplete = std::chrono::steady_clock::now() - m_mainLoadCompletionTime;
- static const double subframePartOfMainLoadThreshold = 1;
+ static const auto subframePartOfMainLoadThreshold = 1s;
m_isMainLoad = isMainFrame || elapsedTimeSinceMainLoadComplete < subframePartOfMainLoadThreshold;
m_client.progressStarted(*m_originatingProgressFrame);
@@ -170,7 +168,7 @@ void ProgressTracker::finalProgressComplete()
{
LOG(Progress, "Final progress complete (%p)", this);
- RefPtr<Frame> frame = m_originatingProgressFrame.release();
+ auto frame = WTFMove(m_originatingProgressFrame);
// Before resetting progress value be sure to send client a least one notification
// with final progress value.
@@ -182,7 +180,7 @@ void ProgressTracker::finalProgressComplete()
reset();
if (m_isMainLoad)
- m_mainLoadCompletionTimeStamp = monotonicallyIncreasingTime();
+ m_mainLoadCompletionTime = std::chrono::steady_clock::now();
frame->loader().client().setMainFrameDocumentReady(true);
m_client.progressFinished(*frame);
@@ -236,7 +234,7 @@ void ProgressTracker::incrementProgress(unsigned long identifier, unsigned bytes
}
int numPendingOrLoadingRequests = frame->loader().numPendingOrLoadingRequests(true);
- estimatedBytesForPendingRequests = progressItemDefaultEstimatedLength * numPendingOrLoadingRequests;
+ estimatedBytesForPendingRequests = static_cast<long long>(progressItemDefaultEstimatedLength) * numPendingOrLoadingRequests;
remainingBytes = ((m_totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - m_totalBytesReceived);
if (remainingBytes > 0) // Prevent divide by 0.
percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes;
@@ -246,7 +244,7 @@ void ProgressTracker::incrementProgress(unsigned long identifier, unsigned bytes
// For documents that use WebCore's layout system, treat first layout as the half-way point.
// FIXME: The hasHTMLView function is a sort of roundabout way of asking "do you use WebCore's layout system".
bool useClampedMaxProgress = frame->loader().client().hasHTMLView()
- && !frame->loader().stateMachine()->firstLayoutDone();
+ && !frame->loader().stateMachine().firstLayoutDone();
double maxProgressValue = useClampedMaxProgress ? 0.5 : finalProgressValue;
increment = (maxProgressValue - m_progressValue) * percentOfRemainingBytes;
m_progressValue += increment;
@@ -255,14 +253,11 @@ void ProgressTracker::incrementProgress(unsigned long identifier, unsigned bytes
m_totalBytesReceived += bytesReceived;
- double now = monotonicallyIncreasingTime();
- double notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime;
+ auto now = std::chrono::steady_clock::now();
+ auto notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime;
LOG(Progress, "Progress incremented (%p) - value %f, tracked frames %d", this, m_progressValue, m_numProgressTrackedFrames);
- double notificationProgressDelta = m_progressValue - m_lastNotifiedProgressValue;
- if ((notificationProgressDelta >= m_progressNotificationInterval ||
- notifiedProgressTimeDelta >= m_progressNotificationTimeInterval) &&
- m_numProgressTrackedFrames > 0) {
+ if ((notifiedProgressTimeDelta >= progressNotificationTimeInterval || m_progressValue == 1) && m_numProgressTrackedFrames > 0) {
if (!m_finalProgressChangedSent) {
if (m_progressValue == 1)
m_finalProgressChangedSent = true;
@@ -310,7 +305,7 @@ bool ProgressTracker::isMainLoadProgressing() const
return m_progressValue && m_progressValue < finalProgressValue && m_heartbeatsWithNoProgress < loadStalledHeartbeatCount;
}
-void ProgressTracker::progressHeartbeatTimerFired(Timer<ProgressTracker>&)
+void ProgressTracker::progressHeartbeatTimerFired()
{
if (m_totalBytesReceived < m_totalBytesReceivedBeforePreviousHeartbeat + minumumBytesPerHeartbeatForProgress)
++m_heartbeatsWithNoProgress;
diff --git a/Source/WebCore/loader/ProgressTracker.h b/Source/WebCore/loader/ProgressTracker.h
index 272de2778..71739aef8 100644
--- a/Source/WebCore/loader/ProgressTracker.h
+++ b/Source/WebCore/loader/ProgressTracker.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,14 +23,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ProgressTracker_h
-#define ProgressTracker_h
+#pragma once
#include "Timer.h"
+#include <chrono>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
namespace WebCore {
@@ -48,7 +47,7 @@ public:
static unsigned long createUniqueIdentifier();
- double estimatedProgress() const;
+ WEBCORE_EXPORT double estimatedProgress() const;
void progressStarted(Frame&);
void progressCompleted(Frame&);
@@ -66,7 +65,7 @@ private:
void reset();
void finalProgressComplete();
- void progressHeartbeatTimerFired(Timer<ProgressTracker>&);
+ void progressHeartbeatTimerFired();
static unsigned long s_uniqueIdentifier;
@@ -74,9 +73,7 @@ private:
long long m_totalPageAndResourceBytesToLoad;
long long m_totalBytesReceived;
double m_lastNotifiedProgressValue;
- double m_lastNotifiedProgressTime;
- double m_progressNotificationInterval;
- double m_progressNotificationTimeInterval;
+ std::chrono::steady_clock::time_point m_lastNotifiedProgressTime;
bool m_finalProgressChangedSent;
double m_progressValue;
RefPtr<Frame> m_originatingProgressFrame;
@@ -84,13 +81,11 @@ private:
int m_numProgressTrackedFrames;
HashMap<unsigned long, std::unique_ptr<ProgressItem>> m_progressItems;
- Timer<ProgressTracker> m_progressHeartbeatTimer;
+ Timer m_progressHeartbeatTimer;
unsigned m_heartbeatsWithNoProgress;
long long m_totalBytesReceivedBeforePreviousHeartbeat;
- double m_mainLoadCompletionTimeStamp;
+ std::chrono::steady_clock::time_point m_mainLoadCompletionTime;
bool m_isMainLoad;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ProgressTrackerClient.h b/Source/WebCore/loader/ProgressTrackerClient.h
index d3ec32e9f..4e31fe282 100644
--- a/Source/WebCore/loader/ProgressTrackerClient.h
+++ b/Source/WebCore/loader/ProgressTrackerClient.h
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ProgressTrackerClient_h
-#define ProgressTrackerClient_h
+#pragma once
namespace WebCore {
@@ -46,5 +45,3 @@ public:
};
} // namespace WebCore
-
-#endif // ProgressTrackerClient_h
diff --git a/Source/WebCore/loader/ResourceBuffer.cpp b/Source/WebCore/loader/ResourceBuffer.cpp
deleted file mode 100644
index 38afaa41a..000000000
--- a/Source/WebCore/loader/ResourceBuffer.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ResourceBuffer.h"
-
-#include "PurgeableBuffer.h"
-
-namespace WebCore {
-
-ResourceBuffer::ResourceBuffer()
- : m_sharedBuffer(SharedBuffer::create())
-{
-}
-
-ResourceBuffer::ResourceBuffer(const char* data, unsigned size)
- : m_sharedBuffer(SharedBuffer::create(data, size))
-{
-}
-
-ResourceBuffer::ResourceBuffer(PassRefPtr<SharedBuffer> sharedBuffer)
- : m_sharedBuffer(sharedBuffer)
-{
- ASSERT(m_sharedBuffer);
-}
-
-ResourceBuffer::~ResourceBuffer()
-{
-}
-
-const char* ResourceBuffer::data() const
-{
- return m_sharedBuffer->data();
-}
-
-unsigned ResourceBuffer::size() const
-{
- return m_sharedBuffer->size();
-}
-
-bool ResourceBuffer::isEmpty() const
-{
- return m_sharedBuffer->isEmpty();
-}
-
-void ResourceBuffer::append(const char* data, unsigned size)
-{
- m_sharedBuffer->append(data, size);
-}
-
-void ResourceBuffer::append(SharedBuffer* buffer)
-{
- m_sharedBuffer->append(buffer);
-}
-
-#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
-void ResourceBuffer::append(CFDataRef data)
-{
- ASSERT(m_sharedBuffer);
- m_sharedBuffer->append(data);
-}
-#endif
-
-void ResourceBuffer::clear()
-{
- m_sharedBuffer->clear();
-}
-
-unsigned ResourceBuffer::getSomeData(const char*& data, unsigned position) const
-{
- return m_sharedBuffer->getSomeData(data, position);
-}
-
-SharedBuffer* ResourceBuffer::sharedBuffer() const
-{
- // Currently all ResourceBuffers are backed by SharedBuffers.
- // In the future we might have to create the SharedBuffer on demand here.
- // We should also phase out as much use of this accessor as possible and have clients
- // either use the ResourceBuffer directly or use getSomeData() when sensical.
- return m_sharedBuffer.get();
-}
-
-PassRefPtr<ResourceBuffer> ResourceBuffer::copy() const
-{
- return ResourceBuffer::adoptSharedBuffer(m_sharedBuffer->copy());
-}
-
-bool ResourceBuffer::hasPurgeableBuffer() const
-{
- return m_sharedBuffer->hasPurgeableBuffer();
-}
-
-#if PLATFORM(IOS)
-void ResourceBuffer::setShouldUsePurgeableMemory(bool shouldUsePurgeableMemory)
-{
- ASSERT(m_sharedBuffer);
- sharedBuffer()->shouldUsePurgeableMemory(shouldUsePurgeableMemory);
-}
-#endif
-
-void ResourceBuffer::createPurgeableBuffer() const
-{
- ASSERT(m_sharedBuffer);
- sharedBuffer()->createPurgeableBuffer();
-}
-
-PassOwnPtr<PurgeableBuffer> ResourceBuffer::releasePurgeableBuffer()
-{
- return m_sharedBuffer->releasePurgeableBuffer();
-}
-
-#if USE(CF)
-RetainPtr<CFDataRef> ResourceBuffer::createCFData()
-{
- return m_sharedBuffer->createCFData();
-}
-#endif
-
-#if ENABLE(DISK_IMAGE_CACHE)
-bool ResourceBuffer::isUsingDiskImageCache() const
-{
- ASSERT(m_sharedBuffer);
- return m_sharedBuffer && m_sharedBuffer->isAllowedToBeMemoryMapped();
-}
-#endif
-
-} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceBuffer.h b/Source/WebCore/loader/ResourceBuffer.h
deleted file mode 100644
index cd6cb6cfb..000000000
--- a/Source/WebCore/loader/ResourceBuffer.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ResourceBuffer_h
-#define ResourceBuffer_h
-
-#include "SharedBuffer.h"
-
-#include <wtf/PassOwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-
-#if PLATFORM(MAC)
-OBJC_CLASS NSData;
-#endif
-
-namespace WebCore {
-
-class PurgeableBuffer;
-class SharedBuffer;
-
-class ResourceBuffer : public RefCounted<ResourceBuffer> {
-public:
-
- static PassRefPtr<ResourceBuffer> create() { return adoptRef(new ResourceBuffer); }
- static PassRefPtr<ResourceBuffer> create(const char* data, unsigned size) { return adoptRef(new ResourceBuffer(data, size)); }
- static PassRefPtr<ResourceBuffer> adoptSharedBuffer(PassRefPtr<SharedBuffer> shared) { return shared ? adoptRef(new ResourceBuffer(shared)) : 0; }
-
- virtual ~ResourceBuffer();
-
- virtual const char* data() const;
- virtual unsigned size() const;
- virtual bool isEmpty() const;
-
- void append(const char*, unsigned);
- void append(SharedBuffer*);
-#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
- void append(CFDataRef);
-#endif
- void clear();
-
- unsigned getSomeData(const char*& data, unsigned position = 0) const;
-
- SharedBuffer* sharedBuffer() const;
-#if PLATFORM(MAC)
- void tryReplaceSharedBufferContents(SharedBuffer*);
-#endif
- PassRefPtr<ResourceBuffer> copy() const;
-
- bool hasPurgeableBuffer() const;
- void createPurgeableBuffer() const;
-
-#if PLATFORM(IOS)
- // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to SharedBuffer.{cpp, h} and SharedBufferCF.cpp.
- void setShouldUsePurgeableMemory(bool);
-#endif
-
- // Ensure this buffer has no other clients before calling this.
- PassOwnPtr<PurgeableBuffer> releasePurgeableBuffer();
-
-#if PLATFORM(MAC)
- SharedBuffer::NSDataRetainPtrWithoutImplicitConversionOperator createNSData();
-#endif
-#if USE(CF)
- RetainPtr<CFDataRef> createCFData();
-#endif
-#if ENABLE(DISK_IMAGE_CACHE)
- bool isUsingDiskImageCache() const;
-#endif
-
-protected:
- ResourceBuffer();
-
-private:
- ResourceBuffer(const char*, unsigned);
- ResourceBuffer(PassRefPtr<SharedBuffer>);
-
- RefPtr<SharedBuffer> m_sharedBuffer;
-};
-
-} // namespace WebCore
-
-#endif // ResourceBuffer_h
diff --git a/Source/WebCore/loader/ResourceLoadInfo.cpp b/Source/WebCore/loader/ResourceLoadInfo.cpp
new file mode 100644
index 000000000..d8e4d1504
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadInfo.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceLoadInfo.h"
+
+#include "ContentExtensionActions.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+ResourceType toResourceType(CachedResource::Type type)
+{
+ switch (type) {
+ case CachedResource::MainResource:
+ return ResourceType::Document;
+ case CachedResource::SVGDocumentResource:
+ return ResourceType::SVGDocument;
+ case CachedResource::ImageResource:
+ return ResourceType::Image;
+ case CachedResource::CSSStyleSheet:
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+#endif
+ return ResourceType::StyleSheet;
+
+ case CachedResource::Script:
+ return ResourceType::Script;
+
+ case CachedResource::FontResource:
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
+ return ResourceType::Font;
+
+ case CachedResource::MediaResource:
+ case CachedResource::RawResource:
+ return ResourceType::Raw;
+
+#if ENABLE(VIDEO_TRACK)
+ case CachedResource::TextTrackResource:
+ return ResourceType::Media;
+#endif
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ case CachedResource::LinkSubresource:
+ ASSERT_NOT_REACHED();
+#endif
+ };
+}
+
+uint16_t readResourceType(const String& name)
+{
+ if (name == "document")
+ return static_cast<uint16_t>(ResourceType::Document);
+ if (name == "image")
+ return static_cast<uint16_t>(ResourceType::Image);
+ if (name == "style-sheet")
+ return static_cast<uint16_t>(ResourceType::StyleSheet);
+ if (name == "script")
+ return static_cast<uint16_t>(ResourceType::Script);
+ if (name == "font")
+ return static_cast<uint16_t>(ResourceType::Font);
+ if (name == "raw")
+ return static_cast<uint16_t>(ResourceType::Raw);
+ if (name == "svg-document")
+ return static_cast<uint16_t>(ResourceType::SVGDocument);
+ if (name == "media")
+ return static_cast<uint16_t>(ResourceType::Media);
+ if (name == "popup")
+ return static_cast<uint16_t>(ResourceType::Popup);
+ return static_cast<uint16_t>(ResourceType::Invalid);
+}
+
+uint16_t readLoadType(const String& name)
+{
+ if (name == "first-party")
+ return static_cast<uint16_t>(LoadType::FirstParty);
+ if (name == "third-party")
+ return static_cast<uint16_t>(LoadType::ThirdParty);
+ return static_cast<uint16_t>(LoadType::Invalid);
+}
+
+bool ResourceLoadInfo::isThirdParty() const
+{
+ Ref<SecurityOrigin> mainDocumentSecurityOrigin = SecurityOrigin::create(mainDocumentURL);
+ Ref<SecurityOrigin> resourceSecurityOrigin = SecurityOrigin::create(resourceURL);
+
+ return !mainDocumentSecurityOrigin->canAccess(resourceSecurityOrigin.get());
+}
+
+ResourceFlags ResourceLoadInfo::getResourceFlags() const
+{
+ ResourceFlags flags = 0;
+ ASSERT(type != ResourceType::Invalid);
+ flags |= static_cast<ResourceFlags>(type);
+ flags |= isThirdParty() ? static_cast<ResourceFlags>(LoadType::ThirdParty) : static_cast<ResourceFlags>(LoadType::FirstParty);
+ return flags;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoadInfo.h b/Source/WebCore/loader/ResourceLoadInfo.h
new file mode 100644
index 000000000..eaf4a6c43
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadInfo.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CachedResource.h"
+#include "URL.h"
+
+namespace WebCore {
+
+enum class ResourceType : uint16_t {
+ Invalid = 0x0000,
+ Document = 0x0001,
+ Image = 0x0002,
+ StyleSheet = 0x0004,
+ Script = 0x0008,
+ Font = 0x0010,
+ Raw = 0x0020,
+ SVGDocument = 0x0040,
+ Media = 0x0080,
+ PlugInStream = 0x0100,
+ Popup = 0x0200,
+};
+const uint16_t ResourceTypeMask = 0x03FF;
+
+enum class LoadType : uint16_t {
+ Invalid = 0x0000,
+ FirstParty = 0x0400,
+ ThirdParty = 0x0800,
+};
+const uint16_t LoadTypeMask = 0x0C00;
+
+typedef uint16_t ResourceFlags;
+
+// The first 32 bits of a uint64_t action are used for the action location.
+// The next 16 bits are used for the flags (ResourceType and LoadType).
+// The next bit is used to mark actions that are from a rule with an if-domain condition.
+// The next bit is used to mark actions that in the default stylesheet.
+// The values -1 and -2 are used for removed and empty values in HashTables.
+const uint64_t ActionFlagMask = 0x0000FFFF00000000;
+const uint64_t IfDomainFlag = 0x0001000000000000;
+
+ResourceType toResourceType(CachedResource::Type);
+uint16_t readResourceType(const String&);
+uint16_t readLoadType(const String&);
+
+struct ResourceLoadInfo {
+ URL resourceURL;
+ URL mainDocumentURL;
+ ResourceType type;
+
+ bool isThirdParty() const;
+ ResourceFlags getResourceFlags() const;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoadNotifier.cpp b/Source/WebCore/loader/ResourceLoadNotifier.cpp
index 9d6b70290..63443d36e 100644
--- a/Source/WebCore/loader/ResourceLoadNotifier.cpp
+++ b/Source/WebCore/loader/ResourceLoadNotifier.cpp
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -39,6 +39,7 @@
#include "Page.h"
#include "ProgressTracker.h"
#include "ResourceLoader.h"
+#include "RuntimeEnabledFeatures.h"
#if USE(QUICK_LOOK)
#include "QuickLook.h"
@@ -61,16 +62,6 @@ void ResourceLoadNotifier::didReceiveAuthenticationChallenge(unsigned long ident
m_frame.loader().client().dispatchDidReceiveAuthenticationChallenge(loader, identifier, currentWebChallenge);
}
-void ResourceLoadNotifier::didCancelAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
-{
- didCancelAuthenticationChallenge(loader->identifier(), loader->documentLoader(), currentWebChallenge);
-}
-
-void ResourceLoadNotifier::didCancelAuthenticationChallenge(unsigned long identifier, DocumentLoader* loader, const AuthenticationChallenge& currentWebChallenge)
-{
- m_frame.loader().client().dispatchDidCancelAuthenticationChallenge(loader, identifier, currentWebChallenge);
-}
-
void ResourceLoadNotifier::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
{
m_frame.loader().applyUserAgent(clientRequest);
@@ -108,6 +99,8 @@ void ResourceLoadNotifier::didFailToLoad(ResourceLoader* loader, const ResourceE
if (Page* page = m_frame.page())
page->progress().completeProgress(loader->identifier());
+ // Notifying the FrameLoaderClient may cause the frame to be destroyed.
+ Ref<Frame> protect(m_frame);
if (!error.isNull())
m_frame.loader().client().dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
@@ -130,6 +123,8 @@ void ResourceLoadNotifier::dispatchWillSendRequest(DocumentLoader* loader, unsig
String oldRequestURL = request.url().string();
m_frame.loader().documentLoader()->didTellClientAboutLoad(request.url());
+ // Notifying the FrameLoaderClient may cause the frame to be destroyed.
+ Ref<Frame> protect(m_frame);
m_frame.loader().client().dispatchWillSendRequest(loader, identifier, request, redirectResponse);
// If the URL changed, then we want to put that new URL in the "did tell client" set too.
@@ -138,24 +133,27 @@ void ResourceLoadNotifier::dispatchWillSendRequest(DocumentLoader* loader, unsig
InspectorInstrumentation::willSendRequest(&m_frame, identifier, loader, request, redirectResponse);
- // Report WebTiming for all frames.
- if (loader && !request.isNull() && request.url() == loader->requestURL())
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
request.setReportLoadTiming(true);
-
-#if ENABLE(RESOURCE_TIMING)
- request.setReportLoadTiming(true);
-#endif
+ else if (loader && !request.isNull() && request.url() == loader->url()) {
+ // Report WebTiming for all frames.
+ request.setReportLoadTiming(true);
+ }
}
void ResourceLoadNotifier::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r, ResourceLoader* resourceLoader)
{
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceResponse(&m_frame, identifier, r);
+ // Notifying the FrameLoaderClient may cause the frame to be destroyed.
+ Ref<Frame> protect(m_frame);
m_frame.loader().client().dispatchDidReceiveResponse(loader, identifier, r);
- InspectorInstrumentation::didReceiveResourceResponse(cookie, identifier, loader, r, resourceLoader);
+
+ InspectorInstrumentation::didReceiveResourceResponse(m_frame, identifier, loader, r, resourceLoader);
}
void ResourceLoadNotifier::dispatchDidReceiveData(DocumentLoader* loader, unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
{
+ // Notifying the FrameLoaderClient may cause the frame to be destroyed.
+ Ref<Frame> protect(m_frame);
m_frame.loader().client().dispatchDidReceiveContentLength(loader, identifier, dataLength);
InspectorInstrumentation::didReceiveData(&m_frame, identifier, data, dataLength, encodedDataLength);
@@ -163,6 +161,8 @@ void ResourceLoadNotifier::dispatchDidReceiveData(DocumentLoader* loader, unsign
void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier, double finishTime)
{
+ // Notifying the FrameLoaderClient may cause the frame to be destroyed.
+ Ref<Frame> protect(m_frame);
m_frame.loader().client().dispatchDidFinishLoading(loader, identifier);
InspectorInstrumentation::didFinishLoading(&m_frame, loader, identifier, finishTime);
@@ -170,6 +170,8 @@ void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsi
void ResourceLoadNotifier::dispatchDidFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
{
+ // Notifying the FrameLoaderClient may cause the frame to be destroyed.
+ Ref<Frame> protect(m_frame);
m_frame.loader().client().dispatchDidFailLoading(loader, identifier, error);
InspectorInstrumentation::didFailLoading(&m_frame, loader, identifier, error);
diff --git a/Source/WebCore/loader/ResourceLoadNotifier.h b/Source/WebCore/loader/ResourceLoadNotifier.h
index d2ce05436..f316ec2e8 100644
--- a/Source/WebCore/loader/ResourceLoadNotifier.h
+++ b/Source/WebCore/loader/ResourceLoadNotifier.h
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,8 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceLoadNotifier_h
-#define ResourceLoadNotifier_h
+#pragma once
#include <wtf/Noncopyable.h>
@@ -50,8 +49,6 @@ public:
void didReceiveAuthenticationChallenge(ResourceLoader*, const AuthenticationChallenge&);
void didReceiveAuthenticationChallenge(unsigned long identifier, DocumentLoader*, const AuthenticationChallenge&);
- void didCancelAuthenticationChallenge(ResourceLoader*, const AuthenticationChallenge&);
- void didCancelAuthenticationChallenge(unsigned long identifier, DocumentLoader*, const AuthenticationChallenge&);
void willSendRequest(ResourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse);
void didReceiveResponse(ResourceLoader*, const ResourceResponse&);
@@ -61,7 +58,7 @@ public:
void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&);
void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse);
- void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&, ResourceLoader* = 0);
+ void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&, ResourceLoader* = nullptr);
void dispatchDidReceiveData(DocumentLoader*, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier, double finishTime);
void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&);
@@ -73,5 +70,3 @@ private:
};
} // namespace WebCore
-
-#endif // ResourceLoadNotifier_h
diff --git a/Source/WebCore/loader/ResourceLoadObserver.cpp b/Source/WebCore/loader/ResourceLoadObserver.cpp
new file mode 100644
index 000000000..8d3da3bd6
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadObserver.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceLoadObserver.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "Logging.h"
+#include "MainFrame.h"
+#include "NetworkStorageSession.h"
+#include "Page.h"
+#include "PlatformStrategies.h"
+#include "PublicSuffix.h"
+#include "ResourceLoadStatistics.h"
+#include "ResourceLoadStatisticsStore.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "SecurityOrigin.h"
+#include "Settings.h"
+#include "SharedBuffer.h"
+#include "URL.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+// One day in seconds.
+static auto timestampResolution = 86400;
+
+ResourceLoadObserver& ResourceLoadObserver::sharedObserver()
+{
+ static NeverDestroyed<ResourceLoadObserver> resourceLoadObserver;
+ return resourceLoadObserver;
+}
+
+RefPtr<ResourceLoadStatisticsStore> ResourceLoadObserver::statisticsStore()
+{
+ ASSERT(m_store);
+ return m_store;
+}
+
+void ResourceLoadObserver::setStatisticsStore(Ref<ResourceLoadStatisticsStore>&& store)
+{
+ m_store = WTFMove(store);
+}
+
+static inline bool is3xxRedirect(const ResourceResponse& response)
+{
+ return response.httpStatusCode() >= 300 && response.httpStatusCode() <= 399;
+}
+
+bool ResourceLoadObserver::shouldLog(Page* page)
+{
+ // FIXME: Err on the safe side until we have sorted out what to do in worker contexts
+ if (!page)
+ return false;
+ return Settings::resourceLoadStatisticsEnabled()
+ && !page->usesEphemeralSession()
+ && m_store;
+}
+
+void ResourceLoadObserver::logFrameNavigation(const Frame& frame, const Frame& topFrame, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
+{
+ ASSERT(frame.document());
+ ASSERT(topFrame.document());
+ ASSERT(topFrame.page());
+
+ if (!shouldLog(topFrame.page()))
+ return;
+
+ bool isRedirect = is3xxRedirect(redirectResponse);
+ bool isMainFrame = frame.isMainFrame();
+ const URL& sourceURL = frame.document()->url();
+ const URL& targetURL = newRequest.url();
+ const URL& mainFrameURL = topFrame.document()->url();
+
+ if (!targetURL.isValid() || !mainFrameURL.isValid())
+ return;
+
+ auto targetHost = targetURL.host();
+ auto mainFrameHost = mainFrameURL.host();
+
+ if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == mainFrameHost || targetHost == sourceURL.host())
+ return;
+
+ auto targetPrimaryDomain = primaryDomain(targetURL);
+ auto mainFramePrimaryDomain = primaryDomain(mainFrameURL);
+ auto sourcePrimaryDomain = primaryDomain(sourceURL);
+
+ if (targetPrimaryDomain == mainFramePrimaryDomain || targetPrimaryDomain == sourcePrimaryDomain)
+ return;
+
+ auto targetOrigin = SecurityOrigin::create(targetURL);
+ auto targetStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(targetPrimaryDomain);
+
+ // Always fire if we have previously removed data records for this domain
+ bool shouldFireDataModificationHandler = targetStatistics.dataRecordsRemoved > 0;
+
+ if (isMainFrame)
+ targetStatistics.topFrameHasBeenNavigatedToBefore = true;
+ else {
+ targetStatistics.subframeHasBeenLoadedBefore = true;
+
+ auto mainFrameOrigin = SecurityOrigin::create(mainFrameURL);
+ auto subframeUnderTopFrameOriginsResult = targetStatistics.subframeUnderTopFrameOrigins.add(mainFramePrimaryDomain);
+ if (subframeUnderTopFrameOriginsResult.isNewEntry)
+ shouldFireDataModificationHandler = true;
+ }
+
+ if (isRedirect) {
+ auto& redirectingOriginResourceStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(sourcePrimaryDomain);
+
+ if (m_store->isPrevalentResource(targetPrimaryDomain))
+ redirectingOriginResourceStatistics.redirectedToOtherPrevalentResourceOrigins.add(targetPrimaryDomain);
+
+ if (isMainFrame) {
+ ++targetStatistics.topFrameHasBeenRedirectedTo;
+ ++redirectingOriginResourceStatistics.topFrameHasBeenRedirectedFrom;
+ } else {
+ ++targetStatistics.subframeHasBeenRedirectedTo;
+ ++redirectingOriginResourceStatistics.subframeHasBeenRedirectedFrom;
+ redirectingOriginResourceStatistics.subframeUniqueRedirectsTo.add(targetPrimaryDomain);
+
+ ++targetStatistics.subframeSubResourceCount;
+ }
+ } else {
+ if (sourcePrimaryDomain.isNull() || sourcePrimaryDomain.isEmpty() || sourcePrimaryDomain == "nullOrigin") {
+ if (isMainFrame)
+ ++targetStatistics.topFrameInitialLoadCount;
+ else
+ ++targetStatistics.subframeSubResourceCount;
+ } else {
+ auto& sourceOriginResourceStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(sourcePrimaryDomain);
+
+ if (isMainFrame) {
+ ++sourceOriginResourceStatistics.topFrameHasBeenNavigatedFrom;
+ ++targetStatistics.topFrameHasBeenNavigatedTo;
+ } else {
+ ++sourceOriginResourceStatistics.subframeHasBeenNavigatedFrom;
+ ++targetStatistics.subframeHasBeenNavigatedTo;
+ }
+ }
+ }
+
+ m_store->setResourceStatisticsForPrimaryDomain(targetPrimaryDomain, WTFMove(targetStatistics));
+ if (shouldFireDataModificationHandler)
+ m_store->fireDataModificationHandler();
+}
+
+void ResourceLoadObserver::logSubresourceLoading(const Frame* frame, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
+{
+ ASSERT(frame->page());
+
+ if (!shouldLog(frame->page()))
+ return;
+
+ bool isRedirect = is3xxRedirect(redirectResponse);
+ const URL& sourceURL = redirectResponse.url();
+ const URL& targetURL = newRequest.url();
+ const URL& mainFrameURL = frame ? frame->mainFrame().document()->url() : URL();
+
+ auto targetHost = targetURL.host();
+ auto mainFrameHost = mainFrameURL.host();
+
+ if (targetHost.isEmpty()
+ || mainFrameHost.isEmpty()
+ || targetHost == mainFrameHost
+ || (isRedirect && targetHost == sourceURL.host()))
+ return;
+
+ auto targetPrimaryDomain = primaryDomain(targetURL);
+ auto mainFramePrimaryDomain = primaryDomain(mainFrameURL);
+ auto sourcePrimaryDomain = primaryDomain(sourceURL);
+
+ if (targetPrimaryDomain == mainFramePrimaryDomain || (isRedirect && targetPrimaryDomain == sourcePrimaryDomain))
+ return;
+
+ auto& targetStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(targetPrimaryDomain);
+
+ // Always fire if we have previously removed data records for this domain
+ bool shouldFireDataModificationHandler = targetStatistics.dataRecordsRemoved > 0;
+
+ auto mainFrameOrigin = SecurityOrigin::create(mainFrameURL);
+ auto subresourceUnderTopFrameOriginsResult = targetStatistics.subresourceUnderTopFrameOrigins.add(mainFramePrimaryDomain);
+ if (subresourceUnderTopFrameOriginsResult.isNewEntry)
+ shouldFireDataModificationHandler = true;
+
+ if (isRedirect) {
+ auto& redirectingOriginStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(sourcePrimaryDomain);
+
+ // We just inserted to the store, so we need to reget 'targetStatistics'
+ auto& updatedTargetStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(targetPrimaryDomain);
+
+ if (m_store->isPrevalentResource(targetPrimaryDomain))
+ redirectingOriginStatistics.redirectedToOtherPrevalentResourceOrigins.add(targetPrimaryDomain);
+
+ ++redirectingOriginStatistics.subresourceHasBeenRedirectedFrom;
+ ++updatedTargetStatistics.subresourceHasBeenRedirectedTo;
+
+ auto subresourceUniqueRedirectsToResult = redirectingOriginStatistics.subresourceUniqueRedirectsTo.add(targetPrimaryDomain);
+ if (subresourceUniqueRedirectsToResult.isNewEntry)
+ shouldFireDataModificationHandler = true;
+
+ ++updatedTargetStatistics.subresourceHasBeenSubresourceCount;
+
+ auto totalVisited = std::max(m_originsVisitedMap.size(), 1U);
+
+ updatedTargetStatistics.subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited = static_cast<double>(updatedTargetStatistics.subresourceHasBeenSubresourceCount) / totalVisited;
+ } else {
+ ++targetStatistics.subresourceHasBeenSubresourceCount;
+
+ auto totalVisited = std::max(m_originsVisitedMap.size(), 1U);
+
+ targetStatistics.subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited = static_cast<double>(targetStatistics.subresourceHasBeenSubresourceCount) / totalVisited;
+ }
+
+ if (shouldFireDataModificationHandler)
+ m_store->fireDataModificationHandler();
+}
+
+void ResourceLoadObserver::logWebSocketLoading(const Frame* frame, const URL& targetURL)
+{
+ // FIXME: Web sockets can run in detached frames. Decide how to count such connections.
+ // See LayoutTests/http/tests/websocket/construct-in-detached-frame.html
+ if (!frame)
+ return;
+
+ if (!shouldLog(frame->page()))
+ return;
+
+ const URL& mainFrameURL = frame->mainFrame().document()->url();
+
+ auto targetHost = targetURL.host();
+ auto mainFrameHost = mainFrameURL.host();
+
+ if (targetHost.isEmpty()
+ || mainFrameHost.isEmpty()
+ || targetHost == mainFrameHost)
+ return;
+
+ auto targetPrimaryDomain = primaryDomain(targetURL);
+ auto mainFramePrimaryDomain = primaryDomain(mainFrameURL);
+
+ if (targetPrimaryDomain == mainFramePrimaryDomain)
+ return;
+
+ auto& targetStatistics = m_store->ensureResourceStatisticsForPrimaryDomain(targetPrimaryDomain);
+
+ // Always fire if we have previously removed data records for this domain
+ bool shouldFireDataModificationHandler = targetStatistics.dataRecordsRemoved > 0;
+
+ auto mainFrameOrigin = SecurityOrigin::create(mainFrameURL);
+ auto subresourceUnderTopFrameOriginsResult = targetStatistics.subresourceUnderTopFrameOrigins.add(mainFramePrimaryDomain);
+ if (subresourceUnderTopFrameOriginsResult.isNewEntry)
+ shouldFireDataModificationHandler = true;
+
+ ++targetStatistics.subresourceHasBeenSubresourceCount;
+
+ auto totalVisited = std::max(m_originsVisitedMap.size(), 1U);
+
+ targetStatistics.subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited = static_cast<double>(targetStatistics.subresourceHasBeenSubresourceCount) / totalVisited;
+
+ if (shouldFireDataModificationHandler)
+ m_store->fireDataModificationHandler();
+}
+
+static double reduceTimeResolutionToOneDay(double seconds)
+{
+ return std::floor(seconds / timestampResolution) * timestampResolution;
+}
+
+void ResourceLoadObserver::logUserInteractionWithReducedTimeResolution(const Document& document)
+{
+ ASSERT(document.page());
+
+ if (!shouldLog(document.page()))
+ return;
+
+ auto& url = document.url();
+ if (url.isBlankURL() || url.isEmpty())
+ return;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+ double newTimestamp = reduceTimeResolutionToOneDay(WTF::currentTime());
+ if (newTimestamp == statistics.mostRecentUserInteraction)
+ return;
+
+ statistics.hadUserInteraction = true;
+ statistics.mostRecentUserInteraction = newTimestamp;
+ m_store->fireDataModificationHandler();
+}
+
+void ResourceLoadObserver::logUserInteraction(const URL& url)
+{
+ if (url.isBlankURL() || url.isEmpty())
+ return;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+ statistics.hadUserInteraction = true;
+ statistics.mostRecentUserInteraction = WTF::currentTime();
+}
+
+void ResourceLoadObserver::clearUserInteraction(const URL& url)
+{
+ if (url.isBlankURL() || url.isEmpty())
+ return;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+
+ statistics.hadUserInteraction = false;
+ statistics.mostRecentUserInteraction = 0;
+}
+
+bool ResourceLoadObserver::hasHadUserInteraction(const URL& url)
+{
+ if (url.isBlankURL() || url.isEmpty())
+ return false;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+
+ return m_store->hasHadRecentUserInteraction(statistics);
+}
+
+void ResourceLoadObserver::setPrevalentResource(const URL& url)
+{
+ if (url.isBlankURL() || url.isEmpty())
+ return;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+
+ statistics.isPrevalentResource = true;
+}
+
+bool ResourceLoadObserver::isPrevalentResource(const URL& url)
+{
+ if (url.isBlankURL() || url.isEmpty())
+ return false;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+
+ return statistics.isPrevalentResource;
+}
+
+void ResourceLoadObserver::clearPrevalentResource(const URL& url)
+{
+ if (url.isBlankURL() || url.isEmpty())
+ return;
+
+ auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+
+ statistics.isPrevalentResource = false;
+}
+
+void ResourceLoadObserver::setTimeToLiveUserInteraction(double seconds)
+{
+ m_store->setTimeToLiveUserInteraction(seconds);
+}
+
+void ResourceLoadObserver::fireDataModificationHandler()
+{
+ m_store->fireDataModificationHandler();
+}
+
+String ResourceLoadObserver::primaryDomain(const URL& url)
+{
+ String primaryDomain;
+ String host = url.host();
+ if (host.isNull() || host.isEmpty())
+ primaryDomain = "nullOrigin";
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+ else {
+ primaryDomain = topPrivatelyControlledDomain(host);
+ // We will have an empty string here if there is no TLD.
+ // Use the host in such case.
+ if (primaryDomain.isEmpty())
+ primaryDomain = host;
+ }
+#else
+ else
+ primaryDomain = host;
+#endif
+
+ return primaryDomain;
+}
+
+String ResourceLoadObserver::statisticsForOrigin(const String& origin)
+{
+ return m_store ? m_store->statisticsForOrigin(origin) : emptyString();
+}
+
+}
diff --git a/Source/WebCore/loader/ResourceLoadObserver.h b/Source/WebCore/loader/ResourceLoadObserver.h
new file mode 100644
index 000000000..c8cce7b03
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadObserver.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ResourceLoadStatisticsStore.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Document;
+class Frame;
+class Page;
+class ResourceRequest;
+class ResourceResponse;
+class URL;
+
+struct ResourceLoadStatistics;
+
+class ResourceLoadObserver {
+ friend class NeverDestroyed<ResourceLoadObserver>;
+public:
+ WEBCORE_EXPORT static ResourceLoadObserver& sharedObserver();
+
+ void logFrameNavigation(const Frame& frame, const Frame& topFrame, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse);
+ void logSubresourceLoading(const Frame*, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse);
+ void logWebSocketLoading(const Frame*, const URL&);
+ void logUserInteractionWithReducedTimeResolution(const Document&);
+
+ WEBCORE_EXPORT void logUserInteraction(const URL&);
+ WEBCORE_EXPORT bool hasHadUserInteraction(const URL&);
+ WEBCORE_EXPORT void clearUserInteraction(const URL&);
+
+ WEBCORE_EXPORT void setPrevalentResource(const URL&);
+ WEBCORE_EXPORT bool isPrevalentResource(const URL&);
+ WEBCORE_EXPORT void clearPrevalentResource(const URL&);
+
+ WEBCORE_EXPORT void setTimeToLiveUserInteraction(double seconds);
+ WEBCORE_EXPORT void setReducedTimestampResolution(double seconds);
+
+ WEBCORE_EXPORT void fireDataModificationHandler();
+
+ WEBCORE_EXPORT RefPtr<ResourceLoadStatisticsStore> statisticsStore();
+ WEBCORE_EXPORT void setStatisticsStore(Ref<ResourceLoadStatisticsStore>&&);
+
+ WEBCORE_EXPORT String statisticsForOrigin(const String&);
+
+private:
+ bool shouldLog(Page*);
+ static String primaryDomain(const URL&);
+
+ RefPtr<ResourceLoadStatisticsStore> m_store;
+ HashMap<String, size_t> m_originsVisitedMap;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoadScheduler.cpp b/Source/WebCore/loader/ResourceLoadScheduler.cpp
deleted file mode 100644
index e8fee1d3f..000000000
--- a/Source/WebCore/loader/ResourceLoadScheduler.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- 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) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- Copyright (C) 2010 Google 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.
- */
-
-#include "config.h"
-#include "ResourceLoadScheduler.h"
-
-#include "Document.h"
-#include "DocumentLoader.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "InspectorInstrumentation.h"
-#include "URL.h"
-#include "LoaderStrategy.h"
-#include "Logging.h"
-#include "NetscapePlugInStreamLoader.h"
-#include "PlatformStrategies.h"
-#include "ResourceLoader.h"
-#include "ResourceRequest.h"
-#include "SubresourceLoader.h"
-#include <wtf/MainThread.h>
-#include <wtf/TemporaryChange.h>
-#include <wtf/text/CString.h>
-
-#if PLATFORM(IOS)
-#include <RuntimeApplicationChecksIOS.h>
-#endif
-
-namespace WebCore {
-
-// Match the parallel connection count used by the networking layer.
-static unsigned maxRequestsInFlightPerHost;
-#if !PLATFORM(IOS)
-static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
-#else
-// Limiting this seems to regress performance in some local cases so let's just make it large.
-static const unsigned maxRequestsInFlightForNonHTTPProtocols = 10000;
-#endif
-
-ResourceLoadScheduler::HostInformation* ResourceLoadScheduler::hostForURL(const URL& url, CreateHostPolicy createHostPolicy)
-{
- if (!url.protocolIsInHTTPFamily())
- return m_nonHTTPProtocolHost;
-
- m_hosts.checkConsistency();
- String hostName = url.host();
- HostInformation* host = m_hosts.get(hostName);
- if (!host && createHostPolicy == CreateIfNotFound) {
- host = new HostInformation(hostName, maxRequestsInFlightPerHost);
- m_hosts.add(hostName, host);
- }
- return host;
-}
-
-ResourceLoadScheduler* resourceLoadScheduler()
-{
- ASSERT(isMainThread());
- static ResourceLoadScheduler* globalScheduler = 0;
-
- if (!globalScheduler) {
- static bool isCallingOutToStrategy = false;
-
- // If we're re-entering resourceLoadScheduler() while calling out to the LoaderStrategy,
- // then the LoaderStrategy is trying to use the default resourceLoadScheduler.
- // So we'll create it here and start using it.
- if (isCallingOutToStrategy) {
- globalScheduler = new ResourceLoadScheduler;
- return globalScheduler;
- }
-
- TemporaryChange<bool> recursionGuard(isCallingOutToStrategy, true);
- globalScheduler = platformStrategies()->loaderStrategy()->resourceLoadScheduler();
- }
-
- return globalScheduler;
-}
-
-ResourceLoadScheduler::ResourceLoadScheduler()
- : m_nonHTTPProtocolHost(new HostInformation(String(), maxRequestsInFlightForNonHTTPProtocols))
- , m_requestTimer(this, &ResourceLoadScheduler::requestTimerFired)
- , m_suspendPendingRequestsCount(0)
- , m_isSerialLoadingEnabled(false)
-{
- maxRequestsInFlightPerHost = initializeMaximumHTTPConnectionCountPerHost();
-}
-
-ResourceLoadScheduler::~ResourceLoadScheduler()
-{
-}
-
-PassRefPtr<SubresourceLoader> ResourceLoadScheduler::scheduleSubresourceLoad(Frame* frame, CachedResource* resource, const ResourceRequest& request, ResourceLoadPriority priority, const ResourceLoaderOptions& options)
-{
- RefPtr<SubresourceLoader> loader = SubresourceLoader::create(frame, resource, request, options);
- if (loader)
- scheduleLoad(loader.get(), priority);
-#if PLATFORM(IOS)
- // Since we defer loader initialization until scheduling on iOS, the frame
- // load delegate that would be called in SubresourceLoader::create() on
- // other ports might be called in scheduleLoad() instead. Our contract to
- // callers of this method is that a null loader is returned if the load was
- // cancelled by a frame load delegate.
- if (!loader || loader->reachedTerminalState())
- return nullptr;
-#endif
- return loader.release();
-}
-
-PassRefPtr<NetscapePlugInStreamLoader> ResourceLoadScheduler::schedulePluginStreamLoad(Frame* frame, NetscapePlugInStreamLoaderClient* client, const ResourceRequest& request)
-{
- PassRefPtr<NetscapePlugInStreamLoader> loader = NetscapePlugInStreamLoader::create(frame, client, request);
- if (loader)
- scheduleLoad(loader.get(), ResourceLoadPriorityLow);
- return loader;
-}
-
-void ResourceLoadScheduler::scheduleLoad(ResourceLoader* resourceLoader, ResourceLoadPriority priority)
-{
- ASSERT(resourceLoader);
- ASSERT(priority != ResourceLoadPriorityUnresolved);
-
- LOG(ResourceLoading, "ResourceLoadScheduler::load resource %p '%s'", resourceLoader, resourceLoader->url().string().latin1().data());
-
-#if PLATFORM(IOS)
- // If there's a web archive resource for this URL, we don't need to schedule the load since it will never touch the network.
- if (!isSuspendingPendingRequests() && resourceLoader->documentLoader()->archiveResourceForURL(resourceLoader->iOSOriginalRequest().url())) {
- resourceLoader->startLoading();
- return;
- }
-#else
- if (resourceLoader->documentLoader()->archiveResourceForURL(resourceLoader->request().url())) {
- resourceLoader->start();
- return;
- }
-#endif
-
-#if PLATFORM(IOS)
- HostInformation* host = hostForURL(resourceLoader->iOSOriginalRequest().url(), CreateIfNotFound);
-#else
- HostInformation* host = hostForURL(resourceLoader->url(), CreateIfNotFound);
-#endif
-
- bool hadRequests = host->hasRequests();
- host->schedule(resourceLoader, priority);
-
-#if PLATFORM(MAC) || USE(CFNETWORK)
- if (!isSuspendingPendingRequests()) {
- // Serve all requests at once to keep the pipeline full at the network layer.
- // FIXME: Does this code do anything useful, given that we also set maxRequestsInFlightPerHost to effectively unlimited on these platforms?
- servePendingRequests(host, ResourceLoadPriorityVeryLow);
- return;
- }
-#endif
-
-#if PLATFORM(IOS)
- if ((priority > ResourceLoadPriorityLow || !resourceLoader->iOSOriginalRequest().url().protocolIsInHTTPFamily() || (priority == ResourceLoadPriorityLow && !hadRequests)) && !isSuspendingPendingRequests()) {
- // Try to request important resources immediately.
- servePendingRequests(host, priority);
- return;
- }
-#else
- if (priority > ResourceLoadPriorityLow || !resourceLoader->url().protocolIsInHTTPFamily() || (priority == ResourceLoadPriorityLow && !hadRequests)) {
- // Try to request important resources immediately.
- servePendingRequests(host, priority);
- return;
- }
-#endif
-
- notifyDidScheduleResourceRequest(resourceLoader);
-
- // Handle asynchronously so early low priority requests don't
- // get scheduled before later high priority ones.
- scheduleServePendingRequests();
-}
-
-void ResourceLoadScheduler::notifyDidScheduleResourceRequest(ResourceLoader* loader)
-{
- InspectorInstrumentation::didScheduleResourceRequest(loader->frameLoader() ? loader->frameLoader()->frame().document() : 0, loader->url());
-}
-
-void ResourceLoadScheduler::remove(ResourceLoader* resourceLoader)
-{
- ASSERT(resourceLoader);
-
- HostInformation* host = hostForURL(resourceLoader->url());
- if (host)
- host->remove(resourceLoader);
-#if PLATFORM(IOS)
- // ResourceLoader::url() doesn't start returning the correct value until the load starts. If we get canceled before that, we need to look for originalRequest url instead.
- // FIXME: ResourceLoader::url() should be made to return a sensible value at all times.
- if (!resourceLoader->iOSOriginalRequest().isNull()) {
- HostInformation* originalHost = hostForURL(resourceLoader->iOSOriginalRequest().url());
- if (originalHost && originalHost != host)
- originalHost->remove(resourceLoader);
- }
-#endif
- scheduleServePendingRequests();
-}
-
-void ResourceLoadScheduler::crossOriginRedirectReceived(ResourceLoader* resourceLoader, const URL& redirectURL)
-{
- HostInformation* oldHost = hostForURL(resourceLoader->url());
- ASSERT(oldHost);
- if (!oldHost)
- return;
-
- HostInformation* newHost = hostForURL(redirectURL, CreateIfNotFound);
-
- if (oldHost->name() == newHost->name())
- return;
-
- newHost->addLoadInProgress(resourceLoader);
- oldHost->remove(resourceLoader);
-}
-
-void ResourceLoadScheduler::servePendingRequests(ResourceLoadPriority minimumPriority)
-{
- LOG(ResourceLoading, "ResourceLoadScheduler::servePendingRequests. m_suspendPendingRequestsCount=%d", m_suspendPendingRequestsCount);
- if (isSuspendingPendingRequests())
- return;
-
- m_requestTimer.stop();
-
- servePendingRequests(m_nonHTTPProtocolHost, minimumPriority);
-
- Vector<HostInformation*> hostsToServe;
- m_hosts.checkConsistency();
- HostMap::iterator end = m_hosts.end();
- for (HostMap::iterator iter = m_hosts.begin(); iter != end; ++iter)
- hostsToServe.append(iter->value);
-
- int size = hostsToServe.size();
- for (int i = 0; i < size; ++i) {
- HostInformation* host = hostsToServe[i];
- if (host->hasRequests())
- servePendingRequests(host, minimumPriority);
- else
- delete m_hosts.take(host->name());
- }
-}
-
-void ResourceLoadScheduler::servePendingRequests(HostInformation* host, ResourceLoadPriority minimumPriority)
-{
- LOG(ResourceLoading, "ResourceLoadScheduler::servePendingRequests HostInformation.m_name='%s'", host->name().latin1().data());
-
- for (int priority = ResourceLoadPriorityHighest; priority >= minimumPriority; --priority) {
- HostInformation::RequestQueue& requestsPending = host->requestsPending(ResourceLoadPriority(priority));
-
- while (!requestsPending.isEmpty()) {
- RefPtr<ResourceLoader> resourceLoader = requestsPending.first();
-
- // For named hosts - which are only http(s) hosts - we should always enforce the connection limit.
- // For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing
- // and we don't know all stylesheets yet.
- Document* document = resourceLoader->frameLoader() ? resourceLoader->frameLoader()->frame().document() : 0;
- bool shouldLimitRequests = !host->name().isNull() || (document && (document->parsing() || !document->haveStylesheetsLoaded()));
- if (shouldLimitRequests && host->limitRequests(ResourceLoadPriority(priority)))
- return;
-
- requestsPending.removeFirst();
- host->addLoadInProgress(resourceLoader.get());
-#if PLATFORM(IOS)
- if (!applicationIsWebProcess()) {
- resourceLoader->startLoading();
- return;
- }
-#endif
- resourceLoader->start();
- }
- }
-}
-
-void ResourceLoadScheduler::suspendPendingRequests()
-{
- ++m_suspendPendingRequestsCount;
-}
-
-void ResourceLoadScheduler::resumePendingRequests()
-{
- ASSERT(m_suspendPendingRequestsCount);
- --m_suspendPendingRequestsCount;
- if (m_suspendPendingRequestsCount)
- return;
- if (!m_hosts.isEmpty() || m_nonHTTPProtocolHost->hasRequests())
- scheduleServePendingRequests();
-}
-
-void ResourceLoadScheduler::scheduleServePendingRequests()
-{
- LOG(ResourceLoading, "ResourceLoadScheduler::scheduleServePendingRequests, m_requestTimer.isActive()=%u", m_requestTimer.isActive());
- if (!m_requestTimer.isActive())
- m_requestTimer.startOneShot(0);
-}
-
-void ResourceLoadScheduler::requestTimerFired(Timer<ResourceLoadScheduler>&)
-{
- LOG(ResourceLoading, "ResourceLoadScheduler::requestTimerFired\n");
- servePendingRequests();
-}
-
-ResourceLoadScheduler::HostInformation::HostInformation(const String& name, unsigned maxRequestsInFlight)
- : m_name(name)
- , m_maxRequestsInFlight(maxRequestsInFlight)
-{
-}
-
-ResourceLoadScheduler::HostInformation::~HostInformation()
-{
- ASSERT(m_requestsLoading.isEmpty());
- for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++)
- ASSERT(m_requestsPending[p].isEmpty());
-}
-
-void ResourceLoadScheduler::HostInformation::schedule(ResourceLoader* resourceLoader, ResourceLoadPriority priority)
-{
- m_requestsPending[priority].append(resourceLoader);
-}
-
-void ResourceLoadScheduler::HostInformation::addLoadInProgress(ResourceLoader* resourceLoader)
-{
- LOG(ResourceLoading, "HostInformation '%s' loading '%s'. Current count %d", m_name.latin1().data(), resourceLoader->url().string().latin1().data(), m_requestsLoading.size());
- m_requestsLoading.add(resourceLoader);
-}
-
-void ResourceLoadScheduler::HostInformation::remove(ResourceLoader* resourceLoader)
-{
- if (m_requestsLoading.remove(resourceLoader))
- return;
-
- for (int priority = ResourceLoadPriorityHighest; priority >= ResourceLoadPriorityLowest; --priority) {
- RequestQueue::iterator end = m_requestsPending[priority].end();
- for (RequestQueue::iterator it = m_requestsPending[priority].begin(); it != end; ++it) {
- if (*it == resourceLoader) {
- m_requestsPending[priority].remove(it);
- return;
- }
- }
- }
-}
-
-bool ResourceLoadScheduler::HostInformation::hasRequests() const
-{
- if (!m_requestsLoading.isEmpty())
- return true;
- for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++) {
- if (!m_requestsPending[p].isEmpty())
- return true;
- }
- return false;
-}
-
-bool ResourceLoadScheduler::HostInformation::limitRequests(ResourceLoadPriority priority) const
-{
- if (priority == ResourceLoadPriorityVeryLow && !m_requestsLoading.isEmpty())
- return true;
- return m_requestsLoading.size() >= (resourceLoadScheduler()->isSerialLoadingEnabled() ? 1 : m_maxRequestsInFlight);
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoadScheduler.h b/Source/WebCore/loader/ResourceLoadScheduler.h
deleted file mode 100644
index 200825d41..000000000
--- a/Source/WebCore/loader/ResourceLoadScheduler.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
- Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
- Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
- Copyright (C) 2010 Google 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 ResourceLoadScheduler_h
-#define ResourceLoadScheduler_h
-
-#include "FrameLoaderTypes.h"
-#include "ResourceLoaderOptions.h"
-#include "ResourceLoadPriority.h"
-#include "Timer.h"
-#include <wtf/Deque.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/text/StringHash.h>
-#include <wtf/text/WTFString.h>
-
-namespace WebCore {
-
-class CachedResource;
-class Frame;
-class URL;
-class NetscapePlugInStreamLoader;
-class NetscapePlugInStreamLoaderClient;
-class ResourceLoader;
-class ResourceRequest;
-class SubresourceLoader;
-
-class ResourceLoadScheduler {
- WTF_MAKE_NONCOPYABLE(ResourceLoadScheduler); WTF_MAKE_FAST_ALLOCATED;
-public:
- friend ResourceLoadScheduler* resourceLoadScheduler();
-
- virtual PassRefPtr<SubresourceLoader> scheduleSubresourceLoad(Frame*, CachedResource*, const ResourceRequest&, ResourceLoadPriority, const ResourceLoaderOptions&);
- virtual PassRefPtr<NetscapePlugInStreamLoader> schedulePluginStreamLoad(Frame*, NetscapePlugInStreamLoaderClient*, const ResourceRequest&);
- virtual void remove(ResourceLoader*);
- virtual void crossOriginRedirectReceived(ResourceLoader*, const URL& redirectURL);
-
- virtual void servePendingRequests(ResourceLoadPriority minimumPriority = ResourceLoadPriorityVeryLow);
- virtual void suspendPendingRequests();
- virtual void resumePendingRequests();
-
- bool isSerialLoadingEnabled() const { return m_isSerialLoadingEnabled; }
- virtual void setSerialLoadingEnabled(bool b) { m_isSerialLoadingEnabled = b; }
-
- class Suspender {
- public:
- explicit Suspender(ResourceLoadScheduler& scheduler) : m_scheduler(scheduler) { m_scheduler.suspendPendingRequests(); }
- ~Suspender() { m_scheduler.resumePendingRequests(); }
- private:
- ResourceLoadScheduler& m_scheduler;
- };
-
-protected:
- ResourceLoadScheduler();
- virtual ~ResourceLoadScheduler();
-
- void notifyDidScheduleResourceRequest(ResourceLoader*);
-
-private:
- void scheduleLoad(ResourceLoader*, ResourceLoadPriority);
- void scheduleServePendingRequests();
- void requestTimerFired(Timer<ResourceLoadScheduler>&);
-
- bool isSuspendingPendingRequests() const { return !!m_suspendPendingRequestsCount; }
-
- class HostInformation {
- WTF_MAKE_NONCOPYABLE(HostInformation); WTF_MAKE_FAST_ALLOCATED;
- public:
- HostInformation(const String&, unsigned);
- ~HostInformation();
-
- const String& name() const { return m_name; }
- void schedule(ResourceLoader*, ResourceLoadPriority = ResourceLoadPriorityVeryLow);
- void addLoadInProgress(ResourceLoader*);
- void remove(ResourceLoader*);
- bool hasRequests() const;
- bool limitRequests(ResourceLoadPriority) const;
-
- typedef Deque<RefPtr<ResourceLoader>> RequestQueue;
- RequestQueue& requestsPending(ResourceLoadPriority priority) { return m_requestsPending[priority]; }
-
- private:
- RequestQueue m_requestsPending[ResourceLoadPriorityHighest + 1];
- typedef HashSet<RefPtr<ResourceLoader>> RequestMap;
- RequestMap m_requestsLoading;
- const String m_name;
- const int m_maxRequestsInFlight;
- };
-
- enum CreateHostPolicy {
- CreateIfNotFound,
- FindOnly
- };
-
- HostInformation* hostForURL(const URL&, CreateHostPolicy = FindOnly);
- void servePendingRequests(HostInformation*, ResourceLoadPriority);
-
- typedef HashMap<String, HostInformation*, StringHash> HostMap;
- HostMap m_hosts;
- HostInformation* m_nonHTTPProtocolHost;
-
- Timer<ResourceLoadScheduler> m_requestTimer;
-
- unsigned m_suspendPendingRequestsCount;
- bool m_isSerialLoadingEnabled;
-};
-
-ResourceLoadScheduler* resourceLoadScheduler();
-
-}
-
-#endif
diff --git a/Source/WebCore/loader/ResourceLoadStatistics.cpp b/Source/WebCore/loader/ResourceLoadStatistics.cpp
new file mode 100644
index 000000000..5aa181469
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadStatistics.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceLoadStatistics.h"
+
+#include "KeyedCoding.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+typedef WTF::HashMap<String, unsigned, StringHash, HashTraits<String>, HashTraits<unsigned>>::KeyValuePairType ResourceLoadStatisticsValue;
+
+static void encodeHashCountedSet(KeyedEncoder& encoder, const String& label, const HashCountedSet<String>& hashCountedSet)
+{
+ if (hashCountedSet.isEmpty())
+ return;
+
+ encoder.encodeObjects(label, hashCountedSet.begin(), hashCountedSet.end(), [](KeyedEncoder& encoderInner, const ResourceLoadStatisticsValue& origin) {
+ encoderInner.encodeString("origin", origin.key);
+ encoderInner.encodeUInt32("count", origin.value);
+ });
+}
+
+void ResourceLoadStatistics::encode(KeyedEncoder& encoder) const
+{
+ encoder.encodeString("PrevalentResourceOrigin", highLevelDomain);
+
+ // User interaction
+ encoder.encodeBool("hadUserInteraction", hadUserInteraction);
+ encoder.encodeDouble("mostRecentUserInteraction", mostRecentUserInteraction);
+ encoder.encodeBool("grandfathered", grandfathered);
+
+ // Top frame stats
+ encoder.encodeBool("topFrameHasBeenNavigatedToBefore", topFrameHasBeenNavigatedToBefore);
+ encoder.encodeUInt32("topFrameHasBeenRedirectedTo", topFrameHasBeenRedirectedTo);
+ encoder.encodeUInt32("topFrameHasBeenRedirectedFrom", topFrameHasBeenRedirectedFrom);
+ encoder.encodeUInt32("topFrameInitialLoadCount", topFrameInitialLoadCount);
+ encoder.encodeUInt32("topFrameHasBeenNavigatedTo", topFrameHasBeenNavigatedTo);
+ encoder.encodeUInt32("topFrameHasBeenNavigatedFrom", topFrameHasBeenNavigatedFrom);
+
+ // Subframe stats
+ encoder.encodeBool("subframeHasBeenLoadedBefore", subframeHasBeenLoadedBefore);
+ encoder.encodeUInt32("subframeHasBeenRedirectedTo", subframeHasBeenRedirectedTo);
+ encoder.encodeUInt32("subframeHasBeenRedirectedFrom", subframeHasBeenRedirectedFrom);
+ encoder.encodeUInt32("subframeSubResourceCount", subframeSubResourceCount);
+ encodeHashCountedSet(encoder, "subframeUnderTopFrameOrigins", subframeUnderTopFrameOrigins);
+ encodeHashCountedSet(encoder, "subframeUniqueRedirectsTo", subframeUniqueRedirectsTo);
+ encoder.encodeUInt32("subframeHasBeenNavigatedTo", subframeHasBeenNavigatedTo);
+ encoder.encodeUInt32("subframeHasBeenNavigatedFrom", subframeHasBeenNavigatedFrom);
+
+ // Subresource stats
+ encoder.encodeUInt32("subresourceHasBeenRedirectedFrom", subresourceHasBeenRedirectedFrom);
+ encoder.encodeUInt32("subresourceHasBeenRedirectedTo", subresourceHasBeenRedirectedTo);
+ encoder.encodeUInt32("subresourceHasBeenSubresourceCount", subresourceHasBeenSubresourceCount);
+ encoder.encodeDouble("subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited", subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited);
+ encodeHashCountedSet(encoder, "subresourceUnderTopFrameOrigins", subresourceUnderTopFrameOrigins);
+ encodeHashCountedSet(encoder, "subresourceUniqueRedirectsTo", subresourceUniqueRedirectsTo);
+
+ // Prevalent Resource
+ encodeHashCountedSet(encoder, "redirectedToOtherPrevalentResourceOrigins", redirectedToOtherPrevalentResourceOrigins);
+ encoder.encodeBool("isPrevalentResource", isPrevalentResource);
+ encoder.encodeUInt32("dataRecordsRemoved", dataRecordsRemoved);
+}
+
+static void decodeHashCountedSet(KeyedDecoder& decoder, const String& label, HashCountedSet<String>& hashCountedSet)
+{
+ Vector<String> ignore;
+ decoder.decodeObjects(label, ignore, [&hashCountedSet](KeyedDecoder& decoderInner, String& origin) {
+ if (!decoderInner.decodeString("origin", origin))
+ return false;
+
+ unsigned count;
+ if (!decoderInner.decodeUInt32("count", count))
+ return false;
+
+ hashCountedSet.add(origin, count);
+ return true;
+ });
+}
+
+bool ResourceLoadStatistics::decode(KeyedDecoder& decoder, unsigned version)
+{
+ if (!decoder.decodeString("PrevalentResourceOrigin", highLevelDomain))
+ return false;
+
+ // User interaction
+ if (!decoder.decodeBool("hadUserInteraction", hadUserInteraction))
+ return false;
+
+ // Top frame stats
+ if (!decoder.decodeBool("topFrameHasBeenNavigatedToBefore", topFrameHasBeenNavigatedToBefore))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenRedirectedTo", topFrameHasBeenRedirectedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenRedirectedFrom", topFrameHasBeenRedirectedFrom))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameInitialLoadCount", topFrameInitialLoadCount))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenNavigatedTo", topFrameHasBeenNavigatedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenNavigatedFrom", topFrameHasBeenNavigatedFrom))
+ return false;
+
+ // Subframe stats
+ if (!decoder.decodeBool("subframeHasBeenLoadedBefore", subframeHasBeenLoadedBefore))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeHasBeenRedirectedTo", subframeHasBeenRedirectedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeHasBeenRedirectedFrom", subframeHasBeenRedirectedFrom))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeSubResourceCount", subframeSubResourceCount))
+ return false;
+
+ decodeHashCountedSet(decoder, "subframeUnderTopFrameOrigins", subframeUnderTopFrameOrigins);
+ decodeHashCountedSet(decoder, "subframeUniqueRedirectsTo", subframeUniqueRedirectsTo);
+
+ if (!decoder.decodeUInt32("subframeHasBeenNavigatedTo", subframeHasBeenNavigatedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeHasBeenNavigatedFrom", subframeHasBeenNavigatedFrom))
+ return false;
+
+ // Subresource stats
+ if (!decoder.decodeUInt32("subresourceHasBeenRedirectedFrom", subresourceHasBeenRedirectedFrom))
+ return false;
+
+ if (!decoder.decodeUInt32("subresourceHasBeenRedirectedTo", subresourceHasBeenRedirectedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("subresourceHasBeenSubresourceCount", subresourceHasBeenSubresourceCount))
+ return false;
+
+ if (!decoder.decodeDouble("subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited", subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited))
+ return false;
+
+ decodeHashCountedSet(decoder, "subresourceUnderTopFrameOrigins", subresourceUnderTopFrameOrigins);
+ decodeHashCountedSet(decoder, "subresourceUniqueRedirectsTo", subresourceUniqueRedirectsTo);
+
+ // Prevalent Resource
+ decodeHashCountedSet(decoder, "redirectedToOtherPrevalentResourceOrigins", redirectedToOtherPrevalentResourceOrigins);
+
+ if (!decoder.decodeBool("isPrevalentResource", isPrevalentResource))
+ return false;
+
+ if (version < 2)
+ return true;
+
+ if (!decoder.decodeUInt32("dataRecordsRemoved", dataRecordsRemoved))
+ return false;
+
+ if (version < 3)
+ return true;
+
+ if (!decoder.decodeDouble("mostRecentUserInteraction", mostRecentUserInteraction))
+ return false;
+
+ if (!decoder.decodeBool("grandfathered", grandfathered))
+ return false;
+
+ return true;
+}
+
+static void appendBoolean(StringBuilder& builder, const String& label, bool flag)
+{
+ builder.appendLiteral(" ");
+ builder.append(label);
+ builder.appendLiteral(": ");
+ builder.append(flag ? "Yes" : "No");
+}
+
+static void appendHashCountedSet(StringBuilder& builder, const String& label, const HashCountedSet<String>& hashCountedSet)
+{
+ if (hashCountedSet.isEmpty())
+ return;
+
+ builder.appendLiteral(" ");
+ builder.append(label);
+ builder.appendLiteral(":\n");
+
+ for (auto& entry : hashCountedSet) {
+ builder.appendLiteral(" ");
+ builder.append(entry.key);
+ builder.appendLiteral(": ");
+ builder.appendNumber(entry.value);
+ builder.append('\n');
+ }
+}
+
+String ResourceLoadStatistics::toString() const
+{
+ StringBuilder builder;
+
+ // User interaction
+ appendBoolean(builder, "hadUserInteraction", hadUserInteraction);
+ builder.append('\n');
+ builder.appendLiteral(" mostRecentUserInteraction: ");
+ builder.appendNumber(mostRecentUserInteraction);
+ builder.append('\n');
+ appendBoolean(builder, " grandfathered", grandfathered);
+ builder.append('\n');
+
+ // Top frame stats
+ appendBoolean(builder, "topFrameHasBeenNavigatedToBefore", topFrameHasBeenNavigatedToBefore);
+ builder.append('\n');
+ builder.appendLiteral(" topFrameHasBeenRedirectedTo: ");
+ builder.appendNumber(topFrameHasBeenRedirectedTo);
+ builder.append('\n');
+ builder.appendLiteral(" topFrameHasBeenRedirectedFrom: ");
+ builder.appendNumber(topFrameHasBeenRedirectedFrom);
+ builder.append('\n');
+ builder.appendLiteral(" topFrameInitialLoadCount: ");
+ builder.appendNumber(topFrameInitialLoadCount);
+ builder.append('\n');
+ builder.appendLiteral(" topFrameHasBeenNavigatedTo: ");
+ builder.appendNumber(topFrameHasBeenNavigatedTo);
+ builder.append('\n');
+ builder.appendLiteral(" topFrameHasBeenNavigatedFrom: ");
+ builder.appendNumber(topFrameHasBeenNavigatedFrom);
+ builder.append('\n');
+
+ // Subframe stats
+ appendBoolean(builder, "subframeHasBeenLoadedBefore", subframeHasBeenLoadedBefore);
+ builder.append('\n');
+ builder.appendLiteral(" subframeHasBeenRedirectedTo: ");
+ builder.appendNumber(subframeHasBeenRedirectedTo);
+ builder.append('\n');
+ builder.appendLiteral(" subframeHasBeenRedirectedFrom: ");
+ builder.appendNumber(subframeHasBeenRedirectedFrom);
+ builder.append('\n');
+ builder.appendLiteral(" subframeSubResourceCount: ");
+ builder.appendNumber(subframeSubResourceCount);
+ builder.append('\n');
+ appendHashCountedSet(builder, "subframeUnderTopFrameOrigins", subframeUnderTopFrameOrigins);
+ appendHashCountedSet(builder, "subframeUniqueRedirectsTo", subframeUniqueRedirectsTo);
+ builder.appendLiteral(" subframeHasBeenNavigatedTo: ");
+ builder.appendNumber(subframeHasBeenNavigatedTo);
+ builder.append('\n');
+ builder.appendLiteral(" subframeHasBeenNavigatedFrom: ");
+ builder.appendNumber(subframeHasBeenNavigatedFrom);
+ builder.append('\n');
+
+ // Subresource stats
+ builder.appendLiteral(" subresourceHasBeenRedirectedFrom: ");
+ builder.appendNumber(subresourceHasBeenRedirectedFrom);
+ builder.append('\n');
+ builder.appendLiteral(" subresourceHasBeenRedirectedTo: ");
+ builder.appendNumber(subresourceHasBeenRedirectedTo);
+ builder.append('\n');
+ builder.appendLiteral(" subresourceHasBeenSubresourceCount: ");
+ builder.appendNumber(subresourceHasBeenSubresourceCount);
+ builder.append('\n');
+ builder.appendLiteral(" subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited: ");
+ builder.appendNumber(subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited);
+ builder.append('\n');
+ appendHashCountedSet(builder, "subresourceUnderTopFrameOrigins", subresourceUnderTopFrameOrigins);
+ appendHashCountedSet(builder, "subresourceUniqueRedirectsTo", subresourceUniqueRedirectsTo);
+
+ // Prevalent Resource
+ appendHashCountedSet(builder, "redirectedToOtherPrevalentResourceOrigins", redirectedToOtherPrevalentResourceOrigins);
+ appendBoolean(builder, "isPrevalentResource", isPrevalentResource);
+ builder.appendLiteral(" dataRecordsRemoved: ");
+ builder.appendNumber(dataRecordsRemoved);
+ builder.append('\n');
+
+ builder.append('\n');
+
+ return builder.toString();
+}
+
+template <typename T>
+static void mergeHashCountedSet(HashCountedSet<T>& to, const HashCountedSet<T>& from)
+{
+ for (auto& entry : from)
+ to.add(entry.key, entry.value);
+}
+
+void ResourceLoadStatistics::merge(const ResourceLoadStatistics& other)
+{
+ ASSERT(other.highLevelDomain == highLevelDomain);
+
+ if (!other.hadUserInteraction) {
+ // If user interaction has been reset do so here too.
+ // Else, do nothing.
+ if (!other.mostRecentUserInteraction) {
+ hadUserInteraction = false;
+ mostRecentUserInteraction = 0;
+ }
+ } else {
+ hadUserInteraction = true;
+ if (mostRecentUserInteraction < other.mostRecentUserInteraction)
+ mostRecentUserInteraction = other.mostRecentUserInteraction;
+ }
+ grandfathered |= other.grandfathered;
+
+ // Top frame stats
+ topFrameHasBeenRedirectedTo += other.topFrameHasBeenRedirectedTo;
+ topFrameHasBeenRedirectedFrom += other.topFrameHasBeenRedirectedFrom;
+ topFrameInitialLoadCount += other.topFrameInitialLoadCount;
+ topFrameHasBeenNavigatedTo += other.topFrameHasBeenNavigatedTo;
+ topFrameHasBeenNavigatedFrom += other.topFrameHasBeenNavigatedFrom;
+ topFrameHasBeenNavigatedToBefore |= other.topFrameHasBeenNavigatedToBefore;
+
+ // Subframe stats
+ mergeHashCountedSet(subframeUnderTopFrameOrigins, other.subframeUnderTopFrameOrigins);
+ subframeHasBeenRedirectedTo += other.subframeHasBeenRedirectedTo;
+ subframeHasBeenRedirectedFrom += other.subframeHasBeenRedirectedFrom;
+ mergeHashCountedSet(subframeUniqueRedirectsTo, other.subframeUniqueRedirectsTo);
+ subframeSubResourceCount += other.subframeSubResourceCount;
+ subframeHasBeenNavigatedTo += other.subframeHasBeenNavigatedTo;
+ subframeHasBeenNavigatedFrom += other.subframeHasBeenNavigatedFrom;
+ subframeHasBeenLoadedBefore |= other.subframeHasBeenLoadedBefore;
+
+ // Subresource stats
+ mergeHashCountedSet(subresourceUnderTopFrameOrigins, other.subresourceUnderTopFrameOrigins);
+ subresourceHasBeenSubresourceCount += other.subresourceHasBeenSubresourceCount;
+ subresourceHasBeenRedirectedFrom += other.subresourceHasBeenRedirectedFrom;
+ subresourceHasBeenRedirectedTo += other.subresourceHasBeenRedirectedTo;
+ mergeHashCountedSet(subresourceUniqueRedirectsTo, other.subresourceUniqueRedirectsTo);
+
+ // Prevalent resource stats
+ mergeHashCountedSet(redirectedToOtherPrevalentResourceOrigins, other.redirectedToOtherPrevalentResourceOrigins);
+ isPrevalentResource |= other.isPrevalentResource;
+ dataRecordsRemoved += other.dataRecordsRemoved;
+}
+
+}
diff --git a/Source/WebCore/loader/ResourceLoadStatistics.h b/Source/WebCore/loader/ResourceLoadStatistics.h
new file mode 100644
index 000000000..1ec25e2ec
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadStatistics.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/HashCountedSet.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class KeyedDecoder;
+class KeyedEncoder;
+
+struct ResourceLoadStatistics {
+ ResourceLoadStatistics(const String& primaryDomain)
+ : highLevelDomain(primaryDomain)
+ {
+ }
+
+ ResourceLoadStatistics() = default;
+
+ void encode(KeyedEncoder&) const;
+ bool decode(KeyedDecoder&, unsigned version);
+
+ String toString() const;
+
+ void merge(const ResourceLoadStatistics&);
+
+ String highLevelDomain;
+
+ // User interaction
+ bool hadUserInteraction { false };
+ // Timestamp. Default value is negative, 0 means it was reset.
+ double mostRecentUserInteraction { -1 };
+ bool grandfathered { false };
+
+ // Top frame stats
+ unsigned topFrameHasBeenRedirectedTo { 0 };
+ unsigned topFrameHasBeenRedirectedFrom { 0 };
+ unsigned topFrameInitialLoadCount { 0 };
+ unsigned topFrameHasBeenNavigatedTo { 0 };
+ unsigned topFrameHasBeenNavigatedFrom { 0 };
+ bool topFrameHasBeenNavigatedToBefore { false };
+
+ // Subframe stats
+ HashCountedSet<String> subframeUnderTopFrameOrigins;
+ unsigned subframeHasBeenRedirectedTo { 0 };
+ unsigned subframeHasBeenRedirectedFrom { 0 };
+ HashCountedSet<String> subframeUniqueRedirectsTo;
+ unsigned subframeSubResourceCount { 0 };
+ unsigned subframeHasBeenNavigatedTo { 0 };
+ unsigned subframeHasBeenNavigatedFrom { 0 };
+ bool subframeHasBeenLoadedBefore { false };
+
+ // Subresource stats
+ HashCountedSet<String> subresourceUnderTopFrameOrigins;
+ unsigned subresourceHasBeenSubresourceCount { 0 };
+ double subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited { 0.0 };
+ unsigned subresourceHasBeenRedirectedFrom { 0 };
+ unsigned subresourceHasBeenRedirectedTo { 0 };
+ HashCountedSet<String> subresourceUniqueRedirectsTo;
+
+ // Prevalent resource stats
+ HashCountedSet<String> redirectedToOtherPrevalentResourceOrigins;
+ bool isPrevalentResource { false };
+ unsigned dataRecordsRemoved { 0 };
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoadStatisticsStore.cpp b/Source/WebCore/loader/ResourceLoadStatisticsStore.cpp
new file mode 100644
index 000000000..16f45676c
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadStatisticsStore.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceLoadStatisticsStore.h"
+
+#include "KeyedCoding.h"
+#include "Logging.h"
+#include "NetworkStorageSession.h"
+#include "PlatformStrategies.h"
+#include "ResourceLoadStatistics.h"
+#include "SharedBuffer.h"
+#include "URL.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+static const auto statisticsModelVersion = 3;
+// 30 days in seconds
+static auto timeToLiveUserInteraction = 2592000;
+
+Ref<ResourceLoadStatisticsStore> ResourceLoadStatisticsStore::create()
+{
+ return adoptRef(*new ResourceLoadStatisticsStore());
+}
+
+bool ResourceLoadStatisticsStore::isPrevalentResource(const String& primaryDomain) const
+{
+ auto mapEntry = m_resourceStatisticsMap.find(primaryDomain);
+ if (mapEntry == m_resourceStatisticsMap.end())
+ return false;
+
+ return mapEntry->value.isPrevalentResource;
+}
+
+ResourceLoadStatistics& ResourceLoadStatisticsStore::ensureResourceStatisticsForPrimaryDomain(const String& primaryDomain)
+{
+ auto addResult = m_resourceStatisticsMap.ensure(primaryDomain, [&primaryDomain] {
+ return ResourceLoadStatistics(primaryDomain);
+ });
+
+ return addResult.iterator->value;
+}
+
+void ResourceLoadStatisticsStore::setResourceStatisticsForPrimaryDomain(const String& primaryDomain, ResourceLoadStatistics&& statistics)
+{
+ m_resourceStatisticsMap.set(primaryDomain, WTFMove(statistics));
+}
+
+typedef HashMap<String, ResourceLoadStatistics>::KeyValuePairType StatisticsValue;
+
+std::unique_ptr<KeyedEncoder> ResourceLoadStatisticsStore::createEncoderFromData()
+{
+ auto encoder = KeyedEncoder::encoder();
+
+ encoder->encodeUInt32("version", statisticsModelVersion);
+ encoder->encodeObjects("browsingStatistics", m_resourceStatisticsMap.begin(), m_resourceStatisticsMap.end(), [this](KeyedEncoder& encoderInner, const StatisticsValue& origin) {
+ origin.value.encode(encoderInner);
+ });
+
+ return encoder;
+}
+
+void ResourceLoadStatisticsStore::readDataFromDecoder(KeyedDecoder& decoder)
+{
+ if (m_resourceStatisticsMap.size())
+ return;
+
+ unsigned version;
+ if (!decoder.decodeUInt32("version", version))
+ version = 1;
+ Vector<ResourceLoadStatistics> loadedStatistics;
+ bool succeeded = decoder.decodeObjects("browsingStatistics", loadedStatistics, [this, version](KeyedDecoder& decoderInner, ResourceLoadStatistics& statistics) {
+ return statistics.decode(decoderInner, version);
+ });
+
+ if (!succeeded)
+ return;
+
+ for (auto& statistics : loadedStatistics)
+ m_resourceStatisticsMap.set(statistics.highLevelDomain, statistics);
+}
+
+String ResourceLoadStatisticsStore::statisticsForOrigin(const String& origin)
+{
+ auto iter = m_resourceStatisticsMap.find(origin);
+ if (iter == m_resourceStatisticsMap.end())
+ return emptyString();
+
+ return "Statistics for " + origin + ":\n" + iter->value.toString();
+}
+
+Vector<ResourceLoadStatistics> ResourceLoadStatisticsStore::takeStatistics()
+{
+ Vector<ResourceLoadStatistics> statistics;
+ statistics.reserveInitialCapacity(m_resourceStatisticsMap.size());
+ for (auto& statistic : m_resourceStatisticsMap.values())
+ statistics.uncheckedAppend(WTFMove(statistic));
+
+ m_resourceStatisticsMap.clear();
+
+ return statistics;
+}
+
+void ResourceLoadStatisticsStore::mergeStatistics(const Vector<ResourceLoadStatistics>& statistics)
+{
+ for (auto& statistic : statistics) {
+ auto result = m_resourceStatisticsMap.ensure(statistic.highLevelDomain, [&statistic] {
+ return ResourceLoadStatistics(statistic.highLevelDomain);
+ });
+
+ result.iterator->value.merge(statistic);
+ }
+}
+
+void ResourceLoadStatisticsStore::setNotificationCallback(std::function<void()> handler)
+{
+ m_dataAddedHandler = WTFMove(handler);
+}
+
+void ResourceLoadStatisticsStore::fireDataModificationHandler()
+{
+ if (m_dataAddedHandler)
+ m_dataAddedHandler();
+}
+
+void ResourceLoadStatisticsStore::setTimeToLiveUserInteraction(double seconds)
+{
+ if (seconds >= 0)
+ timeToLiveUserInteraction = seconds;
+}
+
+void ResourceLoadStatisticsStore::processStatistics(std::function<void(ResourceLoadStatistics&)>&& processFunction)
+{
+ for (auto& resourceStatistic : m_resourceStatisticsMap.values())
+ processFunction(resourceStatistic);
+}
+
+bool ResourceLoadStatisticsStore::hasHadRecentUserInteraction(ResourceLoadStatistics& resourceStatistic)
+{
+ if (!resourceStatistic.hadUserInteraction)
+ return false;
+
+ if (currentTime() > resourceStatistic.mostRecentUserInteraction + timeToLiveUserInteraction) {
+ // Drop privacy sensitive data because we no longer need it.
+ // Set timestamp to 0.0 so that statistics merge will know
+ // it has been reset as opposed to its default -1.
+ resourceStatistic.mostRecentUserInteraction = 0;
+ resourceStatistic.hadUserInteraction = false;
+ return false;
+ }
+
+ return true;
+}
+
+Vector<String> ResourceLoadStatisticsStore::prevalentResourceDomainsWithoutUserInteraction()
+{
+ Vector<String> prevalentResources;
+ for (auto& resourceStatistic : m_resourceStatisticsMap.values()) {
+ if (resourceStatistic.isPrevalentResource && !hasHadRecentUserInteraction(resourceStatistic))
+ prevalentResources.append(resourceStatistic.highLevelDomain);
+ }
+ return prevalentResources;
+}
+
+void ResourceLoadStatisticsStore::updateStatisticsForRemovedDataRecords(const Vector<String>& prevalentResourceDomains)
+{
+ for (auto& prevalentResourceDomain : prevalentResourceDomains) {
+ ResourceLoadStatistics& statisic = ensureResourceStatisticsForPrimaryDomain(prevalentResourceDomain);
+ ++statisic.dataRecordsRemoved;
+ }
+}
+}
diff --git a/Source/WebCore/loader/ResourceLoadStatisticsStore.h b/Source/WebCore/loader/ResourceLoadStatisticsStore.h
new file mode 100644
index 000000000..fcebdf567
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadStatisticsStore.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ResourceLoadStatistics.h"
+
+namespace WebCore {
+
+class KeyedDecoder;
+class KeyedEncoder;
+class URL;
+
+struct ResourceLoadStatistics;
+
+class ResourceLoadStatisticsStore : public RefCounted<ResourceLoadStatisticsStore> {
+public:
+ WEBCORE_EXPORT static Ref<ResourceLoadStatisticsStore> create();
+
+ WEBCORE_EXPORT std::unique_ptr<KeyedEncoder> createEncoderFromData();
+ WEBCORE_EXPORT void readDataFromDecoder(KeyedDecoder&);
+
+ WEBCORE_EXPORT String statisticsForOrigin(const String&);
+
+ bool isEmpty() const { return m_resourceStatisticsMap.isEmpty(); }
+ size_t size() const { return m_resourceStatisticsMap.size(); }
+ void clear() { m_resourceStatisticsMap.clear(); }
+
+ ResourceLoadStatistics& ensureResourceStatisticsForPrimaryDomain(const String&);
+ void setResourceStatisticsForPrimaryDomain(const String&, ResourceLoadStatistics&&);
+
+ bool isPrevalentResource(const String&) const;
+
+ WEBCORE_EXPORT void mergeStatistics(const Vector<ResourceLoadStatistics>&);
+ WEBCORE_EXPORT Vector<ResourceLoadStatistics> takeStatistics();
+
+ WEBCORE_EXPORT void setNotificationCallback(std::function<void()> handler);
+
+ void fireDataModificationHandler();
+ void setTimeToLiveUserInteraction(double seconds);
+
+ WEBCORE_EXPORT void processStatistics(std::function<void(ResourceLoadStatistics&)>&&);
+
+ WEBCORE_EXPORT bool hasHadRecentUserInteraction(ResourceLoadStatistics&);
+ WEBCORE_EXPORT Vector<String> prevalentResourceDomainsWithoutUserInteraction();
+ WEBCORE_EXPORT void updateStatisticsForRemovedDataRecords(const Vector<String>& prevalentResourceDomains);
+private:
+ ResourceLoadStatisticsStore() = default;
+
+ HashMap<String, ResourceLoadStatistics> m_resourceStatisticsMap;
+ std::function<void()> m_dataAddedHandler;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoader.cpp b/Source/WebCore/loader/ResourceLoader.cpp
index ebef76f47..0fbb0c38e 100644
--- a/Source/WebCore/loader/ResourceLoader.cpp
+++ b/Source/WebCore/loader/ResourceLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2007, 2010-2011, 2016 Apple Inc. All rights reserved.
* (C) 2007 Graham Dennis (graham.dennis@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,36 +31,41 @@
#include "ResourceLoader.h"
#include "ApplicationCacheHost.h"
-#include "AsyncFileStream.h"
#include "AuthenticationChallenge.h"
+#include "DataURLDecoder.h"
+#include "DiagnosticLoggingClient.h"
+#include "DiagnosticLoggingKeys.h"
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "InspectorInstrumentation.h"
#include "LoaderStrategy.h"
+#include "MainFrame.h"
#include "Page.h"
#include "PlatformStrategies.h"
#include "ProgressTracker.h"
-#include "ResourceBuffer.h"
#include "ResourceError.h"
#include "ResourceHandle.h"
-#include "ResourceLoadScheduler.h"
#include "SecurityOrigin.h"
-#include "Settings.h"
#include "SharedBuffer.h"
#include <wtf/Ref.h>
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "UserContentController.h"
+#endif
+
+#if USE(QUICK_LOOK)
+#include "PreviewConverter.h"
+#include "QuickLook.h"
+#endif
+
namespace WebCore {
-ResourceLoader::ResourceLoader(Frame* frame, ResourceLoaderOptions options)
- : m_frame(frame)
- , m_documentLoader(frame->loader().activeDocumentLoader())
- , m_identifier(0)
- , m_reachedTerminalState(false)
- , m_notifiedLoadComplete(false)
- , m_cancellationStatus(NotCancelled)
- , m_defersLoading(frame->page()->defersLoading())
+ResourceLoader::ResourceLoader(Frame& frame, ResourceLoaderOptions options)
+ : m_frame(&frame)
+ , m_documentLoader(frame.loader().activeDocumentLoader())
+ , m_defersLoading(options.defersLoadingPolicy == DefersLoadingPolicy::AllowDefersLoading && frame.page()->defersLoading())
, m_options(options)
{
}
@@ -70,6 +75,17 @@ ResourceLoader::~ResourceLoader()
ASSERT(m_reachedTerminalState);
}
+void ResourceLoader::finishNetworkLoad()
+{
+ platformStrategies()->loaderStrategy()->remove(this);
+
+ if (m_handle) {
+ ASSERT(m_handle->client() == this);
+ m_handle->clearClient();
+ m_handle = nullptr;
+ }
+}
+
void ResourceLoader::releaseResources()
{
ASSERT(!m_reachedTerminalState);
@@ -78,27 +94,20 @@ void ResourceLoader::releaseResources()
// deallocated and release the last reference to this object.
// We need to retain to avoid accessing the object after it
// has been deallocated and also to avoid reentering this method.
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
- m_frame = 0;
- m_documentLoader = 0;
+ m_frame = nullptr;
+ m_documentLoader = nullptr;
// We need to set reachedTerminalState to true before we release
// the resources to prevent a double dealloc of WebView <rdar://problem/4372628>
m_reachedTerminalState = true;
- platformStrategies()->loaderStrategy()->resourceLoadScheduler()->remove(this);
- m_identifier = 0;
+ finishNetworkLoad();
- if (m_handle) {
- // Clear out the ResourceHandle's client so that it doesn't try to call
- // us back after we release it, unless it has been replaced by someone else.
- if (m_handle->client() == this)
- m_handle->setClient(0);
- m_handle = 0;
- }
+ m_identifier = 0;
- m_resourceData = 0;
+ m_resourceData = nullptr;
m_deferredRequest = ResourceRequest();
}
@@ -111,6 +120,8 @@ bool ResourceLoader::init(const ResourceRequest& r)
ResourceRequest clientRequest(r);
+ m_loadTiming.markStartTimeAndFetchStart();
+
#if PLATFORM(IOS)
// If the documentLoader was detached while this ResourceLoader was waiting its turn
// in ResourceLoadScheduler queue, don't continue.
@@ -120,8 +131,9 @@ bool ResourceLoader::init(const ResourceRequest& r)
}
#endif
- m_defersLoading = m_frame->page()->defersLoading();
- if (m_options.securityCheck == DoSecurityCheck && !m_frame->document()->securityOrigin()->canDisplay(clientRequest.url())) {
+ m_defersLoading = m_options.defersLoadingPolicy == DefersLoadingPolicy::AllowDefersLoading && m_frame->page()->defersLoading();
+
+ if (m_options.securityCheck == DoSecurityCheck && !m_frame->document()->securityOrigin().canDisplay(clientRequest.url())) {
FrameLoader::reportLocalLoadFailed(m_frame.get(), clientRequest.url().string());
releaseResources();
return false;
@@ -137,7 +149,7 @@ bool ResourceLoader::init(const ResourceRequest& r)
clientRequest.setFirstPartyForCookies(document->firstPartyForCookies());
}
- willSendRequest(clientRequest, ResourceResponse());
+ willSendRequestInternal(clientRequest, ResourceResponse());
#if PLATFORM(IOS)
// If this ResourceLoader was stopped as a result of willSendRequest, bail out.
@@ -154,18 +166,37 @@ bool ResourceLoader::init(const ResourceRequest& r)
return true;
}
+void ResourceLoader::deliverResponseAndData(const ResourceResponse& response, RefPtr<SharedBuffer>&& buffer)
+{
+ Ref<ResourceLoader> protectedThis(*this);
+
+ didReceiveResponse(response);
+ if (reachedTerminalState())
+ return;
+
+ if (buffer) {
+ unsigned size = buffer->size();
+ didReceiveBuffer(buffer.releaseNonNull(), size, DataPayloadWholeResource);
+ if (reachedTerminalState())
+ return;
+ }
+
+ didFinishLoading(0);
+}
+
void ResourceLoader::start()
{
ASSERT(!m_handle);
ASSERT(!m_request.isNull());
ASSERT(m_deferredRequest.isNull());
+ ASSERT(frameLoader());
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
- if (m_documentLoader->scheduleArchiveLoad(this, m_request))
+ if (m_documentLoader->scheduleArchiveLoad(*this, m_request))
return;
#endif
- if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, m_request, m_request.url()))
+ if (m_documentLoader->applicationCacheHost().maybeLoadResource(*this, m_request, m_request.url()))
return;
if (m_defersLoading) {
@@ -173,12 +204,22 @@ void ResourceLoader::start()
return;
}
- if (!m_reachedTerminalState)
- m_handle = ResourceHandle::create(m_frame->loader().networkingContext(), m_request, this, m_defersLoading, m_options.sniffContent == SniffContent);
+ if (m_reachedTerminalState)
+ return;
+
+ if (m_request.url().protocolIsData()) {
+ loadDataURL();
+ return;
+ }
+
+ m_handle = ResourceHandle::create(frameLoader()->networkingContext(), m_request, this, m_defersLoading, m_options.sniffContent == SniffContent);
}
void ResourceLoader::setDefersLoading(bool defers)
{
+ if (m_options.defersLoadingPolicy == DefersLoadingPolicy::DisallowDefersLoading)
+ return;
+
m_defersLoading = defers;
if (m_handle)
m_handle->setDefersLoading(defers);
@@ -187,43 +228,88 @@ void ResourceLoader::setDefersLoading(bool defers)
m_deferredRequest = ResourceRequest();
start();
}
+
+ platformStrategies()->loaderStrategy()->setDefersLoading(this, defers);
}
FrameLoader* ResourceLoader::frameLoader() const
{
if (!m_frame)
- return 0;
+ return nullptr;
return &m_frame->loader();
}
+void ResourceLoader::loadDataURL()
+{
+ auto url = m_request.url();
+ ASSERT(url.protocolIsData());
+
+ RefPtr<ResourceLoader> protectedThis(this);
+ DataURLDecoder::ScheduleContext scheduleContext;
+#if HAVE(RUNLOOP_TIMER)
+ if (auto* scheduledPairs = m_frame->page()->scheduledRunLoopPairs())
+ scheduleContext.scheduledPairs = *scheduledPairs;
+#endif
+ DataURLDecoder::decode(url, scheduleContext, [protectedThis, url](auto decodeResult) {
+ if (protectedThis->reachedTerminalState())
+ return;
+ if (!decodeResult) {
+ protectedThis->didFail(ResourceError(errorDomainWebKitInternal, 0, url, "Data URL decoding failed"));
+ return;
+ }
+ if (protectedThis->wasCancelled())
+ return;
+ auto& result = decodeResult.value();
+ auto dataSize = result.data ? result.data->size() : 0;
+
+ ResourceResponse dataResponse { url, result.mimeType, dataSize, result.charset };
+ dataResponse.setHTTPStatusCode(200);
+ dataResponse.setHTTPStatusText(ASCIILiteral("OK"));
+ dataResponse.setHTTPHeaderField(HTTPHeaderName::ContentType, result.contentType);
+ protectedThis->didReceiveResponse(dataResponse);
+
+ if (!protectedThis->reachedTerminalState() && dataSize)
+ protectedThis->didReceiveBuffer(result.data.releaseNonNull(), dataSize, DataPayloadWholeResource);
+
+ if (!protectedThis->reachedTerminalState())
+ protectedThis->didFinishLoading(currentTime());
+ });
+}
+
void ResourceLoader::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
-{
- m_options.dataBufferingPolicy = dataBufferingPolicy;
+{
+ m_options.dataBufferingPolicy = dataBufferingPolicy;
// Reset any already buffered data
if (dataBufferingPolicy == DoNotBufferData)
- m_resourceData = 0;
+ m_resourceData = nullptr;
+}
+
+void ResourceLoader::willSwitchToSubstituteResource()
+{
+ ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
+ platformStrategies()->loaderStrategy()->remove(this);
+ if (m_handle)
+ m_handle->cancel();
}
-
void ResourceLoader::addDataOrBuffer(const char* data, unsigned length, SharedBuffer* buffer, DataPayloadType dataPayloadType)
{
if (m_options.dataBufferingPolicy == DoNotBufferData)
return;
- if (dataPayloadType == DataPayloadWholeResource) {
- m_resourceData = buffer ? ResourceBuffer::adoptSharedBuffer(buffer) : ResourceBuffer::create(data, length);
- return;
- }
-
- if (!m_resourceData)
- m_resourceData = buffer ? ResourceBuffer::adoptSharedBuffer(buffer) : ResourceBuffer::create(data, length);
- else {
+ if (!m_resourceData || dataPayloadType == DataPayloadWholeResource) {
if (buffer)
- m_resourceData->append(buffer);
+ m_resourceData = buffer;
else
- m_resourceData->append(data, length);
+ m_resourceData = SharedBuffer::create(data, length);
+ return;
}
+
+ if (buffer)
+ m_resourceData->append(*buffer);
+ else
+ m_resourceData->append(data, length);
}
void ResourceLoader::clearResourceData()
@@ -237,26 +323,15 @@ bool ResourceLoader::isSubresourceLoader()
return false;
}
-void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
+void ResourceLoader::willSendRequestInternal(ResourceRequest& request, const ResourceResponse& redirectResponse)
{
// Protect this in this delegate method since the additional processing can do
// anything including possibly derefing this; one example of this is Radar 3266216.
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
ASSERT(!m_reachedTerminalState);
-
-#if PLATFORM(IOS)
- // Ensure an identifier is always set. This ensures that this assetion is not hit:
- // <rdar://problem/11059794> ASSERTION FAILED: !HashTranslator::equal(KeyTraits::emptyValue(), key) in WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace loading the attached web archive
- // This is not needed in WebKit2, as it doesn't use m_identifier in WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace
- if (!m_identifier) {
- m_identifier = m_frame->page()->progress().createUniqueIdentifier();
- frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request);
-
- // If this ResourceLoader was stopped as a result of assignIdentifierToInitialRequest, bail out
- if (m_reachedTerminalState)
- return;
- }
+#if ENABLE(CONTENT_EXTENSIONS)
+ ASSERT(m_resourceType != ResourceType::Invalid);
#endif
// We need a resource identifier for all requests, even if FrameLoader is never going to see it (such as with CORS preflight requests).
@@ -266,43 +341,115 @@ void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceRes
createdResourceIdentifier = true;
}
+#if ENABLE(CONTENT_EXTENSIONS)
+ if (frameLoader()) {
+ Page* page = frameLoader()->frame().page();
+ if (page && m_documentLoader) {
+ auto blockedStatus = page->userContentProvider().processContentExtensionRulesForLoad(request.url(), m_resourceType, *m_documentLoader);
+ applyBlockedStatusToRequest(blockedStatus, request);
+ if (blockedStatus.blockedLoad) {
+ request = { };
+ didFail(blockedByContentBlockerError());
+ return;
+ }
+ }
+ }
+#endif
+
+ if (request.isNull()) {
+ didFail(cannotShowURLError());
+ return;
+ }
+
if (m_options.sendLoadCallbacks == SendCallbacks) {
if (createdResourceIdentifier)
frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request);
+#if PLATFORM(IOS)
+ // If this ResourceLoader was stopped as a result of assignIdentifierToInitialRequest, bail out
+ if (m_reachedTerminalState)
+ return;
+#endif
+
frameLoader()->notifier().willSendRequest(this, request, redirectResponse);
}
-#if ENABLE(INSPECTOR)
else
InspectorInstrumentation::willSendRequest(m_frame.get(), m_identifier, m_frame->loader().documentLoader(), request, redirectResponse);
+
+#if USE(QUICK_LOOK)
+ if (auto previewConverter = m_documentLoader->previewConverter())
+ request = previewConverter->safeRequest(request);
#endif
- if (!redirectResponse.isNull())
- platformStrategies()->loaderStrategy()->resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url());
+ bool isRedirect = !redirectResponse.isNull();
+ if (isRedirect)
+ platformStrategies()->loaderStrategy()->crossOriginRedirectReceived(this, request.url());
m_request = request;
- if (!redirectResponse.isNull() && !m_documentLoader->isCommitted())
- frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad();
+ if (isRedirect) {
+ auto& redirectURL = request.url();
+ if (!m_documentLoader->isCommitted())
+ frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad();
+
+ if (redirectURL.protocolIsData()) {
+ // Handle data URL decoding locally.
+ finishNetworkLoad();
+ loadDataURL();
+ }
+ }
+}
+
+void ResourceLoader::willSendRequest(ResourceRequest&& request, const ResourceResponse& redirectResponse, std::function<void(ResourceRequest&&)>&& callback)
+{
+ willSendRequestInternal(request, redirectResponse);
+ callback(WTFMove(request));
}
void ResourceLoader::didSendData(unsigned long long, unsigned long long)
{
}
+static void logResourceResponseSource(Frame* frame, ResourceResponse::Source source)
+{
+ if (!frame || !frame->page())
+ return;
+
+ String sourceKey;
+ switch (source) {
+ case ResourceResponse::Source::Network:
+ sourceKey = DiagnosticLoggingKeys::networkKey();
+ break;
+ case ResourceResponse::Source::DiskCache:
+ sourceKey = DiagnosticLoggingKeys::diskCacheKey();
+ break;
+ case ResourceResponse::Source::DiskCacheAfterValidation:
+ sourceKey = DiagnosticLoggingKeys::diskCacheAfterValidationKey();
+ break;
+ case ResourceResponse::Source::MemoryCache:
+ case ResourceResponse::Source::MemoryCacheAfterValidation:
+ case ResourceResponse::Source::Unknown:
+ return;
+ }
+
+ frame->page()->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::resourceResponseSourceKey(), sourceKey, ShouldSample::Yes);
+}
+
void ResourceLoader::didReceiveResponse(const ResourceResponse& r)
{
ASSERT(!m_reachedTerminalState);
// Protect this in this delegate method since the additional processing can do
// anything including possibly derefing this; one example of this is Radar 3266216.
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
+
+ logResourceResponseSource(m_frame.get(), r.source());
m_response = r;
if (FormData* data = m_request.httpBody())
data->removeGeneratedFilesIfNeeded();
-
+
if (m_options.sendLoadCallbacks == SendCallbacks)
frameLoader()->notifier().didReceiveResponse(this, m_response);
}
@@ -315,26 +462,25 @@ void ResourceLoader::didReceiveData(const char* data, unsigned length, long long
// ASSERT(con == connection);
// ASSERT(!m_reachedTerminalState);
- didReceiveDataOrBuffer(data, length, 0, encodedDataLength, dataPayloadType);
+ didReceiveDataOrBuffer(data, length, nullptr, encodedDataLength, dataPayloadType);
}
-void ResourceLoader::didReceiveBuffer(PassRefPtr<SharedBuffer> buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
+void ResourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
{
- didReceiveDataOrBuffer(0, 0, buffer, encodedDataLength, dataPayloadType);
+ didReceiveDataOrBuffer(nullptr, 0, WTFMove(buffer), encodedDataLength, dataPayloadType);
}
-void ResourceLoader::didReceiveDataOrBuffer(const char* data, unsigned length, PassRefPtr<SharedBuffer> prpBuffer, long long encodedDataLength, DataPayloadType dataPayloadType)
+void ResourceLoader::didReceiveDataOrBuffer(const char* data, unsigned length, RefPtr<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
{
// This method should only get data+length *OR* a SharedBuffer.
- ASSERT(!prpBuffer || (!data && !length));
+ ASSERT(!buffer || (!data && !length));
// Protect this in this delegate method since the additional processing can do
// anything including possibly derefing this; one example of this is Radar 3266216.
- Ref<ResourceLoader> protect(*this);
- RefPtr<SharedBuffer> buffer = prpBuffer;
+ Ref<ResourceLoader> protectedThis(*this);
addDataOrBuffer(data, length, buffer.get(), dataPayloadType);
-
+
// FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
// However, with today's computers and networking speeds, this won't happen in practice.
// Could be an issue with a giant local file.
@@ -342,15 +488,6 @@ void ResourceLoader::didReceiveDataOrBuffer(const char* data, unsigned length, P
frameLoader()->notifier().didReceiveData(this, buffer ? buffer->data() : data, buffer ? buffer->size() : length, static_cast<int>(encodedDataLength));
}
-void ResourceLoader::willStopBufferingData(const char* data, unsigned length)
-{
- if (m_options.dataBufferingPolicy == DoNotBufferData)
- return;
-
- ASSERT(!m_resourceData);
- m_resourceData = ResourceBuffer::create(data, length);
-}
-
void ResourceLoader::didFinishLoading(double finishTime)
{
didFinishLoadingOnePart(finishTime);
@@ -385,7 +522,7 @@ void ResourceLoader::didFail(const ResourceError& error)
// Protect this in this delegate method since the additional processing can do
// anything including possibly derefing this; one example of this is Radar 3266216.
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
cleanupForError(error);
releaseResources();
@@ -403,12 +540,6 @@ void ResourceLoader::cleanupForError(const ResourceError& error)
frameLoader()->notifier().didFailToLoad(this, error);
}
-void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority)
-{
- if (handle())
- handle()->didChangePriority(loadPriority);
-}
-
void ResourceLoader::cancel()
{
cancel(ResourceError());
@@ -424,7 +555,7 @@ void ResourceLoader::cancel(const ResourceError& error)
// willCancel() and didFailToLoad() both call out to clients that might do
// something causing the last reference to this object to go away.
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
// If we re-enter cancel() from inside willCancel(), we want to pick up from where we left
// off without re-running willCancel()
@@ -445,7 +576,7 @@ void ResourceLoader::cancel(const ResourceError& error)
m_documentLoader->cancelPendingSubstituteLoad(this);
if (m_handle) {
m_handle->cancel();
- m_handle = 0;
+ m_handle = nullptr;
}
cleanupForError(nonNullError);
}
@@ -474,16 +605,22 @@ ResourceError ResourceLoader::blockedError()
return frameLoader()->client().blockedError(m_request);
}
+ResourceError ResourceLoader::blockedByContentBlockerError()
+{
+ return frameLoader()->client().blockedByContentBlockerError(m_request);
+}
+
ResourceError ResourceLoader::cannotShowURLError()
{
return frameLoader()->client().cannotShowURLError(m_request);
}
-void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
+ResourceRequest ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest&& request, ResourceResponse&& redirectResponse)
{
- if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse))
- return;
- willSendRequest(request, redirectResponse);
+ if (documentLoader()->applicationCacheHost().maybeLoadFallbackForRedirect(this, request, redirectResponse))
+ return WTFMove(request);
+ willSendRequestInternal(request, redirectResponse);
+ return WTFMove(request);
}
void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
@@ -491,25 +628,21 @@ void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent,
didSendData(bytesSent, totalBytesToBeSent);
}
-void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
+void ResourceLoader::didReceiveResponse(ResourceHandle*, ResourceResponse&& response)
{
- if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response))
+ if (documentLoader()->applicationCacheHost().maybeLoadFallbackForResponse(this, response))
return;
didReceiveResponse(response);
}
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, unsigned length, int encodedDataLength)
{
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength);
didReceiveData(data, length, encodedDataLength, DataPayloadBytes);
- InspectorInstrumentation::didReceiveResourceData(cookie);
}
-void ResourceLoader::didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int encodedDataLength)
+void ResourceLoader::didReceiveBuffer(ResourceHandle*, Ref<SharedBuffer>&& buffer, int encodedDataLength)
{
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength);
- didReceiveBuffer(buffer, encodedDataLength, DataPayloadBytes);
- InspectorInstrumentation::didReceiveResourceData(cookie);
+ didReceiveBuffer(WTFMove(buffer), encodedDataLength, DataPayloadBytes);
}
void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
@@ -519,7 +652,7 @@ void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
{
- if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error))
+ if (documentLoader()->applicationCacheHost().maybeLoadFallbackForError(this, error))
return;
didFail(error);
}
@@ -538,56 +671,53 @@ bool ResourceLoader::shouldUseCredentialStorage()
{
if (m_options.allowCredentials == DoNotAllowStoredCredentials)
return false;
-
- Ref<ResourceLoader> protect(*this);
+
+ Ref<ResourceLoader> protectedThis(*this);
return frameLoader()->client().shouldUseCredentialStorage(documentLoader(), identifier());
}
+bool ResourceLoader::isAllowedToAskUserForCredentials() const
+{
+ if (m_options.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials)
+ return false;
+ return m_options.credentials == FetchOptions::Credentials::Include || (m_options.credentials == FetchOptions::Credentials::SameOrigin && m_frame->document()->securityOrigin().canRequest(originalRequest().url()));
+}
+
void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
{
- ASSERT(handle()->hasAuthenticationChallenge());
+ ASSERT(m_handle->hasAuthenticationChallenge());
// Protect this in this delegate method since the additional processing can do
// anything including possibly derefing this; one example of this is Radar 3266216.
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
if (m_options.allowCredentials == AllowStoredCredentials) {
- if (m_options.clientCredentialPolicy == AskClientForAllCredentials || (m_options.clientCredentialPolicy == DoNotAskClientForCrossOriginCredentials && m_frame->document()->securityOrigin()->canRequest(originalRequest().url()))) {
+ if (isAllowedToAskUserForCredentials()) {
frameLoader()->notifier().didReceiveAuthenticationChallenge(this, challenge);
return;
}
}
- // Only these platforms provide a way to continue without credentials.
- // If we can't continue with credentials, we need to cancel the load altogether.
-#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) || PLATFORM(GTK) || PLATFORM(EFL)
challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
- ASSERT(!handle() || !handle()->hasAuthenticationChallenge());
-#else
- didFail(blockedError());
-#endif
-}
-
-void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
-{
- // Protect this in this delegate method since the additional processing can do
- // anything including possibly derefing this; one example of this is Radar 3266216.
- Ref<ResourceLoader> protect(*this);
- frameLoader()->notifier().didCancelAuthenticationChallenge(this, challenge);
+ ASSERT(!m_handle || !m_handle->hasAuthenticationChallenge());
}
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+
bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
{
- Ref<ResourceLoader> protect(*this);
+ Ref<ResourceLoader> protectedThis(*this);
return frameLoader()->client().canAuthenticateAgainstProtectionSpace(documentLoader(), identifier(), protectionSpace);
}
+
#endif
#if PLATFORM(IOS)
+
RetainPtr<CFDictionaryRef> ResourceLoader::connectionProperties(ResourceHandle*)
{
return frameLoader()->connectionProperties(this);
}
+
#endif
void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
@@ -595,4 +725,36 @@ void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
cancel();
}
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+
+void ResourceLoader::schedule(SchedulePair& pair)
+{
+ if (m_handle)
+ m_handle->schedule(pair);
+}
+
+void ResourceLoader::unschedule(SchedulePair& pair)
+{
+ if (m_handle)
+ m_handle->unschedule(pair);
+}
+
+#endif
+
+#if USE(QUICK_LOOK)
+bool ResourceLoader::isQuickLookResource() const
+{
+ return !!m_quickLookHandle;
+}
+#endif
+
+bool ResourceLoader::isAlwaysOnLoggingAllowed() const
+{
+ return frameLoader() && frameLoader()->isAlwaysOnLoggingAllowed();
+}
+
+void ResourceLoader::didRetrieveDerivedDataFromCache(const String&, SharedBuffer&)
+{
+}
+
}
diff --git a/Source/WebCore/loader/ResourceLoader.h b/Source/WebCore/loader/ResourceLoader.h
index 6b075ed3d..5bb1eda0a 100644
--- a/Source/WebCore/loader/ResourceLoader.h
+++ b/Source/WebCore/loader/ResourceLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2006, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,17 +26,23 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceLoader_h
-#define ResourceLoader_h
+#pragma once
+#include "LoadTiming.h"
#include "ResourceHandleClient.h"
#include "ResourceLoaderOptions.h"
#include "ResourceLoaderTypes.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
-
#include <wtf/Forward.h>
-#include <wtf/RefCounted.h>
+
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "ResourceLoadInfo.h"
+#endif
+
+namespace WTF {
+class SchedulePair;
+}
namespace WebCore {
@@ -44,18 +50,19 @@ class AuthenticationChallenge;
class DocumentLoader;
class Frame;
class FrameLoader;
+class QuickLookHandle;
class URL;
-class ResourceBuffer;
-class ResourceHandle;
class ResourceLoader : public RefCounted<ResourceLoader>, protected ResourceHandleClient {
public:
- virtual ~ResourceLoader();
+ virtual ~ResourceLoader() = 0;
- void cancel();
+ WEBCORE_EXPORT void cancel();
virtual bool init(const ResourceRequest&);
+ void deliverResponseAndData(const ResourceResponse&, RefPtr<SharedBuffer>&&);
+
#if PLATFORM(IOS)
virtual bool startLoading()
{
@@ -64,16 +71,17 @@ public:
}
virtual const ResourceRequest& iOSOriginalRequest() const { return request(); }
- virtual RetainPtr<CFDictionaryRef> connectionProperties(ResourceHandle*) override;
#endif
- FrameLoader* frameLoader() const;
+ WEBCORE_EXPORT FrameLoader* frameLoader() const;
DocumentLoader* documentLoader() const { return m_documentLoader.get(); }
const ResourceRequest& originalRequest() const { return m_originalRequest; }
-
- virtual void cancel(const ResourceError&);
- ResourceError cancelledError();
+
+ WEBCORE_EXPORT void start();
+ WEBCORE_EXPORT void cancel(const ResourceError&);
+ WEBCORE_EXPORT ResourceError cancelledError();
ResourceError blockedError();
+ ResourceError blockedByContentBlockerError();
ResourceError cannotShowURLError();
virtual void setDefersLoading(bool);
@@ -82,118 +90,136 @@ public:
unsigned long identifier() const { return m_identifier; }
virtual void releaseResources();
- const ResourceResponse& response() const;
+ const ResourceResponse& response() const { return m_response; }
- ResourceBuffer* resourceData() const { return m_resourceData.get(); }
+ SharedBuffer* resourceData() const { return m_resourceData.get(); }
void clearResourceData();
virtual bool isSubresourceLoader();
-
- virtual void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse);
+
+ virtual void willSendRequest(ResourceRequest&&, const ResourceResponse& redirectResponse, std::function<void(ResourceRequest&&)>&& callback);
virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
virtual void didReceiveResponse(const ResourceResponse&);
virtual void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType);
- virtual void didReceiveBuffer(PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType);
- void willStopBufferingData(const char*, unsigned);
+ virtual void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
virtual void didFinishLoading(double finishTime);
virtual void didFail(const ResourceError&);
#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
virtual void didReceiveDataArray(CFArrayRef dataArray);
#endif
- void didChangePriority(ResourceLoadPriority);
+ virtual void didRetrieveDerivedDataFromCache(const String& type, SharedBuffer&);
virtual bool shouldUseCredentialStorage();
virtual void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
- void didCancelAuthenticationChallenge(const AuthenticationChallenge&);
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
virtual bool canAuthenticateAgainstProtectionSpace(const ProtectionSpace&);
#endif
virtual void receivedCancellation(const AuthenticationChallenge&);
- // ResourceHandleClient
- virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& redirectResponse) override;
- virtual void didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) override;
- virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int encodedDataLength) override;
- virtual void didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer>, int encodedDataLength) override;
- virtual void didFinishLoading(ResourceHandle*, double finishTime) override;
- virtual void didFail(ResourceHandle*, const ResourceError&) override;
- virtual void wasBlocked(ResourceHandle*) override;
- virtual void cannotShowURL(ResourceHandle*) override;
-#if PLATFORM(MAC) && !USE(CFNETWORK)
- virtual void willStopBufferingData(ResourceHandle*, const char* data, unsigned length) override { willStopBufferingData(data, length); }
-#endif
- virtual bool shouldUseCredentialStorage(ResourceHandle*) override { return shouldUseCredentialStorage(); }
- virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) override { didReceiveAuthenticationChallenge(challenge); }
- virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) override { didCancelAuthenticationChallenge(challenge); }
-#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
- virtual void didReceiveDataArray(ResourceHandle*, CFArrayRef dataArray) override;
-#endif
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
- virtual bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace& protectionSpace) override { return canAuthenticateAgainstProtectionSpace(protectionSpace); }
-#endif
- virtual void receivedCancellation(ResourceHandle*, const AuthenticationChallenge& challenge) override { receivedCancellation(challenge); }
-#if PLATFORM(MAC)
-#if USE(CFNETWORK)
- virtual CFCachedURLResponseRef willCacheResponse(ResourceHandle*, CFCachedURLResponseRef) override;
-#else
- virtual NSCachedURLResponse* willCacheResponse(ResourceHandle*, NSCachedURLResponse*) override;
-#endif
-#endif // PLATFORM(MAC)
-#if PLATFORM(WIN) && USE(CFNETWORK)
- // FIXME: Windows should use willCacheResponse - <https://bugs.webkit.org/show_bug.cgi?id=57257>.
- virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef) override;
+#if USE(QUICK_LOOK)
+ bool isQuickLookResource() const;
#endif
- const URL& url() const { return m_request.url(); }
+ const URL& url() const { return m_request.url(); }
ResourceHandle* handle() const { return m_handle.get(); }
bool shouldSendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; }
void setSendCallbackPolicy(SendCallbackPolicy sendLoadCallbacks) { m_options.sendLoadCallbacks = sendLoadCallbacks; }
bool shouldSniffContent() const { return m_options.sniffContent == SniffContent; }
- ClientCredentialPolicy clientCredentialPolicy() const { return m_options.clientCredentialPolicy; }
+ WEBCORE_EXPORT bool isAllowedToAskUserForCredentials() const;
+ bool shouldIncludeCertificateInfo() const { return m_options.certificateInfoPolicy == IncludeCertificateInfo; }
bool reachedTerminalState() const { return m_reachedTerminalState; }
+
const ResourceRequest& request() const { return m_request; }
void setDataBufferingPolicy(DataBufferingPolicy);
-protected:
- ResourceLoader(Frame*, ResourceLoaderOptions);
+ void willSwitchToSubstituteResource();
+
+ const LoadTiming& loadTiming() { return m_loadTiming; }
+
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ void schedule(WTF::SchedulePair&);
+ void unschedule(WTF::SchedulePair&);
+#endif
+
+ const Frame* frame() const { return m_frame.get(); }
+ WEBCORE_EXPORT bool isAlwaysOnLoggingAllowed() const;
+
+ const ResourceLoaderOptions& options() const { return m_options; }
- friend class ResourceLoadScheduler; // for access to start()
- // start() actually sends the load to the network (unless the load is being
- // deferred) and should only be called by ResourceLoadScheduler or setDefersLoading().
- void start();
+protected:
+ ResourceLoader(Frame&, ResourceLoaderOptions);
void didFinishLoadingOnePart(double finishTime);
void cleanupForError(const ResourceError&);
bool wasCancelled() const { return m_cancellationStatus >= Cancelled; }
- void didReceiveDataOrBuffer(const char*, unsigned, PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType);
+ void didReceiveDataOrBuffer(const char*, unsigned, RefPtr<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
+
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ NSCachedURLResponse* willCacheResponse(ResourceHandle*, NSCachedURLResponse*) override;
+#endif
+#if PLATFORM(COCOA) && USE(CFURLCONNECTION)
+ CFCachedURLResponseRef willCacheResponse(ResourceHandle*, CFCachedURLResponseRef) override;
+#endif
- const ResourceLoaderOptions& options() { return m_options; }
+ virtual void willSendRequestInternal(ResourceRequest&, const ResourceResponse& redirectResponse);
RefPtr<ResourceHandle> m_handle;
RefPtr<Frame> m_frame;
RefPtr<DocumentLoader> m_documentLoader;
ResourceResponse m_response;
-
+ LoadTiming m_loadTiming;
+#if USE(QUICK_LOOK)
+ std::unique_ptr<QuickLookHandle> m_quickLookHandle;
+#endif
+
private:
virtual void willCancel(const ResourceError&) = 0;
virtual void didCancel(const ResourceError&) = 0;
void addDataOrBuffer(const char*, unsigned, SharedBuffer*, DataPayloadType);
+ void loadDataURL();
+ void finishNetworkLoad();
+
+ // ResourceHandleClient
+ ResourceRequest willSendRequest(ResourceHandle*, ResourceRequest&&, ResourceResponse&& redirectResponse) override;
+ void didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ void didReceiveResponse(ResourceHandle*, ResourceResponse&&) override;
+ void didReceiveData(ResourceHandle*, const char*, unsigned, int encodedDataLength) override;
+ void didReceiveBuffer(ResourceHandle*, Ref<SharedBuffer>&&, int encodedDataLength) override;
+ void didFinishLoading(ResourceHandle*, double finishTime) override;
+ void didFail(ResourceHandle*, const ResourceError&) override;
+ void wasBlocked(ResourceHandle*) override;
+ void cannotShowURL(ResourceHandle*) override;
+#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
+ void didReceiveDataArray(ResourceHandle*, CFArrayRef dataArray) override;
+#endif
+ bool shouldUseCredentialStorage(ResourceHandle*) override { return shouldUseCredentialStorage(); }
+ void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) override { didReceiveAuthenticationChallenge(challenge); }
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace& protectionSpace) override { return canAuthenticateAgainstProtectionSpace(protectionSpace); }
+#endif
+ void receivedCancellation(ResourceHandle*, const AuthenticationChallenge& challenge) override { receivedCancellation(challenge); }
+#if PLATFORM(IOS)
+ RetainPtr<CFDictionaryRef> connectionProperties(ResourceHandle*) override;
+#endif
+#if PLATFORM(WIN) && USE(CFURLCONNECTION)
+ // FIXME: Windows should use willCacheResponse - <https://bugs.webkit.org/show_bug.cgi?id=57257>.
+ bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef) override;
+#endif
ResourceRequest m_request;
ResourceRequest m_originalRequest; // Before redirects.
- RefPtr<ResourceBuffer> m_resourceData;
+ RefPtr<SharedBuffer> m_resourceData;
- unsigned long m_identifier;
+ unsigned long m_identifier { 0 };
- bool m_reachedTerminalState;
- bool m_notifiedLoadComplete;
+ bool m_reachedTerminalState { false };
+ bool m_notifiedLoadComplete { false };
enum CancellationStatus {
NotCancelled,
@@ -201,18 +227,16 @@ private:
Cancelled,
FinishedCancel
};
- CancellationStatus m_cancellationStatus;
+ CancellationStatus m_cancellationStatus { NotCancelled };
bool m_defersLoading;
ResourceRequest m_deferredRequest;
ResourceLoaderOptions m_options;
-};
-
-inline const ResourceResponse& ResourceLoader::response() const
-{
- return m_response;
-}
-
-}
+#if ENABLE(CONTENT_EXTENSIONS)
+protected:
+ ResourceType m_resourceType { ResourceType::Invalid };
#endif
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoaderOptions.h b/Source/WebCore/loader/ResourceLoaderOptions.h
index b87d98722..b93bcb68f 100644
--- a/Source/WebCore/loader/ResourceLoaderOptions.h
+++ b/Source/WebCore/loader/ResourceLoaderOptions.h
@@ -28,13 +28,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceLoaderOptions_h
-#define ResourceLoaderOptions_h
+#pragma once
+#include "FetchOptions.h"
#include "ResourceHandleTypes.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
namespace WebCore {
-
+
enum SendCallbackPolicy {
SendCallbacks,
DoNotSendCallbacks
@@ -55,43 +57,78 @@ enum SecurityCheckPolicy {
DoSecurityCheck
};
-enum RequestOriginPolicy {
- UseDefaultOriginRestrictionsForType,
- RestrictToSameOrigin,
- PotentiallyCrossOriginEnabled // Indicates "potentially CORS-enabled fetch" in HTML standard.
+enum CertificateInfoPolicy {
+ IncludeCertificateInfo,
+ DoNotIncludeCertificateInfo
};
-struct ResourceLoaderOptions {
- ResourceLoaderOptions()
- : sendLoadCallbacks(DoNotSendCallbacks)
- , sniffContent(DoNotSniffContent)
- , dataBufferingPolicy(BufferData)
- , allowCredentials(DoNotAllowStoredCredentials)
- , clientCredentialPolicy(DoNotAskClientForAnyCredentials)
- , securityCheck(DoSecurityCheck)
- , requestOriginPolicy(UseDefaultOriginRestrictionsForType)
- {
- }
+enum class ContentSecurityPolicyImposition : uint8_t {
+ SkipPolicyCheck,
+ DoPolicyCheck
+};
+
+enum class DefersLoadingPolicy : uint8_t {
+ AllowDefersLoading,
+ DisallowDefersLoading
+};
+
+enum class CachingPolicy : uint8_t {
+ AllowCaching,
+ DisallowCaching
+};
+
+enum class ClientCredentialPolicy {
+ CannotAskClientForCredentials,
+ MayAskClientForCredentials
+};
+
+enum class SameOriginDataURLFlag {
+ Set,
+ Unset
+};
+
+enum class InitiatorContext {
+ Document,
+ Worker,
+};
- ResourceLoaderOptions(SendCallbackPolicy sendLoadCallbacks, ContentSniffingPolicy sniffContent, DataBufferingPolicy dataBufferingPolicy, StoredCredentials allowCredentials, ClientCredentialPolicy credentialPolicy, SecurityCheckPolicy securityCheck, RequestOriginPolicy requestOriginPolicy)
+struct ResourceLoaderOptions : public FetchOptions {
+ ResourceLoaderOptions() { }
+
+ ResourceLoaderOptions(const FetchOptions& options) : FetchOptions(options) { }
+
+ ResourceLoaderOptions(SendCallbackPolicy sendLoadCallbacks, ContentSniffingPolicy sniffContent, DataBufferingPolicy dataBufferingPolicy, StoredCredentials allowCredentials, ClientCredentialPolicy credentialPolicy, FetchOptions::Credentials credentials, SecurityCheckPolicy securityCheck, FetchOptions::Mode mode, CertificateInfoPolicy certificateInfoPolicy, ContentSecurityPolicyImposition contentSecurityPolicyImposition, DefersLoadingPolicy defersLoadingPolicy, CachingPolicy cachingPolicy)
: sendLoadCallbacks(sendLoadCallbacks)
, sniffContent(sniffContent)
, dataBufferingPolicy(dataBufferingPolicy)
, allowCredentials(allowCredentials)
- , clientCredentialPolicy(credentialPolicy)
, securityCheck(securityCheck)
- , requestOriginPolicy(requestOriginPolicy)
+ , certificateInfoPolicy(certificateInfoPolicy)
+ , contentSecurityPolicyImposition(contentSecurityPolicyImposition)
+ , defersLoadingPolicy(defersLoadingPolicy)
+ , cachingPolicy(cachingPolicy)
+ , clientCredentialPolicy(credentialPolicy)
{
+ this->credentials = credentials;
+ this->mode = mode;
}
- SendCallbackPolicy sendLoadCallbacks : 1;
- ContentSniffingPolicy sniffContent : 1;
- DataBufferingPolicy dataBufferingPolicy : 1;
- StoredCredentials allowCredentials : 1; // Whether HTTP credentials and cookies are sent with the request.
- ClientCredentialPolicy clientCredentialPolicy : 2; // When we should ask the client for credentials (if we allow credentials at all).
- SecurityCheckPolicy securityCheck : 1;
- RequestOriginPolicy requestOriginPolicy : 2;
-};
-} // namespace WebCore
+ SendCallbackPolicy sendLoadCallbacks { DoNotSendCallbacks };
+ ContentSniffingPolicy sniffContent { DoNotSniffContent };
+ DataBufferingPolicy dataBufferingPolicy { BufferData };
+ StoredCredentials allowCredentials { DoNotAllowStoredCredentials };
+ SecurityCheckPolicy securityCheck { DoSecurityCheck };
+ CertificateInfoPolicy certificateInfoPolicy { DoNotIncludeCertificateInfo };
+ ContentSecurityPolicyImposition contentSecurityPolicyImposition { ContentSecurityPolicyImposition::DoPolicyCheck };
+ DefersLoadingPolicy defersLoadingPolicy { DefersLoadingPolicy::AllowDefersLoading };
+ CachingPolicy cachingPolicy { CachingPolicy::AllowCaching };
+ SameOriginDataURLFlag sameOriginDataURLFlag { SameOriginDataURLFlag::Unset };
+ InitiatorContext initiatorContext { InitiatorContext::Document };
+
+ ClientCredentialPolicy clientCredentialPolicy { ClientCredentialPolicy::CannotAskClientForCredentials };
+ unsigned maxRedirectCount { 20 };
+
+ Vector<String> derivedCachedDataTypesToRetrieve;
+};
-#endif // ResourceLoaderOptions_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceLoaderTypes.h b/Source/WebCore/loader/ResourceLoaderTypes.h
index e85c3c26e..2f14f203f 100644
--- a/Source/WebCore/loader/ResourceLoaderTypes.h
+++ b/Source/WebCore/loader/ResourceLoaderTypes.h
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceLoaderTypes_h
-#define ResourceLoaderTypes_h
+#pragma once
namespace WebCore {
@@ -39,5 +38,3 @@ enum DataPayloadType {
};
} // namespace WebCore
-
-#endif // ResourceLoaderTypes_h
diff --git a/Source/WebCore/loader/ResourceTiming.cpp b/Source/WebCore/loader/ResourceTiming.cpp
new file mode 100644
index 000000000..ccdef73f2
--- /dev/null
+++ b/Source/WebCore/loader/ResourceTiming.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceTiming.h"
+
+#include "CachedResource.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+static bool passesTimingAllowCheck(const ResourceResponse& response, const SecurityOrigin& initiatorSecurityOrigin)
+{
+ Ref<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url());
+ if (resourceOrigin->isSameSchemeHostPort(initiatorSecurityOrigin))
+ return true;
+
+ const String& timingAllowOriginString = response.httpHeaderField(HTTPHeaderName::TimingAllowOrigin);
+ if (timingAllowOriginString.isEmpty() || equalLettersIgnoringASCIICase(timingAllowOriginString, "null"))
+ return false;
+
+ if (timingAllowOriginString == "*")
+ return true;
+
+ const String& securityOrigin = initiatorSecurityOrigin.toString();
+ Vector<String> timingAllowOrigins;
+ timingAllowOriginString.split(',', timingAllowOrigins);
+ for (auto& origin : timingAllowOrigins) {
+ if (origin.stripWhiteSpace() == securityOrigin)
+ return true;
+ }
+
+ return false;
+}
+
+ResourceTiming ResourceTiming::fromCache(const URL& url, const String& initiator, const LoadTiming& loadTiming)
+{
+ return ResourceTiming(url, initiator, loadTiming);
+}
+
+ResourceTiming ResourceTiming::fromLoad(CachedResource& resource, const String& initiator, const LoadTiming& loadTiming, const SecurityOrigin& securityOrigin)
+{
+ return ResourceTiming(resource, initiator, loadTiming, securityOrigin);
+}
+
+ResourceTiming ResourceTiming::fromSynchronousLoad(const URL& url, const String& initiator, const LoadTiming& loadTiming, const NetworkLoadTiming& networkLoadTiming, const ResourceResponse& response, const SecurityOrigin& securityOrigin)
+{
+ return ResourceTiming(url, initiator, loadTiming, networkLoadTiming, response, securityOrigin);
+}
+
+ResourceTiming::ResourceTiming(const URL& url, const String& initiator, const LoadTiming& loadTiming)
+ : m_url(url)
+ , m_initiator(initiator)
+ , m_loadTiming(loadTiming)
+ , m_allowTimingDetails(true)
+{
+}
+
+ResourceTiming::ResourceTiming(CachedResource& resource, const String& initiator, const LoadTiming& loadTiming, const SecurityOrigin& securityOrigin)
+ : m_url(resource.resourceRequest().url())
+ , m_initiator(initiator)
+ , m_loadTiming(loadTiming)
+ , m_networkLoadTiming(resource.response().networkLoadTiming())
+ , m_allowTimingDetails(passesTimingAllowCheck(resource.response(), securityOrigin))
+{
+}
+
+ResourceTiming::ResourceTiming(const URL& url, const String& initiator, const LoadTiming& loadTiming, const NetworkLoadTiming& networkLoadTiming, const ResourceResponse& response, const SecurityOrigin& securityOrigin)
+ : m_url(url)
+ , m_initiator(initiator)
+ , m_loadTiming(loadTiming)
+ , m_networkLoadTiming(networkLoadTiming)
+ , m_allowTimingDetails(passesTimingAllowCheck(response, securityOrigin))
+{
+}
+
+ResourceTiming ResourceTiming::isolatedCopy() const
+{
+ return ResourceTiming(m_url.isolatedCopy(), m_initiator.isolatedCopy(), m_loadTiming.isolatedCopy(), m_networkLoadTiming.isolatedCopy(), m_allowTimingDetails);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceTiming.h b/Source/WebCore/loader/ResourceTiming.h
new file mode 100644
index 000000000..222122ab1
--- /dev/null
+++ b/Source/WebCore/loader/ResourceTiming.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "LoadTiming.h"
+#include "NetworkLoadTiming.h"
+#include "URL.h"
+
+namespace WebCore {
+
+class CachedResource;
+class ResourceResponse;
+class SecurityOrigin;
+
+class ResourceTiming {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static ResourceTiming fromCache(const URL&, const String& initiator, const LoadTiming&);
+ static ResourceTiming fromLoad(CachedResource&, const String& initiator, const LoadTiming&, const SecurityOrigin&);
+ static ResourceTiming fromSynchronousLoad(const URL&, const String& initiator, const LoadTiming&, const NetworkLoadTiming&, const ResourceResponse&, const SecurityOrigin&);
+
+ URL url() const { return m_url; }
+ String initiator() const { return m_initiator; }
+ LoadTiming loadTiming() const { return m_loadTiming; }
+ NetworkLoadTiming networkLoadTiming() const { return m_networkLoadTiming; }
+ bool allowTimingDetails() const { return m_allowTimingDetails; }
+
+ ResourceTiming isolatedCopy() const;
+
+ void overrideInitiatorName(const String& name) { m_initiator = name; }
+
+private:
+ ResourceTiming(CachedResource&, const String& initiator, const LoadTiming&, const SecurityOrigin&);
+ ResourceTiming(const URL&, const String& initiator, const LoadTiming&, const NetworkLoadTiming&, const ResourceResponse&, const SecurityOrigin&);
+ ResourceTiming(const URL&, const String& initiator, const LoadTiming&);
+ ResourceTiming(const URL& url, const String& initiator, const LoadTiming& loadTiming, const NetworkLoadTiming& networkLoadTiming, bool allowTimingDetails)
+ : m_url(url)
+ , m_initiator(initiator)
+ , m_loadTiming(loadTiming)
+ , m_networkLoadTiming(networkLoadTiming)
+ , m_allowTimingDetails(allowTimingDetails)
+ {
+ }
+
+ URL m_url;
+ String m_initiator;
+ LoadTiming m_loadTiming;
+ NetworkLoadTiming m_networkLoadTiming;
+ bool m_allowTimingDetails { false };
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/ResourceTimingInformation.cpp b/Source/WebCore/loader/ResourceTimingInformation.cpp
new file mode 100644
index 000000000..5ef15536c
--- /dev/null
+++ b/Source/WebCore/loader/ResourceTimingInformation.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceTimingInformation.h"
+
+#if ENABLE(WEB_TIMING)
+
+#include "CachedResource.h"
+#include "DOMWindow.h"
+#include "Document.h"
+#include "Frame.h"
+#include "HTMLFrameOwnerElement.h"
+#include "LoadTiming.h"
+#include "Performance.h"
+#include "ResourceTiming.h"
+#include "RuntimeEnabledFeatures.h"
+
+namespace WebCore {
+
+bool ResourceTimingInformation::shouldAddResourceTiming(CachedResource& resource)
+{
+ // FIXME: We can be less restrictive here.
+ // <https://github.com/w3c/resource-timing/issues/100>
+ if (!resource.resourceRequest().url().protocolIsInHTTPFamily())
+ return false;
+ if (resource.response().httpStatusCode() >= 400)
+ return false;
+ if (resource.errorOccurred())
+ return false;
+ if (resource.wasCanceled())
+ return false;
+
+ return true;
+}
+
+void ResourceTimingInformation::addResourceTiming(CachedResource& resource, Document& document, ResourceTiming&& resourceTiming)
+{
+ ASSERT(RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled());
+ if (!ResourceTimingInformation::shouldAddResourceTiming(resource))
+ return;
+
+ auto iterator = m_initiatorMap.find(&resource);
+ if (iterator == m_initiatorMap.end())
+ return;
+
+ InitiatorInfo& info = iterator->value;
+ if (info.added == Added)
+ return;
+
+ Document* initiatorDocument = &document;
+ if (resource.type() == CachedResource::MainResource)
+ initiatorDocument = document.parentDocument();
+ if (!initiatorDocument)
+ return;
+ if (!initiatorDocument->domWindow())
+ return;
+ if (!initiatorDocument->domWindow()->performance())
+ return;
+
+ resourceTiming.overrideInitiatorName(info.name);
+
+ initiatorDocument->domWindow()->performance()->addResourceTiming(WTFMove(resourceTiming));
+
+ info.added = Added;
+}
+
+void ResourceTimingInformation::storeResourceTimingInitiatorInformation(const CachedResourceHandle<CachedResource>& resource, const AtomicString& initiatorName, Frame* frame)
+{
+ ASSERT(RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled());
+ ASSERT(resource.get());
+
+ if (resource->type() == CachedResource::MainResource) {
+ // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
+ ASSERT(frame);
+ if (frame->ownerElement()) {
+ InitiatorInfo info = { frame->ownerElement()->localName(), NotYetAdded };
+ m_initiatorMap.add(resource.get(), info);
+ }
+ } else {
+ InitiatorInfo info = { initiatorName, NotYetAdded };
+ m_initiatorMap.add(resource.get(), info);
+ }
+}
+
+}
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/loader/ResourceTimingInformation.h b/Source/WebCore/loader/ResourceTimingInformation.h
new file mode 100644
index 000000000..594a91a1f
--- /dev/null
+++ b/Source/WebCore/loader/ResourceTimingInformation.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_TIMING)
+
+#include "CachedResourceHandle.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class CachedResource;
+class Document;
+class Frame;
+class ResourceTiming;
+
+class ResourceTimingInformation {
+public:
+ static bool shouldAddResourceTiming(CachedResource&);
+
+ void addResourceTiming(CachedResource&, Document&, ResourceTiming&&);
+ void storeResourceTimingInitiatorInformation(const CachedResourceHandle<CachedResource>&, const AtomicString&, Frame*);
+
+private:
+ enum AlreadyAdded { NotYetAdded, Added };
+ struct InitiatorInfo {
+ AtomicString name;
+ AlreadyAdded added;
+ };
+ HashMap<CachedResource*, InitiatorInfo> m_initiatorMap;
+};
+
+}
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/loader/SinkDocument.cpp b/Source/WebCore/loader/SinkDocument.cpp
index ad2f099e4..a1bf52a3c 100644
--- a/Source/WebCore/loader/SinkDocument.cpp
+++ b/Source/WebCore/loader/SinkDocument.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -32,9 +32,9 @@ namespace WebCore {
class SinkDocumentParser final : public RawDataDocumentParser {
public:
- static PassRefPtr<SinkDocumentParser> create(SinkDocument& document)
+ static Ref<SinkDocumentParser> create(SinkDocument& document)
{
- return adoptRef(new SinkDocumentParser(document));
+ return adoptRef(*new SinkDocumentParser(document));
}
private:
@@ -44,7 +44,7 @@ private:
}
// Ignore all data.
- virtual void appendBytes(DocumentWriter&, const char*, size_t)
+ void appendBytes(DocumentWriter&, const char*, size_t) override
{
}
};
@@ -52,11 +52,11 @@ private:
SinkDocument::SinkDocument(Frame* frame, const URL& url)
: HTMLDocument(frame, url)
{
- setCompatibilityMode(QuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
lockCompatibilityMode();
}
-PassRefPtr<DocumentParser> SinkDocument::createParser()
+Ref<DocumentParser> SinkDocument::createParser()
{
return SinkDocumentParser::create(*this);
}
diff --git a/Source/WebCore/loader/SinkDocument.h b/Source/WebCore/loader/SinkDocument.h
index bde3e59ed..f70f28cbc 100644
--- a/Source/WebCore/loader/SinkDocument.h
+++ b/Source/WebCore/loader/SinkDocument.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SinkDocument_h
-#define SinkDocument_h
+#pragma once
#include "HTMLDocument.h"
@@ -32,18 +31,15 @@ namespace WebCore {
class SinkDocument final : public HTMLDocument {
public:
- static PassRefPtr<SinkDocument> create(Frame* frame, const URL& url)
+ static Ref<SinkDocument> create(Frame* frame, const URL& url)
{
- return adoptRef(new SinkDocument(frame, url));
+ return adoptRef(*new SinkDocument(frame, url));
}
private:
SinkDocument(Frame*, const URL&);
-
- virtual PassRefPtr<DocumentParser> createParser();
-};
+ Ref<DocumentParser> createParser() final;
+};
}; // namespace WebCore
-
-#endif // SinkDocument_h
diff --git a/Source/WebCore/loader/SubframeLoader.cpp b/Source/WebCore/loader/SubframeLoader.cpp
index 2d8ba8164..234625280 100644
--- a/Source/WebCore/loader/SubframeLoader.cpp
+++ b/Source/WebCore/loader/SubframeLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
@@ -14,7 +14,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -33,19 +33,19 @@
#include "config.h"
#include "SubframeLoader.h"
-#include "Chrome.h"
-#include "ChromeClient.h"
#include "ContentSecurityPolicy.h"
+#include "DiagnosticLoggingClient.h"
#include "DiagnosticLoggingKeys.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "HTMLAppletElement.h"
-#include "HTMLAudioElement.h"
-#include "HTMLFrameElementBase.h"
+#include "HTMLFrameElement.h"
+#include "HTMLIFrameElement.h"
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "MIMETypeRegistry.h"
+#include "MainFrame.h"
#include "Page.h"
#include "PluginData.h"
#include "PluginDocument.h"
@@ -56,11 +56,6 @@
#include "SecurityPolicy.h"
#include "Settings.h"
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-#include "HTMLMediaElement.h"
-#include "RenderVideo.h"
-#endif
-
namespace WebCore {
using namespace HTMLNames;
@@ -76,7 +71,7 @@ void SubframeLoader::clear()
m_containsPlugins = false;
}
-bool SubframeLoader::requestFrame(HTMLFrameOwnerElement& ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
+bool SubframeLoader::requestFrame(HTMLFrameOwnerElement& ownerElement, const String& urlString, const AtomicString& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
{
// Support for <frame src="javascript:string">
URL scriptURL;
@@ -87,55 +82,50 @@ bool SubframeLoader::requestFrame(HTMLFrameOwnerElement& ownerElement, const Str
} else
url = completeURL(urlString);
+ if (shouldConvertInvalidURLsToBlank() && !url.isValid())
+ url = blankURL();
+
Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
if (!frame)
return false;
- if (!scriptURL.isEmpty())
+ if (!scriptURL.isEmpty() && ownerElement.isURLAllowed(scriptURL))
frame->script().executeIfJavaScriptURL(scriptURL);
return true;
}
-bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType, bool shouldPreferPlugInsForImages)
+bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType)
{
URL completedURL;
if (!url.isEmpty())
completedURL = completeURL(url);
bool useFallback;
- return shouldUsePlugin(completedURL, mimeType, shouldPreferPlugInsForImages, false, useFallback);
+ return shouldUsePlugin(completedURL, mimeType, false, useFallback);
}
-bool SubframeLoader::pluginIsLoadable(HTMLPlugInImageElement& pluginElement, const URL& url, const String& mimeType)
+bool SubframeLoader::pluginIsLoadable(const URL& url, const String& mimeType)
{
+ auto* document = m_frame.document();
+
if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) {
if (!m_frame.settings().isJavaEnabled())
return false;
- if (document() && document()->securityOrigin()->isLocal() && !m_frame.settings().isJavaEnabledForLocalFiles())
+ if (document && document->securityOrigin().isLocal() && !m_frame.settings().isJavaEnabledForLocalFiles())
return false;
}
- if (document()) {
- if (document()->isSandboxed(SandboxPlugins))
+ if (document) {
+ if (document->isSandboxed(SandboxPlugins))
return false;
- if (!document()->securityOrigin()->canDisplay(url)) {
+ if (!document->securityOrigin().canDisplay(url)) {
FrameLoader::reportLocalLoadFailed(&m_frame, url.string());
return false;
}
- String declaredMimeType = document()->isPluginDocument() && document()->ownerElement() ?
- document()->ownerElement()->fastGetAttribute(HTMLNames::typeAttr) :
- pluginElement.fastGetAttribute(HTMLNames::typeAttr);
- if (!document()->contentSecurityPolicy()->allowObjectFromSource(url)
- || !document()->contentSecurityPolicy()->allowPluginType(mimeType, declaredMimeType, url)) {
- RenderEmbeddedObject* renderer = pluginElement.renderEmbeddedObject();
- renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy);
- return false;
- }
-
- if (!m_frame.loader().mixedContentChecker().canRunInsecureContent(document()->securityOrigin(), url))
+ if (!m_frame.loader().mixedContentChecker().canRunInsecureContent(document->securityOrigin(), url))
return false;
}
@@ -147,10 +137,10 @@ bool SubframeLoader::requestPlugin(HTMLPlugInImageElement& ownerElement, const U
// Application plug-ins are plug-ins implemented by the user agent, for example Qt plug-ins,
// as opposed to third-party code such as Flash. The user agent decides whether or not they are
// permitted, rather than WebKit.
- if ((!allowPlugins(AboutToInstantiatePlugin) && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType)))
+ if ((!allowPlugins() && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType)))
return false;
- if (!pluginIsLoadable(ownerElement, url, mimeType))
+ if (!pluginIsLoadable(url, mimeType))
return false;
ASSERT(ownerElement.hasTagName(objectTag) || ownerElement.hasTagName(embedTag));
@@ -170,11 +160,13 @@ static String findPluginMIMETypeFromURL(Page* page, const String& url)
const PluginData& pluginData = page->pluginData();
- for (size_t i = 0; i < pluginData.mimes().size(); ++i) {
- const MimeClassInfo& mimeClassInfo = pluginData.mimes()[i];
- for (size_t j = 0; j < mimeClassInfo.extensions.size(); ++j) {
- if (equalIgnoringCase(extension, mimeClassInfo.extensions[j]))
- return mimeClassInfo.type;
+ Vector<MimeClassInfo> mimes;
+ Vector<size_t> mimePluginIndices;
+ pluginData.getWebVisibleMimesAndPluginIndices(mimes, mimePluginIndices);
+ for (auto& mime : mimes) {
+ for (auto& mimeExtension : mime.extensions) {
+ if (equalIgnoringASCIICase(extension, mimeExtension))
+ return mime.type;
}
}
@@ -183,7 +175,7 @@ static String findPluginMIMETypeFromURL(Page* page, const String& url)
static void logPluginRequest(Page* page, const String& mimeType, const String& url, bool success)
{
- if (!page || !page->settings().diagnosticLoggingEnabled())
+ if (!page)
return;
String newMIMEType = mimeType;
@@ -194,17 +186,17 @@ static void logPluginRequest(Page* page, const String& mimeType, const String& u
return;
}
- String pluginFile = page->pluginData().pluginFileForMimeType(newMIMEType);
+ String pluginFile = page->pluginData().pluginFileForWebVisibleMimeType(newMIMEType);
String description = !pluginFile ? newMIMEType : pluginFile;
- ChromeClient& chromeClient = page->chrome().client();
- chromeClient.logDiagnosticMessage(success ? DiagnosticLoggingKeys::pluginLoadedKey() : DiagnosticLoggingKeys::pluginLoadingFailedKey(), description, DiagnosticLoggingKeys::noopKey());
+ DiagnosticLoggingClient& diagnosticLoggingClient = page->diagnosticLoggingClient();
+ diagnosticLoggingClient.logDiagnosticMessage(success ? DiagnosticLoggingKeys::pluginLoadedKey() : DiagnosticLoggingKeys::pluginLoadingFailedKey(), description, ShouldSample::No);
if (!page->hasSeenAnyPlugin())
- chromeClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsAtLeastOnePluginKey(), emptyString(), DiagnosticLoggingKeys::noopKey());
-
+ diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsAtLeastOnePluginKey(), emptyString(), ShouldSample::No);
+
if (!page->hasSeenPlugin(description))
- chromeClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsPluginKey(), description, DiagnosticLoggingKeys::noopKey());
+ diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsPluginKey(), description, ShouldSample::No);
page->sawPlugin(description);
}
@@ -214,99 +206,66 @@ bool SubframeLoader::requestObject(HTMLPlugInImageElement& ownerElement, const S
if (url.isEmpty() && mimeType.isEmpty())
return false;
+ auto& document = ownerElement.document();
+
URL completedURL;
if (!url.isEmpty())
completedURL = completeURL(url);
- bool hasFallbackContent = isHTMLObjectElement(ownerElement) && toHTMLObjectElement(ownerElement).hasFallbackContent();
+ document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(completedURL, ContentSecurityPolicy::InsecureRequestType::Load);
+
+ bool hasFallbackContent = is<HTMLObjectElement>(ownerElement) && downcast<HTMLObjectElement>(ownerElement).hasFallbackContent();
bool useFallback;
- if (shouldUsePlugin(completedURL, mimeType, ownerElement.shouldPreferPlugInsForImages(), hasFallbackContent, useFallback)) {
+ if (shouldUsePlugin(completedURL, mimeType, hasFallbackContent, useFallback)) {
bool success = requestPlugin(ownerElement, completedURL, mimeType, paramNames, paramValues, useFallback);
- logPluginRequest(document()->page(), mimeType, completedURL, success);
+ logPluginRequest(document.page(), mimeType, completedURL, success);
return success;
}
// If the plug-in element already contains a subframe, loadOrRedirectSubframe will re-use it. Otherwise,
// it will create a new frame and set it as the RenderWidget's Widget, causing what was previously
// in the widget to be torn down.
- return loadOrRedirectSubframe(ownerElement, completedURL, frameName, true, true);
+ return loadOrRedirectSubframe(ownerElement, completedURL, frameName, LockHistory::Yes, LockBackForwardList::Yes);
}
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-PassRefPtr<Widget> SubframeLoader::loadMediaPlayerProxyPlugin(HTMLMediaElement& mediaElement, const URL& url, const Vector<String>& paramNames, const Vector<String>& paramValues)
-{
- ASSERT(mediaElement.hasTagName(videoTag) || isHTMLAudioElement(mediaElement));
-
- URL completedURL;
- if (!url.isEmpty())
- completedURL = completeURL(url);
-
- if (!m_frame.document()->securityOrigin()->canDisplay(completedURL)) {
- FrameLoader::reportLocalLoadFailed(&m_frame, completedURL.string());
- return nullptr;
- }
-
- if (!m_frame.document()->contentSecurityPolicy()->allowMediaFromSource(completedURL))
- return nullptr;
-
- RenderWidget* renderer = toRenderWidget(mediaElement.renderer());
- IntSize size;
-
- if (renderer)
- size = roundedIntSize(LayoutSize(renderer->contentWidth(), renderer->contentHeight()));
- else if (mediaElement.isVideo())
- size = RenderVideo::defaultSize();
-
- if (!m_frame.loader().mixedContentChecker().canRunInsecureContent(m_frame.document()->securityOrigin(), completedURL))
- return nullptr;
-
- RefPtr<Widget> widget = m_frame.loader().client().createMediaPlayerProxyPlugin(size, &mediaElement, completedURL, paramNames, paramValues, "application/x-media-element-proxy-plugin");
-
- if (widget && renderer) {
- renderer->setWidget(widget);
- renderer->frameOwnerElement().setNeedsStyleRecalc(SyntheticStyleChange);
- }
- m_containsPlugins = true;
-
- return widget ? widget.release() : nullptr;
-}
-#endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-
-PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement& element, const Vector<String>& paramNames, const Vector<String>& paramValues)
+RefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement& element, const Vector<String>& paramNames, const Vector<String>& paramValues)
{
String baseURLString;
String codeBaseURLString;
for (size_t i = 0; i < paramNames.size(); ++i) {
- if (equalIgnoringCase(paramNames[i], "baseurl"))
+ if (equalLettersIgnoringASCIICase(paramNames[i], "baseurl"))
baseURLString = paramValues[i];
- else if (equalIgnoringCase(paramNames[i], "codebase"))
+ else if (equalLettersIgnoringASCIICase(paramNames[i], "codebase"))
codeBaseURLString = paramValues[i];
}
if (!codeBaseURLString.isEmpty()) {
URL codeBaseURL = completeURL(codeBaseURLString);
- if (!element.document().securityOrigin()->canDisplay(codeBaseURL)) {
+ if (!element.document().securityOrigin().canDisplay(codeBaseURL)) {
FrameLoader::reportLocalLoadFailed(&m_frame, codeBaseURL.string());
return nullptr;
}
const char javaAppletMimeType[] = "application/x-java-applet";
- if (!element.document().contentSecurityPolicy()->allowObjectFromSource(codeBaseURL)
- || !element.document().contentSecurityPolicy()->allowPluginType(javaAppletMimeType, javaAppletMimeType, codeBaseURL))
+ ASSERT(element.document().contentSecurityPolicy());
+ auto& contentSecurityPolicy = *element.document().contentSecurityPolicy();
+ // Elements in user agent show tree should load whatever the embedding document policy is.
+ if (!element.isInUserAgentShadowTree()
+ && (!contentSecurityPolicy.allowObjectFromSource(codeBaseURL) || !contentSecurityPolicy.allowPluginType(javaAppletMimeType, javaAppletMimeType, codeBaseURL)))
return nullptr;
}
if (baseURLString.isEmpty())
- baseURLString = m_frame.document()->baseURL().string();
+ baseURLString = element.document().baseURL().string();
URL baseURL = completeURL(baseURLString);
RefPtr<Widget> widget;
- if (allowPlugins(AboutToInstantiatePlugin))
- widget = m_frame.loader().client().createJavaAppletWidget(size, &element, baseURL, paramNames, paramValues);
+ if (allowPlugins())
+ widget = m_frame.loader().client().createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
- logPluginRequest(document()->page(), element.serviceType(), String(), widget);
+ logPluginRequest(m_frame.page(), element.serviceType(), String(), widget);
if (!widget) {
RenderEmbeddedObject* renderer = element.renderEmbeddedObject();
@@ -320,13 +279,18 @@ PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, H
return widget;
}
-Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement& ownerElement, const URL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
+Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement& ownerElement, const URL& requestURL, const AtomicString& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
{
- Frame* frame = ownerElement.contentFrame();
+ auto& initiatingDocument = ownerElement.document();
+
+ URL upgradedRequestURL = requestURL;
+ initiatingDocument.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(upgradedRequestURL, ContentSecurityPolicy::InsecureRequestType::Load);
+
+ auto* frame = ownerElement.contentFrame();
if (frame)
- frame->navigationScheduler().scheduleLocationChange(m_frame.document()->securityOrigin(), url.string(), m_frame.loader().outgoingReferrer(), lockHistory, lockBackForwardList);
+ frame->navigationScheduler().scheduleLocationChange(initiatingDocument, initiatingDocument.securityOrigin(), upgradedRequestURL, m_frame.loader().outgoingReferrer(), lockHistory, lockBackForwardList);
else
- frame = loadSubframe(ownerElement, url, frameName, m_frame.loader().outgoingReferrer());
+ frame = loadSubframe(ownerElement, upgradedRequestURL, frameName, m_frame.loader().outgoingReferrer());
if (!frame)
return nullptr;
@@ -342,14 +306,16 @@ Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement& ownerElement, const U
bool allowsScrolling = true;
int marginWidth = -1;
int marginHeight = -1;
- if (ownerElement.hasTagName(frameTag) || ownerElement.hasTagName(iframeTag)) {
- HTMLFrameElementBase& frameElementBase = toHTMLFrameElementBase(ownerElement);
+ if (is<HTMLFrameElementBase>(ownerElement)) {
+ auto& frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
allowsScrolling = frameElementBase.scrollingMode() != ScrollbarAlwaysOff;
marginWidth = frameElementBase.marginWidth();
marginHeight = frameElementBase.marginHeight();
}
- if (!ownerElement.document().securityOrigin()->canDisplay(url)) {
+ auto document = makeRef(ownerElement.document());
+
+ if (!document->securityOrigin().canDisplay(url)) {
FrameLoader::reportLocalLoadFailed(&m_frame, url.string());
return nullptr;
}
@@ -357,14 +323,20 @@ Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement& ownerElement, const U
if (!SubframeLoadingDisabler::canLoadFrame(ownerElement))
return nullptr;
- String referrerToUse = SecurityPolicy::generateReferrerHeader(ownerElement.document().referrerPolicy(), url, referrer);
- RefPtr<Frame> frame = m_frame.loader().client().createFrame(url, name, &ownerElement, referrerToUse, allowsScrolling, marginWidth, marginHeight);
+ String referrerToUse = SecurityPolicy::generateReferrerHeader(document->referrerPolicy(), url, referrer);
+
+ // Prevent initial empty document load from triggering load events.
+ document->incrementLoadEventDelayCount();
+
+ auto frame = m_frame.loader().client().createFrame(url, name, ownerElement, referrerToUse, allowsScrolling, marginWidth, marginHeight);
+
+ document->decrementLoadEventDelayCount();
if (!frame) {
m_frame.loader().checkCallImplicitClose();
return nullptr;
}
-
+
// All new frames will have m_isComplete set to true at this point due to synchronously loading
// an empty document in FrameLoader::init(). But many frames will now be starting an
// asynchronous load of url, so we set m_isComplete to false and then check if the load is
@@ -373,13 +345,13 @@ Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement& ownerElement, const U
// FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
frame->loader().started();
- RenderObject* renderer = ownerElement.renderer();
- FrameView* view = frame->view();
- if (renderer && renderer->isWidget() && view)
- toRenderWidget(renderer)->setWidget(view);
-
+ auto* renderer = ownerElement.renderer();
+ auto* view = frame->view();
+ if (is<RenderWidget>(renderer) && view)
+ downcast<RenderWidget>(*renderer).setWidget(view);
+
m_frame.loader().checkCallImplicitClose();
-
+
// Some loads are performed synchronously (e.g., about:blank and loads
// cancelled by returning a null ResourceRequest from requestFromDelegate).
// In these cases, the synchronous load would have finished
@@ -395,36 +367,24 @@ Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement& ownerElement, const U
return frame.get();
}
-bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins)
+bool SubframeLoader::allowPlugins()
{
- return m_frame.loader().client().allowPlugins(m_frame.settings().arePluginsEnabled());
+ return m_frame.settings().arePluginsEnabled();
}
-bool SubframeLoader::shouldUsePlugin(const URL& url, const String& mimeType, bool shouldPreferPlugInsForImages, bool hasFallback, bool& useFallback)
+bool SubframeLoader::shouldUsePlugin(const URL& url, const String& mimeType, bool hasFallback, bool& useFallback)
{
if (m_frame.loader().client().shouldAlwaysUsePluginDocument(mimeType)) {
useFallback = false;
return true;
}
- // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
- // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
- if (m_frame.page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
- String pluginName = m_frame.page()->pluginData().pluginNameForMimeType(mimeType);
- if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
- return true;
- }
-
- ObjectContentType objectType = m_frame.loader().client().objectContentType(url, mimeType, shouldPreferPlugInsForImages);
+ ObjectContentType objectType = m_frame.loader().client().objectContentType(url, mimeType);
// If an object's content can't be handled and it has no fallback, let
// it be handled as a plugin to show the broken plugin icon.
- useFallback = objectType == ObjectContentNone && hasFallback;
- return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
-}
+ useFallback = objectType == ObjectContentType::None && hasFallback;
-Document* SubframeLoader::document() const
-{
- return m_frame.document();
+ return objectType == ObjectContentType::None || objectType == ObjectContentType::PlugIn;
}
bool SubframeLoader::loadPlugin(HTMLPlugInImageElement& pluginElement, const URL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
@@ -432,7 +392,9 @@ bool SubframeLoader::loadPlugin(HTMLPlugInImageElement& pluginElement, const URL
if (useFallback)
return false;
- RenderEmbeddedObject* renderer = pluginElement.renderEmbeddedObject();
+ auto& document = pluginElement.document();
+ auto* renderer = pluginElement.renderEmbeddedObject();
+
// FIXME: This code should not depend on renderer!
if (!renderer)
return false;
@@ -440,17 +402,19 @@ bool SubframeLoader::loadPlugin(HTMLPlugInImageElement& pluginElement, const URL
pluginElement.subframeLoaderWillCreatePlugIn(url);
IntSize contentSize = roundedIntSize(LayoutSize(renderer->contentWidth(), renderer->contentHeight()));
- bool loadManually = document()->isPluginDocument() && !m_containsPlugins && toPluginDocument(document())->shouldLoadPluginManually();
+ bool loadManually = is<PluginDocument>(document) && !m_containsPlugins && downcast<PluginDocument>(document).shouldLoadPluginManually();
#if PLATFORM(IOS)
// On iOS, we only tell the plugin to be in full page mode if the containing plugin document is the top level document.
- if (document()->ownerElement())
+ if (document.ownerElement())
loadManually = false;
#endif
- WeakPtr<RenderWidget> weakRenderer = renderer->createWeakPtr();
- // createPlugin *may* cause this renderer to disappear from underneath.
- RefPtr<Widget> widget = m_frame.loader().client().createPlugin(contentSize, &pluginElement, url, paramNames, paramValues, mimeType, loadManually);
+ auto weakRenderer = renderer->createWeakPtr();
+
+ auto widget = m_frame.loader().client().createPlugin(contentSize, pluginElement, url, paramNames, paramValues, mimeType, loadManually);
+
+ // The call to createPlugin *may* cause this renderer to disappear from underneath.
if (!weakRenderer)
return false;
@@ -460,13 +424,9 @@ bool SubframeLoader::loadPlugin(HTMLPlugInImageElement& pluginElement, const URL
return false;
}
- pluginElement.subframeLoaderDidCreatePlugIn(widget.get());
- renderer->setWidget(widget);
+ pluginElement.subframeLoaderDidCreatePlugIn(*widget);
+ renderer->setWidget(WTFMove(widget));
m_containsPlugins = true;
-
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- pluginElement.setNeedsStyleRecalc(SyntheticStyleChange);
-#endif
return true;
}
@@ -476,4 +436,9 @@ URL SubframeLoader::completeURL(const String& url) const
return m_frame.document()->completeURL(url);
}
+bool SubframeLoader::shouldConvertInvalidURLsToBlank() const
+{
+ return m_frame.settings().shouldConvertInvalidURLsToBlank();
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/loader/SubframeLoader.h b/Source/WebCore/loader/SubframeLoader.h
index 1932ae102..12bf7717e 100644
--- a/Source/WebCore/loader/SubframeLoader.h
+++ b/Source/WebCore/loader/SubframeLoader.h
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -28,12 +28,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SubframeLoader_h
-#define SubframeLoader_h
+#pragma once
#include "FrameLoaderTypes.h"
#include <wtf/Forward.h>
-#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
@@ -53,45 +51,39 @@ class Widget;
// This is a slight misnomer. It handles the higher level logic of loading both subframes and plugins.
class SubframeLoader {
- WTF_MAKE_NONCOPYABLE(SubframeLoader);
+ WTF_MAKE_NONCOPYABLE(SubframeLoader); WTF_MAKE_FAST_ALLOCATED;
public:
explicit SubframeLoader(Frame&);
void clear();
- bool requestFrame(HTMLFrameOwnerElement&, const String& url, const AtomicString& frameName, bool lockHistory = true, bool lockBackForwardList = true);
+ bool requestFrame(HTMLFrameOwnerElement&, const String& url, const AtomicString& frameName, LockHistory = LockHistory::Yes, LockBackForwardList = LockBackForwardList::Yes);
bool requestObject(HTMLPlugInImageElement&, const String& url, const AtomicString& frameName,
const String& serviceType, const Vector<String>& paramNames, const Vector<String>& paramValues);
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- PassRefPtr<Widget> loadMediaPlayerProxyPlugin(HTMLMediaElement&, const URL&, const Vector<String>& paramNames, const Vector<String>& paramValues);
-#endif
+ RefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
- PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
-
- bool allowPlugins(ReasonForCallingAllowPlugins);
+ WEBCORE_EXPORT bool allowPlugins();
bool containsPlugins() const { return m_containsPlugins; }
- bool resourceWillUsePlugin(const String& url, const String& mimeType, bool shouldPreferPlugInsForImages);
+ bool resourceWillUsePlugin(const String& url, const String& mimeType);
private:
bool requestPlugin(HTMLPlugInImageElement&, const URL&, const String& serviceType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback);
- Frame* loadOrRedirectSubframe(HTMLFrameOwnerElement&, const URL&, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList);
+ Frame* loadOrRedirectSubframe(HTMLFrameOwnerElement&, const URL&, const AtomicString& frameName, LockHistory, LockBackForwardList);
Frame* loadSubframe(HTMLFrameOwnerElement&, const URL&, const String& name, const String& referrer);
bool loadPlugin(HTMLPlugInImageElement&, const URL&, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback);
- bool shouldUsePlugin(const URL&, const String& mimeType, bool shouldPreferPlugInsForImages, bool hasFallback, bool& useFallback);
- bool pluginIsLoadable(HTMLPlugInImageElement&, const URL&, const String& mimeType);
+ bool shouldUsePlugin(const URL&, const String& mimeType, bool hasFallback, bool& useFallback);
+ bool pluginIsLoadable(const URL&, const String& mimeType);
+
+ URL completeURL(const String&) const;
- Document* document() const;
+ bool shouldConvertInvalidURLsToBlank() const;
bool m_containsPlugins;
Frame& m_frame;
-
- URL completeURL(const String&) const;
};
} // namespace WebCore
-
-#endif // SubframeLoader_h
diff --git a/Source/WebCore/loader/SubresourceLoader.cpp b/Source/WebCore/loader/SubresourceLoader.cpp
index 0f17264e0..dc6f5d77a 100644
--- a/Source/WebCore/loader/SubresourceLoader.cpp
+++ b/Source/WebCore/loader/SubresourceLoader.cpp
@@ -1,18 +1,18 @@
/*
- * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -29,51 +29,68 @@
#include "config.h"
#include "SubresourceLoader.h"
+#include "CachedRawResource.h"
#include "CachedResourceLoader.h"
+#include "CrossOriginAccessControl.h"
+#include "DiagnosticLoggingClient.h"
+#include "DiagnosticLoggingKeys.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "Logging.h"
+#include "MainFrame.h"
#include "MemoryCache.h"
#include "Page.h"
-#include "PageActivityAssertionToken.h"
-#include "ResourceBuffer.h"
+#include "ResourceLoadObserver.h"
+#include "ResourceTiming.h"
+#include "RuntimeEnabledFeatures.h"
#include <wtf/Ref.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/CString.h>
#if PLATFORM(IOS)
-#include <RuntimeApplicationChecksIOS.h>
+#include <RuntimeApplicationChecks.h>
+#endif
+
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "ResourceLoadInfo.h"
+#endif
+
+#if USE(QUICK_LOOK)
+#include "QuickLook.h"
#endif
namespace WebCore {
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, subresourceLoaderCounter, ("SubresourceLoader"));
-SubresourceLoader::RequestCountTracker::RequestCountTracker(CachedResourceLoader* cachedResourceLoader, CachedResource* resource)
+SubresourceLoader::RequestCountTracker::RequestCountTracker(CachedResourceLoader& cachedResourceLoader, const CachedResource& resource)
: m_cachedResourceLoader(cachedResourceLoader)
, m_resource(resource)
{
- m_cachedResourceLoader->incrementRequestCount(m_resource);
+ m_cachedResourceLoader.incrementRequestCount(m_resource);
}
SubresourceLoader::RequestCountTracker::~RequestCountTracker()
{
- m_cachedResourceLoader->decrementRequestCount(m_resource);
+ m_cachedResourceLoader.decrementRequestCount(m_resource);
}
-SubresourceLoader::SubresourceLoader(Frame* frame, CachedResource* resource, const ResourceLoaderOptions& options)
+SubresourceLoader::SubresourceLoader(Frame& frame, CachedResource& resource, const ResourceLoaderOptions& options)
: ResourceLoader(frame, options)
- , m_resource(resource)
+ , m_resource(&resource)
, m_loadingMultipartContent(false)
, m_state(Uninitialized)
- , m_requestCountTracker(adoptPtr(new RequestCountTracker(frame->document()->cachedResourceLoader(), resource)))
+ , m_requestCountTracker(std::in_place, frame.document()->cachedResourceLoader(), resource)
{
#ifndef NDEBUG
subresourceLoaderCounter.increment();
#endif
+#if ENABLE(CONTENT_EXTENSIONS)
+ m_resourceType = toResourceType(resource.type());
+#endif
}
SubresourceLoader::~SubresourceLoader()
@@ -85,11 +102,11 @@ SubresourceLoader::~SubresourceLoader()
#endif
}
-PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, CachedResource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
+RefPtr<SubresourceLoader> SubresourceLoader::create(Frame& frame, CachedResource& resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
{
RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, resource, options)));
#if PLATFORM(IOS)
- if (!applicationIsWebProcess()) {
+ if (!IOSApplication::isWebProcess()) {
// On iOS, do not invoke synchronous resource load delegates while resource load scheduling
// is disabled to avoid re-entering style selection from a different thread (see <rdar://problem/9121719>).
// FIXME: This should be fixed for all ports in <https://bugs.webkit.org/show_bug.cgi?id=56647>.
@@ -99,13 +116,13 @@ PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, CachedReso
#endif
if (!subloader->init(request))
return nullptr;
- return subloader.release();
+ return subloader;
}
#if PLATFORM(IOS)
bool SubresourceLoader::startLoading()
{
- ASSERT(!applicationIsWebProcess());
+ ASSERT(!IOSApplication::isWebProcess());
if (!init(m_iOSOriginalRequest))
return false;
m_iOSOriginalRequest = ResourceRequest();
@@ -135,6 +152,12 @@ bool SubresourceLoader::init(const ResourceRequest& request)
ASSERT(!reachedTerminalState());
m_state = Initialized;
m_documentLoader->addSubresourceLoader(this);
+
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=155633.
+ // SubresourceLoader could use the document origin as a default and set PotentiallyCrossOriginEnabled requests accordingly.
+ // This would simplify resource loader users as they would only need to set fetch mode to Cors.
+ m_origin = m_resource->origin();
+
return true;
}
@@ -143,70 +166,157 @@ bool SubresourceLoader::isSubresourceLoader()
return true;
}
-void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
+void SubresourceLoader::willSendRequestInternal(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
{
// Store the previous URL because the call to ResourceLoader::willSendRequest will modify it.
URL previousURL = request().url();
- Ref<SubresourceLoader> protect(*this);
+ Ref<SubresourceLoader> protectedThis(*this);
+
+ if (!newRequest.url().isValid()) {
+ cancel(cannotShowURLError());
+ return;
+ }
+
+ if (newRequest.requester() != ResourceRequestBase::Requester::Main)
+ ResourceLoadObserver::sharedObserver().logSubresourceLoading(m_frame.get(), newRequest, redirectResponse);
ASSERT(!newRequest.isNull());
if (!redirectResponse.isNull()) {
+ if (options().redirect != FetchOptions::Redirect::Follow) {
+ if (options().redirect == FetchOptions::Redirect::Error) {
+ cancel();
+ return;
+ }
+
+ ResourceResponse opaqueRedirectedResponse;
+ opaqueRedirectedResponse.setURL(redirectResponse.url());
+ opaqueRedirectedResponse.setType(ResourceResponse::Type::Opaqueredirect);
+ m_resource->responseReceived(opaqueRedirectedResponse);
+ didFinishLoading(currentTime());
+ return;
+ } else if (m_redirectCount++ >= options().maxRedirectCount) {
+ cancel(ResourceError(String(), 0, request().url(), ASCIILiteral("Too many redirections"), ResourceError::Type::General));
+ return;
+ }
+
// CachedResources are keyed off their original request URL.
// Requesting the same original URL a second time can redirect to a unique second resource.
// Therefore, if a redirect to a different destination URL occurs, we should no longer consider this a revalidation of the first resource.
// Doing so would have us reusing the resource from the first request if the second request's revalidation succeeds.
if (newRequest.isConditional() && m_resource->resourceToRevalidate() && newRequest.url() != m_resource->resourceToRevalidate()->response().url()) {
newRequest.makeUnconditional();
- memoryCache()->revalidationFailed(m_resource);
+ MemoryCache::singleton().revalidationFailed(*m_resource);
+ if (m_frame && m_frame->page())
+ m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
}
-
- if (!m_documentLoader->cachedResourceLoader().canRequest(m_resource->type(), newRequest.url(), options())) {
+
+ if (!m_documentLoader->cachedResourceLoader().updateRequestAfterRedirection(m_resource->type(), newRequest, options())) {
cancel();
return;
}
- if (m_resource->type() == CachedResource::ImageResource && m_documentLoader->cachedResourceLoader().shouldDeferImageLoad(newRequest.url())) {
+
+ String errorDescription;
+ if (!checkRedirectionCrossOriginAccessControl(request(), redirectResponse, newRequest, errorDescription)) {
+ String errorMessage = "Cross-origin redirection to " + newRequest.url().string() + " denied by Cross-Origin Resource Sharing policy: " + errorDescription;
+ if (m_frame && m_frame->document())
+ m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorMessage);
+ cancel(ResourceError(String(), 0, request().url(), errorMessage, ResourceError::Type::AccessControl));
+ return;
+ }
+
+ if (m_resource->isImage() && m_documentLoader->cachedResourceLoader().shouldDeferImageLoad(newRequest.url())) {
cancel();
return;
}
- m_resource->willSendRequest(newRequest, redirectResponse);
+ m_loadTiming.addRedirect(redirectResponse.url(), newRequest.url());
+ m_resource->redirectReceived(newRequest, redirectResponse);
}
if (newRequest.isNull() || reachedTerminalState())
return;
- ResourceLoader::willSendRequest(newRequest, redirectResponse);
- if (newRequest.isNull())
+ ResourceLoader::willSendRequestInternal(newRequest, redirectResponse);
+
+ if (reachedTerminalState())
+ return;
+
+ if (newRequest.isNull()) {
cancel();
+ return;
+ }
+
+ if (m_resource->type() == CachedResource::MainResource && !redirectResponse.isNull())
+ m_documentLoader->willContinueMainResourceLoadAfterRedirect(newRequest);
}
void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
ASSERT(m_state == Initialized);
- Ref<SubresourceLoader> protect(*this);
+ Ref<SubresourceLoader> protectedThis(*this);
m_resource->didSendData(bytesSent, totalBytesToBeSent);
}
+#if USE(QUICK_LOOK)
+
+bool SubresourceLoader::shouldCreateQuickLookHandleForResponse(const ResourceResponse& response) const
+{
+ if (m_resource->type() != CachedResource::MainResource)
+ return false;
+
+ if (m_quickLookHandle)
+ return false;
+
+ return QuickLookHandle::shouldCreateForMIMEType(response.mimeType());
+}
+
+#endif
+
void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
{
ASSERT(!response.isNull());
ASSERT(m_state == Initialized);
+#if USE(QUICK_LOOK)
+ if (shouldCreateQuickLookHandleForResponse(response)) {
+ m_quickLookHandle = QuickLookHandle::create(*this, response);
+ return;
+ }
+#endif
+
+ // We want redirect responses to be processed through willSendRequestInternal. The only exception is redirection with no Location headers.
+ ASSERT(response.httpStatusCode() < 300 || response.httpStatusCode() >= 400 || response.httpStatusCode() == 304 || !response.httpHeaderField(HTTPHeaderName::Location));
+
// Reference the object in this method since the additional processing can do
// anything including removing the last reference to this object; one example of this is 3266216.
- Ref<SubresourceLoader> protect(*this);
+ Ref<SubresourceLoader> protectedThis(*this);
+
+ if (shouldIncludeCertificateInfo())
+ response.includeCertificateInfo();
if (m_resource->resourceToRevalidate()) {
if (response.httpStatusCode() == 304) {
// 304 Not modified / Use local copy
// Existing resource is ok, just use it updating the expiration time.
m_resource->setResponse(response);
- memoryCache()->revalidationSucceeded(m_resource, response);
+ MemoryCache::singleton().revalidationSucceeded(*m_resource, response);
+ if (m_frame && m_frame->page())
+ m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes);
if (!reachedTerminalState())
ResourceLoader::didReceiveResponse(response);
return;
}
// Did not get 304 response, continue as a regular resource load.
- memoryCache()->revalidationFailed(m_resource);
+ MemoryCache::singleton().revalidationFailed(*m_resource);
+ if (m_frame && m_frame->page())
+ m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
+ }
+
+ String errorDescription;
+ if (!checkResponseCrossOriginAccessControl(response, errorDescription)) {
+ if (m_frame && m_frame->document())
+ m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorDescription);
+ cancel(ResourceError(String(), 0, request().url(), errorDescription, ResourceError::Type::AccessControl));
+ return;
}
m_resource->responseReceived(response);
@@ -223,21 +333,20 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
m_loadingMultipartContent = true;
// We don't count multiParts in a CachedResourceLoader's request count
- m_requestCountTracker.clear();
+ m_requestCountTracker = std::nullopt;
if (!m_resource->isImage()) {
cancel();
return;
}
}
- RefPtr<ResourceBuffer> buffer = resourceData();
+ auto* buffer = resourceData();
if (m_loadingMultipartContent && buffer && buffer->size()) {
// The resource data will change as the next part is loaded, so we need to make a copy.
- RefPtr<ResourceBuffer> copiedData = ResourceBuffer::create(buffer->data(), buffer->size());
- m_resource->finishLoading(copiedData.get());
+ m_resource->finishLoading(buffer->copy().ptr());
clearResourceData();
- // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
- // After the first multipart section is complete, signal to delegates that this load is "finished"
+ // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
+ // After the first multipart section is complete, signal to delegates that this load is "finished"
m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
didFinishLoadingOnePart(0);
}
@@ -247,15 +356,29 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
void SubresourceLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType)
{
- didReceiveDataOrBuffer(data, length, 0, encodedDataLength, dataPayloadType);
+#if USE(QUICK_LOOK)
+ if (auto quickLookHandle = m_quickLookHandle.get()) {
+ if (quickLookHandle->didReceiveData(data, length))
+ return;
+ }
+#endif
+
+ didReceiveDataOrBuffer(data, length, nullptr, encodedDataLength, dataPayloadType);
}
-void SubresourceLoader::didReceiveBuffer(PassRefPtr<SharedBuffer> buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
+void SubresourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
{
- didReceiveDataOrBuffer(0, 0, buffer, encodedDataLength, dataPayloadType);
+#if USE(QUICK_LOOK)
+ if (auto quickLookHandle = m_quickLookHandle.get()) {
+ if (quickLookHandle->didReceiveBuffer(buffer.get()))
+ return;
+ }
+#endif
+
+ didReceiveDataOrBuffer(nullptr, 0, WTFMove(buffer), encodedDataLength, dataPayloadType);
}
-void SubresourceLoader::didReceiveDataOrBuffer(const char* data, int length, PassRefPtr<SharedBuffer> prpBuffer, long long encodedDataLength, DataPayloadType dataPayloadType)
+void SubresourceLoader::didReceiveDataOrBuffer(const char* data, int length, RefPtr<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
{
if (m_resource->response().httpStatusCode() >= 400 && !m_resource->shouldIgnoreHTTPStatusCodeErrors())
return;
@@ -264,14 +387,13 @@ void SubresourceLoader::didReceiveDataOrBuffer(const char* data, int length, Pas
ASSERT(m_state == Initialized);
// Reference the object in this method since the additional processing can do
// anything including removing the last reference to this object; one example of this is 3266216.
- Ref<SubresourceLoader> protect(*this);
- RefPtr<SharedBuffer> buffer = prpBuffer;
-
- ResourceLoader::didReceiveDataOrBuffer(data, length, buffer, encodedDataLength, dataPayloadType);
+ Ref<SubresourceLoader> protectedThis(*this);
+
+ ResourceLoader::didReceiveDataOrBuffer(data, length, buffer.copyRef(), encodedDataLength, dataPayloadType);
if (!m_loadingMultipartContent) {
- if (ResourceBuffer* resourceData = this->resourceData())
- m_resource->addDataBuffer(resourceData);
+ if (auto* resourceData = this->resourceData())
+ m_resource->addDataBuffer(*resourceData);
else
m_resource->addData(buffer ? buffer->data() : data, buffer ? buffer->size() : length);
}
@@ -288,31 +410,151 @@ bool SubresourceLoader::checkForHTTPStatusCodeError()
return true;
}
+static void logResourceLoaded(Frame* frame, CachedResource::Type type)
+{
+ if (!frame || !frame->page())
+ return;
+
+ String resourceType;
+ switch (type) {
+ case CachedResource::MainResource:
+ resourceType = DiagnosticLoggingKeys::mainResourceKey();
+ break;
+ case CachedResource::ImageResource:
+ resourceType = DiagnosticLoggingKeys::imageKey();
+ break;
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+#endif
+ case CachedResource::CSSStyleSheet:
+ resourceType = DiagnosticLoggingKeys::styleSheetKey();
+ break;
+ case CachedResource::Script:
+ resourceType = DiagnosticLoggingKeys::scriptKey();
+ break;
+ case CachedResource::FontResource:
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
+ resourceType = DiagnosticLoggingKeys::fontKey();
+ break;
+ case CachedResource::MediaResource:
+ case CachedResource::RawResource:
+ resourceType = DiagnosticLoggingKeys::rawKey();
+ break;
+ case CachedResource::SVGDocumentResource:
+ resourceType = DiagnosticLoggingKeys::svgDocumentKey();
+ break;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ case CachedResource::LinkSubresource:
+#endif
+#if ENABLE(VIDEO_TRACK)
+ case CachedResource::TextTrackResource:
+#endif
+ resourceType = DiagnosticLoggingKeys::otherKey();
+ break;
+ }
+ frame->page()->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::resourceLoadedKey(), resourceType, ShouldSample::Yes);
+}
+
+bool SubresourceLoader::checkResponseCrossOriginAccessControl(const ResourceResponse& response, String& errorDescription)
+{
+ if (!m_resource->isCrossOrigin() || options().mode != FetchOptions::Mode::Cors)
+ return true;
+
+ ASSERT(m_origin);
+ return passesAccessControlCheck(response, options().allowCredentials, *m_origin, errorDescription);
+}
+
+bool SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse& redirectResponse, ResourceRequest& newRequest, String& errorMessage)
+{
+ bool crossOriginFlag = m_resource->isCrossOrigin();
+ bool isNextRequestCrossOrigin = m_origin && !m_origin->canRequest(newRequest.url());
+
+ if (isNextRequestCrossOrigin)
+ m_resource->setCrossOrigin();
+
+ ASSERT(options().mode != FetchOptions::Mode::SameOrigin || !m_resource->isCrossOrigin());
+
+ if (options().mode != FetchOptions::Mode::Cors)
+ return true;
+
+ // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 8 & 9.
+ if (m_resource->isCrossOrigin() && !isValidCrossOriginRedirectionURL(newRequest.url())) {
+ errorMessage = ASCIILiteral("URL is either a non-HTTP URL or contains credentials.");
+ return false;
+ }
+
+ ASSERT(m_origin);
+ if (crossOriginFlag && !passesAccessControlCheck(redirectResponse, options().allowCredentials, *m_origin, errorMessage))
+ return false;
+
+ bool redirectingToNewOrigin = false;
+ if (m_resource->isCrossOrigin()) {
+ if (!crossOriginFlag && isNextRequestCrossOrigin)
+ redirectingToNewOrigin = true;
+ else
+ redirectingToNewOrigin = !protocolHostAndPortAreEqual(previousRequest.url(), newRequest.url());
+ }
+
+ // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 10.
+ if (crossOriginFlag && redirectingToNewOrigin)
+ m_origin = SecurityOrigin::createUnique();
+
+ if (redirectingToNewOrigin) {
+ cleanRedirectedRequestForAccessControl(newRequest);
+ updateRequestForAccessControl(newRequest, *m_origin, options().allowCredentials);
+ }
+
+ return true;
+}
+
void SubresourceLoader::didFinishLoading(double finishTime)
{
+#if USE(QUICK_LOOK)
+ if (auto quickLookHandle = m_quickLookHandle.get()) {
+ if (quickLookHandle->didFinishLoading())
+ return;
+ }
+#endif
+
if (m_state != Initialized)
return;
ASSERT(!reachedTerminalState());
ASSERT(!m_resource->resourceToRevalidate());
- ASSERT(!m_resource->errorOccurred());
+ // FIXME (129394): We should cancel the load when a decode error occurs instead of continuing the load to completion.
+ ASSERT(!m_resource->errorOccurred() || m_resource->status() == CachedResource::DecodeError || !m_resource->isLoading());
LOG(ResourceLoading, "Received '%s'.", m_resource->url().string().latin1().data());
+ logResourceLoaded(m_frame.get(), m_resource->type());
- Ref<SubresourceLoader> protect(*this);
+ Ref<SubresourceLoader> protectedThis(*this);
+ CachedResourceHandle<CachedResource> protectResource(m_resource);
-#if PLATFORM(IOS)
- if (resourceData())
- resourceData()->setShouldUsePurgeableMemory(true);
+ // FIXME: <https://webkit.org/b/168351> [Resource Timing] Gather timing information with reliable responseEnd time
+ // The finishTime that is passed in is from the NetworkProcess and is more accurate.
+ // However, all other load times are generated from the web process or offsets.
+ // Mixing times from different processes can cause the finish time to be earlier than
+ // the response received time due to inter-process communication lag. This could be solved
+ // by gathering NetworkLoadTiming information at completion time instead of at
+ // didReceiveResponse time.
+ UNUSED_PARAM(finishTime);
+ MonotonicTime responseEndTime = MonotonicTime::now();
+ m_loadTiming.setResponseEnd(responseEndTime);
+
+#if ENABLE(WEB_TIMING)
+ reportResourceTiming();
#endif
- CachedResourceHandle<CachedResource> protectResource(m_resource);
+
m_state = Finishing;
- m_resource->setLoadFinishTime(finishTime);
+ m_resource->setLoadFinishTime(responseEndTime.secondsSinceEpoch().seconds()); // FIXME: Users of the loadFinishTime should use the LoadTiming struct instead.
m_resource->finishLoading(resourceData());
if (wasCancelled())
return;
m_resource->finish();
ASSERT(!reachedTerminalState());
- didFinishLoadingOnePart(finishTime);
+ didFinishLoadingOnePart(responseEndTime.secondsSinceEpoch().seconds());
notifyDone();
if (reachedTerminalState())
return;
@@ -321,19 +563,24 @@ void SubresourceLoader::didFinishLoading(double finishTime)
void SubresourceLoader::didFail(const ResourceError& error)
{
+#if USE(QUICK_LOOK)
+ if (auto quickLookHandle = m_quickLookHandle.get())
+ quickLookHandle->didFail();
+#endif
+
if (m_state != Initialized)
return;
ASSERT(!reachedTerminalState());
LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().string().latin1().data());
- Ref<SubresourceLoader> protect(*this);
+ Ref<SubresourceLoader> protectedThis(*this);
CachedResourceHandle<CachedResource> protectResource(m_resource);
m_state = Finishing;
if (m_resource->resourceToRevalidate())
- memoryCache()->revalidationFailed(m_resource);
+ MemoryCache::singleton().revalidationFailed(*m_resource);
m_resource->setResourceError(error);
if (!m_resource->isPreloaded())
- memoryCache()->remove(m_resource);
+ MemoryCache::singleton().remove(*m_resource);
m_resource->error(CachedResource::LoadError);
cleanupForError(error);
notifyDone();
@@ -356,16 +603,17 @@ void SubresourceLoader::willCancel(const ResourceError& error)
ASSERT(!reachedTerminalState());
LOG(ResourceLoading, "Cancelled load of '%s'.\n", m_resource->url().string().latin1().data());
- Ref<SubresourceLoader> protect(*this);
+ Ref<SubresourceLoader> protectedThis(*this);
#if PLATFORM(IOS)
m_state = m_state == Uninitialized ? CancelledWhileInitializing : Finishing;
#else
m_state = Finishing;
#endif
+ auto& memoryCache = MemoryCache::singleton();
if (m_resource->resourceToRevalidate())
- memoryCache()->revalidationFailed(m_resource);
+ memoryCache.revalidationFailed(*m_resource);
m_resource->setResourceError(error);
- memoryCache()->remove(m_resource);
+ memoryCache.remove(*m_resource);
}
void SubresourceLoader::didCancel(const ResourceError&)
@@ -377,16 +625,23 @@ void SubresourceLoader::didCancel(const ResourceError&)
notifyDone();
}
+void SubresourceLoader::didRetrieveDerivedDataFromCache(const String& type, SharedBuffer& buffer)
+{
+ if (m_state != Initialized)
+ return;
+ m_resource->didRetrieveDerivedDataFromCache(type, buffer);
+}
+
void SubresourceLoader::notifyDone()
{
if (reachedTerminalState())
return;
- m_requestCountTracker.clear();
+ m_requestCountTracker = std::nullopt;
#if PLATFORM(IOS)
- m_documentLoader->cachedResourceLoader().loadDone(m_resource, m_state != CancelledWhileInitializing);
+ m_documentLoader->cachedResourceLoader().loadDone(m_state != CancelledWhileInitializing);
#else
- m_documentLoader->cachedResourceLoader().loadDone(m_resource);
+ m_documentLoader->cachedResourceLoader().loadDone();
#endif
if (reachedTerminalState())
return;
@@ -402,8 +657,39 @@ void SubresourceLoader::releaseResources()
if (m_state != Uninitialized)
#endif
m_resource->clearLoader();
- m_resource = 0;
+ m_resource = nullptr;
ResourceLoader::releaseResources();
}
+#if ENABLE(WEB_TIMING)
+void SubresourceLoader::reportResourceTiming()
+{
+ if (!RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
+ return;
+
+ if (!ResourceTimingInformation::shouldAddResourceTiming(*m_resource))
+ return;
+
+ Document* document = m_documentLoader->cachedResourceLoader().document();
+ if (!document)
+ return;
+
+ SecurityOrigin& origin = m_origin ? *m_origin : document->securityOrigin();
+ ResourceTiming resourceTiming = ResourceTiming::fromLoad(*m_resource, m_resource->initiatorName(), m_loadTiming, origin);
+
+ // Worker resources loaded here are all CachedRawResources loaded through WorkerThreadableLoader.
+ // Pass the ResourceTiming information on so that WorkerThreadableLoader may add them to the
+ // Worker's Performance object.
+ if (options().initiatorContext == InitiatorContext::Worker) {
+ ASSERT(m_origin);
+ ASSERT(is<CachedRawResource>(m_resource));
+ downcast<CachedRawResource>(*m_resource).finishedTimingForWorkerLoad(WTFMove(resourceTiming));
+ return;
+ }
+
+ ASSERT(options().initiatorContext == InitiatorContext::Document);
+ m_documentLoader->cachedResourceLoader().resourceTimingInformation().addResourceTiming(*m_resource, *document, WTFMove(resourceTiming));
+}
+#endif
+
}
diff --git a/Source/WebCore/loader/SubresourceLoader.h b/Source/WebCore/loader/SubresourceLoader.h
index 58a7817bb..929bc563a 100644
--- a/Source/WebCore/loader/SubresourceLoader.h
+++ b/Source/WebCore/loader/SubresourceLoader.h
@@ -1,18 +1,18 @@
/*
- * Copyright (C) 2005, 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SubresourceLoader_h
-#define SubresourceLoader_h
+#pragma once
#include "FrameLoaderTypes.h"
#include "ResourceLoader.h"
@@ -39,57 +38,78 @@ namespace WebCore {
class CachedResource;
class CachedResourceLoader;
class Document;
-class PageActivityAssertionToken;
class ResourceRequest;
+class SecurityOrigin;
-class SubresourceLoader : public ResourceLoader {
+class SubresourceLoader final : public ResourceLoader {
public:
- static PassRefPtr<SubresourceLoader> create(Frame*, CachedResource*, const ResourceRequest&, const ResourceLoaderOptions&);
+ WEBCORE_EXPORT static RefPtr<SubresourceLoader> create(Frame&, CachedResource&, const ResourceRequest&, const ResourceLoaderOptions&);
virtual ~SubresourceLoader();
void cancelIfNotFinishing();
- virtual bool isSubresourceLoader() override;
+ bool isSubresourceLoader() override;
CachedResource* cachedResource();
+ SecurityOrigin* origin() { return m_origin.get(); }
#if PLATFORM(IOS)
- virtual bool startLoading() override;
+ bool startLoading() override;
// FIXME: What is an "iOS" original request? Why is it necessary?
- virtual const ResourceRequest& iOSOriginalRequest() const override { return m_iOSOriginalRequest; }
+ const ResourceRequest& iOSOriginalRequest() const override { return m_iOSOriginalRequest; }
#endif
-private:
- SubresourceLoader(Frame*, CachedResource*, const ResourceLoaderOptions&);
-
- virtual bool init(const ResourceRequest&) override;
+ unsigned redirectCount() const { return m_redirectCount; }
- virtual void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse) override;
- virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
- virtual void didReceiveResponse(const ResourceResponse&) override;
- virtual void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override;
- virtual void didReceiveBuffer(PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType) override;
- virtual void didFinishLoading(double finishTime) override;
- virtual void didFail(const ResourceError&) override;
- virtual void willCancel(const ResourceError&) override;
- virtual void didCancel(const ResourceError&) override;
+private:
+ SubresourceLoader(Frame&, CachedResource&, const ResourceLoaderOptions&);
+
+ bool init(const ResourceRequest&) override;
+
+ void willSendRequestInternal(ResourceRequest&, const ResourceResponse& redirectResponse) override;
+ void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ void didReceiveResponse(const ResourceResponse&) override;
+ void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override;
+ void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType) override;
+ void didFinishLoading(double finishTime) override;
+ void didFail(const ResourceError&) override;
+ void willCancel(const ResourceError&) override;
+ void didCancel(const ResourceError&) override;
+ void didRetrieveDerivedDataFromCache(const String& type, SharedBuffer&) override;
+
+#if PLATFORM(COCOA) && !USE(CFURLCONNECTION)
+ NSCachedURLResponse *willCacheResponse(ResourceHandle*, NSCachedURLResponse*) override;
+#endif
+#if PLATFORM(COCOA) && USE(CFURLCONNECTION)
+ CFCachedURLResponseRef willCacheResponse(ResourceHandle*, CFCachedURLResponseRef) override;
+#endif
#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
- virtual bool supportsDataArray() override { return true; }
- virtual void didReceiveDataArray(CFArrayRef) override;
+ bool supportsDataArray() override { return true; }
+ void didReceiveDataArray(CFArrayRef) override;
#endif
- virtual void releaseResources() override;
+ void releaseResources() override;
#if USE(SOUP)
- virtual char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize) override;
+ char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize) override;
#endif
bool checkForHTTPStatusCodeError();
+ bool checkResponseCrossOriginAccessControl(const ResourceResponse&, String&);
+ bool checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse&, ResourceRequest& newRequest, String&);
- void didReceiveDataOrBuffer(const char*, int, PassRefPtr<SharedBuffer>, long long encodedDataLength, DataPayloadType);
+ void didReceiveDataOrBuffer(const char*, int, RefPtr<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
void notifyDone();
+#if ENABLE(WEB_TIMING)
+ void reportResourceTiming();
+#endif
+
+#if USE(QUICK_LOOK)
+ bool shouldCreateQuickLookHandleForResponse(const ResourceResponse&) const;
+#endif
+
enum SubresourceLoaderState {
Uninitialized,
Initialized,
@@ -100,12 +120,15 @@ private:
};
class RequestCountTracker {
+#if !COMPILER(MSVC)
+ WTF_MAKE_FAST_ALLOCATED;
+#endif
public:
- RequestCountTracker(CachedResourceLoader*, CachedResource*);
+ RequestCountTracker(CachedResourceLoader&, const CachedResource&);
~RequestCountTracker();
private:
- CachedResourceLoader* m_cachedResourceLoader;
- CachedResource* m_resource;
+ CachedResourceLoader& m_cachedResourceLoader;
+ const CachedResource& m_resource;
};
#if PLATFORM(IOS)
@@ -114,9 +137,9 @@ private:
CachedResource* m_resource;
bool m_loadingMultipartContent;
SubresourceLoaderState m_state;
- OwnPtr<RequestCountTracker> m_requestCountTracker;
+ std::optional<RequestCountTracker> m_requestCountTracker;
+ RefPtr<SecurityOrigin> m_origin;
+ unsigned m_redirectCount { 0 };
};
}
-
-#endif // SubresourceLoader_h
diff --git a/Source/WebCore/loader/SubstituteData.h b/Source/WebCore/loader/SubstituteData.h
index 2959de7a8..f10135159 100644
--- a/Source/WebCore/loader/SubstituteData.h
+++ b/Source/WebCore/loader/SubstituteData.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,56 +23,48 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SubstituteData_h
-#define SubstituteData_h
+#pragma once
-#include "URL.h"
+#include "ResourceResponse.h"
#include "SharedBuffer.h"
-#include <wtf/PassRefPtr.h>
+#include "URL.h"
#include <wtf/RefPtr.h>
namespace WebCore {
class SubstituteData {
public:
+ enum class SessionHistoryVisibility {
+ Visible,
+ Hidden,
+ };
+
SubstituteData()
- : m_shouldRevealToSessionHistory(false)
{
}
- SubstituteData(PassRefPtr<SharedBuffer> content, const String& mimeType,
- const String& textEncoding, const URL& failingURL,
- const URL& responseURL = URL(), bool shouldRevealToSessionHistory = false)
- : m_content(content)
- , m_mimeType(mimeType)
- , m_textEncoding(textEncoding)
+ SubstituteData(RefPtr<SharedBuffer>&& content, const URL& failingURL, const ResourceResponse& response, SessionHistoryVisibility shouldRevealToSessionHistory)
+ : m_content(WTFMove(content))
, m_failingURL(failingURL)
- , m_responseURL(responseURL)
+ , m_response(response)
, m_shouldRevealToSessionHistory(shouldRevealToSessionHistory)
{
}
- static const bool ShouldRevealToSessionHistory = true;
-
- bool isValid() const { return m_content != 0; }
- bool shouldRevealToSessionHistory() const { return m_shouldRevealToSessionHistory; }
+ bool isValid() const { return m_content != nullptr; }
+ bool shouldRevealToSessionHistory() const { return m_shouldRevealToSessionHistory == SessionHistoryVisibility::Visible; }
const SharedBuffer* content() const { return m_content.get(); }
- const String& mimeType() const { return m_mimeType; }
- const String& textEncoding() const { return m_textEncoding; }
+ const String& mimeType() const { return m_response.mimeType(); }
+ const String& textEncoding() const { return m_response.textEncodingName(); }
const URL& failingURL() const { return m_failingURL; }
- const URL& responseURL() const { return m_responseURL; }
+ const ResourceResponse& response() const { return m_response; }
private:
RefPtr<SharedBuffer> m_content;
- String m_mimeType;
- String m_textEncoding;
URL m_failingURL;
- URL m_responseURL;
- bool m_shouldRevealToSessionHistory;
+ ResourceResponse m_response;
+ SessionHistoryVisibility m_shouldRevealToSessionHistory { SessionHistoryVisibility::Hidden };
};
-}
-
-#endif // SubstituteData_h
-
+} // namespace WebCore
diff --git a/Source/WebCore/loader/SubstituteResource.h b/Source/WebCore/loader/SubstituteResource.h
index 98c87a235..0e8dd35e2 100644
--- a/Source/WebCore/loader/SubstituteResource.h
+++ b/Source/WebCore/loader/SubstituteResource.h
@@ -23,17 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SubstituteResource_h
-#define SubstituteResource_h
+#pragma once
-#include <wtf/RefCounted.h>
-
-#include "URL.h"
+#include "ResourceLoader.h"
#include "ResourceResponse.h"
#include "SharedBuffer.h"
-#include <wtf/RefPtr.h>
-
namespace WebCore {
class SubstituteResource : public RefCounted<SubstituteResource> {
@@ -42,23 +37,22 @@ public:
const URL& url() const { return m_url; }
const ResourceResponse& response() const { return m_response; }
- SharedBuffer* data() const { return m_data.get(); }
+ SharedBuffer& data() const { return static_reference_cast<SharedBuffer>(m_data); }
+
+ virtual void deliver(ResourceLoader& loader) { loader.deliverResponseAndData(m_response, m_data->copy()); }
protected:
- SubstituteResource(const URL& url, const ResourceResponse& response, PassRefPtr<SharedBuffer> data)
+ SubstituteResource(const URL& url, const ResourceResponse& response, Ref<SharedBuffer>&& data)
: m_url(url)
, m_response(response)
- , m_data(data)
+ , m_data(WTFMove(data))
{
- ASSERT(m_data);
}
-
+
private:
URL m_url;
ResourceResponse m_response;
- RefPtr<SharedBuffer> m_data;
+ Ref<SharedBuffer> m_data;
};
-
-}
-#endif // SubstituteResource_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/TextResourceDecoder.cpp b/Source/WebCore/loader/TextResourceDecoder.cpp
index 5105ae0bb..fe94b7f81 100644
--- a/Source/WebCore/loader/TextResourceDecoder.cpp
+++ b/Source/WebCore/loader/TextResourceDecoder.cpp
@@ -23,9 +23,9 @@
#include "config.h"
#include "TextResourceDecoder.h"
-#include "DOMImplementation.h"
#include "HTMLMetaCharsetParser.h"
#include "HTMLNames.h"
+#include "MIMETypeRegistry.h"
#include "TextCodec.h"
#include "TextEncoding.h"
#include "TextEncodingDetector.h"
@@ -302,11 +302,11 @@ breakBreak:
TextResourceDecoder::ContentType TextResourceDecoder::determineContentType(const String& mimeType)
{
- if (equalIgnoringCase(mimeType, "text/css"))
+ if (equalLettersIgnoringASCIICase(mimeType, "text/css"))
return CSS;
- if (equalIgnoringCase(mimeType, "text/html"))
+ if (equalLettersIgnoringASCIICase(mimeType, "text/html"))
return HTML;
- if (DOMImplementation::isXMLMIMEType(mimeType))
+ if (MIMETypeRegistry::isXMLMIMEType(mimeType))
return XML;
return PlainText;
}
@@ -326,7 +326,7 @@ TextResourceDecoder::TextResourceDecoder(const String& mimeType, const TextEncod
: m_contentType(determineContentType(mimeType))
, m_encoding(defaultEncoding(m_contentType, specifiedDefaultEncoding))
, m_source(DefaultEncoding)
- , m_hintEncoding(0)
+ , m_hintEncoding(nullptr)
, m_checkedForBOM(false)
, m_checkedForCSSCharset(false)
, m_checkedForHeadCharset(false)
@@ -355,10 +355,15 @@ void TextResourceDecoder::setEncoding(const TextEncoding& encoding, EncodingSour
else
m_encoding = encoding;
- m_codec.clear();
+ m_codec = nullptr;
m_source = source;
}
+bool TextResourceDecoder::hasEqualEncodingForCharset(const String& charset) const
+{
+ return defaultEncoding(m_contentType, charset) == m_encoding;
+}
+
// Returns the position of the encoding string.
static int findXMLEncoding(const char* str, int len, int& encodingLength)
{
@@ -475,6 +480,8 @@ bool TextResourceDecoder::checkForCSSCharset(const char* data, size_t len, bool&
int encodingNameLength = pos - dataStart;
++pos;
+ if (pos == dataEnd)
+ return false;
if (*pos == ';')
setEncoding(findTextEncoding(dataStart, encodingNameLength), EncodingFromCSSCharset);
@@ -658,9 +665,15 @@ String TextResourceDecoder::flush()
String result = m_codec->decode(m_buffer.data(), m_buffer.size(), true, m_contentType == XML && !m_useLenientXMLDecoding, m_sawError);
m_buffer.clear();
- m_codec.clear();
+ m_codec = nullptr;
m_checkedForBOM = false; // Skip BOM again when re-decoding.
return result;
}
+String TextResourceDecoder::decodeAndFlush(const char* data, size_t length)
+{
+ String decoded = decode(data, length);
+ return decoded + flush();
+}
+
}
diff --git a/Source/WebCore/loader/TextResourceDecoder.h b/Source/WebCore/loader/TextResourceDecoder.h
index e51f1f7a8..98ec9257a 100644
--- a/Source/WebCore/loader/TextResourceDecoder.h
+++ b/Source/WebCore/loader/TextResourceDecoder.h
@@ -20,8 +20,7 @@
*/
-#ifndef TextResourceDecoder_h
-#define TextResourceDecoder_h
+#pragma once
#include "TextEncoding.h"
#include <wtf/RefCounted.h>
@@ -43,17 +42,21 @@ public:
EncodingFromParentFrame
};
- static PassRefPtr<TextResourceDecoder> create(const String& mimeType, const TextEncoding& defaultEncoding = TextEncoding(), bool usesEncodingDetector = false)
+ static Ref<TextResourceDecoder> create(const String& mimeType, const TextEncoding& defaultEncoding = TextEncoding(), bool usesEncodingDetector = false)
{
- return adoptRef(new TextResourceDecoder(mimeType, defaultEncoding, usesEncodingDetector));
+ return adoptRef(*new TextResourceDecoder(mimeType, defaultEncoding, usesEncodingDetector));
}
- ~TextResourceDecoder();
+ WEBCORE_EXPORT ~TextResourceDecoder();
void setEncoding(const TextEncoding&, EncodingSource);
const TextEncoding& encoding() const { return m_encoding; }
- String decode(const char* data, size_t length);
- String flush();
+ bool hasEqualEncodingForCharset(const String&) const;
+
+ WEBCORE_EXPORT String decode(const char* data, size_t length);
+ WEBCORE_EXPORT String flush();
+
+ WEBCORE_EXPORT String decodeAndFlush(const char* data, size_t length);
void setHintEncoding(const TextResourceDecoder* hintDecoder)
{
@@ -67,7 +70,7 @@ public:
bool sawError() const { return m_sawError; }
private:
- TextResourceDecoder(const String& mimeType, const TextEncoding& defaultEncoding, bool usesEncodingDetector);
+ WEBCORE_EXPORT TextResourceDecoder(const String& mimeType, const TextEncoding& defaultEncoding, bool usesEncodingDetector);
enum ContentType { PlainText, HTML, XML, CSS }; // PlainText only checks for BOM.
static ContentType determineContentType(const String& mimeType);
@@ -82,7 +85,7 @@ private:
ContentType m_contentType;
TextEncoding m_encoding;
- OwnPtr<TextCodec> m_codec;
+ std::unique_ptr<TextCodec> m_codec;
EncodingSource m_source;
const char* m_hintEncoding;
Vector<char> m_buffer;
@@ -96,6 +99,4 @@ private:
std::unique_ptr<HTMLMetaCharsetParser> m_charsetParser;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/TextTrackLoader.cpp b/Source/WebCore/loader/TextTrackLoader.cpp
index 35d788cfb..866096875 100644
--- a/Source/WebCore/loader/TextTrackLoader.cpp
+++ b/Source/WebCore/loader/TextTrackLoader.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -35,10 +36,8 @@
#include "CrossOriginAccessControl.h"
#include "Document.h"
#include "Logging.h"
-#include "ResourceBuffer.h"
-#include "ScriptCallStack.h"
-#include "SecurityOrigin.h"
-#include "TextTrackCue.h"
+#include "SharedBuffer.h"
+#include "VTTCue.h"
#include "WebVTTParser.h"
namespace WebCore {
@@ -46,7 +45,7 @@ namespace WebCore {
TextTrackLoader::TextTrackLoader(TextTrackLoaderClient& client, ScriptExecutionContext* context)
: m_client(client)
, m_scriptExecutionContext(context)
- , m_cueLoadTimer(this, &TextTrackLoader::cueLoadTimerFired)
+ , m_cueLoadTimer(*this, &TextTrackLoader::cueLoadTimerFired)
, m_state(Idle)
, m_parseOffset(0)
, m_newCuesAvailable(false)
@@ -56,13 +55,11 @@ TextTrackLoader::TextTrackLoader(TextTrackLoaderClient& client, ScriptExecutionC
TextTrackLoader::~TextTrackLoader()
{
if (m_resource)
- m_resource->removeClient(this);
+ m_resource->removeClient(*this);
}
-void TextTrackLoader::cueLoadTimerFired(Timer<TextTrackLoader>* timer)
+void TextTrackLoader::cueLoadTimerFired()
{
- ASSERT_UNUSED(timer, timer == &m_cueLoadTimer);
-
if (m_newCuesAvailable) {
m_newCuesAvailable = false;
m_client.newCuesAvailable(this);
@@ -75,24 +72,24 @@ void TextTrackLoader::cueLoadTimerFired(Timer<TextTrackLoader>* timer)
void TextTrackLoader::cancelLoad()
{
if (m_resource) {
- m_resource->removeClient(this);
+ m_resource->removeClient(*this);
m_resource = nullptr;
}
}
-void TextTrackLoader::processNewCueData(CachedResource* resource)
+void TextTrackLoader::processNewCueData(CachedResource& resource)
{
- ASSERT(m_resource == resource);
-
- if (m_state == Failed || !resource->resourceBuffer())
+ ASSERT_UNUSED(resource, m_resource == &resource);
+
+ if (m_state == Failed || !m_resource->resourceBuffer())
return;
-
- ResourceBuffer* buffer = resource->resourceBuffer();
+
+ auto* buffer = m_resource->resourceBuffer();
if (m_parseOffset == buffer->size())
return;
if (!m_cueParser)
- m_cueParser = WebVTTParser::create(this, m_scriptExecutionContext);
+ m_cueParser = std::make_unique<WebVTTParser>(static_cast<WebVTTParserClient*>(this), m_scriptExecutionContext);
const char* data;
unsigned length;
@@ -104,77 +101,67 @@ void TextTrackLoader::processNewCueData(CachedResource* resource)
}
// FIXME: This is a very unusual pattern, no other CachedResourceClient does this. Refactor to use notifyFinished() instead.
-void TextTrackLoader::deprecatedDidReceiveCachedResource(CachedResource* resource)
+void TextTrackLoader::deprecatedDidReceiveCachedResource(CachedResource& resource)
{
- ASSERT(m_resource == resource);
-
- if (!resource->resourceBuffer())
+ ASSERT_UNUSED(resource, m_resource == &resource);
+
+ if (!m_resource->resourceBuffer())
return;
-
- processNewCueData(resource);
+
+ processNewCueData(*m_resource);
}
void TextTrackLoader::corsPolicyPreventedLoad()
{
- DEFINE_STATIC_LOCAL(String, consoleMessage, (ASCIILiteral("Cross-origin text track load denied by Cross-Origin Resource Sharing policy.")));
- Document* document = toDocument(m_scriptExecutionContext);
- document->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, consoleMessage);
+ static NeverDestroyed<String> consoleMessage(ASCIILiteral("Cross-origin text track load denied by Cross-Origin Resource Sharing policy."));
+ Document* document = downcast<Document>(m_scriptExecutionContext);
+ document->addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
m_state = Failed;
}
-void TextTrackLoader::notifyFinished(CachedResource* resource)
+void TextTrackLoader::notifyFinished(CachedResource& resource)
{
- ASSERT(m_resource == resource);
-
- Document* document = toDocument(m_scriptExecutionContext);
- if (!m_crossOriginMode.isNull()
- && !document->securityOrigin()->canRequest(resource->response().url())
- && !resource->passesAccessControlCheck(document->securityOrigin())) {
+ ASSERT_UNUSED(resource, m_resource == &resource);
+ if (m_resource->resourceError().isAccessControl())
corsPolicyPreventedLoad();
- }
if (m_state != Failed) {
- processNewCueData(resource);
+ processNewCueData(*m_resource);
if (m_cueParser)
m_cueParser->fileFinished();
if (m_state != Failed)
- m_state = resource->errorOccurred() ? Failed : Finished;
+ m_state = m_resource->errorOccurred() ? Failed : Finished;
}
+ if (m_state == Finished && m_cueParser)
+ m_cueParser->flush();
+
if (!m_cueLoadTimer.isActive())
m_cueLoadTimer.startOneShot(0);
-
+
cancelLoad();
}
-bool TextTrackLoader::load(const URL& url, const String& crossOriginMode)
+bool TextTrackLoader::load(const URL& url, const String& crossOriginMode, bool isInitiatingElementInUserAgentShadowTree)
{
cancelLoad();
- ASSERT(m_scriptExecutionContext->isDocument());
- Document* document = toDocument(m_scriptExecutionContext);
- CachedResourceRequest cueRequest(ResourceRequest(document->completeURL(url)));
-
- if (!crossOriginMode.isNull()) {
- m_crossOriginMode = crossOriginMode;
- StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
- updateRequestForAccessControl(cueRequest.mutableResourceRequest(), document->securityOrigin(), allowCredentials);
- } else {
- // Cross-origin resources that are not suitably CORS-enabled may not load.
- if (!document->securityOrigin()->canRequest(url)) {
- corsPolicyPreventedLoad();
- return false;
- }
- }
+ ASSERT(is<Document>(m_scriptExecutionContext));
+ Document* document = downcast<Document>(m_scriptExecutionContext);
- CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader();
- m_resource = cachedResourceLoader->requestTextTrack(cueRequest);
+ ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
+ options.contentSecurityPolicyImposition = isInitiatingElementInUserAgentShadowTree ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck;
+
+ CachedResourceRequest cueRequest(ResourceRequest(document->completeURL(url)), options);
+ cueRequest.setAsPotentiallyCrossOrigin(crossOriginMode, *document);
+
+ m_resource = document->cachedResourceLoader().requestTextTrack(WTFMove(cueRequest));
if (!m_resource)
return false;
- m_resource->addClient(this);
-
+ m_resource->addClient(*this);
+
return true;
}
@@ -187,12 +174,10 @@ void TextTrackLoader::newCuesParsed()
m_cueLoadTimer.startOneShot(0);
}
-#if ENABLE(WEBVTT_REGIONS)
void TextTrackLoader::newRegionsParsed()
{
m_client.newRegionsAvailable(this);
}
-#endif
void TextTrackLoader::fileFailedToParse()
{
@@ -212,24 +197,19 @@ void TextTrackLoader::getNewCues(Vector<RefPtr<TextTrackCue>>& outputCues)
if (m_cueParser) {
Vector<RefPtr<WebVTTCueData>> newCues;
m_cueParser->getNewCues(newCues);
- for (size_t i = 0; i < newCues.size(); ++i) {
- RefPtr<WebVTTCueData> data = newCues[i];
- RefPtr<TextTrackCue> cue = TextTrackCue::create(*m_scriptExecutionContext, data->startTime(), data->endTime(), data->content());
- cue->setId(data->id());
- cue->setCueSettings(data->settings());
- outputCues.append(cue);
- }
+
+ for (auto& cueData : newCues)
+ outputCues.append(VTTCue::create(*m_scriptExecutionContext, *cueData));
}
}
-#if ENABLE(WEBVTT_REGIONS)
-void TextTrackLoader::getNewRegions(Vector<RefPtr<TextTrackRegion>>& outputRegions)
+void TextTrackLoader::getNewRegions(Vector<RefPtr<VTTRegion>>& outputRegions)
{
ASSERT(m_cueParser);
if (m_cueParser)
m_cueParser->getNewRegions(outputRegions);
}
-#endif
+
}
#endif
diff --git a/Source/WebCore/loader/TextTrackLoader.h b/Source/WebCore/loader/TextTrackLoader.h
index cd62ca2f7..337c8e131 100644
--- a/Source/WebCore/loader/TextTrackLoader.h
+++ b/Source/WebCore/loader/TextTrackLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextTrackLoader_h
-#define TextTrackLoader_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
@@ -32,7 +31,7 @@
#include "CachedResourceHandle.h"
#include "Timer.h"
#include "WebVTTParser.h"
-#include <wtf/OwnPtr.h>
+#include <memory>
namespace WebCore {
@@ -47,54 +46,42 @@ public:
virtual void newCuesAvailable(TextTrackLoader*) = 0;
virtual void cueLoadingCompleted(TextTrackLoader*, bool loadingFailed) = 0;
-#if ENABLE(WEBVTT_REGIONS)
virtual void newRegionsAvailable(TextTrackLoader*) = 0;
-#endif
};
class TextTrackLoader : public CachedResourceClient, private WebVTTParserClient {
WTF_MAKE_NONCOPYABLE(TextTrackLoader);
WTF_MAKE_FAST_ALLOCATED;
public:
- static PassOwnPtr<TextTrackLoader> create(TextTrackLoaderClient& client, ScriptExecutionContext* context)
- {
- return adoptPtr(new TextTrackLoader(client, context));
- }
+ TextTrackLoader(TextTrackLoaderClient&, ScriptExecutionContext*);
virtual ~TextTrackLoader();
- bool load(const URL&, const String& crossOriginMode);
+ bool load(const URL&, const String& crossOriginMode, bool isInitiatingElementInUserAgentShadowTree);
void cancelLoad();
void getNewCues(Vector<RefPtr<TextTrackCue>>& outputCues);
-#if ENABLE(WEBVTT_REGIONS)
- void getNewRegions(Vector<RefPtr<TextTrackRegion>>& outputRegions);
-#endif
+ void getNewRegions(Vector<RefPtr<VTTRegion>>& outputRegions);
private:
// CachedResourceClient
- virtual void notifyFinished(CachedResource*);
- virtual void deprecatedDidReceiveCachedResource(CachedResource*);
-
+ void notifyFinished(CachedResource&) override;
+ void deprecatedDidReceiveCachedResource(CachedResource&) override;
+
// WebVTTParserClient
- virtual void newCuesParsed();
-#if ENABLE(WEBVTT_REGIONS)
- virtual void newRegionsParsed();
-#endif
- virtual void fileFailedToParse();
-
- TextTrackLoader(TextTrackLoaderClient&, ScriptExecutionContext*);
-
- void processNewCueData(CachedResource*);
- void cueLoadTimerFired(Timer<TextTrackLoader>*);
+ void newCuesParsed() override;
+ void newRegionsParsed() override;
+ void fileFailedToParse() override;
+
+ void processNewCueData(CachedResource&);
+ void cueLoadTimerFired();
void corsPolicyPreventedLoad();
enum State { Idle, Loading, Finished, Failed };
-
+
TextTrackLoaderClient& m_client;
- OwnPtr<WebVTTParser> m_cueParser;
+ std::unique_ptr<WebVTTParser> m_cueParser;
CachedResourceHandle<CachedTextTrack> m_resource;
ScriptExecutionContext* m_scriptExecutionContext;
- Timer<TextTrackLoader> m_cueLoadTimer;
- String m_crossOriginMode;
+ Timer m_cueLoadTimer;
State m_state;
unsigned m_parseOffset;
bool m_newCuesAvailable;
@@ -102,5 +89,4 @@ private:
} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/loader/ThreadableLoader.cpp b/Source/WebCore/loader/ThreadableLoader.cpp
index 8a3a98576..a316da496 100644
--- a/Source/WebCore/loader/ThreadableLoader.cpp
+++ b/Source/WebCore/loader/ThreadableLoader.cpp
@@ -31,10 +31,11 @@
#include "config.h"
#include "ThreadableLoader.h"
+#include "CachedResourceRequestInitiators.h"
#include "Document.h"
#include "DocumentThreadableLoader.h"
+#include "ResourceError.h"
#include "ScriptExecutionContext.h"
-#include "SecurityOrigin.h"
#include "WorkerGlobalScope.h"
#include "WorkerRunLoop.h"
#include "WorkerThreadableLoader.h"
@@ -42,36 +43,75 @@
namespace WebCore {
ThreadableLoaderOptions::ThreadableLoaderOptions()
- : preflightPolicy(ConsiderPreflight)
- , crossOriginRequestPolicy(DenyCrossOriginRequests)
{
+ mode = FetchOptions::Mode::SameOrigin;
}
ThreadableLoaderOptions::~ThreadableLoaderOptions()
{
}
-PassRefPtr<ThreadableLoader> ThreadableLoader::create(ScriptExecutionContext* context, ThreadableLoaderClient* client, const ResourceRequest& request, const ThreadableLoaderOptions& options)
+ThreadableLoaderOptions::ThreadableLoaderOptions(const ResourceLoaderOptions& baseOptions, PreflightPolicy preflightPolicy, ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement, String&& initiator, ResponseFilteringPolicy filteringPolicy)
+ : ResourceLoaderOptions(baseOptions)
+ , preflightPolicy(preflightPolicy)
+ , contentSecurityPolicyEnforcement(contentSecurityPolicyEnforcement)
+ , initiator(WTFMove(initiator))
+ , filteringPolicy(filteringPolicy)
{
- ASSERT(client);
- ASSERT(context);
+}
+
+RefPtr<ThreadableLoader> ThreadableLoader::create(ScriptExecutionContext& context, ThreadableLoaderClient& client, ResourceRequest&& request, const ThreadableLoaderOptions& options, String&& referrer)
+{
+ if (is<WorkerGlobalScope>(context))
+ return WorkerThreadableLoader::create(downcast<WorkerGlobalScope>(context), client, WorkerRunLoop::defaultMode(), WTFMove(request), options, referrer);
- if (context->isWorkerGlobalScope())
- return WorkerThreadableLoader::create(static_cast<WorkerGlobalScope*>(context), client, WorkerRunLoop::defaultMode(), request, options);
+ return DocumentThreadableLoader::create(downcast<Document>(context), client, WTFMove(request), options, WTFMove(referrer));
+}
- return DocumentThreadableLoader::create(toDocument(context), client, request, options);
+void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext& context, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
+{
+ if (is<WorkerGlobalScope>(context))
+ WorkerThreadableLoader::loadResourceSynchronously(downcast<WorkerGlobalScope>(context), WTFMove(request), client, options);
+ else
+ DocumentThreadableLoader::loadResourceSynchronously(downcast<Document>(context), WTFMove(request), client, options);
+ context.didLoadResourceSynchronously();
}
-void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext* context, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
+void ThreadableLoader::logError(ScriptExecutionContext& context, const ResourceError& error, const String& initiator)
{
- ASSERT(context);
+ // FIXME: extend centralized logging to other clients than fetch, at least XHR and EventSource.
+ if (initiator != cachedResourceRequestInitiators().fetch)
+ return;
- if (context->isWorkerGlobalScope()) {
- WorkerThreadableLoader::loadResourceSynchronously(static_cast<WorkerGlobalScope*>(context), request, client, options);
+ if (error.isCancellation())
return;
+
+ // FIXME: Some errors are returned with null URLs. This leads to poor console messages. We should do better for these errors.
+ if (error.failingURL().isNull())
+ return;
+
+ // We further reduce logging to some errors.
+ // FIXME: Log more errors when making so do not make some layout tests flaky.
+ if (error.domain() != errorDomainWebKitInternal && !error.isAccessControl())
+ return;
+
+ const char* messageStart;
+ if (initiator == cachedResourceRequestInitiators().fetch)
+ messageStart = "Fetch API cannot load ";
+ else
+ messageStart = "Cannot load ";
+
+ const char* messageMiddle = ". ";
+ String description = error.localizedDescription();
+ if (description.isEmpty()) {
+ // FIXME: We should probably define default description error message for all error types.
+ if (error.isAccessControl())
+ messageMiddle = ASCIILiteral(" due to access control checks.");
+ else
+ messageMiddle = ".";
}
- DocumentThreadableLoader::loadResourceSynchronously(toDocument(context), request, client, options);
+ context.addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString(messageStart, error.failingURL().string(), messageMiddle, description));
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/ThreadableLoader.h b/Source/WebCore/loader/ThreadableLoader.h
index 0c9a0f253..e924b240a 100644
--- a/Source/WebCore/loader/ThreadableLoader.h
+++ b/Source/WebCore/loader/ThreadableLoader.h
@@ -28,18 +28,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ThreadableLoader_h
-#define ThreadableLoader_h
+#pragma once
#include "ResourceLoaderOptions.h"
#include <wtf/Noncopyable.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
-
-#if ENABLE(RESOURCE_TIMING)
#include <wtf/text/AtomicString.h>
-#endif
namespace WebCore {
@@ -47,14 +41,7 @@ namespace WebCore {
class ResourceRequest;
class ResourceResponse;
class ScriptExecutionContext;
- class SecurityOrigin;
class ThreadableLoaderClient;
-
- enum CrossOriginRequestPolicy {
- DenyCrossOriginRequests,
- UseAccessControl,
- AllowCrossOriginRequests
- };
enum PreflightPolicy {
ConsiderPreflight,
@@ -62,30 +49,43 @@ namespace WebCore {
PreventPreflight
};
- struct ThreadableLoaderOptions : public ResourceLoaderOptions {
+ enum class ContentSecurityPolicyEnforcement {
+ DoNotEnforce,
+ EnforceChildSrcDirective,
+ EnforceConnectSrcDirective,
+ EnforceScriptSrcDirective,
+ };
+
+ enum class ResponseFilteringPolicy {
+ Enable,
+ Disable,
+ };
+
+ struct ThreadableLoaderOptions : ResourceLoaderOptions {
ThreadableLoaderOptions();
+ ThreadableLoaderOptions(const ResourceLoaderOptions&, PreflightPolicy, ContentSecurityPolicyEnforcement, String&& initiator, ResponseFilteringPolicy);
~ThreadableLoaderOptions();
- PreflightPolicy preflightPolicy; // If AccessControl is used, how to determine if a preflight is needed.
- CrossOriginRequestPolicy crossOriginRequestPolicy;
- RefPtr<SecurityOrigin> securityOrigin;
-#if ENABLE(RESOURCE_TIMING)
- AtomicString initiator;
-#endif
+ PreflightPolicy preflightPolicy { ConsiderPreflight };
+ ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement { ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective };
+ String initiator; // This cannot be an AtomicString, as isolatedCopy() wouldn't create an object that's safe for passing to another thread.
+ ResponseFilteringPolicy filteringPolicy { ResponseFilteringPolicy::Disable };
};
- // Useful for doing loader operations from any thread (not threadsafe,
+ // Useful for doing loader operations from any thread (not threadsafe,
// just able to run on threads other than the main thread).
class ThreadableLoader {
WTF_MAKE_NONCOPYABLE(ThreadableLoader);
public:
- static void loadResourceSynchronously(ScriptExecutionContext*, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&);
- static PassRefPtr<ThreadableLoader> create(ScriptExecutionContext*, ThreadableLoaderClient*, const ResourceRequest&, const ThreadableLoaderOptions&);
+ static void loadResourceSynchronously(ScriptExecutionContext&, ResourceRequest&&, ThreadableLoaderClient&, const ThreadableLoaderOptions&);
+ static RefPtr<ThreadableLoader> create(ScriptExecutionContext&, ThreadableLoaderClient&, ResourceRequest&&, const ThreadableLoaderOptions&, String&& referrer = String());
virtual void cancel() = 0;
void ref() { refThreadableLoader(); }
void deref() { derefThreadableLoader(); }
+ static void logError(ScriptExecutionContext&, const ResourceError&, const String&);
+
protected:
ThreadableLoader() { }
virtual ~ThreadableLoader() { }
@@ -94,5 +94,3 @@ namespace WebCore {
};
} // namespace WebCore
-
-#endif // ThreadableLoader_h
diff --git a/Source/WebCore/loader/ThreadableLoaderClient.h b/Source/WebCore/loader/ThreadableLoaderClient.h
index e8936528d..a51c3883d 100644
--- a/Source/WebCore/loader/ThreadableLoaderClient.h
+++ b/Source/WebCore/loader/ThreadableLoaderClient.h
@@ -28,14 +28,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ThreadableLoaderClient_h
-#define ThreadableLoaderClient_h
-
+#pragma once
namespace WebCore {
class ResourceError;
class ResourceResponse;
+ class ResourceTiming;
class ThreadableLoaderClient {
WTF_MAKE_NONCOPYABLE(ThreadableLoaderClient); WTF_MAKE_FAST_ALLOCATED;
@@ -46,10 +45,10 @@ namespace WebCore {
virtual void didReceiveData(const char*, int /*dataLength*/) { }
virtual void didFinishLoading(unsigned long /*identifier*/, double /*finishTime*/) { }
virtual void didFail(const ResourceError&) { }
- virtual void didFailAccessControlCheck(const ResourceError& error) { didFail(error); }
- virtual void didFailRedirectCheck() { }
- virtual bool isDocumentThreadableLoaderClient() { return false; }
+#if ENABLE(WEB_TIMING)
+ virtual void didFinishTiming(const ResourceTiming&) { }
+#endif
protected:
ThreadableLoaderClient() { }
@@ -57,5 +56,3 @@ namespace WebCore {
};
} // namespace WebCore
-
-#endif // ThreadableLoaderClient_h
diff --git a/Source/WebCore/loader/ThreadableLoaderClientWrapper.h b/Source/WebCore/loader/ThreadableLoaderClientWrapper.h
index 715c5aa64..602b2f295 100644
--- a/Source/WebCore/loader/ThreadableLoaderClientWrapper.h
+++ b/Source/WebCore/loader/ThreadableLoaderClientWrapper.h
@@ -28,27 +28,26 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ThreadableLoaderClientWrapper_h
-#define ThreadableLoaderClientWrapper_h
+#pragma once
#include "ThreadableLoaderClient.h"
#include <wtf/Noncopyable.h>
-#include <wtf/PassRefPtr.h>
+#include <wtf/Ref.h>
#include <wtf/Threading.h>
namespace WebCore {
class ThreadableLoaderClientWrapper : public ThreadSafeRefCounted<ThreadableLoaderClientWrapper> {
public:
- static PassRefPtr<ThreadableLoaderClientWrapper> create(ThreadableLoaderClient* client)
+ static Ref<ThreadableLoaderClientWrapper> create(ThreadableLoaderClient& client, const String& initiator)
{
- return adoptRef(new ThreadableLoaderClientWrapper(client));
+ return adoptRef(*new ThreadableLoaderClientWrapper(client, initiator));
}
void clearClient()
{
m_done = true;
- m_client = 0;
+ m_client = nullptr;
}
bool done() const
@@ -88,37 +87,26 @@ public:
m_client->didFail(error);
}
- void didFailAccessControlCheck(const ResourceError& error)
- {
- m_done = true;
- if (m_client)
- m_client->didFailAccessControlCheck(error);
- }
-
- void didFailRedirectCheck()
- {
- m_done = true;
- if (m_client)
- m_client->didFailRedirectCheck();
- }
-
void didReceiveAuthenticationCancellation(unsigned long identifier, const ResourceResponse& response)
{
if (m_client)
m_client->didReceiveResponse(identifier, response);
}
+ const String& initiator() const { return m_initiator; }
+
protected:
- explicit ThreadableLoaderClientWrapper(ThreadableLoaderClient* client)
- : m_client(client)
- , m_done(false)
- {
- }
+ explicit ThreadableLoaderClientWrapper(ThreadableLoaderClient&, const String&);
ThreadableLoaderClient* m_client;
- bool m_done;
+ String m_initiator;
+ bool m_done { false };
};
-} // namespace WebCore
+inline ThreadableLoaderClientWrapper::ThreadableLoaderClientWrapper(ThreadableLoaderClient& client, const String& initiator)
+ : m_client(&client)
+ , m_initiator(initiator)
+{
+}
-#endif // ThreadableLoaderClientWrapper_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/WorkerThreadableLoader.cpp b/Source/WebCore/loader/WorkerThreadableLoader.cpp
index d10ef7ed2..31ea9bb83 100644
--- a/Source/WebCore/loader/WorkerThreadableLoader.cpp
+++ b/Source/WebCore/loader/WorkerThreadableLoader.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,29 +32,30 @@
#include "config.h"
#include "WorkerThreadableLoader.h"
+#include "ContentSecurityPolicy.h"
#include "Document.h"
#include "DocumentThreadableLoader.h"
-#include "CrossThreadTask.h"
+#include "Performance.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "ResourceTiming.h"
#include "SecurityOrigin.h"
#include "ThreadableLoader.h"
#include "WorkerGlobalScope.h"
#include "WorkerLoaderProxy.h"
#include "WorkerThread.h"
#include <wtf/MainThread.h>
-#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
namespace WebCore {
static const char loadResourceSynchronouslyMode[] = "loadResourceSynchronouslyMode";
-WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope* workerGlobalScope, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, const ThreadableLoaderOptions& options)
+WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalScope, ThreadableLoaderClient& client, const String& taskMode, ResourceRequest&& request, const ThreadableLoaderOptions& options, const String& referrer)
: m_workerGlobalScope(workerGlobalScope)
- , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client))
- , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerGlobalScope->thread()->workerLoaderProxy(), taskMode, request, options, workerGlobalScope->url().strippedForUseAsReferrer())))
+ , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client, options.initiator))
+ , m_bridge(*new MainThreadBridge(m_workerClientWrapper.get(), workerGlobalScope.thread().workerLoaderProxy(), taskMode, WTFMove(request), options, referrer.isEmpty() ? workerGlobalScope.url().strippedForUseAsReferrer() : referrer, workerGlobalScope.securityOrigin(), workerGlobalScope.contentSecurityPolicy()))
{
}
@@ -62,18 +64,18 @@ WorkerThreadableLoader::~WorkerThreadableLoader()
m_bridge.destroy();
}
-void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope* workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
+void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
{
- WorkerRunLoop& runLoop = workerGlobalScope->thread()->runLoop();
+ WorkerRunLoop& runLoop = workerGlobalScope.thread().runLoop();
// Create a unique mode just for this synchronous resource load.
String mode = loadResourceSynchronouslyMode;
mode.append(String::number(runLoop.createUniqueId()));
- RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, &client, mode, request, options);
+ RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, client, mode, WTFMove(request), options, String());
MessageQueueWaitResult result = MessageQueueMessageReceived;
while (!loader->done() && result != MessageQueueTerminated)
- result = runLoop.runInMode(workerGlobalScope, mode);
+ result = runLoop.runInMode(&workerGlobalScope, mode);
if (!loader->done() && result == MessageQueueTerminated)
loader->cancel();
@@ -84,41 +86,51 @@ void WorkerThreadableLoader::cancel()
m_bridge.cancel();
}
-WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode,
- const ResourceRequest& request, const ThreadableLoaderOptions& options, const String& outgoingReferrer)
- : m_workerClientWrapper(workerClientWrapper)
- , m_loaderProxy(loaderProxy)
- , m_taskMode(taskMode.isolatedCopy())
-{
- ASSERT(m_workerClientWrapper.get());
- m_loaderProxy.postTaskToLoader(
- createCallbackTask(&MainThreadBridge::mainThreadCreateLoader,
- AllowCrossThreadAccess(this), request, options, outgoingReferrer));
-}
+struct LoaderTaskOptions {
+ LoaderTaskOptions(const ThreadableLoaderOptions&, const String&, Ref<SecurityOrigin>&&);
+ ThreadableLoaderOptions options;
+ String referrer;
+ Ref<SecurityOrigin> origin;
+};
-WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge()
+LoaderTaskOptions::LoaderTaskOptions(const ThreadableLoaderOptions& options, const String& referrer, Ref<SecurityOrigin>&& origin)
+ : options(options, options.preflightPolicy, options.contentSecurityPolicyEnforcement, options.initiator.isolatedCopy(), options.filteringPolicy)
+ , referrer(referrer.isolatedCopy())
+ , origin(WTFMove(origin))
{
}
-void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, PassOwnPtr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options, const String& outgoingReferrer)
+WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(ThreadableLoaderClientWrapper& workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode,
+ ResourceRequest&& request, const ThreadableLoaderOptions& options, const String& outgoingReferrer,
+ const SecurityOrigin* securityOrigin, const ContentSecurityPolicy* contentSecurityPolicy)
+ : m_workerClientWrapper(&workerClientWrapper)
+ , m_loaderProxy(loaderProxy)
+ , m_taskMode(taskMode.isolatedCopy())
{
- ASSERT(isMainThread());
- Document* document = toDocument(context);
-
- OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData));
- request->setHTTPReferrer(outgoingReferrer);
- // FIXME: If the a site requests a local resource, then this will return a non-zero value but the sync path
- // will return a 0 value. Either this should return 0 or the other code path should do a callback with
- // a failure.
- thisPtr->m_mainThreadLoader = DocumentThreadableLoader::create(document, thisPtr, *request, options);
- ASSERT(thisPtr->m_mainThreadLoader);
-}
+ ASSERT(securityOrigin);
+ ASSERT(contentSecurityPolicy);
-void WorkerThreadableLoader::MainThreadBridge::mainThreadDestroy(ScriptExecutionContext* context, MainThreadBridge* thisPtr)
-{
- ASSERT(isMainThread());
- ASSERT_UNUSED(context, context->isDocument());
- delete thisPtr;
+ auto securityOriginCopy = securityOrigin->isolatedCopy();
+ auto contentSecurityPolicyCopy = std::make_unique<ContentSecurityPolicy>(securityOriginCopy);
+ contentSecurityPolicyCopy->copyStateFrom(contentSecurityPolicy);
+ contentSecurityPolicyCopy->copyUpgradeInsecureRequestStateFrom(*contentSecurityPolicy);
+
+ auto optionsCopy = std::make_unique<LoaderTaskOptions>(options, request.httpReferrer().isNull() ? outgoingReferrer : request.httpReferrer(), WTFMove(securityOriginCopy));
+
+ // All loads start out as Document. Inside WorkerThreadableLoader we upgrade this to a Worker load.
+ ASSERT(optionsCopy->options.initiatorContext == InitiatorContext::Document);
+ optionsCopy->options.initiatorContext = InitiatorContext::Worker;
+
+ // Can we benefit from request being an r-value to create more efficiently its isolated copy?
+ m_loaderProxy.postTaskToLoader([this, request = request.isolatedCopy(), options = WTFMove(optionsCopy), contentSecurityPolicyCopy = WTFMove(contentSecurityPolicyCopy)](ScriptExecutionContext& context) mutable {
+ ASSERT(isMainThread());
+ Document& document = downcast<Document>(context);
+
+ // FIXME: If the site requests a local resource, then this will return a non-zero value but the sync path will return a 0 value.
+ // Either this should return 0 or the other code path should call a failure callback.
+ m_mainThreadLoader = DocumentThreadableLoader::create(document, *this, WTFMove(request), options->options, WTFMove(options->origin), WTFMove(contentSecurityPolicyCopy), WTFMove(options->referrer), DocumentThreadableLoader::ShouldLogError::No);
+ ASSERT(m_mainThreadLoader || m_loadingFinished);
+ });
}
void WorkerThreadableLoader::MainThreadBridge::destroy()
@@ -127,34 +139,35 @@ void WorkerThreadableLoader::MainThreadBridge::destroy()
clearClientWrapper();
// "delete this" and m_mainThreadLoader::deref() on the worker object's thread.
- m_loaderProxy.postTaskToLoader(
- createCallbackTask(&MainThreadBridge::mainThreadDestroy, AllowCrossThreadAccess(this)));
+ m_loaderProxy.postTaskToLoader([self = std::unique_ptr<WorkerThreadableLoader::MainThreadBridge>(this)] (ScriptExecutionContext& context) {
+ ASSERT(isMainThread());
+ ASSERT_UNUSED(context, context.isDocument());
+ });
}
-void WorkerThreadableLoader::MainThreadBridge::mainThreadCancel(ScriptExecutionContext* context, MainThreadBridge* thisPtr)
+void WorkerThreadableLoader::MainThreadBridge::cancel()
{
- ASSERT(isMainThread());
- ASSERT_UNUSED(context, context->isDocument());
+ m_loaderProxy.postTaskToLoader([this] (ScriptExecutionContext& context) {
+ ASSERT(isMainThread());
+ ASSERT_UNUSED(context, context.isDocument());
- if (!thisPtr->m_mainThreadLoader)
- return;
- thisPtr->m_mainThreadLoader->cancel();
- thisPtr->m_mainThreadLoader = 0;
-}
+ if (!m_mainThreadLoader)
+ return;
+ m_mainThreadLoader->cancel();
+ m_mainThreadLoader = nullptr;
+ });
-void WorkerThreadableLoader::MainThreadBridge::cancel()
-{
- m_loaderProxy.postTaskToLoader(
- createCallbackTask(&MainThreadBridge::mainThreadCancel, AllowCrossThreadAccess(this)));
- ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper.get();
- if (!clientWrapper->done()) {
- // If the client hasn't reached a termination state, then transition it by sending a cancellation error.
- // Note: no more client callbacks will be done after this method -- the clearClientWrapper() call ensures that.
- ResourceError error(String(), 0, String(), String());
- error.setIsCancellation(true);
- clientWrapper->didFail(error);
+ if (m_workerClientWrapper->done()) {
+ clearClientWrapper();
+ return;
}
- clearClientWrapper();
+ // Taking a ref of client wrapper as call to didFail may take out the last reference of it.
+ Ref<ThreadableLoaderClientWrapper> protectedWorkerClientWrapper(*m_workerClientWrapper);
+ // If the client hasn't reached a termination state, then transition it by sending a cancellation error.
+ // Note: no more client callbacks will be done after this method -- we clear the client wrapper to ensure that.
+ ResourceError error(ResourceError::Type::Cancellation);
+ protectedWorkerClientWrapper->didFail(error);
+ protectedWorkerClientWrapper->clearClient();
}
void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper()
@@ -162,84 +175,64 @@ void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper()
m_workerClientWrapper->clearClient();
}
-static void workerGlobalScopeDidSendData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didSendData(bytesSent, totalBytesToBeSent);
-}
-
void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent), m_taskMode);
-}
-
-static void workerGlobalScopeDidReceiveResponse(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier, PassOwnPtr<CrossThreadResourceResponseData> responseData)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- OwnPtr<ResourceResponse> response(ResourceResponse::adopt(responseData));
- workerClientWrapper->didReceiveResponse(identifier, *response);
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), bytesSent, totalBytesToBeSent] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didSendData(bytesSent, totalBytesToBeSent);
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveResponse, m_workerClientWrapper, identifier, response), m_taskMode);
-}
-
-static void workerGlobalScopeDidReceiveData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char>> vectorData)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didReceiveData(vectorData->data(), vectorData->size());
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), identifier, responseData = response.crossThreadData()] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didReceiveResponse(identifier, ResourceResponse::fromCrossThreadData(WTFMove(responseData)));
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int dataLength)
{
- OwnPtr<Vector<char>> vector = adoptPtr(new Vector<char>(dataLength)); // needs to be an OwnPtr for usage with createCallbackTask.
- memcpy(vector->data(), data, dataLength);
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveData, m_workerClientWrapper, vector.release()), m_taskMode);
-}
-
-static void workerGlobalScopeDidFinishLoading(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier, double finishTime)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFinishLoading(identifier, finishTime);
+ Vector<char> vector(dataLength);
+ memcpy(vector.data(), data, dataLength);
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), vector = WTFMove(vector)] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didReceiveData(vector.data(), vector.size());
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didFinishLoading(unsigned long identifier, double finishTime)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFinishLoading, m_workerClientWrapper, identifier, finishTime), m_taskMode);
-}
-
-static void workerGlobalScopeDidFail(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, const ResourceError& error)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFail(error);
+ m_loadingFinished = true;
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), identifier, finishTime] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didFinishLoading(identifier, finishTime);
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didFail(const ResourceError& error)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFail, m_workerClientWrapper, error), m_taskMode);
-}
+ m_loadingFinished = true;
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([workerClientWrapper = Ref<ThreadableLoaderClientWrapper>(*m_workerClientWrapper), error = error.isolatedCopy()] (ScriptExecutionContext& context) mutable {
+ ASSERT(context.isWorkerGlobalScope());
-static void workerGlobalScopeDidFailAccessControlCheck(ScriptExecutionContext* context, PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, const ResourceError& error)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFailAccessControlCheck(error);
-}
+ ThreadableLoader::logError(context, error, workerClientWrapper->initiator());
-void WorkerThreadableLoader::MainThreadBridge::didFailAccessControlCheck(const ResourceError& error)
-{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFailAccessControlCheck, m_workerClientWrapper, error), m_taskMode);
+ workerClientWrapper->didFail(error);
+ }, m_taskMode);
}
-static void workerGlobalScopeDidFailRedirectCheck(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper)
+#if ENABLE(WEB_TIMING)
+void WorkerThreadableLoader::MainThreadBridge::didFinishTiming(const ResourceTiming& resourceTiming)
{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFailRedirectCheck();
-}
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), resourceTiming = resourceTiming.isolatedCopy()] (ScriptExecutionContext& context) mutable {
+ ASSERT(context.isWorkerGlobalScope());
+ ASSERT(!resourceTiming.initiator().isEmpty());
-void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck()
-{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFailRedirectCheck, m_workerClientWrapper), m_taskMode);
+ // No need to notify clients, just add the performance timing entry.
+ downcast<WorkerGlobalScope>(context).performance().addResourceTiming(WTFMove(resourceTiming));
+ }, m_taskMode);
}
+#endif
} // namespace WebCore
diff --git a/Source/WebCore/loader/WorkerThreadableLoader.h b/Source/WebCore/loader/WorkerThreadableLoader.h
index 4db0f4534..c0a570527 100644
--- a/Source/WebCore/loader/WorkerThreadableLoader.h
+++ b/Source/WebCore/loader/WorkerThreadableLoader.h
@@ -28,41 +28,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef WorkerThreadableLoader_h
-#define WorkerThreadableLoader_h
+#pragma once
#include "ThreadableLoader.h"
#include "ThreadableLoaderClient.h"
#include "ThreadableLoaderClientWrapper.h"
-
-#include <wtf/PassOwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
#include <wtf/Threading.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
+ class ContentSecurityPolicy;
class ResourceError;
class ResourceRequest;
+ class SecurityOrigin;
class WorkerGlobalScope;
class WorkerLoaderProxy;
- struct CrossThreadResourceResponseData;
- struct CrossThreadResourceRequestData;
class WorkerThreadableLoader : public RefCounted<WorkerThreadableLoader>, public ThreadableLoader {
WTF_MAKE_FAST_ALLOCATED;
public:
- static void loadResourceSynchronously(WorkerGlobalScope*, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&);
- static PassRefPtr<WorkerThreadableLoader> create(WorkerGlobalScope* workerGlobalScope, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, const ThreadableLoaderOptions& options)
+ static void loadResourceSynchronously(WorkerGlobalScope&, ResourceRequest&&, ThreadableLoaderClient&, const ThreadableLoaderOptions&);
+ static Ref<WorkerThreadableLoader> create(WorkerGlobalScope& workerGlobalScope, ThreadableLoaderClient& client, const String& taskMode, ResourceRequest&& request, const ThreadableLoaderOptions& options, const String& referrer)
{
- return adoptRef(new WorkerThreadableLoader(workerGlobalScope, client, taskMode, request, options));
+ return adoptRef(*new WorkerThreadableLoader(workerGlobalScope, client, taskMode, WTFMove(request), options, referrer));
}
~WorkerThreadableLoader();
- virtual void cancel() override;
+ void cancel() override;
bool done() const { return m_workerClientWrapper->done(); }
@@ -70,8 +64,8 @@ namespace WebCore {
using RefCounted<WorkerThreadableLoader>::deref;
protected:
- virtual void refThreadableLoader() override { ref(); }
- virtual void derefThreadableLoader() override { deref(); }
+ void refThreadableLoader() override { ref(); }
+ void derefThreadableLoader() override { deref(); }
private:
// Creates a loader on the main thread and bridges communication between
@@ -90,13 +84,12 @@ namespace WebCore {
// case 2. xhr gets aborted and the worker context continues running.
// The ThreadableLoaderClientWrapper has the underlying client cleared, so no more calls
// go through it. All tasks posted from the worker object's thread to the worker context's
- // thread do "ThreadableLoaderClientWrapper::ref" (automatically inside of the cross thread copy
- // done in createCallbackTask), so the ThreadableLoaderClientWrapper instance is there until all
- // tasks are executed.
+ // thread contain the RefPtr<ThreadableLoaderClientWrapper> object, so the
+ // ThreadableLoaderClientWrapper instance is there until all tasks are executed.
class MainThreadBridge : public ThreadableLoaderClient {
public:
// All executed on the worker context's thread.
- MainThreadBridge(PassRefPtr<ThreadableLoaderClientWrapper>, WorkerLoaderProxy&, const String& taskMode, const ResourceRequest&, const ThreadableLoaderOptions&, const String& outgoingReferrer);
+ MainThreadBridge(ThreadableLoaderClientWrapper&, WorkerLoaderProxy&, const String& taskMode, ResourceRequest&&, const ThreadableLoaderOptions&, const String& outgoingReferrer, const SecurityOrigin*, const ContentSecurityPolicy*);
void cancel();
void destroy();
@@ -105,21 +98,19 @@ namespace WebCore {
void clearClientWrapper();
// All executed on the main thread.
- static void mainThreadDestroy(ScriptExecutionContext*, MainThreadBridge*);
- ~MainThreadBridge();
-
- static void mainThreadCreateLoader(ScriptExecutionContext*, MainThreadBridge*, PassOwnPtr<CrossThreadResourceRequestData>, ThreadableLoaderOptions, const String& outgoingReferrer);
- static void mainThreadCancel(ScriptExecutionContext*, MainThreadBridge*);
- virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
- virtual void didReceiveResponse(unsigned long identifier, const ResourceResponse&) override;
- virtual void didReceiveData(const char*, int dataLength) override;
- virtual void didFinishLoading(unsigned long identifier, double finishTime) override;
- virtual void didFail(const ResourceError&) override;
- virtual void didFailAccessControlCheck(const ResourceError&) override;
- virtual void didFailRedirectCheck() override;
+ void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ void didReceiveResponse(unsigned long identifier, const ResourceResponse&) override;
+ void didReceiveData(const char*, int dataLength) override;
+ void didFinishLoading(unsigned long identifier, double finishTime) override;
+ void didFail(const ResourceError&) override;
+
+#if ENABLE(WEB_TIMING)
+ void didFinishTiming(const ResourceTiming&) override;
+#endif
// Only to be used on the main thread.
RefPtr<ThreadableLoader> m_mainThreadLoader;
+ bool m_loadingFinished { false };
// ThreadableLoaderClientWrapper is to be used on the worker context thread.
// The ref counting is done on either thread.
@@ -132,13 +123,11 @@ namespace WebCore {
String m_taskMode;
};
- WorkerThreadableLoader(WorkerGlobalScope*, ThreadableLoaderClient*, const String& taskMode, const ResourceRequest&, const ThreadableLoaderOptions&);
+ WorkerThreadableLoader(WorkerGlobalScope&, ThreadableLoaderClient&, const String& taskMode, ResourceRequest&&, const ThreadableLoaderOptions&, const String& referrer);
- RefPtr<WorkerGlobalScope> m_workerGlobalScope;
- RefPtr<ThreadableLoaderClientWrapper> m_workerClientWrapper;
+ Ref<WorkerGlobalScope> m_workerGlobalScope;
+ Ref<ThreadableLoaderClientWrapper> m_workerClientWrapper;
MainThreadBridge& m_bridge;
};
} // namespace WebCore
-
-#endif // WorkerThreadableLoader_h
diff --git a/Source/WebCore/loader/appcache/ApplicationCache.cpp b/Source/WebCore/loader/appcache/ApplicationCache.cpp
index 983becc21..a95ed2cac 100644
--- a/Source/WebCore/loader/appcache/ApplicationCache.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCache.cpp
@@ -30,7 +30,6 @@
#include "ApplicationCacheResource.h"
#include "ApplicationCacheStorage.h"
#include "ResourceRequest.h"
-#include "SecurityOrigin.h"
#include <algorithm>
#include <stdio.h>
#include <wtf/text/CString.h>
@@ -43,17 +42,13 @@ static inline bool fallbackURLLongerThan(const std::pair<URL, URL>& lhs, const s
}
ApplicationCache::ApplicationCache()
- : m_group(0)
- , m_manifest(0)
- , m_estimatedSizeInStorage(0)
- , m_storageID(0)
{
}
ApplicationCache::~ApplicationCache()
{
- if (m_group && !m_group->isCopy())
- m_group->cacheDestroyed(this);
+ if (m_group)
+ m_group->cacheDestroyed(*this);
}
void ApplicationCache::setGroup(ApplicationCacheGroup* group)
@@ -62,59 +57,41 @@ void ApplicationCache::setGroup(ApplicationCacheGroup* group)
m_group = group;
}
-bool ApplicationCache::isComplete() const
+bool ApplicationCache::isComplete()
{
- return !m_group->cacheIsBeingUpdated(this);
+ return m_group && m_group->cacheIsComplete(*this);
}
-void ApplicationCache::setManifestResource(PassRefPtr<ApplicationCacheResource> manifest)
+void ApplicationCache::setManifestResource(Ref<ApplicationCacheResource>&& manifest)
{
- ASSERT(manifest);
ASSERT(!m_manifest);
ASSERT(manifest->type() & ApplicationCacheResource::Manifest);
-
- m_manifest = manifest.get();
-
- addResource(manifest);
+
+ m_manifest = manifest.ptr();
+
+ addResource(WTFMove(manifest));
}
-void ApplicationCache::addResource(PassRefPtr<ApplicationCacheResource> resource)
+void ApplicationCache::addResource(Ref<ApplicationCacheResource>&& resource)
{
- ASSERT(resource);
-
- const String& url = resource->url();
-
+ auto& url = resource->url();
+
+ ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier());
ASSERT(!m_resources.contains(url));
-
+
if (m_storageID) {
ASSERT(!resource->storageID());
ASSERT(resource->type() & ApplicationCacheResource::Master);
-
+
// Add the resource to the storage.
- cacheStorage().store(resource.get(), this);
+ m_group->storage().store(resource.ptr(), this);
}
m_estimatedSizeInStorage += resource->estimatedSizeInStorage();
- m_resources.set(url, resource);
+ m_resources.set(url, WTFMove(resource));
}
-unsigned ApplicationCache::removeResource(const String& url)
-{
- HashMap<String, RefPtr<ApplicationCacheResource>>::iterator it = m_resources.find(url);
- if (it == m_resources.end())
- return 0;
-
- // The resource exists, get its type so we can return it.
- unsigned type = it->value->type();
-
- m_estimatedSizeInStorage -= it->value->estimatedSizeInStorage();
-
- m_resources.remove(it);
-
- return type;
-}
-
ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url)
{
ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier());
@@ -123,25 +100,17 @@ ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url)
bool ApplicationCache::requestIsHTTPOrHTTPSGet(const ResourceRequest& request)
{
- if (!request.url().protocolIsInHTTPFamily())
- return false;
-
- if (!equalIgnoringCase(request.httpMethod(), "GET"))
- return false;
-
- return true;
-}
+ return request.url().protocolIsInHTTPFamily() && equalLettersIgnoringASCIICase(request.httpMethod(), "get");
+}
ApplicationCacheResource* ApplicationCache::resourceForRequest(const ResourceRequest& request)
{
// We only care about HTTP/HTTPS GET requests.
if (!requestIsHTTPOrHTTPSGet(request))
- return 0;
+ return nullptr;
URL url(request.url());
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
-
+ url.removeFragmentIdentifier();
return resourceForURL(url);
}
@@ -153,9 +122,8 @@ void ApplicationCache::setOnlineWhitelist(const Vector<URL>& onlineWhitelist)
bool ApplicationCache::isURLInOnlineWhitelist(const URL& url)
{
- size_t whitelistSize = m_onlineWhitelist.size();
- for (size_t i = 0; i < whitelistSize; ++i) {
- if (protocolHostAndPortAreEqual(url, m_onlineWhitelist[i]) && url.string().startsWith(m_onlineWhitelist[i].string()))
+ for (auto& whitelistURL : m_onlineWhitelist) {
+ if (protocolHostAndPortAreEqual(url, whitelistURL) && url.string().startsWith(whitelistURL.string()))
return true;
}
return false;
@@ -171,11 +139,10 @@ void ApplicationCache::setFallbackURLs(const FallbackURLVector& fallbackURLs)
bool ApplicationCache::urlMatchesFallbackNamespace(const URL& url, URL* fallbackURL)
{
- size_t fallbackCount = m_fallbackURLs.size();
- for (size_t i = 0; i < fallbackCount; ++i) {
- if (protocolHostAndPortAreEqual(url, m_fallbackURLs[i].first) && url.string().startsWith(m_fallbackURLs[i].first.string())) {
+ for (auto& fallback : m_fallbackURLs) {
+ if (protocolHostAndPortAreEqual(url, fallback.first) && url.string().startsWith(fallback.first.string())) {
if (fallbackURL)
- *fallbackURL = m_fallbackURLs[i].second;
+ *fallbackURL = fallback.second;
return true;
}
}
@@ -190,43 +157,12 @@ void ApplicationCache::clearStorageID()
resource->clearStorageID();
}
-void ApplicationCache::deleteCacheForOrigin(SecurityOrigin* origin)
-{
- Vector<URL> urls;
- if (!cacheStorage().manifestURLs(&urls)) {
- LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs");
- return;
- }
-
- URL originURL(URL(), origin->toString());
-
- size_t count = urls.size();
- for (size_t i = 0; i < count; ++i) {
- if (protocolHostAndPortAreEqual(urls[i], originURL)) {
- ApplicationCacheGroup* group = cacheStorage().findInMemoryCacheGroup(urls[i]);
- if (group)
- group->makeObsolete();
- else
- cacheStorage().deleteCacheGroup(urls[i]);
- }
- }
-}
-
-int64_t ApplicationCache::diskUsageForOrigin(SecurityOrigin* origin)
-{
- int64_t usage = 0;
- cacheStorage().calculateUsageForOrigin(origin, usage);
- return usage;
-}
-
#ifndef NDEBUG
void ApplicationCache::dump()
{
- HashMap<String, RefPtr<ApplicationCacheResource>>::const_iterator end = m_resources.end();
-
- for (HashMap<String, RefPtr<ApplicationCacheResource>>::const_iterator it = m_resources.begin(); it != end; ++it) {
- printf("%s ", it->key.ascii().data());
- ApplicationCacheResource::dumpType(it->value->type());
+ for (const auto& urlAndResource : m_resources) {
+ printf("%s ", urlAndResource.key.utf8().data());
+ ApplicationCacheResource::dumpType(urlAndResource.value->type());
}
}
#endif
diff --git a/Source/WebCore/loader/appcache/ApplicationCache.h b/Source/WebCore/loader/appcache/ApplicationCache.h
index 680635def..5df5f6017 100644
--- a/Source/WebCore/loader/appcache/ApplicationCache.h
+++ b/Source/WebCore/loader/appcache/ApplicationCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,45 +23,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ApplicationCache_h
-#define ApplicationCache_h
+#pragma once
#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
#include <wtf/text/StringHash.h>
-#include <wtf/text/WTFString.h>
namespace WebCore {
class ApplicationCacheGroup;
class ApplicationCacheResource;
-class DocumentLoader;
-class URL;
class ResourceRequest;
-class SecurityOrigin;
+class URL;
-typedef Vector<std::pair<URL, URL>> FallbackURLVector;
+using FallbackURLVector = Vector<std::pair<URL, URL>>;
class ApplicationCache : public RefCounted<ApplicationCache> {
public:
- static PassRefPtr<ApplicationCache> create() { return adoptRef(new ApplicationCache); }
-
- static void deleteCacheForOrigin(SecurityOrigin*);
-
+ static Ref<ApplicationCache> create() { return adoptRef(*new ApplicationCache); }
+
~ApplicationCache();
- void addResource(PassRefPtr<ApplicationCacheResource> resource);
- unsigned removeResource(const String& url);
-
- void setManifestResource(PassRefPtr<ApplicationCacheResource> manifest);
+ void addResource(Ref<ApplicationCacheResource>&&);
+
+ void setManifestResource(Ref<ApplicationCacheResource>&&);
ApplicationCacheResource* manifestResource() const { return m_manifest; }
-
+
void setGroup(ApplicationCacheGroup*);
ApplicationCacheGroup* group() const { return m_group; }
- bool isComplete() const;
+ bool isComplete();
ApplicationCacheResource* resourceForRequest(const ResourceRequest&);
ApplicationCacheResource* resourceForURL(const String& url);
@@ -74,45 +64,39 @@ public:
void setFallbackURLs(const FallbackURLVector&);
const FallbackURLVector& fallbackURLs() const { return m_fallbackURLs; }
- bool urlMatchesFallbackNamespace(const URL&, URL* fallbackURL = 0);
-
+ bool urlMatchesFallbackNamespace(const URL&, URL* fallbackURL = nullptr);
+
#ifndef NDEBUG
void dump();
#endif
- typedef HashMap<String, RefPtr<ApplicationCacheResource>> ResourceMap;
- ResourceMap::const_iterator begin() const { return m_resources.begin(); }
- ResourceMap::const_iterator end() const { return m_resources.end(); }
-
+ using ResourceMap = HashMap<String, RefPtr<ApplicationCacheResource>>;
+ const ResourceMap& resources() const { return m_resources; }
+
void setStorageID(unsigned storageID) { m_storageID = storageID; }
unsigned storageID() const { return m_storageID; }
void clearStorageID();
-
+
static bool requestIsHTTPOrHTTPSGet(const ResourceRequest&);
- static int64_t diskUsageForOrigin(SecurityOrigin*);
-
int64_t estimatedSizeInStorage() const { return m_estimatedSizeInStorage; }
private:
ApplicationCache();
-
- ApplicationCacheGroup* m_group;
+
+ ApplicationCacheGroup* m_group { nullptr };
ResourceMap m_resources;
- ApplicationCacheResource* m_manifest;
+ ApplicationCacheResource* m_manifest { nullptr };
- bool m_allowAllNetworkRequests;
+ bool m_allowAllNetworkRequests { false };
Vector<URL> m_onlineWhitelist;
FallbackURLVector m_fallbackURLs;
// The total size of the resources belonging to this Application Cache instance.
- // This is an estimation of the size this Application Cache occupies in the
- // database file.
- int64_t m_estimatedSizeInStorage;
+ // This is an estimation of the size this Application Cache occupies in the database file.
+ int64_t m_estimatedSizeInStorage { 0 };
- unsigned m_storageID;
+ unsigned m_storageID { 0 };
};
} // namespace WebCore
-
-#endif // ApplicationCache_h
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp b/Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp
new file mode 100644
index 000000000..73eaf7214
--- /dev/null
+++ b/Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+
+#include "ApplicationCache.cpp"
+#include "ApplicationCacheGroup.cpp"
+#include "ApplicationCacheHost.cpp"
+#include "ApplicationCacheResource.cpp"
+#include "ApplicationCacheStorage.cpp"
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp
index 8e67597a6..9f9ab000c 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -32,161 +32,151 @@
#include "ApplicationCacheStorage.h"
#include "Chrome.h"
#include "ChromeClient.h"
-#include "Console.h"
#include "DOMApplicationCache.h"
-#include "DOMWindow.h"
#include "DocumentLoader.h"
+#include "EventNames.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
+#include "HTTPHeaderNames.h"
#include "InspectorInstrumentation.h"
#include "ManifestParser.h"
#include "Page.h"
-#include "ResourceBuffer.h"
+#include "ProgressTracker.h"
#include "ResourceHandle.h"
-#include "ScriptProfile.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#include <wtf/HashMap.h>
#include <wtf/MainThread.h>
-#if ENABLE(INSPECTOR)
-#include "ProgressTracker.h"
-#endif
-
namespace WebCore {
-ApplicationCacheGroup::ApplicationCacheGroup(const URL& manifestURL, bool isCopy)
- : m_manifestURL(manifestURL)
+ApplicationCacheGroup::ApplicationCacheGroup(Ref<ApplicationCacheStorage>&& storage, const URL& manifestURL)
+ : m_storage(WTFMove(storage))
+ , m_manifestURL(manifestURL)
, m_origin(SecurityOrigin::create(manifestURL))
- , m_updateStatus(Idle)
- , m_downloadingPendingMasterResourceLoadersCount(0)
- , m_progressTotal(0)
- , m_progressDone(0)
- , m_frame(0)
- , m_storageID(0)
- , m_isObsolete(false)
- , m_completionType(None)
- , m_isCopy(isCopy)
- , m_calledReachedMaxAppCacheSize(false)
, m_availableSpaceInQuota(ApplicationCacheStorage::unknownQuota())
- , m_originQuotaExceededPreviously(false)
{
}
ApplicationCacheGroup::~ApplicationCacheGroup()
{
- if (m_isCopy) {
- ASSERT(m_newestCache);
- ASSERT(m_caches.size() == 1);
- ASSERT(m_caches.contains(m_newestCache.get()));
- ASSERT(!m_cacheBeingUpdated);
- ASSERT(m_associatedDocumentLoaders.isEmpty());
- ASSERT(m_pendingMasterResourceLoaders.isEmpty());
- ASSERT(m_newestCache->group() == this);
-
- return;
- }
-
ASSERT(!m_newestCache);
ASSERT(m_caches.isEmpty());
-
+
stopLoading();
-
- cacheStorage().cacheGroupDestroyed(this);
+
+ m_storage->cacheGroupDestroyed(*this);
}
-ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader*)
+ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader* documentLoader)
{
if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
- return 0;
+ return nullptr;
URL url(request.url());
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
+ url.removeFragmentIdentifier();
- if (ApplicationCacheGroup* group = cacheStorage().cacheGroupForURL(url)) {
- ASSERT(group->newestCache());
- ASSERT(!group->isObsolete());
-
- return group->newestCache();
- }
-
- return 0;
+ auto* page = documentLoader->frame() ? documentLoader->frame()->page() : nullptr;
+ if (!page || page->usesEphemeralSession())
+ return nullptr;
+
+ auto* group = page->applicationCacheStorage().cacheGroupForURL(url);
+ if (!group)
+ return nullptr;
+
+ ASSERT(group->newestCache());
+ ASSERT(!group->isObsolete());
+
+ return group->newestCache();
}
-ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader*)
+ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader* documentLoader)
{
if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
- return 0;
+ return nullptr;
+
+ auto* frame = documentLoader->frame();
+ if (!frame)
+ return nullptr;
+
+ auto* page = frame->page();
+ if (!page)
+ return nullptr;
URL url(request.url());
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
+ url.removeFragmentIdentifier();
- if (ApplicationCacheGroup* group = cacheStorage().fallbackCacheGroupForURL(url)) {
- ASSERT(group->newestCache());
- ASSERT(!group->isObsolete());
+ auto* group = page->applicationCacheStorage().fallbackCacheGroupForURL(url);
+ if (!group)
+ return nullptr;
- return group->newestCache();
- }
-
- return 0;
+ ASSERT(group->newestCache());
+ ASSERT(!group->isObsolete());
+
+ return group->newestCache();
}
-void ApplicationCacheGroup::selectCache(Frame* frame, const URL& passedManifestURL)
+void ApplicationCacheGroup::selectCache(Frame& frame, const URL& passedManifestURL)
{
- ASSERT(frame && frame->page());
-
- if (!frame->settings().offlineWebApplicationCacheEnabled())
- return;
+ ASSERT(frame.document());
+ ASSERT(frame.page());
+ ASSERT(frame.loader().documentLoader());
- if (!frame->document()->securityOrigin()->canAccessApplicationCache(frame->tree().top().document()->securityOrigin()))
+ if (!frame.settings().offlineWebApplicationCacheEnabled())
return;
-
- DocumentLoader* documentLoader = frame->loader().documentLoader();
- ASSERT(!documentLoader->applicationCacheHost()->applicationCache());
+
+ auto& documentLoader = *frame.loader().documentLoader();
+ ASSERT(!documentLoader.applicationCacheHost().applicationCache());
if (passedManifestURL.isNull()) {
- selectCacheWithoutManifestURL(frame);
+ selectCacheWithoutManifestURL(frame);
+ return;
+ }
+
+ // Don't access anything on disk if private browsing is enabled.
+ if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin().canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) {
+ postListenerTask(eventNames().checkingEvent, documentLoader);
+ postListenerTask(eventNames().errorEvent, documentLoader);
return;
}
URL manifestURL(passedManifestURL);
- if (manifestURL.hasFragmentIdentifier())
- manifestURL.removeFragmentIdentifier();
+ manifestURL.removeFragmentIdentifier();
- ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache();
+ auto* mainResourceCache = documentLoader.applicationCacheHost().mainResourceApplicationCache();
if (mainResourceCache) {
+ ASSERT(mainResourceCache->group());
if (manifestURL == mainResourceCache->group()->m_manifestURL) {
// The cache may have gotten obsoleted after we've loaded from it, but before we parsed the document and saw cache manifest.
if (mainResourceCache->group()->isObsolete())
return;
- mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
+ mainResourceCache->group()->associateDocumentLoaderWithCache(&documentLoader, mainResourceCache);
mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
} else {
// The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign.
- URL resourceURL(documentLoader->responseURL());
- if (resourceURL.hasFragmentIdentifier())
- resourceURL.removeFragmentIdentifier();
- ApplicationCacheResource* resource = mainResourceCache->resourceForURL(resourceURL);
- bool inStorage = resource->storageID();
- resource->addType(ApplicationCacheResource::Foreign);
+ URL resourceURL { documentLoader.responseURL() };
+ resourceURL.removeFragmentIdentifier();
+
+ ASSERT(mainResourceCache->resourceForURL(resourceURL));
+ auto& resource = *mainResourceCache->resourceForURL(resourceURL);
+
+ bool inStorage = resource.storageID();
+ resource.addType(ApplicationCacheResource::Foreign);
if (inStorage)
- cacheStorage().storeUpdatedType(resource, mainResourceCache);
+ frame.page()->applicationCacheStorage().storeUpdatedType(&resource, mainResourceCache);
// Restart the current navigation from the top of the navigation algorithm, undoing any changes that were made
// as part of the initial load.
// The navigation will not result in the same resource being loaded, because "foreign" entries are never picked during navigation.
- frame->navigationScheduler().scheduleLocationChange(frame->document()->securityOrigin(), documentLoader->url(), frame->loader().referrer());
+ frame.navigationScheduler().scheduleLocationChange(*frame.document(), frame.document()->securityOrigin(), documentLoader.url(), frame.loader().referrer());
}
-
return;
}
-
+
// The resource was loaded from the network, check if it is a HTTP/HTTPS GET.
- const ResourceRequest& request = frame->loader().activeDocumentLoader()->request();
+ auto& request = frame.loader().activeDocumentLoader()->request();
if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
return;
@@ -195,49 +185,48 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const URL& passedManifestU
if (!protocolHostAndPortAreEqual(manifestURL, request.url()))
return;
- // Don't change anything on disk if private browsing is enabled.
- if (frame->settings().privateBrowsingEnabled()) {
- postListenerTask(ApplicationCacheHost::CHECKING_EVENT, documentLoader);
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, documentLoader);
- return;
- }
-
- ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL);
+ auto& group = *frame.page()->applicationCacheStorage().findOrCreateCacheGroup(manifestURL);
- documentLoader->applicationCacheHost()->setCandidateApplicationCacheGroup(group);
- group->m_pendingMasterResourceLoaders.add(documentLoader);
- group->m_downloadingPendingMasterResourceLoadersCount++;
+ documentLoader.applicationCacheHost().setCandidateApplicationCacheGroup(&group);
+ group.m_pendingMasterResourceLoaders.add(&documentLoader);
+ group.m_downloadingPendingMasterResourceLoadersCount++;
- ASSERT(!group->m_cacheBeingUpdated || group->m_updateStatus != Idle);
- group->update(frame, ApplicationCacheUpdateWithBrowsingContext);
+ ASSERT(!group.m_cacheBeingUpdated || group.m_updateStatus != Idle);
+ group.update(frame, ApplicationCacheUpdateWithBrowsingContext);
}
-void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame)
+void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame& frame)
{
- if (!frame->settings().offlineWebApplicationCacheEnabled())
- return;
-
- if (!frame->document()->securityOrigin()->canAccessApplicationCache(frame->tree().top().document()->securityOrigin()))
+ if (!frame.settings().offlineWebApplicationCacheEnabled())
return;
- DocumentLoader* documentLoader = frame->loader().documentLoader();
- ASSERT(!documentLoader->applicationCacheHost()->applicationCache());
+ ASSERT(frame.document());
+ ASSERT(frame.page());
+ ASSERT(frame.loader().documentLoader());
+ auto& documentLoader = *frame.loader().documentLoader();
+ ASSERT(!documentLoader.applicationCacheHost().applicationCache());
- ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache();
+ // Don't access anything on disk if private browsing is enabled.
+ if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin().canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) {
+ postListenerTask(eventNames().checkingEvent, documentLoader);
+ postListenerTask(eventNames().errorEvent, documentLoader);
+ return;
+ }
- if (mainResourceCache) {
- mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
- mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
+ if (auto* mainResourceCache = documentLoader.applicationCacheHost().mainResourceApplicationCache()) {
+ ASSERT(mainResourceCache->group());
+ auto& group = *mainResourceCache->group();
+ group.associateDocumentLoaderWithCache(&documentLoader, mainResourceCache);
+ group.update(frame, ApplicationCacheUpdateWithBrowsingContext);
}
}
-void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader)
+void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader& loader)
{
- ASSERT(m_pendingMasterResourceLoaders.contains(loader));
+ ASSERT(m_pendingMasterResourceLoaders.contains(&loader));
ASSERT(m_completionType == None || m_pendingEntries.isEmpty());
- URL url = loader->url();
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
+ URL url = loader.url();
+ url.removeFragmentIdentifier();
switch (m_completionType) {
case None:
@@ -245,39 +234,32 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader)
return;
case NoUpdate:
ASSERT(!m_cacheBeingUpdated);
- associateDocumentLoaderWithCache(loader, m_newestCache.get());
-
- if (ApplicationCacheResource* resource = m_newestCache->resourceForURL(url)) {
+ associateDocumentLoaderWithCache(&loader, m_newestCache.get());
+ if (auto* resource = m_newestCache->resourceForURL(url)) {
if (!(resource->type() & ApplicationCacheResource::Master)) {
resource->addType(ApplicationCacheResource::Master);
ASSERT(!resource->storageID());
}
- } else {
- RefPtr<ResourceBuffer> buffer = loader->mainResourceData();
- m_newestCache->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, buffer ? buffer->sharedBuffer() : 0));
- }
-
+ } else
+ m_newestCache->addResource(ApplicationCacheResource::create(url, loader.response(), ApplicationCacheResource::Master, loader.mainResourceData()));
break;
case Failure:
// Cache update has been a failure, so there is no reason to keep the document associated with the incomplete cache
// (its main resource was not cached yet, so it is likely that the application changed significantly server-side).
ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading().
- loader->applicationCacheHost()->setApplicationCache(0); // Will unset candidate, too.
- m_associatedDocumentLoaders.remove(loader);
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader);
+ loader.applicationCacheHost().setApplicationCache(nullptr); // Will unset candidate, too.
+ m_associatedDocumentLoaders.remove(&loader);
+ postListenerTask(eventNames().errorEvent, loader);
break;
case Completed:
- ASSERT(m_associatedDocumentLoaders.contains(loader));
-
- if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) {
+ ASSERT(m_associatedDocumentLoaders.contains(&loader));
+ if (auto* resource = m_cacheBeingUpdated->resourceForURL(url)) {
if (!(resource->type() & ApplicationCacheResource::Master)) {
resource->addType(ApplicationCacheResource::Master);
ASSERT(!resource->storageID());
}
- } else {
- RefPtr<ResourceBuffer> buffer = loader->mainResourceData();
- m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, buffer ? buffer->sharedBuffer() : 0));
- }
+ } else
+ m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader.response(), ApplicationCacheResource::Master, loader.mainResourceData()));
// The "cached" event will be posted to all associated documents once update is complete.
break;
}
@@ -287,9 +269,9 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader)
checkIfLoadIsComplete();
}
-void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader)
+void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader& loader)
{
- ASSERT(m_pendingMasterResourceLoaders.contains(loader));
+ ASSERT(m_pendingMasterResourceLoaders.contains(&loader));
ASSERT(m_completionType == None || m_pendingEntries.isEmpty());
switch (m_completionType) {
@@ -298,32 +280,27 @@ void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader)
return;
case NoUpdate:
ASSERT(!m_cacheBeingUpdated);
-
// The manifest didn't change, and we have a relevant cache - but the main resource download failed mid-way, so it cannot be stored to the cache,
// and the loader does not get associated to it. If there are other main resources being downloaded for this cache group, they may still succeed.
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader);
-
+ postListenerTask(eventNames().errorEvent, loader);
break;
case Failure:
// Cache update failed, too.
ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading().
- ASSERT(!loader->applicationCacheHost()->applicationCache() || loader->applicationCacheHost()->applicationCache() == m_cacheBeingUpdated);
-
- loader->applicationCacheHost()->setApplicationCache(0); // Will unset candidate, too.
- m_associatedDocumentLoaders.remove(loader);
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader);
+ ASSERT(!loader.applicationCacheHost().applicationCache() || loader.applicationCacheHost().applicationCache()->group() == this);
+ loader.applicationCacheHost().setApplicationCache(nullptr); // Will unset candidate, too.
+ m_associatedDocumentLoaders.remove(&loader);
+ postListenerTask(eventNames().errorEvent, loader);
break;
case Completed:
// The cache manifest didn't list this main resource, and all cache entries were already updated successfully - but the main resource failed to load,
// so it cannot be stored to the cache. If there are other main resources being downloaded for this cache group, they may still succeed.
- ASSERT(m_associatedDocumentLoaders.contains(loader));
- ASSERT(loader->applicationCacheHost()->applicationCache() == m_cacheBeingUpdated);
- ASSERT(!loader->applicationCacheHost()->candidateApplicationCacheGroup());
- m_associatedDocumentLoaders.remove(loader);
- loader->applicationCacheHost()->setApplicationCache(0);
-
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader);
-
+ ASSERT(m_associatedDocumentLoaders.contains(&loader));
+ ASSERT(loader.applicationCacheHost().applicationCache() == m_cacheBeingUpdated);
+ ASSERT(!loader.applicationCacheHost().candidateApplicationCacheGroup());
+ m_associatedDocumentLoaders.remove(&loader);
+ loader.applicationCacheHost().setApplicationCache(nullptr);
+ postListenerTask(eventNames().errorEvent, loader);
break;
}
@@ -338,10 +315,10 @@ void ApplicationCacheGroup::stopLoading()
ASSERT(!m_currentHandle);
ASSERT(m_manifestHandle->client() == this);
- m_manifestHandle->setClient(0);
+ m_manifestHandle->clearClient();
m_manifestHandle->cancel();
- m_manifestHandle = 0;
+ m_manifestHandle = nullptr;
}
if (m_currentHandle) {
@@ -349,23 +326,24 @@ void ApplicationCacheGroup::stopLoading()
ASSERT(m_cacheBeingUpdated);
ASSERT(m_currentHandle->client() == this);
- m_currentHandle->setClient(0);
+ m_currentHandle->clearClient();
m_currentHandle->cancel();
- m_currentHandle = 0;
+ m_currentHandle = nullptr;
}
// FIXME: Resetting just a tiny part of the state in this function is confusing. Callers have to take care of a lot more.
- m_cacheBeingUpdated = 0;
+ m_cacheBeingUpdated = nullptr;
m_pendingEntries.clear();
}
-void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader* loader)
+void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader& loader)
{
- m_associatedDocumentLoaders.remove(loader);
- m_pendingMasterResourceLoaders.remove(loader);
+ m_associatedDocumentLoaders.remove(&loader);
+ m_pendingMasterResourceLoaders.remove(&loader);
- loader->applicationCacheHost()->setApplicationCache(0); // Will set candidate to 0, too.
+ if (auto* host = loader.applicationCacheHostUnlessBeingDestroyed())
+ host->setApplicationCache(nullptr); // Will set candidate group to null, too.
if (!m_associatedDocumentLoaders.isEmpty() || !m_pendingMasterResourceLoaders.isEmpty())
return;
@@ -382,29 +360,29 @@ void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader* loader)
// Release our reference to the newest cache. This could cause us to be deleted.
// Any ongoing updates will be stopped from destructor.
- m_newestCache.release();
+ m_newestCache = nullptr;
}
-void ApplicationCacheGroup::cacheDestroyed(ApplicationCache* cache)
+void ApplicationCacheGroup::cacheDestroyed(ApplicationCache& cache)
{
- if (m_caches.remove(cache) && m_caches.isEmpty()) {
+ if (m_caches.remove(&cache) && m_caches.isEmpty()) {
ASSERT(m_associatedDocumentLoaders.isEmpty());
ASSERT(m_pendingMasterResourceLoaders.isEmpty());
delete this;
}
}
-void ApplicationCacheGroup::stopLoadingInFrame(Frame* frame)
+void ApplicationCacheGroup::stopLoadingInFrame(Frame& frame)
{
- if (frame != m_frame)
+ if (&frame != m_frame)
return;
cacheUpdateFailed();
}
-void ApplicationCacheGroup::setNewestCache(PassRefPtr<ApplicationCache> newestCache)
+void ApplicationCacheGroup::setNewestCache(Ref<ApplicationCache>&& newestCache)
{
- m_newestCache = newestCache;
+ m_newestCache = WTFMove(newestCache);
m_caches.add(m_newestCache.get());
m_newestCache->setGroup(this);
@@ -416,40 +394,43 @@ void ApplicationCacheGroup::makeObsolete()
return;
m_isObsolete = true;
- cacheStorage().cacheGroupMadeObsolete(this);
+ m_storage->cacheGroupMadeObsolete(*this);
ASSERT(!m_storageID);
}
-void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption updateOption)
+void ApplicationCacheGroup::update(Frame& frame, ApplicationCacheUpdateOption updateOption)
{
+ ASSERT(frame.loader().documentLoader());
+ auto& documentLoader = *frame.loader().documentLoader();
+
if (m_updateStatus == Checking || m_updateStatus == Downloading) {
if (updateOption == ApplicationCacheUpdateWithBrowsingContext) {
- postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader().documentLoader());
+ postListenerTask(eventNames().checkingEvent, documentLoader);
if (m_updateStatus == Downloading)
- postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, frame->loader().documentLoader());
+ postListenerTask(eventNames().downloadingEvent, documentLoader);
}
return;
}
- // Don't change anything on disk if private browsing is enabled.
- if (frame->settings().privateBrowsingEnabled()) {
+ // Don't access anything on disk if private browsing is enabled.
+ if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin().canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) {
ASSERT(m_pendingMasterResourceLoaders.isEmpty());
ASSERT(m_pendingEntries.isEmpty());
ASSERT(!m_cacheBeingUpdated);
- postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader().documentLoader());
- postListenerTask(ApplicationCacheHost::NOUPDATE_EVENT, frame->loader().documentLoader());
+ postListenerTask(eventNames().checkingEvent, documentLoader);
+ postListenerTask(eventNames().errorEvent, documentLoader);
return;
}
ASSERT(!m_frame);
- m_frame = frame;
+ m_frame = &frame;
setUpdateStatus(Checking);
- postListenerTask(ApplicationCacheHost::CHECKING_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().checkingEvent, m_associatedDocumentLoaders);
if (!m_newestCache) {
ASSERT(updateOption == ApplicationCacheUpdateWithBrowsingContext);
- postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader().documentLoader());
+ postListenerTask(eventNames().checkingEvent, documentLoader);
}
ASSERT(!m_manifestHandle);
@@ -462,7 +443,7 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up
m_manifestHandle = createResourceHandle(m_manifestURL, m_newestCache ? m_newestCache->manifestResource() : 0);
}
-void ApplicationCacheGroup::abort(Frame* frame)
+void ApplicationCacheGroup::abort(Frame& frame)
{
if (m_updateStatus == Idle)
return;
@@ -471,56 +452,51 @@ void ApplicationCacheGroup::abort(Frame* frame)
if (m_completionType != None)
return;
- frame->document()->addConsoleMessage(NetworkMessageSource, DebugMessageLevel, "Application Cache download process was aborted.");
+ frame.document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Debug, ASCIILiteral("Application Cache download process was aborted."));
cacheUpdateFailed();
}
-PassRefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const URL& url, ApplicationCacheResource* newestCachedResource)
+RefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const URL& url, ApplicationCacheResource* newestCachedResource)
{
ResourceRequest request(url);
m_frame->loader().applyUserAgent(request);
- request.setHTTPHeaderField("Cache-Control", "max-age=0");
+ request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
if (newestCachedResource) {
- const String& lastModified = newestCachedResource->response().httpHeaderField("Last-Modified");
- const String& eTag = newestCachedResource->response().httpHeaderField("ETag");
+ const String& lastModified = newestCachedResource->response().httpHeaderField(HTTPHeaderName::LastModified);
+ const String& eTag = newestCachedResource->response().httpHeaderField(HTTPHeaderName::ETag);
if (!lastModified.isEmpty() || !eTag.isEmpty()) {
if (!lastModified.isEmpty())
- request.setHTTPHeaderField("If-Modified-Since", lastModified);
+ request.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
if (!eTag.isEmpty())
- request.setHTTPHeaderField("If-None-Match", eTag);
+ request.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
}
}
RefPtr<ResourceHandle> handle = ResourceHandle::create(m_frame->loader().networkingContext(), request, this, false, true);
-#if ENABLE(INSPECTOR)
+
// Because willSendRequest only gets called during redirects, we initialize
// the identifier and the first willSendRequest here.
m_currentResourceIdentifier = m_frame->page()->progress().createUniqueIdentifier();
ResourceResponse redirectResponse = ResourceResponse();
InspectorInstrumentation::willSendRequest(m_frame, m_currentResourceIdentifier, m_frame->loader().documentLoader(), request, redirectResponse);
-#endif
return handle;
}
-void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
+void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, ResourceResponse&& response)
{
-#if ENABLE(INSPECTOR)
- DocumentLoader* loader = (handle == m_manifestHandle) ? 0 : m_frame->loader().documentLoader();
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceResponse(m_frame, m_currentResourceIdentifier, response);
- InspectorInstrumentation::didReceiveResourceResponse(cookie, m_currentResourceIdentifier, loader, response, 0);
-#endif
+ ASSERT(m_frame);
+ InspectorInstrumentation::didReceiveResourceResponse(*m_frame, m_currentResourceIdentifier, m_frame->loader().documentLoader(), response, nullptr);
if (handle == m_manifestHandle) {
didReceiveManifestResponse(response);
return;
}
-
+
ASSERT(handle == m_currentHandle);
URL url(handle->firstRequest().url());
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
+ url.removeFragmentIdentifier();
ASSERT(!m_currentResource);
ASSERT(m_pendingEntries.contains(url));
@@ -534,10 +510,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
if (m_newestCache && response.httpStatusCode() == 304) { // Not modified.
ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url);
if (newestCachedResource) {
- m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path()));
+ m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path()));
m_pendingEntries.remove(m_currentHandle->firstRequest().url());
m_currentHandle->cancel();
- m_currentHandle = 0;
+ m_currentHandle = nullptr;
// Load the next resource, if any.
startLoadingEntry();
return;
@@ -547,14 +523,14 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->firstRequest().url()) {
if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) {
- m_frame->document()->addConsoleMessage(AppCacheMessageSource, ErrorMessageLevel, "Application Cache update failed, because " + m_currentHandle->firstRequest().url().stringCenterEllipsizedToLength() +
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, "Application Cache update failed, because " + m_currentHandle->firstRequest().url().stringCenterEllipsizedToLength() +
((response.httpStatusCode() / 100 != 2) ? " could not be fetched." : " was redirected."));
// Note that cacheUpdateFailed() can cause the cache group to be deleted.
cacheUpdateFailed();
} else if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) {
// Skip this resource. It is dropped from the cache.
m_currentHandle->cancel();
- m_currentHandle = 0;
+ m_currentHandle = nullptr;
m_pendingEntries.remove(url);
// Load the next resource, if any.
startLoadingEntry();
@@ -564,10 +540,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
ASSERT(m_newestCache);
ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->firstRequest().url());
ASSERT(newestCachedResource);
- m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path()));
+ m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path()));
m_pendingEntries.remove(m_currentHandle->firstRequest().url());
m_currentHandle->cancel();
- m_currentHandle = 0;
+ m_currentHandle = nullptr;
// Load the next resource, if any.
startLoadingEntry();
}
@@ -581,9 +557,7 @@ void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* d
{
UNUSED_PARAM(encodedDataLength);
-#if ENABLE(INSPECTOR)
InspectorInstrumentation::didReceiveData(m_frame, m_currentResourceIdentifier, 0, length, 0);
-#endif
if (handle == m_manifestHandle) {
didReceiveManifestData(data, length);
@@ -593,16 +567,12 @@ void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* d
ASSERT(handle == m_currentHandle);
ASSERT(m_currentResource);
- m_currentResource->data()->append(data, length);
+ m_currentResource->data().append(data, length);
}
void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double finishTime)
{
-#if ENABLE(INSPECTOR)
InspectorInstrumentation::didFinishLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, finishTime);
-#else
- UNUSED_PARAM(finishTime);
-#endif
if (handle == m_manifestHandle) {
didFinishLoadingManifest();
@@ -616,8 +586,8 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double fini
ASSERT(m_cacheBeingUpdated);
- m_cacheBeingUpdated->addResource(m_currentResource.release());
- m_currentHandle = 0;
+ m_cacheBeingUpdated->addResource(m_currentResource.releaseNonNull());
+ m_currentHandle = nullptr;
// While downloading check to see if we have exceeded the available quota.
// We can stop immediately if we have already previously failed
@@ -625,8 +595,8 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double fini
// of the quota being reached and decided not to increase it then.
// FIXME: Should we break earlier and prevent redownloading on later page loads?
if (m_originQuotaExceededPreviously && m_availableSpaceInQuota < m_cacheBeingUpdated->estimatedSizeInStorage()) {
- m_currentResource = 0;
- m_frame->document()->addConsoleMessage(AppCacheMessageSource, ErrorMessageLevel, "Application Cache update failed, because size quota was exceeded.");
+ m_currentResource = nullptr;
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded."));
cacheUpdateFailed();
return;
}
@@ -637,11 +607,7 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double fini
void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& error)
{
-#if ENABLE(INSPECTOR)
InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, error);
-#else
- UNUSED_PARAM(error);
-#endif
if (handle == m_manifestHandle) {
// A network error is logged elsewhere, no need to log again. Also, it's normal for manifest fetching to fail when working offline.
@@ -653,15 +619,14 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError&
unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->firstRequest().url());
URL url(handle->firstRequest().url());
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
+ url.removeFragmentIdentifier();
ASSERT(!m_currentResource || !m_pendingEntries.contains(url));
- m_currentResource = 0;
+ m_currentResource = nullptr;
m_pendingEntries.remove(url);
if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) {
- m_frame->document()->addConsoleMessage(AppCacheMessageSource, ErrorMessageLevel, "Application Cache update failed, because " + url.stringCenterEllipsizedToLength() + " could not be fetched.");
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, "Application Cache update failed, because " + url.stringCenterEllipsizedToLength() + " could not be fetched.");
// Note that cacheUpdateFailed() can cause the cache group to be deleted.
cacheUpdateFailed();
} else {
@@ -670,7 +635,7 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError&
ASSERT(m_newestCache);
ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url);
ASSERT(newestCachedResource);
- m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path()));
+ m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path()));
// Load the next resource, if any.
startLoadingEntry();
}
@@ -682,6 +647,8 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r
ASSERT(m_manifestHandle);
if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) {
+ InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest()));
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, makeString("Application Cache manifest could not be fetched, because the manifest had a ", String::number(response.httpStatusCode()), " response."));
manifestNotFound();
return;
}
@@ -690,13 +657,15 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r
return;
if (response.httpStatusCode() / 100 != 2) {
- m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be fetched.");
+ InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest()));
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, makeString("Application Cache manifest could not be fetched, because the manifest had a ", String::number(response.httpStatusCode()), " response."));
cacheUpdateFailed();
return;
}
if (response.url() != m_manifestHandle->firstRequest().url()) {
- m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be fetched, because a redirection was attempted.");
+ InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest()));
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be fetched, because a redirection was attempted."));
cacheUpdateFailed();
return;
}
@@ -707,7 +676,7 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r
void ApplicationCacheGroup::didReceiveManifestData(const char* data, int length)
{
if (m_manifestResource)
- m_manifestResource->data()->append(data, length);
+ m_manifestResource->data().append(data, length);
}
void ApplicationCacheGroup::didFinishLoadingManifest()
@@ -716,12 +685,12 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
if (!isUpgradeAttempt && !m_manifestResource) {
// The server returned 304 Not Modified even though we didn't send a conditional request.
- m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be fetched because of an unexpected 304 Not Modified server response.");
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be fetched because of an unexpected 304 Not Modified server response."));
cacheUpdateFailed();
return;
}
- m_manifestHandle = 0;
+ m_manifestHandle = nullptr;
// Check if the manifest was not modified.
if (isUpgradeAttempt) {
@@ -729,10 +698,10 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
ASSERT(newestManifest);
if (!m_manifestResource || // The resource will be null if HTTP response was 304 Not Modified.
- (newestManifest->data()->size() == m_manifestResource->data()->size() && !memcmp(newestManifest->data()->data(), m_manifestResource->data()->data(), newestManifest->data()->size()))) {
+ (newestManifest->data().size() == m_manifestResource->data().size() && !memcmp(newestManifest->data().data(), m_manifestResource->data().data(), newestManifest->data().size()))) {
m_completionType = NoUpdate;
- m_manifestResource = 0;
+ m_manifestResource = nullptr;
deliverDelayedMainResources();
return;
@@ -740,9 +709,9 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
}
Manifest manifest;
- if (!parseManifest(m_manifestURL, m_manifestResource->data()->data(), m_manifestResource->data()->size(), manifest)) {
+ if (!parseManifest(m_manifestURL, m_manifestResource->data().data(), m_manifestResource->data().size(), manifest)) {
// At the time of this writing, lack of "CACHE MANIFEST" signature is the only reason for parseManifest to fail.
- m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be parsed. Does it start with CACHE MANIFEST?");
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be parsed. Does it start with CACHE MANIFEST?"));
cacheUpdateFailed();
return;
}
@@ -751,19 +720,18 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
m_cacheBeingUpdated = ApplicationCache::create();
m_cacheBeingUpdated->setGroup(this);
- HashSet<DocumentLoader*>::const_iterator masterEnd = m_pendingMasterResourceLoaders.end();
- for (HashSet<DocumentLoader*>::const_iterator iter = m_pendingMasterResourceLoaders.begin(); iter != masterEnd; ++iter)
- associateDocumentLoaderWithCache(*iter, m_cacheBeingUpdated.get());
+ for (auto& loader : m_pendingMasterResourceLoaders)
+ associateDocumentLoaderWithCache(loader, m_cacheBeingUpdated.get());
// We have the manifest, now download the resources.
setUpdateStatus(Downloading);
- postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().downloadingEvent, m_associatedDocumentLoaders);
ASSERT(m_pendingEntries.isEmpty());
if (isUpgradeAttempt) {
- for (const auto& urlAndResource : *m_newestCache) {
+ for (const auto& urlAndResource : m_newestCache->resources()) {
unsigned type = urlAndResource.value->type();
if (type & ApplicationCacheResource::Master)
addEntry(urlAndResource.key, type);
@@ -773,9 +741,8 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
for (const auto& explicitURL : manifest.explicitURLs)
addEntry(explicitURL, ApplicationCacheResource::Explicit);
- size_t fallbackCount = manifest.fallbackURLs.size();
- for (size_t i = 0; i < fallbackCount; ++i)
- addEntry(manifest.fallbackURLs[i].second, ApplicationCacheResource::Fallback);
+ for (auto& fallbackURL : manifest.fallbackURLs)
+ addEntry(fallbackURL.second, ApplicationCacheResource::Fallback);
m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs);
m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs);
@@ -793,7 +760,7 @@ void ApplicationCacheGroup::didReachMaxAppCacheSize()
{
ASSERT(m_frame);
ASSERT(m_cacheBeingUpdated);
- m_frame->page()->chrome().client().reachedMaxAppCacheSize(cacheStorage().spaceNeeded(m_cacheBeingUpdated->estimatedSizeInStorage()));
+ m_frame->page()->chrome().client().reachedMaxAppCacheSize(m_frame->page()->applicationCacheStorage().spaceNeeded(m_cacheBeingUpdated->estimatedSizeInStorage()));
m_calledReachedMaxAppCacheSize = true;
checkIfLoadIsComplete();
}
@@ -808,7 +775,7 @@ void ApplicationCacheGroup::didReachOriginQuota(int64_t totalSpaceNeeded)
void ApplicationCacheGroup::cacheUpdateFailed()
{
stopLoading();
- m_manifestResource = 0;
+ m_manifestResource = nullptr;
// Wait for master resource loads to finish.
m_completionType = Failure;
@@ -817,7 +784,7 @@ void ApplicationCacheGroup::cacheUpdateFailed()
void ApplicationCacheGroup::recalculateAvailableSpaceInQuota()
{
- if (!cacheStorage().calculateRemainingSizeForOriginExcludingCache(m_origin.get(), m_newestCache.get(), m_availableSpaceInQuota)) {
+ if (!m_frame->page()->applicationCacheStorage().calculateRemainingSizeForOriginExcludingCache(m_origin, m_newestCache.get(), m_availableSpaceInQuota)) {
// Failed to determine what is left in the quota. Fallback to allowing anything.
m_availableSpaceInQuota = ApplicationCacheStorage::noQuota();
}
@@ -827,27 +794,27 @@ void ApplicationCacheGroup::manifestNotFound()
{
makeObsolete();
- postListenerTask(ApplicationCacheHost::OBSOLETE_EVENT, m_associatedDocumentLoaders);
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_pendingMasterResourceLoaders);
+ postListenerTask(eventNames().obsoleteEvent, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().errorEvent, m_pendingMasterResourceLoaders);
stopLoading();
ASSERT(m_pendingEntries.isEmpty());
- m_manifestResource = 0;
+ m_manifestResource = nullptr;
while (!m_pendingMasterResourceLoaders.isEmpty()) {
HashSet<DocumentLoader*>::iterator it = m_pendingMasterResourceLoaders.begin();
- ASSERT((*it)->applicationCacheHost()->candidateApplicationCacheGroup() == this);
- ASSERT(!(*it)->applicationCacheHost()->applicationCache());
- (*it)->applicationCacheHost()->setCandidateApplicationCacheGroup(0);
+ ASSERT((*it)->applicationCacheHost().candidateApplicationCacheGroup() == this);
+ ASSERT(!(*it)->applicationCacheHost().applicationCache());
+ (*it)->applicationCacheHost().setCandidateApplicationCacheGroup(nullptr);
m_pendingMasterResourceLoaders.remove(it);
}
m_downloadingPendingMasterResourceLoadersCount = 0;
setUpdateStatus(Idle);
- m_frame = 0;
-
+ m_frame = nullptr;
+
if (m_caches.isEmpty()) {
ASSERT(m_associatedDocumentLoaders.isEmpty());
ASSERT(!m_cacheBeingUpdated);
@@ -874,13 +841,13 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// The storage could have been manually emptied by the user.
if (!m_storageID)
- cacheStorage().storeNewestCache(this);
+ m_storage->storeNewestCache(*this);
- postListenerTask(ApplicationCacheHost::NOUPDATE_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().noupdateEvent, m_associatedDocumentLoaders);
break;
case Failure:
ASSERT(!m_cacheBeingUpdated);
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().errorEvent, m_associatedDocumentLoaders);
if (m_caches.isEmpty()) {
ASSERT(m_associatedDocumentLoaders.isEmpty());
delete this;
@@ -892,14 +859,14 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
ASSERT(m_cacheBeingUpdated);
if (m_manifestResource)
- m_cacheBeingUpdated->setManifestResource(m_manifestResource.release());
+ m_cacheBeingUpdated->setManifestResource(m_manifestResource.releaseNonNull());
else {
// We can get here as a result of retrying the Complete step, following
// a failure of the cache storage to save the newest cache due to hitting
// the maximum size. In such a case, m_manifestResource may be 0, as
// the manifest was already set on the newest cache object.
ASSERT(m_cacheBeingUpdated->manifestResource());
- ASSERT(cacheStorage().isMaximumSizeReached());
+ ASSERT(m_storage->isMaximumSizeReached());
ASSERT(m_calledReachedMaxAppCacheSize);
}
@@ -908,22 +875,22 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// If we exceeded the origin quota while downloading we can request a quota
// increase now, before we attempt to store the cache.
int64_t totalSpaceNeeded;
- if (!cacheStorage().checkOriginQuota(this, oldNewestCache.get(), m_cacheBeingUpdated.get(), totalSpaceNeeded))
+ if (!m_storage->checkOriginQuota(this, oldNewestCache.get(), m_cacheBeingUpdated.get(), totalSpaceNeeded))
didReachOriginQuota(totalSpaceNeeded);
ApplicationCacheStorage::FailureReason failureReason;
- setNewestCache(m_cacheBeingUpdated.release());
- if (cacheStorage().storeNewestCache(this, oldNewestCache.get(), failureReason)) {
+ setNewestCache(m_cacheBeingUpdated.releaseNonNull());
+ if (m_storage->storeNewestCache(*this, oldNewestCache.get(), failureReason)) {
// New cache stored, now remove the old cache.
if (oldNewestCache)
- cacheStorage().remove(oldNewestCache.get());
+ m_storage->remove(oldNewestCache.get());
// Fire the final progress event.
ASSERT(m_progressDone == m_progressTotal);
- postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().progressEvent, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
// Fire the success event.
- postListenerTask(isUpgradeAttempt ? ApplicationCacheHost::UPDATEREADY_EVENT : ApplicationCacheHost::CACHED_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(isUpgradeAttempt ? eventNames().updatereadyEvent : eventNames().cachedEvent, m_associatedDocumentLoaders);
// It is clear that the origin quota was not reached, so clear the flag if it was set.
m_originQuotaExceededPreviously = false;
} else {
@@ -931,7 +898,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// We ran out of space for this origin. Fall down to the normal error handling
// after recording this state.
m_originQuotaExceededPreviously = true;
- m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache update failed, because size quota was exceeded.");
+ m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded."));
}
if (failureReason == ApplicationCacheStorage::TotalQuotaReached && !m_calledReachedMaxAppCacheSize) {
@@ -943,11 +910,9 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// save the new cache.
// Save a reference to the new cache.
- m_cacheBeingUpdated = m_newestCache.release();
- if (oldNewestCache) {
- // Reinstate the oldNewestCache.
- setNewestCache(oldNewestCache.release());
- }
+ m_cacheBeingUpdated = WTFMove(m_newestCache);
+ if (oldNewestCache)
+ setNewestCache(oldNewestCache.releaseNonNull());
scheduleReachedMaxAppCacheSizeCallback();
return;
}
@@ -955,7 +920,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// Run the "cache failure steps"
// Fire the error events to all pending master entries, as well any other cache hosts
// currently associated with a cache in this group.
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().errorEvent, m_associatedDocumentLoaders);
// Disassociate the pending master entries from the failed new cache. Note that
// all other loaders in the m_associatedDocumentLoaders are still associated with
// some other cache in this group. They are not associated with the failed new cache.
@@ -963,14 +928,13 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// Need to copy loaders, because the cache group may be destroyed at the end of iteration.
Vector<DocumentLoader*> loaders;
copyToVector(m_pendingMasterResourceLoaders, loaders);
- size_t count = loaders.size();
- for (size_t i = 0; i != count; ++i)
- disassociateDocumentLoader(loaders[i]); // This can delete this group.
+ for (auto& loader : loaders)
+ disassociateDocumentLoader(*loader); // This can delete this group.
// Reinstate the oldNewestCache, if there was one.
if (oldNewestCache) {
// This will discard the failed new cache.
- setNewestCache(oldNewestCache.release());
+ setNewestCache(oldNewestCache.releaseNonNull());
} else {
// We must have been deleted by the last call to disassociateDocumentLoader().
return;
@@ -984,7 +948,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
m_pendingMasterResourceLoaders.clear();
m_completionType = None;
setUpdateStatus(Idle);
- m_frame = 0;
+ m_frame = nullptr;
m_availableSpaceInQuota = ApplicationCacheStorage::unknownQuota();
m_calledReachedMaxAppCacheSize = false;
}
@@ -999,14 +963,13 @@ void ApplicationCacheGroup::startLoadingEntry()
return;
}
- EntryMap::const_iterator it = m_pendingEntries.begin();
+ auto firstPendingEntryURL = m_pendingEntries.begin()->key;
- postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
+ postListenerTask(eventNames().progressEvent, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
m_progressDone++;
ASSERT(!m_currentHandle);
-
- m_currentHandle = createResourceHandle(URL(ParsedURLString, it->key), m_newestCache ? m_newestCache->resourceForURL(it->key) : 0);
+ m_currentHandle = createResourceHandle(URL(ParsedURLString, firstPendingEntryURL), m_newestCache ? m_newestCache->resourceForURL(firstPendingEntryURL) : 0);
}
void ApplicationCacheGroup::deliverDelayedMainResources()
@@ -1014,19 +977,15 @@ void ApplicationCacheGroup::deliverDelayedMainResources()
// Need to copy loaders, because the cache group may be destroyed at the end of iteration.
Vector<DocumentLoader*> loaders;
copyToVector(m_pendingMasterResourceLoaders, loaders);
- size_t count = loaders.size();
- for (size_t i = 0; i != count; ++i) {
- DocumentLoader* loader = loaders[i];
+ for (auto* loader : loaders) {
if (loader->isLoadingMainResource())
continue;
-
- const ResourceError& error = loader->mainDocumentError();
- if (error.isNull())
- finishedLoadingMainResource(loader);
+ if (loader->mainDocumentError().isNull())
+ finishedLoadingMainResource(*loader);
else
- failedLoadingMainResource(loader);
+ failedLoadingMainResource(*loader);
}
- if (!count)
+ if (loaders.isEmpty())
checkIfLoadIsComplete();
}
@@ -1034,13 +993,12 @@ void ApplicationCacheGroup::addEntry(const String& url, unsigned type)
{
ASSERT(m_cacheBeingUpdated);
ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier());
-
+
// Don't add the URL if we already have an master resource in the cache
// (i.e., the main resource finished loading before the manifest).
- if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) {
+ if (auto* resource = m_cacheBeingUpdated->resourceForURL(url)) {
ASSERT(resource->type() & ApplicationCacheResource::Master);
ASSERT(!m_frame->loader().documentLoader()->isLoadingMainResource());
-
resource->addType(type);
return;
}
@@ -1051,11 +1009,8 @@ void ApplicationCacheGroup::addEntry(const String& url, unsigned type)
m_manifestResource->addType(type);
return;
}
-
- EntryMap::AddResult result = m_pendingEntries.add(url, type);
-
- if (!result.isNewEntry)
- result.iterator->value |= type;
+
+ m_pendingEntries.add(url, type).iterator->value |= type;
}
void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loader, ApplicationCache* cache)
@@ -1066,90 +1021,64 @@ void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loa
ASSERT(!m_isObsolete);
- loader->applicationCacheHost()->setApplicationCache(cache);
+ loader->applicationCacheHost().setApplicationCache(cache);
ASSERT(!m_associatedDocumentLoaders.contains(loader));
m_associatedDocumentLoaders.add(loader);
}
-class ChromeClientCallbackTimer: public TimerBase {
+class ChromeClientCallbackTimer final : public TimerBase {
public:
- ChromeClientCallbackTimer(ApplicationCacheGroup* cacheGroup)
- : m_cacheGroup(cacheGroup)
+ ChromeClientCallbackTimer(ApplicationCacheGroup& group)
+ : m_group(group)
{
}
private:
- virtual void fired() override
+ void fired() final
{
- m_cacheGroup->didReachMaxAppCacheSize();
+ m_group.didReachMaxAppCacheSize();
delete this;
}
- // Note that there is no need to use a RefPtr here. The ApplicationCacheGroup instance is guaranteed
- // to be alive when the timer fires since invoking the ChromeClient callback is part of its normal
+
+ // Note that there is no need to use a Ref here. The ApplicationCacheGroup instance is guaranteed
+ // to be alive when the timer fires since invoking the callback is part of its normal
// update machinery and nothing can yet cause it to get deleted.
- ApplicationCacheGroup* m_cacheGroup;
+ ApplicationCacheGroup& m_group;
};
void ApplicationCacheGroup::scheduleReachedMaxAppCacheSizeCallback()
{
ASSERT(isMainThread());
- ChromeClientCallbackTimer* timer = new ChromeClientCallbackTimer(this);
+ auto* timer = new ChromeClientCallbackTimer(*this);
timer->startOneShot(0);
// The timer will delete itself once it fires.
}
-class CallCacheListenerTask : public ScriptExecutionContext::Task {
-public:
- static PassOwnPtr<CallCacheListenerTask> create(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone)
- {
- return adoptPtr(new CallCacheListenerTask(loader, eventID, progressTotal, progressDone));
- }
-
- virtual void performTask(ScriptExecutionContext* context) override
- {
-
- ASSERT_UNUSED(context, context->isDocument());
- Frame* frame = m_documentLoader->frame();
- if (!frame)
- return;
-
- ASSERT(frame->loader().documentLoader() == m_documentLoader.get());
-
- m_documentLoader->applicationCacheHost()->notifyDOMApplicationCache(m_eventID, m_progressTotal, m_progressDone);
- }
-
-private:
- CallCacheListenerTask(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone)
- : m_documentLoader(loader)
- , m_eventID(eventID)
- , m_progressTotal(progressTotal)
- , m_progressDone(progressDone)
- {
- }
-
- RefPtr<DocumentLoader> m_documentLoader;
- ApplicationCacheHost::EventID m_eventID;
- int m_progressTotal;
- int m_progressDone;
-};
-
-void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone, const HashSet<DocumentLoader*>& loaderSet)
+void ApplicationCacheGroup::postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, const HashSet<DocumentLoader*>& loaderSet)
{
- HashSet<DocumentLoader*>::const_iterator loaderSetEnd = loaderSet.end();
- for (HashSet<DocumentLoader*>::const_iterator iter = loaderSet.begin(); iter != loaderSetEnd; ++iter)
- postListenerTask(eventID, progressTotal, progressDone, *iter);
+ for (auto& loader : loaderSet)
+ postListenerTask(eventType, progressTotal, progressDone, *loader);
}
-void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone, DocumentLoader* loader)
+void ApplicationCacheGroup::postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, DocumentLoader& loader)
{
- Frame* frame = loader->frame();
+ auto* frame = loader.frame();
if (!frame)
return;
- ASSERT(frame->loader().documentLoader() == loader);
+ ASSERT(frame->loader().documentLoader() == &loader);
+
+ RefPtr<DocumentLoader> protectedLoader(&loader);
+ frame->document()->postTask([protectedLoader, &eventType, progressTotal, progressDone] (ScriptExecutionContext& context) {
+ ASSERT_UNUSED(context, context.isDocument());
+ auto* frame = protectedLoader->frame();
+ if (!frame)
+ return;
- frame->document()->postTask(CallCacheListenerTask::create(loader, eventID, progressTotal, progressDone));
+ ASSERT(frame->loader().documentLoader() == protectedLoader);
+ protectedLoader->applicationCacheHost().notifyDOMApplicationCache(eventType, progressTotal, progressDone);
+ });
}
void ApplicationCacheGroup::setUpdateStatus(UpdateStatus status)
@@ -1160,8 +1089,7 @@ void ApplicationCacheGroup::setUpdateStatus(UpdateStatus status)
void ApplicationCacheGroup::clearStorageID()
{
m_storageID = 0;
-
- for (const auto& cache : m_caches)
+ for (auto& cache : m_caches)
cache->clearStorageID();
}
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheGroup.h b/Source/WebCore/loader/appcache/ApplicationCacheGroup.h
index e1fb198ed..ceb83dfc6 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheGroup.h
+++ b/Source/WebCore/loader/appcache/ApplicationCacheGroup.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,13 +23,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ApplicationCacheGroup_h
-#define ApplicationCacheGroup_h
+#pragma once
#include "DOMApplicationCache.h"
#include "URL.h"
#include "ResourceHandleClient.h"
-#include "SharedBuffer.h"
#include <wtf/Noncopyable.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
@@ -39,6 +37,7 @@ namespace WebCore {
class ApplicationCache;
class ApplicationCacheResource;
+class ApplicationCacheStorage;
class Document;
class DocumentLoader;
class Frame;
@@ -50,10 +49,11 @@ enum ApplicationCacheUpdateOption {
ApplicationCacheUpdateWithoutBrowsingContext
};
-class ApplicationCacheGroup : ResourceHandleClient {
- WTF_MAKE_NONCOPYABLE(ApplicationCacheGroup); WTF_MAKE_FAST_ALLOCATED;
+class ApplicationCacheGroup final : private ResourceHandleClient {
+ WTF_MAKE_NONCOPYABLE(ApplicationCacheGroup);
+ WTF_MAKE_FAST_ALLOCATED;
public:
- ApplicationCacheGroup(const URL& manifestURL, bool isCopy = false);
+ explicit ApplicationCacheGroup(Ref<ApplicationCacheStorage>&&, const URL& manifestURL);
virtual ~ApplicationCacheGroup();
enum UpdateStatus { Idle, Checking, Downloading };
@@ -61,11 +61,12 @@ public:
static ApplicationCache* cacheForMainRequest(const ResourceRequest&, DocumentLoader*);
static ApplicationCache* fallbackCacheForMainRequest(const ResourceRequest&, DocumentLoader*);
- static void selectCache(Frame*, const URL& manifestURL);
- static void selectCacheWithoutManifestURL(Frame*);
-
+ static void selectCache(Frame&, const URL& manifestURL);
+ static void selectCacheWithoutManifestURL(Frame&);
+
+ ApplicationCacheStorage& storage() { return m_storage; }
const URL& manifestURL() const { return m_manifestURL; }
- const SecurityOrigin* origin() const { return m_origin.get(); }
+ const SecurityOrigin& origin() const { return m_origin.get(); }
UpdateStatus updateStatus() const { return m_updateStatus; }
void setUpdateStatus(UpdateStatus status);
@@ -73,46 +74,44 @@ public:
unsigned storageID() const { return m_storageID; }
void clearStorageID();
- void update(Frame*, ApplicationCacheUpdateOption); // FIXME: Frame should not be needed when updating without browsing context.
- void cacheDestroyed(ApplicationCache*);
+ void update(Frame&, ApplicationCacheUpdateOption); // FIXME: Frame should not be needed when updating without browsing context.
+ void cacheDestroyed(ApplicationCache&);
- void abort(Frame*);
+ void abort(Frame&);
- bool cacheIsBeingUpdated(const ApplicationCache* cache) const { return cache == m_cacheBeingUpdated; }
+ bool cacheIsComplete(ApplicationCache& cache) { return m_caches.contains(&cache); }
- void stopLoadingInFrame(Frame*);
+ void stopLoadingInFrame(Frame&);
ApplicationCache* newestCache() const { return m_newestCache.get(); }
- void setNewestCache(PassRefPtr<ApplicationCache>);
+ void setNewestCache(Ref<ApplicationCache>&&);
void makeObsolete();
bool isObsolete() const { return m_isObsolete; }
- void finishedLoadingMainResource(DocumentLoader*);
- void failedLoadingMainResource(DocumentLoader*);
-
- void disassociateDocumentLoader(DocumentLoader*);
+ void finishedLoadingMainResource(DocumentLoader&);
+ void failedLoadingMainResource(DocumentLoader&);
- bool isCopy() const { return m_isCopy; }
+ void disassociateDocumentLoader(DocumentLoader&);
private:
- static void postListenerTask(ApplicationCacheHost::EventID id, const HashSet<DocumentLoader*>& set) { postListenerTask(id, 0, 0, set); }
- static void postListenerTask(ApplicationCacheHost::EventID id, DocumentLoader* loader) { postListenerTask(id, 0, 0, loader); }
- static void postListenerTask(ApplicationCacheHost::EventID, int progressTotal, int progressDone, const HashSet<DocumentLoader*>&);
- static void postListenerTask(ApplicationCacheHost::EventID, int progressTotal, int progressDone, DocumentLoader*);
+ static void postListenerTask(const AtomicString& eventType, const HashSet<DocumentLoader*>& set) { postListenerTask(eventType, 0, 0, set); }
+ static void postListenerTask(const AtomicString& eventType, DocumentLoader& loader) { postListenerTask(eventType, 0, 0, loader); }
+ static void postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, const HashSet<DocumentLoader*>&);
+ static void postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, DocumentLoader&);
void scheduleReachedMaxAppCacheSizeCallback();
- PassRefPtr<ResourceHandle> createResourceHandle(const URL&, ApplicationCacheResource* newestCachedResource);
+ RefPtr<ResourceHandle> createResourceHandle(const URL&, ApplicationCacheResource* newestCachedResource);
// For normal resource loading, WebKit client is asked about each resource individually. Since application cache does not belong to any particular document,
// the existing client callback cannot be used, so assume that any client that enables application cache also wants it to use credential storage.
- virtual bool shouldUseCredentialStorage(ResourceHandle*) override { return true; }
+ bool shouldUseCredentialStorage(ResourceHandle*) override { return true; }
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) override;
- virtual void didReceiveData(ResourceHandle*, const char*, unsigned length, int encodedDataLength) override;
- virtual void didFinishLoading(ResourceHandle*, double finishTime) override;
- virtual void didFail(ResourceHandle*, const ResourceError&) override;
+ void didReceiveResponse(ResourceHandle*, ResourceResponse&&) override;
+ void didReceiveData(ResourceHandle*, const char*, unsigned length, int encodedDataLength) override;
+ void didFinishLoading(ResourceHandle*, double finishTime) override;
+ void didFail(ResourceHandle*, const ResourceError&) override;
void didReceiveManifestResponse(const ResourceResponse&);
void didReceiveManifestData(const char*, int);
@@ -132,10 +131,12 @@ private:
void associateDocumentLoaderWithCache(DocumentLoader*, ApplicationCache*);
void stopLoading();
-
+
+ Ref<ApplicationCacheStorage> m_storage;
+
URL m_manifestURL;
- RefPtr<SecurityOrigin> m_origin;
- UpdateStatus m_updateStatus;
+ Ref<SecurityOrigin> m_origin;
+ UpdateStatus m_updateStatus { Idle };
// This is the newest complete cache in the group.
RefPtr<ApplicationCache> m_newestCache;
@@ -150,26 +151,25 @@ private:
// List of pending master entries, used during the update process to ensure that new master entries are cached.
HashSet<DocumentLoader*> m_pendingMasterResourceLoaders;
// How many of the above pending master entries have not yet finished downloading.
- int m_downloadingPendingMasterResourceLoadersCount;
+ int m_downloadingPendingMasterResourceLoadersCount { 0 };
// These are all the document loaders that are associated with a cache in this group.
HashSet<DocumentLoader*> m_associatedDocumentLoaders;
// The URLs and types of pending cache entries.
- typedef HashMap<String, unsigned> EntryMap;
- EntryMap m_pendingEntries;
+ HashMap<String, unsigned> m_pendingEntries;
// The total number of items to be processed to update the cache group and the number that have been done.
- int m_progressTotal;
- int m_progressDone;
+ int m_progressTotal { 0 };
+ int m_progressDone { 0 };
// Frame used for fetching resources when updating.
// FIXME: An update started by a particular frame should not stop if it is destroyed, but there are other frames associated with the same cache group.
- Frame* m_frame;
+ Frame* m_frame { nullptr };
// An obsolete cache group is never stored, but the opposite is not true - storing may fail for multiple reasons, such as exceeding disk quota.
- unsigned m_storageID;
- bool m_isObsolete;
+ unsigned m_storageID { 0 };
+ bool m_isObsolete { false };
// During update, this is used to handle asynchronously arriving results.
enum CompletionType {
@@ -178,32 +178,24 @@ private:
Failure,
Completed
};
- CompletionType m_completionType;
-
- // Whether this cache group is a copy that's only used for transferring the cache to another file.
- bool m_isCopy;
+ CompletionType m_completionType { None };
// This flag is set immediately after the ChromeClient::reachedMaxAppCacheSize() callback is invoked as a result of the storage layer failing to save a cache
// due to reaching the maximum size of the application cache database file. This flag is used by ApplicationCacheGroup::checkIfLoadIsComplete() to decide
// the course of action in case of this failure (i.e. call the ChromeClient callback or run the failure steps).
- bool m_calledReachedMaxAppCacheSize;
+ bool m_calledReachedMaxAppCacheSize { false };
RefPtr<ResourceHandle> m_currentHandle;
RefPtr<ApplicationCacheResource> m_currentResource;
-
-#if ENABLE(INSPECTOR)
unsigned long m_currentResourceIdentifier;
-#endif
RefPtr<ApplicationCacheResource> m_manifestResource;
RefPtr<ResourceHandle> m_manifestHandle;
int64_t m_availableSpaceInQuota;
- bool m_originQuotaExceededPreviously;
+ bool m_originQuotaExceededPreviously { false };
friend class ChromeClientCallbackTimer;
};
} // namespace WebCore
-
-#endif // ApplicationCacheGroup_h
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
index 9cc3f8d85..9114699c8 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2016 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,33 +29,33 @@
#include "ApplicationCache.h"
#include "ApplicationCacheGroup.h"
#include "ApplicationCacheResource.h"
+#include "ContentSecurityPolicy.h"
#include "DocumentLoader.h"
#include "DOMApplicationCache.h"
+#include "EventNames.h"
+#include "FileSystem.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "InspectorInstrumentation.h"
+#include "MainFrame.h"
+#include "Page.h"
#include "ProgressEvent.h"
#include "ResourceHandle.h"
-#include "ResourceLoader.h"
#include "ResourceRequest.h"
#include "Settings.h"
+#include "SubresourceLoader.h"
namespace WebCore {
-ApplicationCacheHost::ApplicationCacheHost(DocumentLoader* documentLoader)
- : m_domApplicationCache(0)
- , m_documentLoader(documentLoader)
- , m_defersEvents(true)
- , m_candidateApplicationCacheGroup(0)
+ApplicationCacheHost::ApplicationCacheHost(DocumentLoader& documentLoader)
+ : m_documentLoader(documentLoader)
{
- ASSERT(m_documentLoader);
}
ApplicationCacheHost::~ApplicationCacheHost()
{
ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup);
-
if (m_applicationCache)
m_applicationCache->group()->disassociateDocumentLoader(m_documentLoader);
else if (m_candidateApplicationCacheGroup)
@@ -64,31 +64,41 @@ ApplicationCacheHost::~ApplicationCacheHost()
void ApplicationCacheHost::selectCacheWithoutManifest()
{
- ApplicationCacheGroup::selectCacheWithoutManifestURL(m_documentLoader->frame());
+ ASSERT(m_documentLoader.frame());
+ ApplicationCacheGroup::selectCacheWithoutManifestURL(*m_documentLoader.frame());
}
void ApplicationCacheHost::selectCacheWithManifest(const URL& manifestURL)
{
- ApplicationCacheGroup::selectCache(m_documentLoader->frame(), manifestURL);
+ ASSERT(m_documentLoader.frame());
+ ApplicationCacheGroup::selectCache(*m_documentLoader.frame(), manifestURL);
}
void ApplicationCacheHost::maybeLoadMainResource(ResourceRequest& request, SubstituteData& substituteData)
{
// Check if this request should be loaded from the application cache
- if (!substituteData.isValid() && isApplicationCacheEnabled()) {
+ if (!substituteData.isValid() && isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) {
ASSERT(!m_mainResourceApplicationCache);
- m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, m_documentLoader);
+ m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, &m_documentLoader);
if (m_mainResourceApplicationCache) {
// Get the resource from the application cache. By definition, cacheForMainRequest() returns a cache that contains the resource.
ApplicationCacheResource* resource = m_mainResourceApplicationCache->resourceForRequest(request);
- substituteData = SubstituteData(resource->data(),
- resource->response().mimeType(),
- resource->response().textEncodingName(),
- URL(),
+
+ // ApplicationCache resources have fragment identifiers stripped off of their URLs,
+ // but we'll need to restore that for the SubstituteData.
+ ResourceResponse responseToUse = resource->response();
+ if (request.url().hasFragmentIdentifier()) {
+ URL url = responseToUse.url();
+ url.setFragmentIdentifier(request.url().fragmentIdentifier());
+ responseToUse.setURL(url);
+ }
+
+ substituteData = SubstituteData(&resource->data(),
URL(),
- SubstituteData::ShouldRevealToSessionHistory);
+ responseToUse,
+ SubstituteData::SessionHistoryVisibility::Visible);
}
}
}
@@ -103,10 +113,10 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceReques
{
if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) {
ASSERT(!m_mainResourceApplicationCache);
- if (isApplicationCacheEnabled()) {
- m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, documentLoader());
+ if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) {
+ m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, &m_documentLoader);
- if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get()))
+ if (scheduleLoadFallbackResourceFromApplicationCache(m_documentLoader.mainResourceLoader(), m_mainResourceApplicationCache.get()))
return true;
}
}
@@ -117,10 +127,10 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest&
{
if (!error.isCancellation()) {
ASSERT(!m_mainResourceApplicationCache);
- if (isApplicationCacheEnabled()) {
- m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, m_documentLoader);
+ if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) {
+ m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, &m_documentLoader);
- if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get()))
+ if (scheduleLoadFallbackResourceFromApplicationCache(m_documentLoader.mainResourceLoader(), m_mainResourceApplicationCache.get()))
return true;
}
}
@@ -129,12 +139,11 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest&
void ApplicationCacheHost::mainResourceDataReceived(const char*, int, long long, bool)
{
- // This method is here to facilitate alternate implemetations of this interface by the host browser.
}
void ApplicationCacheHost::failedLoadingMainResource()
{
- ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
+ auto* group = m_candidateApplicationCacheGroup;
if (!group && m_applicationCache) {
if (mainResourceApplicationCache()) {
// Even when the main resource is being loaded from an application cache, loading can fail if aborted.
@@ -149,7 +158,7 @@ void ApplicationCacheHost::failedLoadingMainResource()
void ApplicationCacheHost::finishedLoadingMainResource()
{
- ApplicationCacheGroup* group = candidateApplicationCacheGroup();
+ auto* group = candidateApplicationCacheGroup();
if (!group && applicationCache() && !mainResourceApplicationCache())
group = applicationCache()->group();
@@ -157,9 +166,9 @@ void ApplicationCacheHost::finishedLoadingMainResource()
group->finishedLoadingMainResource(m_documentLoader);
}
-bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceRequest& request, const URL& originalURL)
+bool ApplicationCacheHost::maybeLoadResource(ResourceLoader& loader, const ResourceRequest& request, const URL& originalURL)
{
- if (!isApplicationCacheEnabled())
+ if (!isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request))
return false;
if (request.url() != originalURL)
@@ -168,33 +177,33 @@ bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceReq
ApplicationCacheResource* resource;
if (!shouldLoadResourceFromApplicationCache(request, resource))
return false;
-
- m_documentLoader->m_pendingSubstituteResources.set(loader, resource);
- m_documentLoader->deliverSubstituteResourcesAfterDelay();
-
+
+ m_documentLoader.scheduleSubstituteResourceLoad(loader, *resource);
return true;
}
bool ApplicationCacheHost::maybeLoadFallbackForRedirect(ResourceLoader* resourceLoader, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
- if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url()))
+ if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) {
if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader))
return true;
+ }
return false;
}
bool ApplicationCacheHost::maybeLoadFallbackForResponse(ResourceLoader* resourceLoader, const ResourceResponse& response)
{
- if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5)
+ if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) {
if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader))
return true;
+ }
return false;
}
bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoader, const ResourceError& error)
{
if (!error.isCancellation()) {
- if (resourceLoader == m_documentLoader->mainResourceLoader())
+ if (resourceLoader == m_documentLoader.mainResourceLoader())
return maybeLoadFallbackForMainError(resourceLoader->request(), error);
if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader))
return true;
@@ -202,22 +211,51 @@ bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoa
return false;
}
-bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+URL ApplicationCacheHost::createFileURL(const String& path)
+{
+ // FIXME: Can we just use fileURLWithFileSystemPath instead?
+
+ // fileURLWithFileSystemPath function is not suitable because URL::setPath uses encodeWithURLEscapeSequences, which it notes
+ // does not correctly escape '#' and '?'. This function works for our purposes because
+ // app cache media files are always created with encodeForFileName(createCanonicalUUIDString()).
+
+#if USE(CF) && PLATFORM(WIN)
+ URL url(adoptCF(CFURLCreateWithFileSystemPath(0, path.createCFString().get(), kCFURLWindowsPathStyle, false)).get());
+#else
+ URL url;
+ url.setProtocol(ASCIILiteral("file"));
+ url.setPath(path);
+#endif
+ return url;
+}
+
+static inline RefPtr<SharedBuffer> bufferFromResource(ApplicationCacheResource& resource)
+{
+ // FIXME: Clients probably do not need a copy of the SharedBuffer.
+ // Remove the call to copy() once we ensure SharedBuffer will not be modified.
+ if (resource.path().isEmpty())
+ return resource.data().copy();
+ return SharedBuffer::createWithContentsOfFile(resource.path());
+}
+
+bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data)
{
ApplicationCacheResource* resource;
- if (shouldLoadResourceFromApplicationCache(request, resource)) {
- if (resource) {
- response = resource->response();
- data.append(resource->data()->data(), resource->data()->size());
- } else {
- error = documentLoader()->frameLoader()->client().cannotShowURLError(request);
- }
+ if (!shouldLoadResourceFromApplicationCache(request, resource))
+ return false;
+
+ auto responseData = resource ? bufferFromResource(*resource) : nullptr;
+ if (!responseData) {
+ error = m_documentLoader.frameLoader()->client().cannotShowURLError(request);
return true;
}
- return false;
+
+ response = resource->response();
+ data = WTFMove(responseData);
+ return true;
}
-void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data)
{
// If normal loading results in a redirect to a resource with another origin (indicative of a captive portal), or a 4xx or 5xx status code or equivalent,
// or if there were network errors (but not if the user canceled the download), then instead get, from the cache, the resource of the fallback entry
@@ -228,8 +266,9 @@ void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest&
ApplicationCacheResource* resource;
if (getApplicationCacheFallbackResource(request, resource)) {
response = resource->response();
- data.clear();
- data.append(resource->data()->data(), resource->data()->size());
+ // FIXME: Clients proably do not need a copy of the SharedBuffer.
+ // Remove the call to copy() once we ensure SharedBuffer will not be modified.
+ data = resource->data().copy();
}
}
}
@@ -245,20 +284,21 @@ void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplic
m_domApplicationCache = domApplicationCache;
}
-void ApplicationCacheHost::notifyDOMApplicationCache(EventID id, int total, int done)
+void ApplicationCacheHost::notifyDOMApplicationCache(const AtomicString& eventType, int total, int done)
{
- if (id != PROGRESS_EVENT)
- InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame());
+ if (eventType != eventNames().progressEvent)
+ InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader.frame());
if (m_defersEvents) {
// Event dispatching is deferred until document.onload has fired.
- m_deferredEvents.append(DeferredEvent(id, total, done));
+ m_deferredEvents.append({ eventType, total, done });
return;
}
- dispatchDOMEvent(id, total, done);
+
+ dispatchDOMEvent(eventType, total, done);
}
-void ApplicationCacheHost::stopLoadingInFrame(Frame* frame)
+void ApplicationCacheHost::stopLoadingInFrame(Frame& frame)
{
ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup);
@@ -270,56 +310,69 @@ void ApplicationCacheHost::stopLoadingInFrame(Frame* frame)
void ApplicationCacheHost::stopDeferringEvents()
{
- RefPtr<DocumentLoader> protect(documentLoader());
- for (unsigned i = 0; i < m_deferredEvents.size(); ++i) {
- const DeferredEvent& deferred = m_deferredEvents[i];
- dispatchDOMEvent(deferred.eventID, deferred.progressTotal, deferred.progressDone);
+ Ref<DocumentLoader> protect(m_documentLoader);
+
+ // Note, do not cache the size in a local variable.
+ // This code needs to properly handle the case where more events are added to
+ // m_deferredEvents while iterating it. This is why we don't use a modern for loop.
+ for (size_t i = 0; i < m_deferredEvents.size(); ++i) {
+ auto& event = m_deferredEvents[i];
+ dispatchDOMEvent(event.eventType, event.progressTotal, event.progressDone);
}
+
m_deferredEvents.clear();
m_defersEvents = false;
}
-#if ENABLE(INSPECTOR)
-void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources)
+Vector<ApplicationCacheHost::ResourceInfo> ApplicationCacheHost::resourceList()
{
- ApplicationCache* cache = applicationCache();
+ Vector<ResourceInfo> result;
+
+ auto* cache = applicationCache();
if (!cache || !cache->isComplete())
- return;
-
- for (const auto& urlAndResource : *cache) {
- RefPtr<ApplicationCacheResource> resource = urlAndResource.value;
- unsigned type = resource->type();
- bool isMaster = type & ApplicationCacheResource::Master;
+ return result;
+
+ result.reserveInitialCapacity(cache->resources().size());
+
+ for (auto& urlAndResource : cache->resources()) {
+ ASSERT(urlAndResource.value);
+ auto& resource = *urlAndResource.value;
+
+ unsigned type = resource.type();
+ bool isMaster = type & ApplicationCacheResource::Master;
bool isManifest = type & ApplicationCacheResource::Manifest;
bool isExplicit = type & ApplicationCacheResource::Explicit;
- bool isForeign = type & ApplicationCacheResource::Foreign;
+ bool isForeign = type & ApplicationCacheResource::Foreign;
bool isFallback = type & ApplicationCacheResource::Fallback;
- resources->append(ResourceInfo(resource->url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource->estimatedSizeInStorage()));
+
+ result.uncheckedAppend({ resource.url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource.estimatedSizeInStorage() });
}
+
+ return result;
}
-
+
ApplicationCacheHost::CacheInfo ApplicationCacheHost::applicationCacheInfo()
{
- ApplicationCache* cache = applicationCache();
+ auto* cache = applicationCache();
if (!cache || !cache->isComplete())
- return CacheInfo(URL(), 0, 0, 0);
-
+ return { { }, 0, 0, 0 };
+
// FIXME: Add "Creation Time" and "Update Time" to Application Caches.
- return CacheInfo(cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage());
+ return { cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage() };
}
-#endif
-void ApplicationCacheHost::dispatchDOMEvent(EventID id, int total, int done)
+static Ref<Event> createApplicationCacheEvent(const AtomicString& eventType, int total, int done)
{
- if (m_domApplicationCache) {
- const AtomicString& eventType = DOMApplicationCache::toEventType(id);
- RefPtr<Event> event;
- if (id == PROGRESS_EVENT)
- event = ProgressEvent::create(eventType, true, done, total);
- else
- event = Event::create(eventType, false, false);
- m_domApplicationCache->dispatchEvent(event, ASSERT_NO_EXCEPTION);
- }
+ if (eventType == eventNames().progressEvent)
+ return ProgressEvent::create(eventType, true, done, total);
+ return Event::create(eventType, false, false);
+}
+
+void ApplicationCacheHost::dispatchDOMEvent(const AtomicString& eventType, int total, int done)
+{
+ if (!m_domApplicationCache)
+ return;
+ m_domApplicationCache->dispatchEvent(createApplicationCacheEvent(eventType, total, done));
}
void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group)
@@ -328,25 +381,30 @@ void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGro
m_candidateApplicationCacheGroup = group;
}
-void ApplicationCacheHost::setApplicationCache(PassRefPtr<ApplicationCache> applicationCache)
+void ApplicationCacheHost::setApplicationCache(RefPtr<ApplicationCache>&& applicationCache)
{
if (m_candidateApplicationCacheGroup) {
ASSERT(!m_applicationCache);
- m_candidateApplicationCacheGroup = 0;
+ m_candidateApplicationCacheGroup = nullptr;
}
-
- m_applicationCache = applicationCache;
+ m_applicationCache = WTFMove(applicationCache);
}
-bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource)
+bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& originalRequest, ApplicationCacheResource*& resource)
{
- ApplicationCache* cache = applicationCache();
+ auto* cache = applicationCache();
if (!cache || !cache->isComplete())
return false;
+ ResourceRequest request(originalRequest);
+ if (auto* loaderFrame = m_documentLoader.frame()) {
+ if (auto* document = loaderFrame->document())
+ document->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load);
+ }
+
// If the resource is not to be fetched using the HTTP GET mechanism or equivalent, or if its URL has a different
// <scheme> component than the application cache's manifest, then fetch the resource normally.
- if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request) || !equalIgnoringCase(request.url().protocol(), cache->manifestResource()->url().protocol()))
+ if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request) || !equalIgnoringASCIICase(request.url().protocol(), cache->manifestResource()->url().protocol()))
return false;
// If the resource's URL is an master entry, the manifest, an explicit entry, or a fallback entry
@@ -385,45 +443,40 @@ bool ApplicationCacheHost::getApplicationCacheFallbackResource(const ResourceReq
resource = cache->resourceForURL(fallbackURL);
ASSERT(resource);
-
return true;
}
bool ApplicationCacheHost::scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader* loader, ApplicationCache* cache)
{
- if (!isApplicationCacheEnabled())
+ if (!isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(loader->request()))
return false;
ApplicationCacheResource* resource;
if (!getApplicationCacheFallbackResource(loader->request(), resource, cache))
return false;
- m_documentLoader->m_pendingSubstituteResources.set(loader, resource);
- m_documentLoader->deliverSubstituteResourcesAfterDelay();
-
- loader->handle()->cancel();
-
+ loader->willSwitchToSubstituteResource();
+ m_documentLoader.scheduleSubstituteResourceLoad(*loader, *resource);
return true;
}
ApplicationCacheHost::Status ApplicationCacheHost::status() const
{
- ApplicationCache* cache = applicationCache();
+ auto* cache = applicationCache();
if (!cache)
return UNCACHED;
switch (cache->group()->updateStatus()) {
- case ApplicationCacheGroup::Checking:
- return CHECKING;
- case ApplicationCacheGroup::Downloading:
- return DOWNLOADING;
- case ApplicationCacheGroup::Idle: {
- if (cache->group()->isObsolete())
- return OBSOLETE;
- if (cache != cache->group()->newestCache())
- return UPDATEREADY;
- return IDLE;
- }
+ case ApplicationCacheGroup::Checking:
+ return CHECKING;
+ case ApplicationCacheGroup::Downloading:
+ return DOWNLOADING;
+ case ApplicationCacheGroup::Idle:
+ if (cache->group()->isObsolete())
+ return OBSOLETE;
+ if (cache != cache->group()->newestCache())
+ return UPDATEREADY;
+ return IDLE;
}
ASSERT_NOT_REACHED();
@@ -432,16 +485,19 @@ ApplicationCacheHost::Status ApplicationCacheHost::status() const
bool ApplicationCacheHost::update()
{
- ApplicationCache* cache = applicationCache();
+ auto* cache = applicationCache();
if (!cache)
return false;
- cache->group()->update(m_documentLoader->frame(), ApplicationCacheUpdateWithoutBrowsingContext);
+ auto* frame = m_documentLoader.frame();
+ if (!frame)
+ return false;
+ cache->group()->update(*frame, ApplicationCacheUpdateWithoutBrowsingContext);
return true;
}
bool ApplicationCacheHost::swapCache()
{
- ApplicationCache* cache = applicationCache();
+ auto* cache = applicationCache();
if (!cache)
return false;
@@ -452,31 +508,40 @@ bool ApplicationCacheHost::swapCache()
}
// If there is no newer cache, raise an INVALID_STATE_ERR exception.
- ApplicationCache* newestCache = cache->group()->newestCache();
+ auto* newestCache = cache->group()->newestCache();
if (cache == newestCache)
return false;
ASSERT(cache->group() == newestCache->group());
setApplicationCache(newestCache);
- InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame());
+ InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader.frame());
return true;
}
void ApplicationCacheHost::abort()
{
- ApplicationCacheGroup* cacheGroup = candidateApplicationCacheGroup();
- if (cacheGroup)
- cacheGroup->abort(m_documentLoader->frame());
- else {
- ApplicationCache* cache = applicationCache();
- if (cache)
- cache->group()->abort(m_documentLoader->frame());
- }
+ auto* frame = m_documentLoader.frame();
+ if (!frame)
+ return;
+ if (auto* cacheGroup = candidateApplicationCacheGroup())
+ cacheGroup->abort(*frame);
+ else if (auto* cache = applicationCache())
+ cache->group()->abort(*frame);
}
bool ApplicationCacheHost::isApplicationCacheEnabled()
{
- return m_documentLoader->frame() && m_documentLoader->frame()->settings().offlineWebApplicationCacheEnabled();
+ return m_documentLoader.frame() && m_documentLoader.frame()->settings().offlineWebApplicationCacheEnabled() && !m_documentLoader.frame()->page()->usesEphemeralSession();
+}
+
+bool ApplicationCacheHost::isApplicationCacheBlockedForRequest(const ResourceRequest& request)
+{
+ auto* frame = m_documentLoader.frame();
+ if (!frame)
+ return false;
+ if (frame->isMainFrame())
+ return false;
+ return !SecurityOrigin::create(request.url())->canAccessApplicationCache(frame->document()->topOrigin());
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.h b/Source/WebCore/loader/appcache/ApplicationCacheHost.h
index f6e0d0b94..2bfdc62f9 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheHost.h
+++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.h
@@ -1,6 +1,7 @@
/*
- * Copyright (c) 2009, Google Inc. All rights reserved.
- *
+ * Copyright (c) 2009, Google Inc. All rights reserved.
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
@@ -28,172 +29,138 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ApplicationCacheHost_h
-#define ApplicationCacheHost_h
+#pragma once
#include "URL.h"
#include <wtf/Deque.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
namespace WebCore {
- class DOMApplicationCache;
- class DocumentLoader;
- class Frame;
- class ResourceLoader;
- class ResourceError;
- class ResourceRequest;
- class ResourceResponse;
- class SubstituteData;
- class ApplicationCache;
- class ApplicationCacheGroup;
- class ApplicationCacheResource;
- class ApplicationCacheStorage;
-
- class ApplicationCacheHost {
- WTF_MAKE_NONCOPYABLE(ApplicationCacheHost); WTF_MAKE_FAST_ALLOCATED;
- public:
- // The Status numeric values are specified in the HTML5 spec.
- enum Status {
- UNCACHED = 0,
- IDLE = 1,
- CHECKING = 2,
- DOWNLOADING = 3,
- UPDATEREADY = 4,
- OBSOLETE = 5
- };
-
- enum EventID {
- CHECKING_EVENT = 0,
- ERROR_EVENT,
- NOUPDATE_EVENT,
- DOWNLOADING_EVENT,
- PROGRESS_EVENT,
- UPDATEREADY_EVENT,
- CACHED_EVENT,
- OBSOLETE_EVENT // Must remain the last value, this is used to size arrays.
- };
-
-#if ENABLE(INSPECTOR)
- struct CacheInfo {
- CacheInfo(const URL& manifest, double creationTime, double updateTime, long long size)
- : m_manifest(manifest)
- , m_creationTime(creationTime)
- , m_updateTime(updateTime)
- , m_size(size) { }
- URL m_manifest;
- double m_creationTime;
- double m_updateTime;
- long long m_size;
- };
-
- struct ResourceInfo {
- ResourceInfo(const URL& resource, bool isMaster, bool isManifest, bool isFallback, bool isForeign, bool isExplicit, long long size)
- : m_resource(resource)
- , m_isMaster(isMaster)
- , m_isManifest(isManifest)
- , m_isFallback(isFallback)
- , m_isForeign(isForeign)
- , m_isExplicit(isExplicit)
- , m_size(size) { }
- URL m_resource;
- bool m_isMaster;
- bool m_isManifest;
- bool m_isFallback;
- bool m_isForeign;
- bool m_isExplicit;
- long long m_size;
- };
-
- typedef Vector<ResourceInfo> ResourceInfoList;
-#endif
-
- ApplicationCacheHost(DocumentLoader*);
- ~ApplicationCacheHost();
-
- void selectCacheWithoutManifest();
- void selectCacheWithManifest(const URL& manifestURL);
-
- void maybeLoadMainResource(ResourceRequest&, SubstituteData&);
- void maybeLoadMainResourceForRedirect(ResourceRequest&, SubstituteData&);
- bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&);
- void mainResourceDataReceived(const char* data, int length, long long encodedDataLength, bool allAtOnce);
- void finishedLoadingMainResource();
- void failedLoadingMainResource();
-
- bool maybeLoadResource(ResourceLoader*, ResourceRequest&, const URL& originalURL);
- bool maybeLoadFallbackForRedirect(ResourceLoader*, ResourceRequest&, const ResourceResponse&);
- bool maybeLoadFallbackForResponse(ResourceLoader*, const ResourceResponse&);
- bool maybeLoadFallbackForError(ResourceLoader*, const ResourceError&);
-
- bool maybeLoadSynchronously(ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data);
- void maybeLoadFallbackSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data);
-
- bool canCacheInPageCache();
-
- Status status() const;
- bool update();
- bool swapCache();
- void abort();
-
- void setDOMApplicationCache(DOMApplicationCache*);
- void notifyDOMApplicationCache(EventID, int progressTotal, int progressDone);
-
- void stopLoadingInFrame(Frame*);
-
- void stopDeferringEvents(); // Also raises the events that have been queued up.
-
-#if ENABLE(INSPECTOR)
- void fillResourceList(ResourceInfoList*);
- CacheInfo applicationCacheInfo();
-#endif
-
- bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&);
- bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = 0);
-
- private:
- bool isApplicationCacheEnabled();
- DocumentLoader* documentLoader() const { return m_documentLoader; }
-
- struct DeferredEvent {
- EventID eventID;
- int progressTotal;
- int progressDone;
- DeferredEvent(EventID id, int total, int done) : eventID(id), progressTotal(total), progressDone(done) { }
- };
-
- DOMApplicationCache* m_domApplicationCache;
- DocumentLoader* m_documentLoader;
- bool m_defersEvents; // Events are deferred until after document onload.
- Vector<DeferredEvent> m_deferredEvents;
-
- void dispatchDOMEvent(EventID, int progressTotal, int progressDone);
-
- friend class ApplicationCacheGroup;
- friend class ApplicationCacheStorage;
-
- bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, ApplicationCache* = 0);
- void setCandidateApplicationCacheGroup(ApplicationCacheGroup* group);
- ApplicationCacheGroup* candidateApplicationCacheGroup() const { return m_candidateApplicationCacheGroup; }
- void setApplicationCache(PassRefPtr<ApplicationCache> applicationCache);
- ApplicationCache* applicationCache() const { return m_applicationCache.get(); }
- ApplicationCache* mainResourceApplicationCache() const { return m_mainResourceApplicationCache.get(); }
- bool maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError&);
-
-
- // The application cache that the document loader is associated with (if any).
- RefPtr<ApplicationCache> m_applicationCache;
-
- // Before an application cache has finished loading, this will be the candidate application
- // group that the document loader is associated with.
- ApplicationCacheGroup* m_candidateApplicationCacheGroup;
-
- // This is the application cache the main resource was loaded from (if any).
- RefPtr<ApplicationCache> m_mainResourceApplicationCache;
+
+class ApplicationCache;
+class ApplicationCacheGroup;
+class ApplicationCacheResource;
+class ApplicationCacheStorage;
+class DOMApplicationCache;
+class DocumentLoader;
+class Frame;
+class ResourceError;
+class ResourceLoader;
+class ResourceRequest;
+class ResourceResponse;
+class SharedBuffer;
+class SubstituteData;
+
+class ApplicationCacheHost {
+ WTF_MAKE_NONCOPYABLE(ApplicationCacheHost); WTF_MAKE_FAST_ALLOCATED;
+public:
+ // The Status numeric values are specified in the HTML5 spec.
+ enum Status {
+ UNCACHED = 0,
+ IDLE = 1,
+ CHECKING = 2,
+ DOWNLOADING = 3,
+ UPDATEREADY = 4,
+ OBSOLETE = 5
};
-} // namespace WebCore
+ struct CacheInfo {
+ URL manifest;
+ double creationTime;
+ double updateTime;
+ long long size;
+ };
+
+ struct ResourceInfo {
+ URL resource;
+ bool isMaster;
+ bool isManifest;
+ bool isFallback;
+ bool isForeign;
+ bool isExplicit;
+ long long size;
+ };
+
+ explicit ApplicationCacheHost(DocumentLoader&);
+ ~ApplicationCacheHost();
+
+ static URL createFileURL(const String&);
+
+ void selectCacheWithoutManifest();
+ void selectCacheWithManifest(const URL& manifestURL);
+
+ void maybeLoadMainResource(ResourceRequest&, SubstituteData&);
+ void maybeLoadMainResourceForRedirect(ResourceRequest&, SubstituteData&);
+ bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&);
+ void mainResourceDataReceived(const char* data, int length, long long encodedDataLength, bool allAtOnce);
+ void finishedLoadingMainResource();
+ void failedLoadingMainResource();
+
+ WEBCORE_EXPORT bool maybeLoadResource(ResourceLoader&, const ResourceRequest&, const URL& originalURL);
+ WEBCORE_EXPORT bool maybeLoadFallbackForRedirect(ResourceLoader*, ResourceRequest&, const ResourceResponse&);
+ WEBCORE_EXPORT bool maybeLoadFallbackForResponse(ResourceLoader*, const ResourceResponse&);
+ WEBCORE_EXPORT bool maybeLoadFallbackForError(ResourceLoader*, const ResourceError&);
+
+ bool maybeLoadSynchronously(ResourceRequest&, ResourceError&, ResourceResponse&, RefPtr<SharedBuffer>&);
+ void maybeLoadFallbackSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, RefPtr<SharedBuffer>&);
+
+ bool canCacheInPageCache();
+
+ Status status() const;
+ bool update();
+ bool swapCache();
+ void abort();
+
+ void setDOMApplicationCache(DOMApplicationCache*);
+ void notifyDOMApplicationCache(const AtomicString& eventType, int progressTotal, int progressDone);
+
+ void stopLoadingInFrame(Frame&);
-#endif // ApplicationCacheHost_h
+ void stopDeferringEvents(); // Also raises the events that have been queued up.
+
+ Vector<ResourceInfo> resourceList();
+ CacheInfo applicationCacheInfo();
+
+ bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&);
+ bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = nullptr);
+
+private:
+ friend class ApplicationCacheGroup;
+
+ struct DeferredEvent {
+ AtomicString eventType;
+ int progressTotal;
+ int progressDone;
+ };
+
+ bool isApplicationCacheEnabled();
+ bool isApplicationCacheBlockedForRequest(const ResourceRequest&);
+
+ void dispatchDOMEvent(const AtomicString& eventType, int progressTotal, int progressDone);
+
+ bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, ApplicationCache* = nullptr);
+ void setCandidateApplicationCacheGroup(ApplicationCacheGroup*);
+ ApplicationCacheGroup* candidateApplicationCacheGroup() const { return m_candidateApplicationCacheGroup; }
+ void setApplicationCache(RefPtr<ApplicationCache>&&);
+ ApplicationCache* applicationCache() const { return m_applicationCache.get(); }
+ ApplicationCache* mainResourceApplicationCache() const { return m_mainResourceApplicationCache.get(); }
+ bool maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError&);
+
+ DOMApplicationCache* m_domApplicationCache { nullptr };
+ DocumentLoader& m_documentLoader;
+
+ bool m_defersEvents { true }; // Events are deferred until after document onload.
+ Vector<DeferredEvent> m_deferredEvents;
+
+ // The application cache that the document loader is associated with (if any).
+ RefPtr<ApplicationCache> m_applicationCache;
+
+ // Before an application cache has finished loading, this will be the candidate application
+ // group that the document loader is associated with.
+ ApplicationCacheGroup* m_candidateApplicationCacheGroup { nullptr };
+
+ // This is the application cache the main resource was loaded from (if any).
+ RefPtr<ApplicationCache> m_mainResourceApplicationCache;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp b/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp
index 2d9a8f1e6..f854a7212 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp
@@ -29,8 +29,8 @@
namespace WebCore {
-ApplicationCacheResource::ApplicationCacheResource(const URL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> data, const String& path)
- : SubstituteResource(url, response, data)
+ApplicationCacheResource::ApplicationCacheResource(const URL& url, const ResourceResponse& response, unsigned type, Ref<SharedBuffer>&& data, const String& path)
+ : SubstituteResource(url, response, WTFMove(data))
, m_type(type)
, m_storageID(0)
, m_estimatedSizeInStorage(0)
@@ -38,6 +38,11 @@ ApplicationCacheResource::ApplicationCacheResource(const URL& url, const Resourc
{
}
+void ApplicationCacheResource::deliver(ResourceLoader& loader)
+{
+ loader.deliverResponseAndData(response(), m_path.isEmpty() ? data().copy() : SharedBuffer::createWithContentsOfFile(m_path));
+}
+
void ApplicationCacheResource::addType(unsigned type)
{
// Caller should take care of storing the new type in database.
@@ -49,8 +54,7 @@ int64_t ApplicationCacheResource::estimatedSizeInStorage()
if (m_estimatedSizeInStorage)
return m_estimatedSizeInStorage;
- if (data())
- m_estimatedSizeInStorage = data()->size();
+ m_estimatedSizeInStorage = data().size();
for (const auto& headerField : response().httpHeaderFields())
m_estimatedSizeInStorage += (headerField.key.length() + headerField.value.length() + 2) * sizeof(UChar);
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResource.h b/Source/WebCore/loader/appcache/ApplicationCacheResource.h
index d8d3f1aa0..a39613fa3 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheResource.h
+++ b/Source/WebCore/loader/appcache/ApplicationCacheResource.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ApplicationCacheResource_h
-#define ApplicationCacheResource_h
+#pragma once
#include "SubstituteResource.h"
@@ -40,10 +39,12 @@ public:
Fallback = 1 << 4
};
- static PassRefPtr<ApplicationCacheResource> create(const URL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> buffer = SharedBuffer::create(), const String& path = String())
+ static Ref<ApplicationCacheResource> create(const URL& url, const ResourceResponse& response, unsigned type, RefPtr<SharedBuffer> buffer = SharedBuffer::create(), const String& path = String())
{
ASSERT(!url.hasFragmentIdentifier());
- return adoptRef(new ApplicationCacheResource(url, response, type, buffer, path));
+ if (!buffer)
+ buffer = SharedBuffer::create();
+ return adoptRef(*new ApplicationCacheResource(url, response, type, buffer.releaseNonNull(), path));
}
unsigned type() const { return m_type; }
@@ -62,7 +63,9 @@ public:
#endif
private:
- ApplicationCacheResource(const URL&, const ResourceResponse&, unsigned type, PassRefPtr<SharedBuffer>, const String& path);
+ ApplicationCacheResource(const URL&, const ResourceResponse&, unsigned type, Ref<SharedBuffer>&&, const String& path);
+
+ void deliver(ResourceLoader&) override;
unsigned m_type;
unsigned m_storageID;
@@ -71,5 +74,3 @@ private:
};
} // namespace WebCore
-
-#endif // ApplicationCacheResource_h
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp
index e5751ac59..b6b9d7a7c 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp
@@ -31,13 +31,14 @@
#include "ApplicationCacheHost.h"
#include "ApplicationCacheResource.h"
#include "FileSystem.h"
-#include "NotImplemented.h"
#include "SQLiteDatabaseTracker.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
#include "SecurityOrigin.h"
+#include "SecurityOriginData.h"
#include "URL.h"
#include "UUID.h"
+#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
#include <wtf/StringExtras.h>
#include <wtf/text/CString.h>
@@ -45,16 +46,13 @@
namespace WebCore {
-static const char flatFileSubdirectory[] = "ApplicationCache";
-
template <class T>
class StorageIDJournal {
public:
~StorageIDJournal()
{
- size_t size = m_records.size();
- for (size_t i = 0; i < size; ++i)
- m_records[i].restore();
+ for (auto& record : m_records)
+ record.restore();
}
void add(T* resource, unsigned storageID)
@@ -70,7 +68,7 @@ public:
private:
class Record {
public:
- Record() : m_resource(0), m_storageID(0) { }
+ Record() : m_resource(nullptr), m_storageID(0) { }
Record(T* resource, unsigned storageID) : m_resource(resource), m_storageID(storageID) { }
void restore()
@@ -105,59 +103,55 @@ ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const URL& manife
openDatabase(false);
if (!m_database.isOpen())
- return 0;
+ return nullptr;
SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL AND manifestURL=?");
- if (statement.prepare() != SQLResultOk)
- return 0;
+ if (statement.prepare() != SQLITE_OK)
+ return nullptr;
statement.bindText(1, manifestURL);
int result = statement.step();
- if (result == SQLResultDone)
- return 0;
+ if (result == SQLITE_DONE)
+ return nullptr;
- if (result != SQLResultRow) {
+ if (result != SQLITE_ROW) {
LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());
- return 0;
+ return nullptr;
}
unsigned newestCacheStorageID = static_cast<unsigned>(statement.getColumnInt64(2));
- RefPtr<ApplicationCache> cache = loadCache(newestCacheStorageID);
+ auto cache = loadCache(newestCacheStorageID);
if (!cache)
- return 0;
+ return nullptr;
- ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);
-
- group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
- group->setNewestCache(cache.release());
-
- return group;
+ auto& group = *new ApplicationCacheGroup(*this, manifestURL);
+ group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
+ group.setNewestCache(cache.releaseNonNull());
+ return &group;
}
ApplicationCacheGroup* ApplicationCacheStorage::findOrCreateCacheGroup(const URL& manifestURL)
{
ASSERT(!manifestURL.hasFragmentIdentifier());
- CacheGroupMap::AddResult result = m_cachesInMemory.add(manifestURL, nullptr);
-
+ auto result = m_cachesInMemory.add(manifestURL, nullptr);
if (!result.isNewEntry) {
ASSERT(result.iterator->value);
return result.iterator->value;
}
// Look up the group in the database
- ApplicationCacheGroup* group = loadCacheGroup(manifestURL);
+ auto* group = loadCacheGroup(manifestURL);
// If the group was not found we need to create it
if (!group) {
- group = new ApplicationCacheGroup(manifestURL);
+ group = new ApplicationCacheGroup(*this, manifestURL);
m_cacheHostSet.add(urlHostHash(manifestURL));
}
-
+
result.iterator->value = group;
-
return group;
}
@@ -185,10 +179,10 @@ void ApplicationCacheStorage::loadManifestHostHashes()
// Fetch the host hashes.
SQLiteStatement statement(m_database, "SELECT manifestHostHash FROM CacheGroups");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return;
- while (statement.step() == SQLResultRow)
+ while (statement.step() == SQLITE_ROW)
m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0)));
}
@@ -200,7 +194,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url)
// Hash the host name and see if there's a manifest with the same host.
if (!m_cacheHostSet.contains(urlHostHash(url)))
- return 0;
+ return nullptr;
// Check if a cache already exists in memory.
for (const auto& group : m_cachesInMemory.values()) {
@@ -220,17 +214,17 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url)
}
if (!m_database.isOpen())
- return 0;
+ return nullptr;
SQLiteTransactionInProgressAutoCounter transactionCounter;
// Check the database. Look for all cache groups with a newest cache.
SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL");
- if (statement.prepare() != SQLResultOk)
- return 0;
+ if (statement.prepare() != SQLITE_OK)
+ return nullptr;
int result;
- while ((result = statement.step()) == SQLResultRow) {
+ while ((result = statement.step()) == SQLITE_ROW) {
URL manifestURL = URL(ParsedURLString, statement.getColumnText(1));
if (m_cachesInMemory.contains(manifestURL))
@@ -242,30 +236,28 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url)
// We found a cache group that matches. Now check if the newest cache has a resource with
// a matching URL.
unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2));
- RefPtr<ApplicationCache> cache = loadCache(newestCacheID);
+ auto cache = loadCache(newestCacheID);
if (!cache)
continue;
- ApplicationCacheResource* resource = cache->resourceForURL(url);
+ auto* resource = cache->resourceForURL(url);
if (!resource)
continue;
if (resource->type() & ApplicationCacheResource::Foreign)
continue;
- ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);
-
- group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
- group->setNewestCache(cache.release());
-
- m_cachesInMemory.set(group->manifestURL(), group);
-
- return group;
+ auto& group = *new ApplicationCacheGroup(*this, manifestURL);
+ group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
+ group.setNewestCache(cache.releaseNonNull());
+ m_cachesInMemory.set(group.manifestURL(), &group);
+
+ return &group;
}
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());
- return 0;
+ return nullptr;
}
ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const URL& url)
@@ -275,10 +267,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U
ASSERT(!url.hasFragmentIdentifier());
// Check if an appropriate cache already exists in memory.
- CacheGroupMap::const_iterator end = m_cachesInMemory.end();
- for (CacheGroupMap::const_iterator it = m_cachesInMemory.begin(); it != end; ++it) {
- ApplicationCacheGroup* group = it->value;
-
+ for (auto* group : m_cachesInMemory.values()) {
ASSERT(!group->isObsolete());
if (ApplicationCache* cache = group->newestCache()) {
@@ -294,15 +283,15 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U
}
if (!m_database.isOpen())
- return 0;
+ return nullptr;
// Check the database. Look for all cache groups with a newest cache.
SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL");
- if (statement.prepare() != SQLResultOk)
- return 0;
+ if (statement.prepare() != SQLITE_OK)
+ return nullptr;
int result;
- while ((result = statement.step()) == SQLResultRow) {
+ while ((result = statement.step()) == SQLITE_ROW) {
URL manifestURL = URL(ParsedURLString, statement.getColumnText(1));
if (m_cachesInMemory.contains(manifestURL))
@@ -315,7 +304,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U
// We found a cache group that matches. Now check if the newest cache has a resource with
// a matching fallback namespace.
unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2));
- RefPtr<ApplicationCache> cache = loadCache(newestCacheID);
+ auto cache = loadCache(newestCacheID);
URL fallbackURL;
if (cache->isURLInOnlineWhitelist(url))
@@ -325,57 +314,48 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U
if (cache->resourceForURL(fallbackURL)->type() & ApplicationCacheResource::Foreign)
continue;
- ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);
-
- group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
- group->setNewestCache(cache.release());
-
- m_cachesInMemory.set(group->manifestURL(), group);
-
- return group;
+ auto& group = *new ApplicationCacheGroup(*this, manifestURL);
+ group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
+ group.setNewestCache(cache.releaseNonNull());
+
+ m_cachesInMemory.set(group.manifestURL(), &group);
+
+ return &group;
}
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());
- return 0;
+ return nullptr;
}
-void ApplicationCacheStorage::cacheGroupDestroyed(ApplicationCacheGroup* group)
+void ApplicationCacheStorage::cacheGroupDestroyed(ApplicationCacheGroup& group)
{
- if (group->isObsolete()) {
- ASSERT(!group->storageID());
- ASSERT(m_cachesInMemory.get(group->manifestURL()) != group);
+ if (group.isObsolete()) {
+ ASSERT(!group.storageID());
+ ASSERT(m_cachesInMemory.get(group.manifestURL()) != &group);
return;
}
- ASSERT(m_cachesInMemory.get(group->manifestURL()) == group);
+ ASSERT(m_cachesInMemory.get(group.manifestURL()) == &group);
- m_cachesInMemory.remove(group->manifestURL());
+ m_cachesInMemory.remove(group.manifestURL());
// If the cache group is half-created, we don't want it in the saved set (as it is not stored in database).
- if (!group->storageID())
- m_cacheHostSet.remove(urlHostHash(group->manifestURL()));
+ if (!group.storageID())
+ m_cacheHostSet.remove(urlHostHash(group.manifestURL()));
}
-void ApplicationCacheStorage::cacheGroupMadeObsolete(ApplicationCacheGroup* group)
+void ApplicationCacheStorage::cacheGroupMadeObsolete(ApplicationCacheGroup& group)
{
- ASSERT(m_cachesInMemory.get(group->manifestURL()) == group);
- ASSERT(m_cacheHostSet.contains(urlHostHash(group->manifestURL())));
+ ASSERT(m_cachesInMemory.get(group.manifestURL()) == &group);
+ ASSERT(m_cacheHostSet.contains(urlHostHash(group.manifestURL())));
- if (ApplicationCache* newestCache = group->newestCache())
+ if (auto* newestCache = group.newestCache())
remove(newestCache);
- m_cachesInMemory.remove(group->manifestURL());
- m_cacheHostSet.remove(urlHostHash(group->manifestURL()));
-}
-
-void ApplicationCacheStorage::setCacheDirectory(const String& cacheDirectory)
-{
- ASSERT(m_cacheDirectory.isNull());
- ASSERT(!cacheDirectory.isNull());
-
- m_cacheDirectory = cacheDirectory;
+ m_cachesInMemory.remove(group.manifestURL());
+ m_cacheHostSet.remove(urlHostHash(group.manifestURL()));
}
const String& ApplicationCacheStorage::cacheDirectory() const
@@ -441,7 +421,7 @@ void ApplicationCacheStorage::setDefaultOriginQuota(int64_t quota)
m_defaultOriginQuota = quota;
}
-bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin* origin, int64_t& quota)
+bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin& origin, int64_t& quota)
{
SQLiteTransactionInProgressAutoCounter transactionCounter;
@@ -449,14 +429,14 @@ bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin* orig
// Using the count to determine if a record existed or not is a safe way to determine
// if a quota of 0 is real, from the record, or from null.
SQLiteStatement statement(m_database, "SELECT COUNT(quota), quota FROM Origins WHERE origin=?");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return false;
- statement.bindText(1, origin->databaseIdentifier());
+ statement.bindText(1, SecurityOriginData::fromSecurityOrigin(origin).databaseIdentifier());
int result = statement.step();
// Return the quota, or if it was null the default.
- if (result == SQLResultRow) {
+ if (result == SQLITE_ROW) {
bool wasNoRecord = statement.getColumnInt64(0) == 0;
quota = wasNoRecord ? m_defaultOriginQuota : statement.getColumnInt64(1);
return true;
@@ -477,13 +457,13 @@ bool ApplicationCacheStorage::calculateUsageForOrigin(const SecurityOrigin* orig
" INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
" INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
" WHERE Origins.origin=?");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return false;
- statement.bindText(1, origin->databaseIdentifier());
+ statement.bindText(1, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier());
int result = statement.step();
- if (result == SQLResultRow) {
+ if (result == SQLITE_ROW) {
usage = statement.getColumnInt64(0);
return true;
}
@@ -492,7 +472,7 @@ bool ApplicationCacheStorage::calculateUsageForOrigin(const SecurityOrigin* orig
return false;
}
-bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin* origin, ApplicationCache* cache, int64_t& remainingSize)
+bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin& origin, ApplicationCache* cache, int64_t& remainingSize)
{
SQLiteTransactionInProgressAutoCounter transactionCounter;
@@ -520,17 +500,17 @@ bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(cons
}
SQLiteStatement statement(m_database, query);
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return false;
- statement.bindText(1, origin->databaseIdentifier());
+ statement.bindText(1, SecurityOriginData::fromSecurityOrigin(origin).databaseIdentifier());
if (excludingCacheIdentifier != 0)
statement.bindInt64(2, excludingCacheIdentifier);
int result = statement.step();
// If the count was 0 that then we have to query the origin table directly
// for its quota. Otherwise we can use the calculated value.
- if (result == SQLResultRow) {
+ if (result == SQLITE_ROW) {
int64_t numberOfCaches = statement.getColumnInt64(0);
if (numberOfCaches == 0)
calculateQuotaForOrigin(origin, remainingSize);
@@ -555,11 +535,11 @@ bool ApplicationCacheStorage::storeUpdatedQuotaForOrigin(const SecurityOrigin* o
return false;
SQLiteStatement updateStatement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
- if (updateStatement.prepare() != SQLResultOk)
+ if (updateStatement.prepare() != SQLITE_OK)
return false;
updateStatement.bindInt64(1, quota);
- updateStatement.bindText(2, origin->databaseIdentifier());
+ updateStatement.bindText(2, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier());
return executeStatement(updateStatement);
}
@@ -590,7 +570,9 @@ void ApplicationCacheStorage::verifySchemaVersion()
if (version == schemaVersion)
return;
- deleteTables();
+ // Version will be 0 if we just created an empty file. Trying to delete tables would cause errors, because they don't exist yet.
+ if (version)
+ deleteTables();
// Update user version.
SQLiteTransaction setDatabaseVersion(m_database);
@@ -601,7 +583,7 @@ void ApplicationCacheStorage::verifySchemaVersion()
ASSERT_UNUSED(unusedNumBytes, static_cast<int>(sizeof(userVersionSQL)) >= unusedNumBytes);
SQLiteStatement statement(m_database, userVersionSQL);
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return;
executeStatement(statement);
@@ -701,19 +683,19 @@ bool ApplicationCacheStorage::store(ApplicationCacheGroup* group, GroupStorageID
deleteCacheGroupRecord(group->manifestURL());
SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return false;
statement.bindInt64(1, urlHostHash(group->manifestURL()));
statement.bindText(2, group->manifestURL());
- statement.bindText(3, group->origin()->databaseIdentifier());
+ statement.bindText(3, SecurityOriginData::fromSecurityOrigin(group->origin()).databaseIdentifier());
if (!executeStatement(statement))
return false;
unsigned groupStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
- if (!ensureOriginRecord(group->origin()))
+ if (!ensureOriginRecord(&group->origin()))
return false;
group->setStorageID(groupStorageID);
@@ -729,7 +711,7 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo
ASSERT(storageIDJournal);
SQLiteStatement statement(m_database, "INSERT INTO Caches (cacheGroup, size) VALUES (?, ?)");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return false;
statement.bindInt64(1, cache->group()->storageID());
@@ -741,28 +723,24 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo
unsigned cacheStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
// Store all resources
- {
- ApplicationCache::ResourceMap::const_iterator end = cache->end();
- for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) {
- unsigned oldStorageID = it->value->storageID();
- if (!store(it->value.get(), cacheStorageID))
- return false;
+ for (auto& resource : cache->resources().values()) {
+ unsigned oldStorageID = resource->storageID();
+ if (!store(resource.get(), cacheStorageID))
+ return false;
- // Storing the resource succeeded. Log its old storageID in case
- // it needs to be restored later.
- storageIDJournal->add(it->value.get(), oldStorageID);
- }
+ // Storing the resource succeeded. Log its old storageID in case
+ // it needs to be restored later.
+ storageIDJournal->add(resource.get(), oldStorageID);
}
// Store the online whitelist
const Vector<URL>& onlineWhitelist = cache->onlineWhitelist();
{
- size_t whitelistSize = onlineWhitelist.size();
- for (size_t i = 0; i < whitelistSize; ++i) {
+ for (auto& whitelistURL : onlineWhitelist) {
SQLiteStatement statement(m_database, "INSERT INTO CacheWhitelistURLs (url, cache) VALUES (?, ?)");
statement.prepare();
- statement.bindText(1, onlineWhitelist[i]);
+ statement.bindText(1, whitelistURL);
statement.bindInt64(2, cacheStorageID);
if (!executeStatement(statement))
@@ -785,13 +763,12 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo
// Store fallback URLs.
const FallbackURLVector& fallbackURLs = cache->fallbackURLs();
{
- size_t fallbackCount = fallbackURLs.size();
- for (size_t i = 0; i < fallbackCount; ++i) {
+ for (auto& fallbackURL : fallbackURLs) {
SQLiteStatement statement(m_database, "INSERT INTO FallbackURLs (namespace, fallbackURL, cache) VALUES (?, ?, ?)");
statement.prepare();
- statement.bindText(1, fallbackURLs[i].first);
- statement.bindText(2, fallbackURLs[i].second);
+ statement.bindText(1, fallbackURL.first);
+ statement.bindText(2, fallbackURL.second);
statement.bindInt64(3, cacheStorageID);
if (!executeStatement(statement))
@@ -817,7 +794,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
// First, insert the data
SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data, path) VALUES (?, ?)");
- if (dataStatement.prepare() != SQLResultOk)
+ if (dataStatement.prepare() != SQLITE_OK)
return false;
@@ -827,12 +804,12 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
else if (shouldStoreResourceAsFlatFile(resource)) {
// First, check to see if creating the flat file would violate the maximum total quota. We don't need
// to check the per-origin quota here, as it was already checked in storeNewestCache().
- if (m_database.totalSize() + flatFileAreaSize() + resource->data()->size() > m_maximumSize) {
+ if (m_database.totalSize() + flatFileAreaSize() + resource->data().size() > m_maximumSize) {
m_isMaximumSizeReached = true;
return false;
}
- String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory);
+ String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
makeAllDirectories(flatFileDirectory);
String extension;
@@ -850,8 +827,8 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
resource->setPath(fullPath);
dataStatement.bindText(2, path);
} else {
- if (resource->data()->size())
- dataStatement.bindBlob(1, resource->data()->data(), resource->data()->size());
+ if (resource->data().size())
+ dataStatement.bindBlob(1, resource->data().data(), resource->data().size());
}
if (!dataStatement.executeCommand()) {
@@ -869,18 +846,17 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
// Serialize the headers
StringBuilder stringBuilder;
- HTTPHeaderMap::const_iterator end = resource->response().httpHeaderFields().end();
- for (HTTPHeaderMap::const_iterator it = resource->response().httpHeaderFields().begin(); it!= end; ++it) {
- stringBuilder.append(it->key);
+ for (const auto& header : resource->response().httpHeaderFields()) {
+ stringBuilder.append(header.key);
stringBuilder.append(':');
- stringBuilder.append(it->value);
+ stringBuilder.append(header.value);
stringBuilder.append('\n');
}
String headers = stringBuilder.toString();
SQLiteStatement resourceStatement(m_database, "INSERT INTO CacheResources (url, statusCode, responseURL, headers, data, mimeType, textEncodingName) VALUES (?, ?, ?, ?, ?, ?, ?)");
- if (resourceStatement.prepare() != SQLResultOk)
+ if (resourceStatement.prepare() != SQLITE_OK)
return false;
// The same ApplicationCacheResource are used in ApplicationCacheResource::size()
@@ -901,7 +877,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
// Finally, insert the cache entry
SQLiteStatement entryStatement(m_database, "INSERT INTO CacheEntries (cache, type, resource) VALUES (?, ?, ?)");
- if (entryStatement.prepare() != SQLResultOk)
+ if (entryStatement.prepare() != SQLITE_OK)
return false;
entryStatement.bindInt64(1, cacheStorageID);
@@ -915,7 +891,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
// release the resource's data and free up a potentially large amount
// of memory:
if (!fullPath.isEmpty())
- resource->data()->clear();
+ resource->data().clear();
resource->setStorageID(resourceId);
return true;
@@ -930,7 +906,7 @@ bool ApplicationCacheStorage::storeUpdatedType(ApplicationCacheResource* resourc
// First, insert the data
SQLiteStatement entryStatement(m_database, "UPDATE CacheEntries SET type=? WHERE resource=?");
- if (entryStatement.prepare() != SQLResultOk)
+ if (entryStatement.prepare() != SQLITE_OK)
return false;
entryStatement.bindInt64(1, resource->type());
@@ -963,7 +939,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, Applicat
// A resource was added to the cache. Update the total data size for the cache.
SQLiteStatement sizeUpdateStatement(m_database, "UPDATE Caches SET size=size+? WHERE id=?");
- if (sizeUpdateStatement.prepare() != SQLResultOk)
+ if (sizeUpdateStatement.prepare() != SQLITE_OK)
return false;
sizeUpdateStatement.bindInt64(1, resource->estimatedSizeInStorage());
@@ -980,10 +956,10 @@ bool ApplicationCacheStorage::ensureOriginRecord(const SecurityOrigin* origin)
{
ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
SQLiteStatement insertOriginStatement(m_database, "INSERT INTO Origins (origin, quota) VALUES (?, ?)");
- if (insertOriginStatement.prepare() != SQLResultOk)
+ if (insertOriginStatement.prepare() != SQLITE_OK)
return false;
- insertOriginStatement.bindText(1, origin->databaseIdentifier());
+ insertOriginStatement.bindText(1, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier());
insertOriginStatement.bindInt64(2, m_defaultOriginQuota);
if (!executeStatement(insertOriginStatement))
return false;
@@ -995,7 +971,7 @@ bool ApplicationCacheStorage::checkOriginQuota(ApplicationCacheGroup* group, App
{
// Check if the oldCache with the newCache would reach the per-origin quota.
int64_t remainingSpaceInOrigin;
- const SecurityOrigin* origin = group->origin();
+ auto& origin = group->origin();
if (calculateRemainingSizeForOriginExcludingCache(origin, oldCache, remainingSpaceInOrigin)) {
if (remainingSpaceInOrigin < newCache->estimatedSizeInStorage()) {
int64_t quota;
@@ -1013,7 +989,7 @@ bool ApplicationCacheStorage::checkOriginQuota(ApplicationCacheGroup* group, App
return true;
}
-bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, ApplicationCache* oldCache, FailureReason& failureReason)
+bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup& group, ApplicationCache* oldCache, FailureReason& failureReason)
{
openDatabase(true);
@@ -1029,24 +1005,24 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App
// Check if this would reach the per-origin quota.
int64_t totalSpaceNeededIgnored;
- if (!checkOriginQuota(group, oldCache, group->newestCache(), totalSpaceNeededIgnored)) {
+ if (!checkOriginQuota(&group, oldCache, group.newestCache(), totalSpaceNeededIgnored)) {
failureReason = OriginQuotaReached;
return false;
}
GroupStorageIDJournal groupStorageIDJournal;
- if (!group->storageID()) {
+ if (!group.storageID()) {
// Store the group
- if (!store(group, &groupStorageIDJournal)) {
+ if (!store(&group, &groupStorageIDJournal)) {
checkForMaxSizeReached();
failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
return false;
}
}
- ASSERT(group->newestCache());
- ASSERT(!group->isObsolete());
- ASSERT(!group->newestCache()->storageID());
+ ASSERT(group.newestCache());
+ ASSERT(!group.isObsolete());
+ ASSERT(!group.newestCache()->storageID());
// Log the storageID changes to the in-memory resource objects. The journal
// object will roll them back automatically in case a database operation
@@ -1054,7 +1030,7 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App
ResourceStorageIDJournal resourceStorageIDJournal;
// Store the newest cache
- if (!store(group->newestCache(), &resourceStorageIDJournal)) {
+ if (!store(group.newestCache(), &resourceStorageIDJournal)) {
checkForMaxSizeReached();
failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
return false;
@@ -1063,13 +1039,13 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App
// Update the newest cache in the group.
SQLiteStatement statement(m_database, "UPDATE CacheGroups SET newestCache=? WHERE id=?");
- if (statement.prepare() != SQLResultOk) {
+ if (statement.prepare() != SQLITE_OK) {
failureReason = DiskOrOperationFailure;
return false;
}
- statement.bindInt64(1, group->newestCache()->storageID());
- statement.bindInt64(2, group->storageID());
+ statement.bindInt64(1, group.newestCache()->storageID());
+ statement.bindInt64(2, group.storageID());
if (!executeStatement(statement)) {
failureReason = DiskOrOperationFailure;
@@ -1082,22 +1058,24 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App
return true;
}
-bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
+bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup& group)
{
// Ignore the reason for failing, just attempt the store.
FailureReason ignoredFailureReason;
- return storeNewestCache(group, 0, ignoredFailureReason);
+ return storeNewestCache(group, nullptr, ignoredFailureReason);
}
-template <typename CharacterType>
-static inline void parseHeader(const CharacterType* header, size_t headerLength, ResourceResponse& response)
+template<typename CharacterType>
+static inline void parseHeader(const CharacterType* header, unsigned headerLength, ResourceResponse& response)
{
- size_t pos = find(header, headerLength, ':');
- ASSERT(pos != notFound);
-
- AtomicString headerName = AtomicString(header, pos);
- String headerValue = String(header + pos + 1, headerLength - pos - 1);
-
+ ASSERT(find(header, headerLength, ':') != notFound);
+ unsigned colonPosition = find(header, headerLength, ':');
+
+ // Save memory by putting the header names into atomic strings so each is stored only once,
+ // even though the setHTTPHeaderField function does not require an atomic string.
+ AtomicString headerName { header, colonPosition };
+ String headerValue { header + colonPosition + 1, headerLength - colonPosition - 1 };
+
response.setHTTPHeaderField(headerName, headerValue);
}
@@ -1124,25 +1102,25 @@ static inline void parseHeaders(const String& headers, ResourceResponse& respons
}
}
-PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID)
+RefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID)
{
ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
SQLiteStatement cacheStatement(m_database,
"SELECT url, statusCode, type, mimeType, textEncodingName, headers, CacheResourceData.data, CacheResourceData.path FROM CacheEntries INNER JOIN CacheResources ON CacheEntries.resource=CacheResources.id "
"INNER JOIN CacheResourceData ON CacheResourceData.id=CacheResources.data WHERE CacheEntries.cache=?");
- if (cacheStatement.prepare() != SQLResultOk) {
+ if (cacheStatement.prepare() != SQLITE_OK) {
LOG_ERROR("Could not prepare cache statement, error \"%s\"", m_database.lastErrorMsg());
- return 0;
+ return nullptr;
}
cacheStatement.bindInt64(1, storageID);
- RefPtr<ApplicationCache> cache = ApplicationCache::create();
+ auto cache = ApplicationCache::create();
- String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory);
+ String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
int result;
- while ((result = cacheStatement.step()) == SQLResultRow) {
+ while ((result = cacheStatement.step()) == SQLITE_ROW) {
URL url(ParsedURLString, cacheStatement.getColumnText(0));
int httpStatusCode = cacheStatement.getColumnInt(1);
@@ -1152,7 +1130,7 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage
Vector<char> blob;
cacheStatement.getColumnBlobAsVector(6, blob);
- RefPtr<SharedBuffer> data = SharedBuffer::adoptVector(blob);
+ auto data = SharedBuffer::adoptVector(blob);
String path = cacheStatement.getColumnText(7);
long long size = 0;
@@ -1166,21 +1144,21 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage
String mimeType = cacheStatement.getColumnText(3);
String textEncodingName = cacheStatement.getColumnText(4);
- ResourceResponse response(url, mimeType, size, textEncodingName, "");
+ ResourceResponse response(url, mimeType, size, textEncodingName);
response.setHTTPStatusCode(httpStatusCode);
String headers = cacheStatement.getColumnText(5);
parseHeaders(headers, response);
- RefPtr<ApplicationCacheResource> resource = ApplicationCacheResource::create(url, response, type, data.release(), path);
+ auto resource = ApplicationCacheResource::create(url, response, type, WTFMove(data), path);
if (type & ApplicationCacheResource::Manifest)
- cache->setManifestResource(resource.release());
+ cache->setManifestResource(WTFMove(resource));
else
- cache->addResource(resource.release());
+ cache->addResource(WTFMove(resource));
}
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Could not load cache resources, error \"%s\"", m_database.lastErrorMsg());
if (!cache->manifestResource()) {
@@ -1190,52 +1168,52 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage
// Load the online whitelist
SQLiteStatement whitelistStatement(m_database, "SELECT url FROM CacheWhitelistURLs WHERE cache=?");
- if (whitelistStatement.prepare() != SQLResultOk)
- return 0;
+ if (whitelistStatement.prepare() != SQLITE_OK)
+ return nullptr;
whitelistStatement.bindInt64(1, storageID);
Vector<URL> whitelist;
- while ((result = whitelistStatement.step()) == SQLResultRow)
+ while ((result = whitelistStatement.step()) == SQLITE_ROW)
whitelist.append(URL(ParsedURLString, whitelistStatement.getColumnText(0)));
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Could not load cache online whitelist, error \"%s\"", m_database.lastErrorMsg());
cache->setOnlineWhitelist(whitelist);
// Load online whitelist wildcard flag.
SQLiteStatement whitelistWildcardStatement(m_database, "SELECT wildcard FROM CacheAllowsAllNetworkRequests WHERE cache=?");
- if (whitelistWildcardStatement.prepare() != SQLResultOk)
- return 0;
+ if (whitelistWildcardStatement.prepare() != SQLITE_OK)
+ return nullptr;
whitelistWildcardStatement.bindInt64(1, storageID);
result = whitelistWildcardStatement.step();
- if (result != SQLResultRow)
+ if (result != SQLITE_ROW)
LOG_ERROR("Could not load cache online whitelist wildcard flag, error \"%s\"", m_database.lastErrorMsg());
cache->setAllowsAllNetworkRequests(whitelistWildcardStatement.getColumnInt64(0));
- if (whitelistWildcardStatement.step() != SQLResultDone)
+ if (whitelistWildcardStatement.step() != SQLITE_DONE)
LOG_ERROR("Too many rows for online whitelist wildcard flag");
// Load fallback URLs.
SQLiteStatement fallbackStatement(m_database, "SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?");
- if (fallbackStatement.prepare() != SQLResultOk)
- return 0;
+ if (fallbackStatement.prepare() != SQLITE_OK)
+ return nullptr;
fallbackStatement.bindInt64(1, storageID);
FallbackURLVector fallbackURLs;
- while ((result = fallbackStatement.step()) == SQLResultRow)
+ while ((result = fallbackStatement.step()) == SQLITE_ROW)
fallbackURLs.append(std::make_pair(URL(ParsedURLString, fallbackStatement.getColumnText(0)), URL(ParsedURLString, fallbackStatement.getColumnText(1))));
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Could not load fallback URLs, error \"%s\"", m_database.lastErrorMsg());
cache->setFallbackURLs(fallbackURLs);
cache->setStorageID(storageID);
- return cache.release();
+ return WTFMove(cache);
}
void ApplicationCacheStorage::remove(ApplicationCache* cache)
@@ -1254,7 +1232,7 @@ void ApplicationCacheStorage::remove(ApplicationCache* cache)
// All associated data will be deleted by database triggers.
SQLiteStatement statement(m_database, "DELETE FROM Caches WHERE id=?");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return;
statement.bindInt64(1, cache->storageID());
@@ -1265,7 +1243,7 @@ void ApplicationCacheStorage::remove(ApplicationCache* cache)
if (cache->group()->newestCache() == cache) {
// Currently, there are no triggers on the cache group, which is why the cache had to be removed separately above.
SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
- if (groupStatement.prepare() != SQLResultOk)
+ if (groupStatement.prepare() != SQLITE_OK)
return;
groupStatement.bindInt64(1, cache->group()->storageID());
@@ -1294,10 +1272,9 @@ void ApplicationCacheStorage::empty()
// Clear the storage IDs for the caches in memory.
// The caches will still work, but cached resources will not be saved to disk
// until a cache update process has been initiated.
- CacheGroupMap::const_iterator end = m_cachesInMemory.end();
- for (CacheGroupMap::const_iterator it = m_cachesInMemory.begin(); it != end; ++it)
- it->value->clearStorageID();
-
+ for (auto* group : m_cachesInMemory.values())
+ group->clearStorageID();
+
checkForDeletedResources();
}
@@ -1313,7 +1290,7 @@ bool ApplicationCacheStorage::shouldStoreResourceAsFlatFile(ApplicationCacheReso
|| resource->response().mimeType().startsWith("video/", false);
}
-bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* data, const String& directory, String& path, const String& fileExtension)
+bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer& data, const String& directory, String& path, const String& fileExtension)
{
String fullPath;
@@ -1332,10 +1309,10 @@ bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* dat
if (!handle)
return false;
- int64_t writtenBytes = writeToFile(handle, data->data(), data->size());
+ int64_t writtenBytes = writeToFile(handle, data.data(), data.size());
closeFile(handle);
- if (writtenBytes != static_cast<int64_t>(data->size())) {
+ if (writtenBytes != static_cast<int64_t>(data.size())) {
deleteFile(fullPath);
return false;
}
@@ -1343,45 +1320,7 @@ bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* dat
return true;
}
-bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost* cacheHost)
-{
- SQLiteTransactionInProgressAutoCounter transactionCounter;
-
- ApplicationCache* cache = cacheHost->applicationCache();
- if (!cache)
- return true;
-
- // Create a new cache.
- RefPtr<ApplicationCache> cacheCopy = ApplicationCache::create();
-
- cacheCopy->setOnlineWhitelist(cache->onlineWhitelist());
- cacheCopy->setFallbackURLs(cache->fallbackURLs());
-
- // Traverse the cache and add copies of all resources.
- ApplicationCache::ResourceMap::const_iterator end = cache->end();
- for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) {
- ApplicationCacheResource* resource = it->value.get();
-
- RefPtr<ApplicationCacheResource> resourceCopy = ApplicationCacheResource::create(resource->url(), resource->response(), resource->type(), resource->data(), resource->path());
-
- cacheCopy->addResource(resourceCopy.release());
- }
-
- // Now create a new cache group.
- OwnPtr<ApplicationCacheGroup> groupCopy(adoptPtr(new ApplicationCacheGroup(cache->group()->manifestURL(), true)));
-
- groupCopy->setNewestCache(cacheCopy);
-
- ApplicationCacheStorage copyStorage;
- copyStorage.setCacheDirectory(cacheDirectory);
-
- // Empty the cache in case something was there before.
- copyStorage.empty();
-
- return copyStorage.storeNewestCache(groupCopy.get());
-}
-
-bool ApplicationCacheStorage::manifestURLs(Vector<URL>* urls)
+bool ApplicationCacheStorage::getManifestURLs(Vector<URL>* urls)
{
SQLiteTransactionInProgressAutoCounter transactionCounter;
@@ -1392,10 +1331,10 @@ bool ApplicationCacheStorage::manifestURLs(Vector<URL>* urls)
SQLiteStatement selectURLs(m_database, "SELECT manifestURL FROM CacheGroups");
- if (selectURLs.prepare() != SQLResultOk)
+ if (selectURLs.prepare() != SQLITE_OK)
return false;
- while (selectURLs.step() == SQLResultRow)
+ while (selectURLs.step() == SQLITE_ROW)
urls->append(URL(ParsedURLString, selectURLs.getColumnText(0)));
return true;
@@ -1411,16 +1350,16 @@ bool ApplicationCacheStorage::cacheGroupSize(const String& manifestURL, int64_t*
return false;
SQLiteStatement statement(m_database, "SELECT sum(Caches.size) FROM Caches INNER JOIN CacheGroups ON Caches.cacheGroup=CacheGroups.id WHERE CacheGroups.manifestURL=?");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLITE_OK)
return false;
statement.bindText(1, manifestURL);
int result = statement.step();
- if (result == SQLResultDone)
+ if (result == SQLITE_DONE)
return false;
- if (result != SQLResultRow) {
+ if (result != SQLITE_ROW) {
LOG_ERROR("Could not get the size of the cache group, error \"%s\"", m_database.lastErrorMsg());
return false;
}
@@ -1433,23 +1372,23 @@ bool ApplicationCacheStorage::deleteCacheGroupRecord(const String& manifestURL)
{
ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
- if (idStatement.prepare() != SQLResultOk)
+ if (idStatement.prepare() != SQLITE_OK)
return false;
idStatement.bindText(1, manifestURL);
int result = idStatement.step();
- if (result != SQLResultRow)
+ if (result != SQLITE_ROW)
return false;
int64_t groupId = idStatement.getColumnInt64(0);
SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
- if (cacheStatement.prepare() != SQLResultOk)
+ if (cacheStatement.prepare() != SQLITE_OK)
return false;
SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
- if (groupStatement.prepare() != SQLResultOk)
+ if (groupStatement.prepare() != SQLITE_OK)
return false;
cacheStatement.bindInt64(1, groupId);
@@ -1464,10 +1403,11 @@ bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL)
SQLiteTransactionInProgressAutoCounter transactionCounter;
SQLiteTransaction deleteTransaction(m_database);
+
// Check to see if the group is in memory.
- ApplicationCacheGroup* group = m_cachesInMemory.get(manifestURL);
+ auto* group = m_cachesInMemory.get(manifestURL);
if (group)
- cacheGroupMadeObsolete(group);
+ cacheGroupMadeObsolete(*group);
else {
// The cache group is not in memory, so remove it from the disk.
openDatabase(false);
@@ -1480,9 +1420,9 @@ bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL)
}
deleteTransaction.commit();
-
+
checkForDeletedResources();
-
+
return true;
}
@@ -1499,7 +1439,7 @@ void ApplicationCacheStorage::vacuumDatabaseFile()
void ApplicationCacheStorage::checkForMaxSizeReached()
{
- if (m_database.lastError() == SQLResultFull)
+ if (m_database.lastError() == SQLITE_FULL)
m_isMaximumSizeReached = true;
}
@@ -1516,10 +1456,10 @@ void ApplicationCacheStorage::checkForDeletedResources()
"ON DeletedCacheResources.path = CacheResourceData.path "
"WHERE (SELECT DeletedCacheResources.path == CacheResourceData.path) IS NULL");
- if (selectPaths.prepare() != SQLResultOk)
+ if (selectPaths.prepare() != SQLITE_OK)
return;
- if (selectPaths.step() != SQLResultRow)
+ if (selectPaths.step() != SQLITE_ROW)
return;
do {
@@ -1527,7 +1467,7 @@ void ApplicationCacheStorage::checkForDeletedResources()
if (path.isEmpty())
continue;
- String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory);
+ String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
String fullPath = pathByAppendingComponent(flatFileDirectory, path);
// Don't exit the flatFileDirectory! This should only happen if the "path" entry contains a directory
@@ -1536,7 +1476,7 @@ void ApplicationCacheStorage::checkForDeletedResources()
continue;
deleteFile(fullPath);
- } while (selectPaths.step() == SQLResultRow);
+ } while (selectPaths.step() == SQLITE_ROW);
executeSQLCommand("DELETE FROM DeletedCacheResources");
}
@@ -1549,14 +1489,14 @@ long long ApplicationCacheStorage::flatFileAreaSize()
SQLiteStatement selectPaths(m_database, "SELECT path FROM CacheResourceData WHERE path NOT NULL");
- if (selectPaths.prepare() != SQLResultOk) {
+ if (selectPaths.prepare() != SQLITE_OK) {
LOG_ERROR("Could not load flat file cache resource data, error \"%s\"", m_database.lastErrorMsg());
return 0;
}
long long totalSize = 0;
- String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory);
- while (selectPaths.step() == SQLResultRow) {
+ String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
+ while (selectPaths.step() == SQLITE_ROW) {
String path = selectPaths.getColumnText(0);
String fullPath = pathByAppendingComponent(flatFileDirectory, path);
long long pathSize = 0;
@@ -1571,18 +1511,12 @@ long long ApplicationCacheStorage::flatFileAreaSize()
void ApplicationCacheStorage::getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>>& origins)
{
Vector<URL> urls;
- if (!manifestURLs(&urls)) {
- LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs");
- return;
- }
+ getManifestURLs(&urls);
// Multiple manifest URLs might share the same SecurityOrigin, so we might be creating extra, wasted origins here.
// The current schema doesn't allow for a more efficient way of building this list.
- size_t count = urls.size();
- for (size_t i = 0; i < count; ++i) {
- RefPtr<SecurityOrigin> origin = SecurityOrigin::create(urls[i]);
- origins.add(origin);
- }
+ for (auto& url : urls)
+ origins.add(SecurityOrigin::create(url));
}
void ApplicationCacheStorage::deleteAllEntries()
@@ -1591,18 +1525,57 @@ void ApplicationCacheStorage::deleteAllEntries()
vacuumDatabaseFile();
}
-ApplicationCacheStorage::ApplicationCacheStorage()
- : m_maximumSize(ApplicationCacheStorage::noQuota())
+void ApplicationCacheStorage::deleteAllCaches()
+{
+ HashSet<RefPtr<SecurityOrigin>> origins;
+
+ getOriginsWithCache(origins);
+ for (auto& origin : origins)
+ deleteCacheForOrigin(*origin);
+
+ vacuumDatabaseFile();
+}
+
+void ApplicationCacheStorage::deleteCacheForOrigin(const SecurityOrigin& securityOrigin)
+{
+ Vector<URL> urls;
+ if (!getManifestURLs(&urls)) {
+ LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs");
+ return;
+ }
+
+ URL originURL(URL(), securityOrigin.toString());
+
+ for (const auto& url : urls) {
+ if (!protocolHostAndPortAreEqual(url, originURL))
+ continue;
+
+ if (auto* group = findInMemoryCacheGroup(url))
+ group->makeObsolete();
+ else
+ deleteCacheGroup(url);
+ }
+}
+
+int64_t ApplicationCacheStorage::diskUsageForOrigin(const SecurityOrigin& securityOrigin)
+{
+ int64_t usage = 0;
+ calculateUsageForOrigin(&securityOrigin, usage);
+ return usage;
+}
+
+ApplicationCacheStorage::ApplicationCacheStorage(const String& cacheDirectory, const String& flatFileSubdirectoryName)
+ : m_cacheDirectory(cacheDirectory)
+ , m_flatFileSubdirectoryName(flatFileSubdirectoryName)
+ , m_maximumSize(ApplicationCacheStorage::noQuota())
, m_isMaximumSizeReached(false)
, m_defaultOriginQuota(ApplicationCacheStorage::noQuota())
{
}
-ApplicationCacheStorage& cacheStorage()
+Ref<ApplicationCacheStorage> ApplicationCacheStorage::create(const String& cacheDirectory, const String& flatFileSubdirectoryName)
{
- DEFINE_STATIC_LOCAL(ApplicationCacheStorage, storage, ());
-
- return storage;
+ return adoptRef(*new ApplicationCacheStorage(cacheDirectory, flatFileSubdirectoryName));
}
-} // namespace WebCore
+}
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheStorage.h b/Source/WebCore/loader/appcache/ApplicationCacheStorage.h
index 76eaa3ecf..9d17a1bcd 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheStorage.h
+++ b/Source/WebCore/loader/appcache/ApplicationCacheStorage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2010, 2011 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ApplicationCacheStorage_h
-#define ApplicationCacheStorage_h
+#pragma once
#include "SecurityOriginHash.h"
#include "SQLiteDatabase.h"
@@ -42,10 +41,9 @@ class ApplicationCacheResource;
class URL;
class SecurityOrigin;
class SharedBuffer;
-template <class T> class StorageIDJournal;
+template<typename> class StorageIDJournal;
-class ApplicationCacheStorage {
- WTF_MAKE_NONCOPYABLE(ApplicationCacheStorage); WTF_MAKE_FAST_ALLOCATED;
+class ApplicationCacheStorage : public RefCounted<ApplicationCacheStorage> {
public:
enum FailureReason {
OriginQuotaReached,
@@ -53,20 +51,21 @@ public:
DiskOrOperationFailure
};
- void setCacheDirectory(const String&);
+ WEBCORE_EXPORT static Ref<ApplicationCacheStorage> create(const String& cacheDirectory, const String& flatFileSubdirectoryName);
+
const String& cacheDirectory() const;
- void setMaximumSize(int64_t size);
- int64_t maximumSize() const;
+ WEBCORE_EXPORT void setMaximumSize(int64_t size);
+ WEBCORE_EXPORT int64_t maximumSize() const;
bool isMaximumSizeReached() const;
int64_t spaceNeeded(int64_t cacheToSave);
int64_t defaultOriginQuota() const { return m_defaultOriginQuota; }
- void setDefaultOriginQuota(int64_t quota);
- bool calculateUsageForOrigin(const SecurityOrigin*, int64_t& usage);
- bool calculateQuotaForOrigin(const SecurityOrigin*, int64_t& quota);
- bool calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin*, ApplicationCache*, int64_t& remainingSize);
- bool storeUpdatedQuotaForOrigin(const SecurityOrigin*, int64_t quota);
+ WEBCORE_EXPORT void setDefaultOriginQuota(int64_t quota);
+ WEBCORE_EXPORT bool calculateUsageForOrigin(const SecurityOrigin*, int64_t& usage);
+ WEBCORE_EXPORT bool calculateQuotaForOrigin(const SecurityOrigin&, int64_t& quota);
+ bool calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin&, ApplicationCache*, int64_t& remainingSize);
+ WEBCORE_EXPORT bool storeUpdatedQuotaForOrigin(const SecurityOrigin*, int64_t quota);
bool checkOriginQuota(ApplicationCacheGroup*, ApplicationCache* oldCache, ApplicationCache* newCache, int64_t& totalSpaceNeeded);
ApplicationCacheGroup* cacheGroupForURL(const URL&); // Cache to load a main resource from.
@@ -74,38 +73,47 @@ public:
ApplicationCacheGroup* findOrCreateCacheGroup(const URL& manifestURL);
ApplicationCacheGroup* findInMemoryCacheGroup(const URL& manifestURL) const;
- void cacheGroupDestroyed(ApplicationCacheGroup*);
- void cacheGroupMadeObsolete(ApplicationCacheGroup*);
-
- bool storeNewestCache(ApplicationCacheGroup*, ApplicationCache* oldCache, FailureReason& failureReason);
- bool storeNewestCache(ApplicationCacheGroup*); // Updates the cache group, but doesn't remove old cache.
+ void cacheGroupDestroyed(ApplicationCacheGroup&);
+ void cacheGroupMadeObsolete(ApplicationCacheGroup&);
+
+ bool storeNewestCache(ApplicationCacheGroup&, ApplicationCache* oldCache, FailureReason&);
+ bool storeNewestCache(ApplicationCacheGroup&); // Updates the cache group, but doesn't remove old cache.
bool store(ApplicationCacheResource*, ApplicationCache*);
bool storeUpdatedType(ApplicationCacheResource*, ApplicationCache*);
// Removes the group if the cache to be removed is the newest one (so, storeNewestCache() needs to be called beforehand when updating).
void remove(ApplicationCache*);
-
- void empty();
-
- static bool storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost*);
- bool manifestURLs(Vector<URL>* urls);
+ WEBCORE_EXPORT void empty();
+
+ bool getManifestURLs(Vector<URL>* urls);
bool cacheGroupSize(const String& manifestURL, int64_t* size);
bool deleteCacheGroup(const String& manifestURL);
- void vacuumDatabaseFile();
+ WEBCORE_EXPORT void vacuumDatabaseFile();
+
+ WEBCORE_EXPORT void getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>&);
+ WEBCORE_EXPORT void deleteAllEntries();
+
+ // FIXME: This should be consolidated with deleteAllEntries().
+ WEBCORE_EXPORT void deleteAllCaches();
+
+ // FIXME: This should be consolidated with deleteCacheGroup().
+ WEBCORE_EXPORT void deleteCacheForOrigin(const SecurityOrigin&);
- void getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>&);
- void deleteAllEntries();
+ // FIXME: This should be consolidated with calculateUsageForOrigin().
+ WEBCORE_EXPORT int64_t diskUsageForOrigin(const SecurityOrigin&);
static int64_t unknownQuota() { return -1; }
static int64_t noQuota() { return std::numeric_limits<int64_t>::max(); }
+
private:
- ApplicationCacheStorage();
- PassRefPtr<ApplicationCache> loadCache(unsigned storageID);
+ ApplicationCacheStorage(const String& cacheDirectory, const String& flatFileSubdirectoryName);
+
+ RefPtr<ApplicationCache> loadCache(unsigned storageID);
ApplicationCacheGroup* loadCacheGroup(const URL& manifestURL);
- typedef StorageIDJournal<ApplicationCacheResource> ResourceStorageIDJournal;
- typedef StorageIDJournal<ApplicationCacheGroup> GroupStorageIDJournal;
+ using ResourceStorageIDJournal = StorageIDJournal<ApplicationCacheResource>;
+ using GroupStorageIDJournal = StorageIDJournal<ApplicationCacheGroup>;
bool store(ApplicationCacheGroup*, GroupStorageIDJournal*);
bool store(ApplicationCache*, ResourceStorageIDJournal*);
@@ -115,7 +123,7 @@ private:
bool ensureOriginRecord(const SecurityOrigin*);
bool shouldStoreResourceAsFlatFile(ApplicationCacheResource*);
void deleteTables();
- bool writeDataToUniqueFileInDirectory(SharedBuffer*, const String& directory, String& outFilename, const String& fileExtension);
+ bool writeDataToUniqueFileInDirectory(SharedBuffer&, const String& directory, String& outFilename, const String& fileExtension);
void loadManifestHostHashes();
@@ -129,8 +137,9 @@ private:
void checkForMaxSizeReached();
void checkForDeletedResources();
long long flatFileAreaSize();
-
- String m_cacheDirectory;
+
+ const String m_cacheDirectory;
+ const String m_flatFileSubdirectoryName;
String m_cacheFile;
int64_t m_maximumSize;
@@ -144,14 +153,9 @@ private:
// we keep a hash set of the hosts of the manifest URLs of all non-obsolete cache groups.
HashCountedSet<unsigned, AlreadyHashed> m_cacheHostSet;
- typedef HashMap<String, ApplicationCacheGroup*> CacheGroupMap;
- CacheGroupMap m_cachesInMemory; // Excludes obsolete cache groups.
+ HashMap<String, ApplicationCacheGroup*> m_cachesInMemory; // Excludes obsolete cache groups.
- friend ApplicationCacheStorage& cacheStorage();
+ friend class WTF::NeverDestroyed<ApplicationCacheStorage>;
};
-
-ApplicationCacheStorage& cacheStorage();
-
-} // namespace WebCore
-#endif // ApplicationCacheStorage_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/appcache/DOMApplicationCache.cpp b/Source/WebCore/loader/appcache/DOMApplicationCache.cpp
index 56437a80d..ed8fad8f6 100644
--- a/Source/WebCore/loader/appcache/DOMApplicationCache.cpp
+++ b/Source/WebCore/loader/appcache/DOMApplicationCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,110 +29,84 @@
#include "ApplicationCacheHost.h"
#include "Document.h"
#include "DocumentLoader.h"
-#include "Event.h"
-#include "EventException.h"
-#include "EventListener.h"
-#include "EventNames.h"
#include "ExceptionCode.h"
#include "Frame.h"
-#include "FrameLoader.h"
namespace WebCore {
-DOMApplicationCache::DOMApplicationCache(Frame* frame)
- : DOMWindowProperty(frame)
+DOMApplicationCache::DOMApplicationCache(Frame& frame)
+ : DOMWindowProperty(&frame)
{
- ApplicationCacheHost* cacheHost = applicationCacheHost();
- if (cacheHost)
- cacheHost->setDOMApplicationCache(this);
+ if (auto* host = applicationCacheHost())
+ host->setDOMApplicationCache(this);
}
-void DOMApplicationCache::disconnectFrameForPageCache()
+void DOMApplicationCache::disconnectFrameForDocumentSuspension()
{
- if (ApplicationCacheHost* cacheHost = applicationCacheHost())
- cacheHost->setDOMApplicationCache(0);
- DOMWindowProperty::disconnectFrameForPageCache();
+ if (auto* host = applicationCacheHost())
+ host->setDOMApplicationCache(nullptr);
+ DOMWindowProperty::disconnectFrameForDocumentSuspension();
}
-void DOMApplicationCache::reconnectFrameFromPageCache(Frame* frame)
+void DOMApplicationCache::reconnectFrameFromDocumentSuspension(Frame* frame)
{
- DOMWindowProperty::reconnectFrameFromPageCache(frame);
- if (ApplicationCacheHost* cacheHost = applicationCacheHost())
- cacheHost->setDOMApplicationCache(this);
+ DOMWindowProperty::reconnectFrameFromDocumentSuspension(frame);
+ if (auto* host = applicationCacheHost())
+ host->setDOMApplicationCache(this);
}
void DOMApplicationCache::willDestroyGlobalObjectInFrame()
{
- if (ApplicationCacheHost* cacheHost = applicationCacheHost())
- cacheHost->setDOMApplicationCache(0);
+ if (auto* host = applicationCacheHost())
+ host->setDOMApplicationCache(nullptr);
DOMWindowProperty::willDestroyGlobalObjectInFrame();
}
ApplicationCacheHost* DOMApplicationCache::applicationCacheHost() const
{
- if (!m_frame || !m_frame->loader().documentLoader())
- return 0;
- return m_frame->loader().documentLoader()->applicationCacheHost();
+ if (!m_frame)
+ return nullptr;
+ auto* documentLoader = m_frame->loader().documentLoader();
+ if (!documentLoader)
+ return nullptr;
+ return &documentLoader->applicationCacheHost();
}
unsigned short DOMApplicationCache::status() const
{
- ApplicationCacheHost* cacheHost = applicationCacheHost();
- if (!cacheHost)
+ auto* host = applicationCacheHost();
+ if (!host)
return ApplicationCacheHost::UNCACHED;
- return cacheHost->status();
+ return host->status();
}
-void DOMApplicationCache::update(ExceptionCode& ec)
+ExceptionOr<void> DOMApplicationCache::update()
{
- ApplicationCacheHost* cacheHost = applicationCacheHost();
- if (!cacheHost || !cacheHost->update())
- ec = INVALID_STATE_ERR;
+ auto* host = applicationCacheHost();
+ if (!host || !host->update())
+ return Exception { INVALID_STATE_ERR };
+ return { };
}
-void DOMApplicationCache::swapCache(ExceptionCode& ec)
+ExceptionOr<void> DOMApplicationCache::swapCache()
{
- ApplicationCacheHost* cacheHost = applicationCacheHost();
- if (!cacheHost || !cacheHost->swapCache())
- ec = INVALID_STATE_ERR;
+ auto* host = applicationCacheHost();
+ if (!host || !host->swapCache())
+ return Exception { INVALID_STATE_ERR };
+ return { };
}
void DOMApplicationCache::abort()
{
- ApplicationCacheHost* cacheHost = applicationCacheHost();
- if (cacheHost)
- cacheHost->abort();
+ if (auto* host = applicationCacheHost())
+ host->abort();
}
ScriptExecutionContext* DOMApplicationCache::scriptExecutionContext() const
{
- if (m_frame)
- return m_frame->document();
- return 0;
-}
-
-const AtomicString& DOMApplicationCache::toEventType(ApplicationCacheHost::EventID id)
-{
- switch (id) {
- case ApplicationCacheHost::CHECKING_EVENT:
- return eventNames().checkingEvent;
- case ApplicationCacheHost::ERROR_EVENT:
- return eventNames().errorEvent;
- case ApplicationCacheHost::NOUPDATE_EVENT:
- return eventNames().noupdateEvent;
- case ApplicationCacheHost::DOWNLOADING_EVENT:
- return eventNames().downloadingEvent;
- case ApplicationCacheHost::PROGRESS_EVENT:
- return eventNames().progressEvent;
- case ApplicationCacheHost::UPDATEREADY_EVENT:
- return eventNames().updatereadyEvent;
- case ApplicationCacheHost::CACHED_EVENT:
- return eventNames().cachedEvent;
- case ApplicationCacheHost::OBSOLETE_EVENT:
- return eventNames().obsoleteEvent;
- }
- ASSERT_NOT_REACHED();
- return eventNames().errorEvent;
+ if (!m_frame)
+ return nullptr;
+ return m_frame->document();
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/appcache/DOMApplicationCache.h b/Source/WebCore/loader/appcache/DOMApplicationCache.h
index 910cb7502..cf6d2a9d9 100644
--- a/Source/WebCore/loader/appcache/DOMApplicationCache.h
+++ b/Source/WebCore/loader/appcache/DOMApplicationCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,68 +23,43 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DOMApplicationCache_h
-#define DOMApplicationCache_h
+#pragma once
-#include "ApplicationCacheHost.h"
#include "DOMWindowProperty.h"
-#include "EventNames.h"
#include "EventTarget.h"
-#include "ScriptWrappable.h"
-#include <wtf/Forward.h>
-#include <wtf/HashMap.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
-#include <wtf/text/AtomicStringHash.h>
namespace WebCore {
+class ApplicationCacheHost;
class Frame;
-class URL;
-class DOMApplicationCache final : public ScriptWrappable, public RefCounted<DOMApplicationCache>, public EventTargetWithInlineData, public DOMWindowProperty {
+class DOMApplicationCache final : public RefCounted<DOMApplicationCache>, public EventTargetWithInlineData, public DOMWindowProperty {
public:
- static PassRefPtr<DOMApplicationCache> create(Frame* frame) { return adoptRef(new DOMApplicationCache(frame)); }
+ static Ref<DOMApplicationCache> create(Frame& frame) { return adoptRef(*new DOMApplicationCache(frame)); }
virtual ~DOMApplicationCache() { ASSERT(!m_frame); }
- virtual void disconnectFrameForPageCache() override;
- virtual void reconnectFrameFromPageCache(Frame*) override;
- virtual void willDestroyGlobalObjectInFrame() override;
-
unsigned short status() const;
- void update(ExceptionCode&);
- void swapCache(ExceptionCode&);
+ ExceptionOr<void> update();
+ ExceptionOr<void> swapCache();
void abort();
- using RefCounted<DOMApplicationCache>::ref;
- using RefCounted<DOMApplicationCache>::deref;
-
- // Explicitly named attribute event listener helpers
-
- DEFINE_ATTRIBUTE_EVENT_LISTENER(checking);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(noupdate);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(downloading);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(updateready);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(cached);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(obsolete);
+ using RefCounted::ref;
+ using RefCounted::deref;
- virtual EventTargetInterface eventTargetInterface() const override { return DOMApplicationCacheEventTargetInterfaceType; }
- virtual ScriptExecutionContext* scriptExecutionContext() const override;
+private:
+ explicit DOMApplicationCache(Frame&);
- static const AtomicString& toEventType(ApplicationCacheHost::EventID id);
+ void refEventTarget() final { ref(); }
+ void derefEventTarget() final { deref(); }
-private:
- explicit DOMApplicationCache(Frame*);
+ EventTargetInterface eventTargetInterface() const final { return DOMApplicationCacheEventTargetInterfaceType; }
+ ScriptExecutionContext* scriptExecutionContext() const final;
- virtual void refEventTarget() override { ref(); }
- virtual void derefEventTarget() override { deref(); }
+ void disconnectFrameForDocumentSuspension() final;
+ void reconnectFrameFromDocumentSuspension(Frame*) final;
+ void willDestroyGlobalObjectInFrame() final;
ApplicationCacheHost* applicationCacheHost() const;
};
} // namespace WebCore
-
-#endif // DOMApplicationCache_h
diff --git a/Source/WebCore/loader/appcache/DOMApplicationCache.idl b/Source/WebCore/loader/appcache/DOMApplicationCache.idl
index 9622c128b..1799f2e38 100644
--- a/Source/WebCore/loader/appcache/DOMApplicationCache.idl
+++ b/Source/WebCore/loader/appcache/DOMApplicationCache.idl
@@ -24,11 +24,10 @@
*/
[
- NoInterfaceObject,
- EventTarget,
DoNotCheckConstants,
GenerateIsReachable=ImplFrame,
-] interface DOMApplicationCache {
+ InterfaceName=ApplicationCache,
+] interface DOMApplicationCache : EventTarget {
// update status
const unsigned short UNCACHED = 0;
const unsigned short IDLE = 1;
@@ -38,27 +37,17 @@
const unsigned short OBSOLETE = 5;
readonly attribute unsigned short status;
- [RaisesException] void update();
- [RaisesException] void swapCache();
+ [MayThrowException] void update();
+ [MayThrowException] void swapCache();
void abort();
- // events
- attribute EventListener onchecking;
- attribute EventListener onerror;
- attribute EventListener onnoupdate;
- attribute EventListener ondownloading;
- attribute EventListener onprogress;
- attribute EventListener onupdateready;
- attribute EventListener oncached;
- attribute EventListener onobsolete;
-
- // EventTarget interface
- void addEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- void removeEventListener(DOMString type,
- EventListener listener,
- optional boolean useCapture);
- [RaisesException] boolean dispatchEvent(Event evt);
+ attribute EventHandler onchecking;
+ attribute EventHandler onerror;
+ attribute EventHandler onnoupdate;
+ attribute EventHandler ondownloading;
+ attribute EventHandler onprogress;
+ attribute EventHandler onupdateready;
+ attribute EventHandler oncached;
+ attribute EventHandler onobsolete;
};
diff --git a/Source/WebCore/loader/appcache/ManifestParser.cpp b/Source/WebCore/loader/appcache/ManifestParser.cpp
index a47aa150e..5c151359d 100644
--- a/Source/WebCore/loader/appcache/ManifestParser.cpp
+++ b/Source/WebCore/loader/appcache/ManifestParser.cpp
@@ -28,6 +28,7 @@
#include "TextResourceDecoder.h"
#include "URL.h"
+#include <wtf/text/StringView.h>
#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
@@ -43,9 +44,7 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes
Mode mode = Explicit;
- RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/cache-manifest", "UTF-8");
- String s = decoder->decode(data, length);
- s.append(decoder->flush());
+ String s = TextResourceDecoder::create("text/cache-manifest", "UTF-8")->decodeAndFlush(data, length);
// Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by TextResourceDecoder).
// Example: "CACHE MANIFEST #comment" is a valid signature.
@@ -53,8 +52,10 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes
if (!s.startsWith("CACHE MANIFEST"))
return false;
- const UChar* end = s.deprecatedCharacters() + s.length();
- const UChar* p = s.deprecatedCharacters() + 14; // "CACHE MANIFEST" is 14 characters.
+ StringView manifestAfterSignature = StringView(s).substring(14); // "CACHE MANIFEST" is 14 characters.
+ auto upconvertedCharacters = manifestAfterSignature.upconvertedCharacters();
+ const UChar* p = upconvertedCharacters;
+ const UChar* end = p + manifestAfterSignature.length();
if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
return false;
@@ -99,28 +100,28 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes
else if (mode == Unknown)
continue;
else if (mode == Explicit || mode == OnlineWhitelist) {
- const UChar* p = line.deprecatedCharacters();
+ auto upconvertedLineCharacters = StringView(line).upconvertedCharacters();
+ const UChar* p = upconvertedLineCharacters;
const UChar* lineEnd = p + line.length();
// Look for whitespace separating the URL from subsequent ignored tokens.
while (p < lineEnd && *p != '\t' && *p != ' ')
p++;
- if (mode == OnlineWhitelist && p - line.deprecatedCharacters() == 1 && *line.deprecatedCharacters() == '*') {
+ if (mode == OnlineWhitelist && p - upconvertedLineCharacters == 1 && line[0] == '*') {
// Wildcard was found.
manifest.allowAllNetworkRequests = true;
continue;
}
- URL url(manifestURL, String(line.deprecatedCharacters(), p - line.deprecatedCharacters()));
+ URL url(manifestURL, line.substring(0, p - upconvertedLineCharacters));
if (!url.isValid())
continue;
- if (url.hasFragmentIdentifier())
- url.removeFragmentIdentifier();
+ url.removeFragmentIdentifier();
- if (!equalIgnoringCase(url.protocol(), manifestURL.protocol()))
+ if (!equalIgnoringASCIICase(url.protocol(), manifestURL.protocol()))
continue;
if (mode == Explicit && manifestURL.protocolIs("https") && !protocolHostAndPortAreEqual(manifestURL, url))
@@ -132,7 +133,8 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes
manifest.onlineWhitelistedURLs.append(url);
} else if (mode == Fallback) {
- const UChar* p = line.deprecatedCharacters();
+ auto upconvertedLineCharacters = StringView(line).upconvertedCharacters();
+ const UChar* p = upconvertedLineCharacters;
const UChar* lineEnd = p + line.length();
// Look for whitespace separating the two URLs
@@ -144,11 +146,10 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes
continue;
}
- URL namespaceURL(manifestURL, String(line.deprecatedCharacters(), p - line.deprecatedCharacters()));
+ URL namespaceURL(manifestURL, line.substring(0, p - upconvertedLineCharacters));
if (!namespaceURL.isValid())
continue;
- if (namespaceURL.hasFragmentIdentifier())
- namespaceURL.removeFragmentIdentifier();
+ namespaceURL.removeFragmentIdentifier();
if (!protocolHostAndPortAreEqual(manifestURL, namespaceURL))
continue;
@@ -165,8 +166,7 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes
URL fallbackURL(manifestURL, String(fallbackStart, p - fallbackStart));
if (!fallbackURL.isValid())
continue;
- if (fallbackURL.hasFragmentIdentifier())
- fallbackURL.removeFragmentIdentifier();
+ fallbackURL.removeFragmentIdentifier();
if (!protocolHostAndPortAreEqual(manifestURL, fallbackURL))
continue;
diff --git a/Source/WebCore/loader/appcache/ManifestParser.h b/Source/WebCore/loader/appcache/ManifestParser.h
index 28315dde6..b28249ebe 100644
--- a/Source/WebCore/loader/appcache/ManifestParser.h
+++ b/Source/WebCore/loader/appcache/ManifestParser.h
@@ -23,24 +23,22 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ManifestParser_h
-#define ManifestParser_h
+#pragma once
#include "ApplicationCache.h"
+#include <wtf/HashSet.h>
namespace WebCore {
- class URL;
+class URL;
- struct Manifest {
- Vector<URL> onlineWhitelistedURLs;
- HashSet<String> explicitURLs;
- FallbackURLVector fallbackURLs;
- bool allowAllNetworkRequests; // Wildcard found in NETWORK section.
- };
+struct Manifest {
+ Vector<URL> onlineWhitelistedURLs;
+ HashSet<String> explicitURLs;
+ FallbackURLVector fallbackURLs;
+ bool allowAllNetworkRequests; // Wildcard found in NETWORK section.
+};
- bool parseManifest(const URL& manifestURL, const char* data, int length, Manifest&);
+bool parseManifest(const URL& manifestURL, const char* data, int length, Manifest&);
-}
-
-#endif // ManifestParser_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/archive/Archive.cpp b/Source/WebCore/loader/archive/Archive.cpp
index 86d7558e1..5e05be22c 100644
--- a/Source/WebCore/loader/archive/Archive.cpp
+++ b/Source/WebCore/loader/archive/Archive.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -37,17 +37,17 @@ Archive::~Archive()
void Archive::clearAllSubframeArchives()
{
- Vector<RefPtr<Archive>> clearedArchives;
- clearAllSubframeArchivesImpl(&clearedArchives);
+ HashSet<Archive*> clearedArchives;
+ clearedArchives.add(this);
+ clearAllSubframeArchives(clearedArchives);
}
-void Archive::clearAllSubframeArchivesImpl(Vector<RefPtr<Archive>>* clearedArchives)
+void Archive::clearAllSubframeArchives(HashSet<Archive*>& clearedArchives)
{
- for (Vector<RefPtr<Archive>>::iterator it = m_subframeArchives.begin(); it != m_subframeArchives.end(); ++it) {
- if (!clearedArchives->contains(*it)) {
- clearedArchives->append(*it);
- (*it)->clearAllSubframeArchivesImpl(clearedArchives);
- }
+ ASSERT(clearedArchives.contains(this));
+ for (auto& archive : m_subframeArchives) {
+ if (clearedArchives.add(archive.ptr()))
+ archive->clearAllSubframeArchives(clearedArchives);
}
m_subframeArchives.clear();
}
diff --git a/Source/WebCore/loader/archive/Archive.h b/Source/WebCore/loader/archive/Archive.h
index 15f6b7563..ff74ce283 100644
--- a/Source/WebCore/loader/archive/Archive.h
+++ b/Source/WebCore/loader/archive/Archive.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,47 +26,41 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef Archive_h
-#define Archive_h
+#pragma once
#include "ArchiveResource.h"
-
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
+#include <wtf/HashSet.h>
namespace WebCore {
class Archive : public RefCounted<Archive> {
public:
- enum Type {
- WebArchive,
- MHTML
- };
virtual ~Archive();
- virtual Type type() const = 0;
+
+ virtual bool shouldLoadFromArchiveOnly() const = 0;
+ virtual bool shouldOverrideBaseURL() const = 0;
+ virtual bool shouldUseMainResourceEncoding() const = 0;
+ virtual bool shouldUseMainResourceURL() const = 0;
+
ArchiveResource* mainResource() { return m_mainResource.get(); }
- const Vector<RefPtr<ArchiveResource>>& subresources() const { return m_subresources; }
- const Vector<RefPtr<Archive>>& subframeArchives() const { return m_subframeArchives; }
+ const Vector<Ref<ArchiveResource>>& subresources() const { return m_subresources; }
+ const Vector<Ref<Archive>>& subframeArchives() const { return m_subframeArchives; }
protected:
// These methods are meant for subclasses for different archive types to add resources in to the archive,
// and should not be exposed as archives should be immutable to clients
- void setMainResource(PassRefPtr<ArchiveResource> mainResource) { m_mainResource = mainResource; }
- void addSubresource(PassRefPtr<ArchiveResource> subResource) { m_subresources.append(subResource); }
- void addSubframeArchive(PassRefPtr<Archive> subframeArchive) { m_subframeArchives.append(subframeArchive); }
+ void setMainResource(Ref<ArchiveResource>&& mainResource) { m_mainResource = WTFMove(mainResource); }
+ void addSubresource(Ref<ArchiveResource>&& resource) { m_subresources.append(WTFMove(resource)); }
+ void addSubframeArchive(Ref<Archive>&& subframeArchive) { m_subframeArchives.append(WTFMove(subframeArchive)); }
void clearAllSubframeArchives();
private:
- void clearAllSubframeArchivesImpl(Vector<RefPtr<Archive>>* clearedArchives);
+ void clearAllSubframeArchives(HashSet<Archive*>&);
RefPtr<ArchiveResource> m_mainResource;
- Vector<RefPtr<ArchiveResource>> m_subresources;
- Vector<RefPtr<Archive>> m_subframeArchives;
+ Vector<Ref<ArchiveResource>> m_subresources;
+ Vector<Ref<Archive>> m_subframeArchives;
};
-}
-
-#endif // Archive
+} // namespace WebCore
diff --git a/Source/WebCore/loader/archive/ArchiveFactory.cpp b/Source/WebCore/loader/archive/ArchiveFactory.cpp
index adbd5da44..417ac47a7 100644
--- a/Source/WebCore/loader/archive/ArchiveFactory.cpp
+++ b/Source/WebCore/loader/archive/ArchiveFactory.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -40,41 +40,42 @@
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-typedef PassRefPtr<Archive> RawDataCreationFunction(const URL&, SharedBuffer*);
-typedef HashMap<String, RawDataCreationFunction*, CaseFoldingHash> ArchiveMIMETypesMap;
+typedef RefPtr<Archive> RawDataCreationFunction(const URL&, SharedBuffer&);
+typedef HashMap<String, RawDataCreationFunction*, ASCIICaseInsensitiveHash> ArchiveMIMETypesMap;
-// The create functions in the archive classes return PassRefPtr to concrete subclasses
+// The create functions in the archive classes return RefPtr to concrete subclasses
// of Archive. This adaptor makes the functions have a uniform return type.
-template <typename ArchiveClass> static PassRefPtr<Archive> archiveFactoryCreate(const URL& url, SharedBuffer* buffer)
+template<typename ArchiveClass> static RefPtr<Archive> archiveFactoryCreate(const URL& url, SharedBuffer& buffer)
{
return ArchiveClass::create(url, buffer);
}
-static ArchiveMIMETypesMap& archiveMIMETypes()
+static ArchiveMIMETypesMap createArchiveMIMETypesMap()
{
- DEFINE_STATIC_LOCAL(ArchiveMIMETypesMap, mimeTypes, ());
- static bool initialized = false;
-
- if (initialized)
- return mimeTypes;
+ ArchiveMIMETypesMap map;
- // FIXME: Remove unnecessary 'static_cast<RawDataCreationFunction*>' from the following 'mimeTypes.set' operations
- // once we switch to a non-broken Visual Studio compiler. https://bugs.webkit.org/show_bug.cgi?id=121235
#if ENABLE(WEB_ARCHIVE) && USE(CF)
- mimeTypes.set("application/x-webarchive", static_cast<RawDataCreationFunction*>(&archiveFactoryCreate<LegacyWebArchive>));
+ map.add(ASCIILiteral { "application/x-webarchive" }, archiveFactoryCreate<LegacyWebArchive>);
#endif
+
#if ENABLE(MHTML)
- mimeTypes.set("multipart/related", static_cast<RawDataCreationFunction*>(&archiveFactoryCreate<MHTMLArchive>));
- mimeTypes.set("application/x-mimearchive", static_cast<RawDataCreationFunction*>(&archiveFactoryCreate<MHTMLArchive>));
+ map.add(ASCIILiteral { "multipart/related" }, archiveFactoryCreate<MHTMLArchive>);
+ map.add(ASCIILiteral { "application/x-mimearchive" }, archiveFactoryCreate<MHTMLArchive>);
#endif
- initialized = true;
- return mimeTypes;
+ return map;
+}
+
+static ArchiveMIMETypesMap& archiveMIMETypes()
+{
+ static NeverDestroyed<ArchiveMIMETypesMap> map = createArchiveMIMETypesMap();
+ return map;
}
bool ArchiveFactory::isArchiveMimeType(const String& mimeType)
@@ -82,17 +83,22 @@ bool ArchiveFactory::isArchiveMimeType(const String& mimeType)
return !mimeType.isEmpty() && archiveMIMETypes().contains(mimeType);
}
-PassRefPtr<Archive> ArchiveFactory::create(const URL& url, SharedBuffer* data, const String& mimeType)
+RefPtr<Archive> ArchiveFactory::create(const URL& url, SharedBuffer* data, const String& mimeType)
{
- RawDataCreationFunction* function = mimeType.isEmpty() ? 0 : archiveMIMETypes().get(mimeType);
- return function ? function(url, data) : PassRefPtr<Archive>(0);
+ if (!data)
+ return nullptr;
+ if (mimeType.isEmpty())
+ return nullptr;
+ auto* function = archiveMIMETypes().get(mimeType);
+ if (!function)
+ return nullptr;
+ return function(url, *data);
}
void ArchiveFactory::registerKnownArchiveMIMETypes()
{
- HashSet<String>& mimeTypes = MIMETypeRegistry::getSupportedNonImageMIMETypes();
-
- for (const auto& mimeType : archiveMIMETypes().keys())
+ auto& mimeTypes = MIMETypeRegistry::getSupportedNonImageMIMETypes();
+ for (auto& mimeType : archiveMIMETypes().keys())
mimeTypes.add(mimeType);
}
diff --git a/Source/WebCore/loader/archive/ArchiveFactory.h b/Source/WebCore/loader/archive/ArchiveFactory.h
index 54b64dd77..f37b3c51d 100644
--- a/Source/WebCore/loader/archive/ArchiveFactory.h
+++ b/Source/WebCore/loader/archive/ArchiveFactory.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,13 +26,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ArchiveFactory_h
-#define ArchiveFactory_h
+#pragma once
#include "Archive.h"
#include <wtf/Forward.h>
-#include <wtf/PassRefPtr.h>
namespace WebCore {
@@ -41,10 +39,8 @@ class SharedBuffer;
class ArchiveFactory {
public:
static bool isArchiveMimeType(const String&);
- static PassRefPtr<Archive> create(const URL&, SharedBuffer* data, const String& mimeType);
+ static RefPtr<Archive> create(const URL&, SharedBuffer* data, const String& mimeType);
static void registerKnownArchiveMIMETypes();
};
-}
-
-#endif // ArchiveFactory_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/archive/ArchiveResource.cpp b/Source/WebCore/loader/archive/ArchiveResource.cpp
index 21000c828..bf1e8461b 100644
--- a/Source/WebCore/loader/archive/ArchiveResource.cpp
+++ b/Source/WebCore/loader/archive/ArchiveResource.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -33,8 +33,8 @@
namespace WebCore {
-inline ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const URL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
- : SubstituteResource(url, response, data)
+inline ArchiveResource::ArchiveResource(Ref<SharedBuffer>&& data, const URL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
+ : SubstituteResource(url, response, WTFMove(data))
, m_mimeType(mimeType)
, m_textEncoding(textEncoding)
, m_frameName(frameName)
@@ -42,21 +42,21 @@ inline ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const URL
{
}
-PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const URL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
+RefPtr<ArchiveResource> ArchiveResource::create(RefPtr<SharedBuffer>&& data, const URL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
{
if (!data)
- return 0;
+ return nullptr;
if (response.isNull()) {
unsigned dataSize = data->size();
- return adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName,
- ResourceResponse(url, mimeType, dataSize, textEncoding, String())));
+ return adoptRef(*new ArchiveResource(data.releaseNonNull(), url, mimeType, textEncoding, frameName,
+ ResourceResponse(url, mimeType, dataSize, textEncoding)));
}
- return adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName, response));
+ return adoptRef(*new ArchiveResource(data.releaseNonNull(), url, mimeType, textEncoding, frameName, response));
}
-PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const URL& url, const ResourceResponse& response)
+RefPtr<ArchiveResource> ArchiveResource::create(RefPtr<SharedBuffer>&& data, const URL& url, const ResourceResponse& response)
{
- return create(data, url, response.mimeType(), response.textEncodingName(), String(), response);
+ return create(WTFMove(data), url, response.mimeType(), response.textEncodingName(), String(), response);
}
}
diff --git a/Source/WebCore/loader/archive/ArchiveResource.h b/Source/WebCore/loader/archive/ArchiveResource.h
index 9b4b01b9c..209e9717a 100644
--- a/Source/WebCore/loader/archive/ArchiveResource.h
+++ b/Source/WebCore/loader/archive/ArchiveResource.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ArchiveResource_h
-#define ArchiveResource_h
+#pragma once
#include "SubstituteResource.h"
@@ -35,8 +34,8 @@ namespace WebCore {
class ArchiveResource : public SubstituteResource {
public:
- static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const URL&, const ResourceResponse&);
- static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const URL&,
+ static RefPtr<ArchiveResource> create(RefPtr<SharedBuffer>&&, const URL&, const ResourceResponse&);
+ WEBCORE_EXPORT static RefPtr<ArchiveResource> create(RefPtr<SharedBuffer>&&, const URL&,
const String& mimeType, const String& textEncoding, const String& frameName,
const ResourceResponse& = ResourceResponse());
@@ -48,7 +47,7 @@ public:
bool shouldIgnoreWhenUnarchiving() const { return m_shouldIgnoreWhenUnarchiving; }
private:
- ArchiveResource(PassRefPtr<SharedBuffer>, const URL&, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse&);
+ ArchiveResource(Ref<SharedBuffer>&&, const URL&, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse&);
String m_mimeType;
String m_textEncoding;
@@ -57,6 +56,4 @@ private:
bool m_shouldIgnoreWhenUnarchiving;
};
-}
-
-#endif // ArchiveResource_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/archive/ArchiveResourceCollection.cpp b/Source/WebCore/loader/archive/ArchiveResourceCollection.cpp
index ac9e377b5..a3705ec77 100644
--- a/Source/WebCore/loader/archive/ArchiveResourceCollection.cpp
+++ b/Source/WebCore/loader/archive/ArchiveResourceCollection.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,64 +29,43 @@
#include "config.h"
#include "ArchiveResourceCollection.h"
-namespace WebCore {
+#include "Archive.h"
-ArchiveResourceCollection::ArchiveResourceCollection()
-{
-}
+namespace WebCore {
-void ArchiveResourceCollection::addAllResources(Archive* archive)
+void ArchiveResourceCollection::addAllResources(Archive& archive)
{
- ASSERT(archive);
- if (!archive)
- return;
+ for (auto& subresource : archive.subresources())
+ m_subresources.set(subresource->url(), subresource.ptr());
- const Vector<RefPtr<ArchiveResource>>& subresources = archive->subresources();
- for (Vector<RefPtr<ArchiveResource>>::const_iterator iterator = subresources.begin(); iterator != subresources.end(); ++iterator)
- m_subresources.set((*iterator)->url(), iterator->get());
-
- const Vector<RefPtr<Archive>>& subframes = archive->subframeArchives();
- for (Vector<RefPtr<Archive>>::const_iterator iterator = subframes.begin(); iterator != subframes.end(); ++iterator) {
- RefPtr<Archive> archive = *iterator;
- ASSERT(archive->mainResource());
-
- const String& frameName = archive->mainResource()->frameName();
- if (!frameName.isNull())
- m_subframes.set(frameName, archive.get());
- else {
- // In the MHTML case, frames don't have a name so we use the URL instead.
- m_subframes.set(archive->mainResource()->url().string(), archive.get());
+ for (auto& subframeArchive : archive.subframeArchives()) {
+ ASSERT(subframeArchive->mainResource());
+ auto frameName = subframeArchive->mainResource()->frameName();
+ if (frameName.isNull()) {
+ // In the MHTML case, frames don't have a name, so we use the URL instead.
+ frameName = subframeArchive->mainResource()->url().string();
}
+ m_subframes.set(frameName, subframeArchive.ptr());
}
}
// FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
// Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
-void ArchiveResourceCollection::addResource(PassRefPtr<ArchiveResource> resource)
+void ArchiveResourceCollection::addResource(Ref<ArchiveResource>&& resource)
{
- ASSERT(resource);
- if (!resource)
- return;
-
- const URL& url = resource->url(); // get before passing PassRefPtr (which sets it to 0)
- m_subresources.set(url, resource);
+ auto& url = resource->url();
+ m_subresources.set(url, WTFMove(resource));
}
ArchiveResource* ArchiveResourceCollection::archiveResourceForURL(const URL& url)
{
- ArchiveResource* resource = m_subresources.get(url);
- if (!resource)
- return 0;
-
- return resource;
+ return m_subresources.get(url);
}
-PassRefPtr<Archive> ArchiveResourceCollection::popSubframeArchive(const String& frameName, const URL& url)
+RefPtr<Archive> ArchiveResourceCollection::popSubframeArchive(const String& frameName, const URL& url)
{
- RefPtr<Archive> archive = m_subframes.take(frameName);
- if (archive)
- return archive.release();
-
+ if (auto archive = m_subframes.take(frameName))
+ return archive;
return m_subframes.take(url.string());
}
diff --git a/Source/WebCore/loader/archive/ArchiveResourceCollection.h b/Source/WebCore/loader/archive/ArchiveResourceCollection.h
index 1927a8952..37df68b36 100644
--- a/Source/WebCore/loader/archive/ArchiveResourceCollection.h
+++ b/Source/WebCore/loader/archive/ArchiveResourceCollection.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,35 +26,35 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ArchiveResourceCollection_h
-#define ArchiveResourceCollection_h
-
-#include "Archive.h"
-#include "ArchiveResource.h"
-#include "URL.h"
-#include <wtf/text/WTFString.h>
+#pragma once
+#include <wtf/Forward.h>
#include <wtf/HashMap.h>
-#include <wtf/RefCounted.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
+class Archive;
+class ArchiveResource;
+class URL;
+
class ArchiveResourceCollection {
- WTF_MAKE_NONCOPYABLE(ArchiveResourceCollection); WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(ArchiveResourceCollection);
+ WTF_MAKE_FAST_ALLOCATED;
+
public:
- ArchiveResourceCollection();
+ ArchiveResourceCollection() = default;
- void addResource(PassRefPtr<ArchiveResource>);
- void addAllResources(Archive*);
+ void addResource(Ref<ArchiveResource>&&);
+ void addAllResources(Archive&);
- ArchiveResource* archiveResourceForURL(const URL&);
- PassRefPtr<Archive> popSubframeArchive(const String& frameName, const URL&);
+ WEBCORE_EXPORT ArchiveResource* archiveResourceForURL(const URL&);
+ RefPtr<Archive> popSubframeArchive(const String& frameName, const URL&);
private:
HashMap<String, RefPtr<ArchiveResource>> m_subresources;
HashMap<String, RefPtr<Archive>> m_subframes;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/archive/mhtml/MHTMLArchive.cpp b/Source/WebCore/loader/archive/mhtml/MHTMLArchive.cpp
index 4708bf11e..2ca67e27b 100644
--- a/Source/WebCore/loader/archive/mhtml/MHTMLArchive.cpp
+++ b/Source/WebCore/loader/archive/mhtml/MHTMLArchive.cpp
@@ -59,7 +59,6 @@ namespace WebCore {
const char* const quotedPrintable = "quoted-printable";
const char* const base64 = "base64";
-const char* const binary = "binary";
static String generateRandomBoundary()
{
@@ -102,50 +101,40 @@ MHTMLArchive::~MHTMLArchive()
clearAllSubframeArchives();
}
-PassRefPtr<MHTMLArchive> MHTMLArchive::create()
+Ref<MHTMLArchive> MHTMLArchive::create()
{
- return adoptRef(new MHTMLArchive);
+ return adoptRef(*new MHTMLArchive);
}
-PassRefPtr<MHTMLArchive> MHTMLArchive::create(const URL& url, SharedBuffer* data)
+RefPtr<MHTMLArchive> MHTMLArchive::create(const URL& url, SharedBuffer& data)
{
// For security reasons we only load MHTML pages from local URLs.
- if (!SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
- return 0;
+ if (!SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol().toString()))
+ return nullptr;
- MHTMLParser parser(data);
+ MHTMLParser parser(&data);
RefPtr<MHTMLArchive> mainArchive = parser.parseArchive();
if (!mainArchive)
- return 0; // Invalid MHTML file.
+ return nullptr; // Invalid MHTML file.
// Since MHTML is a flat format, we need to make all frames aware of all resources.
for (size_t i = 0; i < parser.frameCount(); ++i) {
RefPtr<MHTMLArchive> archive = parser.frameAt(i);
for (size_t j = 1; j < parser.frameCount(); ++j) {
if (i != j)
- archive->addSubframeArchive(parser.frameAt(j));
+ archive->addSubframeArchive(*parser.frameAt(j));
}
for (size_t j = 0; j < parser.subResourceCount(); ++j)
- archive->addSubresource(parser.subResourceAt(j));
+ archive->addSubresource(*parser.subResourceAt(j));
}
- return mainArchive.release();
+ return mainArchive;
}
-PassRefPtr<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page)
-{
- return generateMHTMLData(page, false);
-}
-
-PassRefPtr<SharedBuffer> MHTMLArchive::generateMHTMLDataUsingBinaryEncoding(Page* page)
-{
- return generateMHTMLData(page, true);
-}
-
-PassRefPtr<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page, bool useBinaryEncoding)
+RefPtr<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page)
{
Vector<PageSerializer::Resource> resources;
- PageSerializer pageSerializer(&resources);
- pageSerializer.serialize(page);
+ PageSerializer pageSerializer(resources);
+ pageSerializer.serialize(*page);
String boundary = generateRandomBoundary();
String endOfResourceBoundary = makeString("--", boundary, "\r\n");
@@ -176,18 +165,14 @@ PassRefPtr<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page, bool useBin
RefPtr<SharedBuffer> mhtmlData = SharedBuffer::create();
mhtmlData->append(asciiString.data(), asciiString.length());
- for (size_t i = 0; i < resources.size(); ++i) {
- const PageSerializer::Resource& resource = resources[i];
-
+ for (auto& resource : resources) {
stringBuilder.clear();
stringBuilder.append(endOfResourceBoundary);
stringBuilder.append("Content-Type: ");
stringBuilder.append(resource.mimeType);
- const char* contentEncoding = 0;
- if (useBinaryEncoding)
- contentEncoding = binary;
- else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(resource.mimeType) || MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType))
+ const char* contentEncoding = nullptr;
+ if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(resource.mimeType) || MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType))
contentEncoding = quotedPrintable;
else
contentEncoding = base64;
@@ -201,36 +186,27 @@ PassRefPtr<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page, bool useBin
asciiString = stringBuilder.toString().utf8();
mhtmlData->append(asciiString.data(), asciiString.length());
- if (!strcmp(contentEncoding, binary)) {
- const char* data;
- size_t position = 0;
- while (size_t length = resource.data->getSomeData(data, position)) {
- mhtmlData->append(data, length);
- position += length;
- }
+ // FIXME: ideally we would encode the content as a stream without having to fetch it all.
+ const char* data = resource.data->data();
+ size_t dataLength = resource.data->size();
+ Vector<char> encodedData;
+ if (!strcmp(contentEncoding, quotedPrintable)) {
+ quotedPrintableEncode(data, dataLength, encodedData);
+ mhtmlData->append(encodedData.data(), encodedData.size());
+ mhtmlData->append("\r\n", 2);
} else {
- // FIXME: ideally we would encode the content as a stream without having to fetch it all.
- const char* data = resource.data->data();
- size_t dataLength = resource.data->size();
- Vector<char> encodedData;
- if (!strcmp(contentEncoding, quotedPrintable)) {
- quotedPrintableEncode(data, dataLength, encodedData);
- mhtmlData->append(encodedData.data(), encodedData.size());
+ ASSERT(!strcmp(contentEncoding, base64));
+ // We are not specifying insertLFs = true below as it would cut the lines with LFs and MHTML requires CRLFs.
+ base64Encode(data, dataLength, encodedData);
+ const size_t maximumLineLength = 76;
+ size_t index = 0;
+ size_t encodedDataLength = encodedData.size();
+ do {
+ size_t lineLength = std::min(encodedDataLength - index, maximumLineLength);
+ mhtmlData->append(encodedData.data() + index, lineLength);
mhtmlData->append("\r\n", 2);
- } else {
- ASSERT(!strcmp(contentEncoding, base64));
- // We are not specifying insertLFs = true below as it would cut the lines with LFs and MHTML requires CRLFs.
- base64Encode(data, dataLength, encodedData);
- const size_t maximumLineLength = 76;
- size_t index = 0;
- size_t encodedDataLength = encodedData.size();
- do {
- size_t lineLength = std::min(encodedDataLength - index, maximumLineLength);
- mhtmlData->append(encodedData.data() + index, lineLength);
- mhtmlData->append("\r\n", 2);
- index += maximumLineLength;
- } while (index < encodedDataLength);
- }
+ index += maximumLineLength;
+ } while (index < encodedDataLength);
}
}
diff --git a/Source/WebCore/loader/archive/mhtml/MHTMLArchive.h b/Source/WebCore/loader/archive/mhtml/MHTMLArchive.h
index 14cd87572..8524659aa 100644
--- a/Source/WebCore/loader/archive/mhtml/MHTMLArchive.h
+++ b/Source/WebCore/loader/archive/mhtml/MHTMLArchive.h
@@ -28,8 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MHTMLArchive_h
-#define MHTMLArchive_h
+#pragma once
#if ENABLE(MHTML)
@@ -41,27 +40,26 @@ class MHTMLParser;
class Page;
class SharedBuffer;
-class MHTMLArchive : public Archive {
+class MHTMLArchive final : public Archive {
public:
- virtual Type type() const { return MHTML; }
+ static Ref<MHTMLArchive> create();
+ static RefPtr<MHTMLArchive> create(const URL&, SharedBuffer&);
- static PassRefPtr<MHTMLArchive> create();
- static PassRefPtr<MHTMLArchive> create(const URL&, SharedBuffer*);
-
- static PassRefPtr<SharedBuffer> generateMHTMLData(Page*);
- // Binary encoding results in smaller MHTML files but they might not work in other browsers.
- static PassRefPtr<SharedBuffer> generateMHTMLDataUsingBinaryEncoding(Page*);
+ static RefPtr<SharedBuffer> generateMHTMLData(Page*);
virtual ~MHTMLArchive();
private:
- static PassRefPtr<SharedBuffer> generateMHTMLData(Page*, bool useBinaryEncoding);
-
friend class MHTMLParser;
+
MHTMLArchive();
+
+ bool shouldLoadFromArchiveOnly() const final { return true; }
+ bool shouldOverrideBaseURL() const final { return true; }
+ bool shouldUseMainResourceEncoding() const final { return false; }
+ bool shouldUseMainResourceURL() const final { return false; }
};
-}
+} // namespace WebCore
-#endif
-#endif
+#endif // ENABLE(MHTML)
diff --git a/Source/WebCore/loader/archive/mhtml/MHTMLParser.cpp b/Source/WebCore/loader/archive/mhtml/MHTMLParser.cpp
index d8760f9ed..b0414ebc9 100644
--- a/Source/WebCore/loader/archive/mhtml/MHTMLParser.cpp
+++ b/Source/WebCore/loader/archive/mhtml/MHTMLParser.cpp
@@ -37,7 +37,6 @@
#include "MIMEHeader.h"
#include "MIMETypeRegistry.h"
#include "QuotedPrintable.h"
-#include <wtf/HashMap.h>
#include <wtf/text/Base64.h>
namespace WebCore {
@@ -57,17 +56,16 @@ MHTMLParser::MHTMLParser(SharedBuffer* data)
{
}
-PassRefPtr<MHTMLArchive> MHTMLParser::parseArchive()
+RefPtr<MHTMLArchive> MHTMLParser::parseArchive()
{
- RefPtr<MIMEHeader> header = MIMEHeader::parseHeader(&m_lineReader);
- return parseArchiveWithHeader(header.get());
+ return parseArchiveWithHeader(MIMEHeader::parseHeader(m_lineReader).get());
}
-PassRefPtr<MHTMLArchive> MHTMLParser::parseArchiveWithHeader(MIMEHeader* header)
+RefPtr<MHTMLArchive> MHTMLParser::parseArchiveWithHeader(MIMEHeader* header)
{
if (!header) {
LOG_ERROR("Failed to parse MHTML part: no header.");
- return 0;
+ return nullptr;
}
RefPtr<MHTMLArchive> archive = MHTMLArchive::create();
@@ -76,8 +74,8 @@ PassRefPtr<MHTMLArchive> MHTMLParser::parseArchiveWithHeader(MIMEHeader* header)
bool endOfArchiveReached = false;
RefPtr<ArchiveResource> resource = parseNextPart(*header, String(), String(), endOfArchiveReached);
if (!resource)
- return 0;
- archive->setMainResource(resource);
+ return nullptr;
+ archive->setMainResource(resource.releaseNonNull());
return archive;
}
@@ -86,31 +84,31 @@ PassRefPtr<MHTMLArchive> MHTMLParser::parseArchiveWithHeader(MIMEHeader* header)
bool endOfArchive = false;
while (!endOfArchive) {
- RefPtr<MIMEHeader> resourceHeader = MIMEHeader::parseHeader(&m_lineReader);
+ RefPtr<MIMEHeader> resourceHeader = MIMEHeader::parseHeader(m_lineReader);
if (!resourceHeader) {
LOG_ERROR("Failed to parse MHTML, invalid MIME header.");
- return 0;
+ return nullptr;
}
if (resourceHeader->contentType() == "multipart/alternative") {
// Ignore IE nesting which makes little sense (IE seems to nest only some of the frames).
RefPtr<MHTMLArchive> subframeArchive = parseArchiveWithHeader(resourceHeader.get());
if (!subframeArchive) {
LOG_ERROR("Failed to parse MHTML subframe.");
- return 0;
+ return nullptr;
}
bool endOfPartReached = skipLinesUntilBoundaryFound(m_lineReader, header->endOfPartBoundary());
ASSERT_UNUSED(endOfPartReached, endOfPartReached);
// The top-frame is the first frame found, regardless of the nesting level.
if (subframeArchive->mainResource())
addResourceToArchive(subframeArchive->mainResource(), archive.get());
- archive->addSubframeArchive(subframeArchive);
+ archive->addSubframeArchive(subframeArchive.releaseNonNull());
continue;
}
RefPtr<ArchiveResource> resource = parseNextPart(*resourceHeader, header->endOfPartBoundary(), header->endOfDocumentBoundary(), endOfArchive);
if (!resource) {
LOG_ERROR("Failed to parse MHTML part.");
- return 0;
+ return nullptr;
}
addResourceToArchive(resource.get(), archive.get());
}
@@ -128,17 +126,17 @@ void MHTMLParser::addResourceToArchive(ArchiveResource* resource, MHTMLArchive*
// The first document suitable resource is the main frame.
if (!archive->mainResource()) {
- archive->setMainResource(resource);
+ archive->setMainResource(*resource);
m_frames.append(archive);
return;
}
RefPtr<MHTMLArchive> subframe = MHTMLArchive::create();
- subframe->setMainResource(resource);
+ subframe->setMainResource(*resource);
m_frames.append(subframe);
}
-PassRefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHeader, const String& endOfPartBoundary, const String& endOfDocumentBoundary, bool& endOfArchiveReached)
+RefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHeader, const String& endOfPartBoundary, const String& endOfDocumentBoundary, bool& endOfArchiveReached)
{
ASSERT(endOfPartBoundary.isEmpty() == endOfDocumentBoundary.isEmpty());
@@ -148,31 +146,31 @@ PassRefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHea
if (mimeHeader.contentTransferEncoding() == MIMEHeader::Binary) {
if (!checkBoundary) {
LOG_ERROR("Binary contents requires end of part");
- return 0;
+ return nullptr;
}
m_lineReader.setSeparator(endOfPartBoundary.utf8().data());
Vector<char> part;
if (!m_lineReader.nextChunk(part)) {
LOG_ERROR("Binary contents requires end of part");
- return 0;
- }
- content->append(part);
- m_lineReader.setSeparator("\r\n");
- Vector<char> nextChars;
- if (m_lineReader.peek(nextChars, 2) != 2) {
- LOG_ERROR("Invalid seperator.");
- return 0;
- }
- endOfPartReached = true;
- ASSERT(nextChars.size() == 2);
- endOfArchiveReached = (nextChars[0] == '-' && nextChars[1] == '-');
- if (!endOfArchiveReached) {
- String line = m_lineReader.nextChunkAsUTF8StringWithLatin1Fallback();
- if (!line.isEmpty()) {
- LOG_ERROR("No CRLF at end of binary section.");
- return 0;
- }
- }
+ return nullptr;
+ }
+ content->append(part);
+ m_lineReader.setSeparator("\r\n");
+ Vector<char> nextChars;
+ if (m_lineReader.peek(nextChars, 2) != 2) {
+ LOG_ERROR("Invalid seperator.");
+ return nullptr;
+ }
+ endOfPartReached = true;
+ ASSERT(nextChars.size() == 2);
+ endOfArchiveReached = (nextChars[0] == '-' && nextChars[1] == '-');
+ if (!endOfArchiveReached) {
+ String line = m_lineReader.nextChunkAsUTF8StringWithLatin1Fallback();
+ if (!line.isEmpty()) {
+ LOG_ERROR("No CRLF at end of binary section.");
+ return nullptr;
+ }
+ }
} else {
String line;
while (!(line = m_lineReader.nextChunkAsUTF8StringWithLatin1Fallback()).isNull()) {
@@ -191,7 +189,7 @@ PassRefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHea
}
if (!endOfPartReached && checkBoundary) {
LOG_ERROR("No bounday found for MHTML part.");
- return 0;
+ return nullptr;
}
Vector<char> data;
@@ -199,7 +197,7 @@ PassRefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHea
case MIMEHeader::Base64:
if (!base64Decode(content->data(), content->size(), data)) {
LOG_ERROR("Invalid base64 content for MHTML part.");
- return 0;
+ return nullptr;
}
break;
case MIMEHeader::QuotedPrintable:
@@ -211,14 +209,14 @@ PassRefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHea
break;
default:
LOG_ERROR("Invalid encoding for MHTML part.");
- return 0;
+ return nullptr;
}
RefPtr<SharedBuffer> contentBuffer = SharedBuffer::adoptVector(data);
// FIXME: the URL in the MIME header could be relative, we should resolve it if it is.
// The specs mentions 5 ways to resolve a URL: http://tools.ietf.org/html/rfc2557#section-5
// IE and Firefox (UNMht) seem to generate only absolute URLs.
URL location = URL(URL(), mimeHeader.contentLocation());
- return ArchiveResource::create(contentBuffer, location, mimeHeader.contentType(), mimeHeader.charset(), String());
+ return ArchiveResource::create(WTFMove(contentBuffer), location, mimeHeader.contentType(), mimeHeader.charset(), String());
}
size_t MHTMLParser::frameCount() const
diff --git a/Source/WebCore/loader/archive/mhtml/MHTMLParser.h b/Source/WebCore/loader/archive/mhtml/MHTMLParser.h
index 4f1b126bc..1e9bd4d77 100644
--- a/Source/WebCore/loader/archive/mhtml/MHTMLParser.h
+++ b/Source/WebCore/loader/archive/mhtml/MHTMLParser.h
@@ -28,10 +28,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MHTMLParser_h
-#define MHTMLParser_h
+#pragma once
#if ENABLE(MHTML)
+
#include "SharedBufferChunkReader.h"
#include <wtf/RefPtr.h>
#include <wtf/text/WTFString.h>
@@ -48,7 +48,7 @@ class MHTMLParser {
public:
explicit MHTMLParser(SharedBuffer*);
- PassRefPtr<MHTMLArchive> parseArchive();
+ RefPtr<MHTMLArchive> parseArchive();
size_t frameCount() const;
MHTMLArchive* frameAt(size_t) const;
@@ -57,8 +57,8 @@ public:
ArchiveResource* subResourceAt(size_t) const;
private:
- PassRefPtr<MHTMLArchive> parseArchiveWithHeader(MIMEHeader*);
- PassRefPtr<ArchiveResource> parseNextPart(const MIMEHeader&, const String& endOfPartBoundary, const String& endOfDocumentBoundary, bool& endOfArchiveReached);
+ RefPtr<MHTMLArchive> parseArchiveWithHeader(MIMEHeader*);
+ RefPtr<ArchiveResource> parseNextPart(const MIMEHeader&, const String& endOfPartBoundary, const String& endOfDocumentBoundary, bool& endOfArchiveReached);
void addResourceToArchive(ArchiveResource*, MHTMLArchive*);
@@ -67,8 +67,6 @@ private:
Vector<RefPtr<MHTMLArchive>> m_frames;
};
-}
-
-#endif
-#endif
+} // namespace WebCore
+#endif // ENABLE(MHTML)
diff --git a/Source/WebCore/loader/cache/CachePolicy.h b/Source/WebCore/loader/cache/CachePolicy.h
index 0b9010b63..b8a1013c3 100644
--- a/Source/WebCore/loader/cache/CachePolicy.h
+++ b/Source/WebCore/loader/cache/CachePolicy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,19 +23,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachePolicy_h
-#define CachePolicy_h
+#pragma once
namespace WebCore {
- enum CachePolicy {
- CachePolicyCache,
- CachePolicyVerify,
- CachePolicyRevalidate,
- CachePolicyReload,
- CachePolicyHistoryBuffer
- };
+enum CachePolicy {
+ CachePolicyVerify,
+ CachePolicyRevalidate,
+ CachePolicyReload,
+ CachePolicyHistoryBuffer
+};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp b/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
index 69bce8f40..af40cc204 100644
--- a/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
+++ b/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
@@ -3,7 +3,7 @@
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004-2017 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
@@ -19,9 +19,6 @@
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.
-
- This class provides all functionality needed for loading images, style sheets and html
- pages from the web. It has a memory cache for these objects.
*/
#include "config.h"
@@ -29,24 +26,22 @@
#include "CSSStyleSheet.h"
#include "CachedResourceClientWalker.h"
+#include "CachedResourceRequest.h"
#include "CachedStyleSheetClient.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
#include "MemoryCache.h"
-#include "ResourceBuffer.h"
+#include "SharedBuffer.h"
#include "StyleSheetContents.h"
#include "TextResourceDecoder.h"
#include <wtf/CurrentTime.h>
-#include <wtf/Vector.h>
namespace WebCore {
-CachedCSSStyleSheet::CachedCSSStyleSheet(const ResourceRequest& resourceRequest, const String& charset)
- : CachedResource(resourceRequest, CSSStyleSheet)
- , m_decoder(TextResourceDecoder::create("text/css", charset))
+CachedCSSStyleSheet::CachedCSSStyleSheet(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedResource(WTFMove(request), CSSStyleSheet, sessionID)
+ , m_decoder(TextResourceDecoder::create("text/css", request.charset()))
{
- // Prefer text/css but accept any type (dell.com serves a stylesheet
- // as text/html; see <http://bugs.webkit.org/show_bug.cgi?id=11451>).
- setAccept("text/css,*/*;q=0.1");
}
CachedCSSStyleSheet::~CachedCSSStyleSheet()
@@ -55,16 +50,16 @@ CachedCSSStyleSheet::~CachedCSSStyleSheet()
m_parsedStyleSheetCache->removedFromMemoryCache();
}
-void CachedCSSStyleSheet::didAddClient(CachedResourceClient* c)
+void CachedCSSStyleSheet::didAddClient(CachedResourceClient& client)
{
- ASSERT(c->resourceClientType() == CachedStyleSheetClient::expectedType());
+ ASSERT(client.resourceClientType() == CachedStyleSheetClient::expectedType());
// CachedResource::didAddClient() must be before setCSSStyleSheet(),
// because setCSSStyleSheet() may cause scripts to be executed, which could destroy 'c' if it is an instance of HTMLLinkElement.
// see the comment of HTMLLinkElement::setCSSStyleSheet.
- CachedResource::didAddClient(c);
+ CachedResource::didAddClient(client);
if (!isLoading())
- static_cast<CachedStyleSheetClient*>(c)->setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
+ static_cast<CachedStyleSheetClient&>(client).setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
}
void CachedCSSStyleSheet::setEncoding(const String& chs)
@@ -76,32 +71,39 @@ String CachedCSSStyleSheet::encoding() const
{
return m_decoder->encoding().name();
}
-
-const String CachedCSSStyleSheet::sheetText(bool enforceMIMEType, bool* hasValidMIMEType) const
-{
- ASSERT(!isPurgeable());
- if (!m_data || m_data->isEmpty() || !canUseSheet(enforceMIMEType, hasValidMIMEType))
+const String CachedCSSStyleSheet::sheetText(MIMETypeCheck mimeTypeCheck, bool* hasValidMIMEType) const
+{
+ if (!m_data || m_data->isEmpty() || !canUseSheet(mimeTypeCheck, hasValidMIMEType))
return String();
-
+
if (!m_decodedSheetText.isNull())
return m_decodedSheetText;
-
+
// Don't cache the decoded text, regenerating is cheap and it can use quite a bit of memory
- String sheetText = m_decoder->decode(m_data->data(), m_data->size());
- sheetText.append(m_decoder->flush());
- return sheetText;
+ return m_decoder->decodeAndFlush(m_data->data(), m_data->size());
}
-void CachedCSSStyleSheet::finishLoading(ResourceBuffer* data)
+void CachedCSSStyleSheet::setBodyDataFrom(const CachedResource& resource)
+{
+ ASSERT(resource.type() == type());
+ const CachedCSSStyleSheet& sheet = static_cast<const CachedCSSStyleSheet&>(resource);
+
+ CachedResource::setBodyDataFrom(resource);
+
+ m_decoder = sheet.m_decoder;
+ m_decodedSheetText = sheet.m_decodedSheetText;
+ if (sheet.m_parsedStyleSheetCache)
+ saveParsedStyleSheet(*sheet.m_parsedStyleSheetCache);
+}
+
+void CachedCSSStyleSheet::finishLoading(SharedBuffer* data)
{
m_data = data;
- setEncodedSize(m_data.get() ? m_data->size() : 0);
+ setEncodedSize(data ? data->size() : 0);
// Decode the data to find out the encoding and keep the sheet text around during checkNotify()
- if (m_data) {
- m_decodedSheetText = m_decoder->decode(m_data->data(), m_data->size());
- m_decodedSheetText.append(m_decoder->flush());
- }
+ if (data)
+ m_decodedSheetText = m_decoder->decodeAndFlush(data->data(), data->size());
setLoading(false);
checkNotify();
// Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
@@ -118,12 +120,12 @@ void CachedCSSStyleSheet::checkNotify()
c->setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
}
-bool CachedCSSStyleSheet::canUseSheet(bool enforceMIMEType, bool* hasValidMIMEType) const
+bool CachedCSSStyleSheet::canUseSheet(MIMETypeCheck mimeTypeCheck, bool* hasValidMIMEType) const
{
if (errorOccurred())
return false;
-
- if (!enforceMIMEType && !hasValidMIMEType)
+
+ if (mimeTypeCheck == MIMETypeCheck::Lax)
return true;
// This check exactly matches Firefox. Note that we grab the Content-Type
@@ -133,12 +135,10 @@ bool CachedCSSStyleSheet::canUseSheet(bool enforceMIMEType, bool* hasValidMIMETy
//
// This code defaults to allowing the stylesheet for non-HTTP protocols so
// folks can use standards mode for local HTML documents.
- String mimeType = extractMIMETypeFromMediaType(response().httpHeaderField("Content-Type"));
- bool typeOK = mimeType.isEmpty() || equalIgnoringCase(mimeType, "text/css") || equalIgnoringCase(mimeType, "application/x-unknown-content-type");
+ String mimeType = extractMIMETypeFromMediaType(response().httpHeaderField(HTTPHeaderName::ContentType));
+ bool typeOK = mimeType.isEmpty() || equalLettersIgnoringASCIICase(mimeType, "text/css") || equalLettersIgnoringASCIICase(mimeType, "application/x-unknown-content-type");
if (hasValidMIMEType)
*hasValidMIMEType = typeOK;
- if (!enforceMIMEType)
- return true;
return typeOK;
}
@@ -148,22 +148,19 @@ void CachedCSSStyleSheet::destroyDecodedData()
return;
m_parsedStyleSheetCache->removedFromMemoryCache();
- m_parsedStyleSheetCache.clear();
+ m_parsedStyleSheetCache = nullptr;
setDecodedSize(0);
-
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
- makePurgeable(true);
}
-PassRefPtr<StyleSheetContents> CachedCSSStyleSheet::restoreParsedStyleSheet(const CSSParserContext& context)
+RefPtr<StyleSheetContents> CachedCSSStyleSheet::restoreParsedStyleSheet(const CSSParserContext& context, CachePolicy cachePolicy)
{
if (!m_parsedStyleSheetCache)
- return 0;
- if (m_parsedStyleSheetCache->hasFailedOrCanceledSubresources()) {
+ return nullptr;
+ if (!m_parsedStyleSheetCache->subresourcesAllowReuse(cachePolicy)) {
m_parsedStyleSheetCache->removedFromMemoryCache();
- m_parsedStyleSheetCache.clear();
- return 0;
+ m_parsedStyleSheetCache = nullptr;
+ return nullptr;
}
ASSERT(m_parsedStyleSheetCache->isCacheable());
@@ -171,20 +168,20 @@ PassRefPtr<StyleSheetContents> CachedCSSStyleSheet::restoreParsedStyleSheet(cons
// Contexts must be identical so we know we would get the same exact result if we parsed again.
if (m_parsedStyleSheetCache->parserContext() != context)
- return 0;
+ return nullptr;
didAccessDecodedData(monotonicallyIncreasingTime());
return m_parsedStyleSheetCache;
}
-void CachedCSSStyleSheet::saveParsedStyleSheet(PassRef<StyleSheetContents> sheet)
+void CachedCSSStyleSheet::saveParsedStyleSheet(Ref<StyleSheetContents>&& sheet)
{
- ASSERT(sheet.get().isCacheable());
+ ASSERT(sheet->isCacheable());
if (m_parsedStyleSheetCache)
m_parsedStyleSheetCache->removedFromMemoryCache();
- m_parsedStyleSheetCache = std::move(sheet);
+ m_parsedStyleSheetCache = WTFMove(sheet);
m_parsedStyleSheetCache->addedToMemoryCache();
setDecodedSize(m_parsedStyleSheetCache->estimatedSizeInBytes());
diff --git a/Source/WebCore/loader/cache/CachedCSSStyleSheet.h b/Source/WebCore/loader/cache/CachedCSSStyleSheet.h
index 19ad61939..c33aa2e40 100644
--- a/Source/WebCore/loader/cache/CachedCSSStyleSheet.h
+++ b/Source/WebCore/loader/cache/CachedCSSStyleSheet.h
@@ -2,7 +2,7 @@
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 Apple Inc. All rights reserved.
+ Copyright (C) 2004-2017 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
@@ -18,55 +18,53 @@
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.
-
- This class provides all functionality needed for loading images, style sheets and html
- pages from the web. It has a memory cache for these objects.
*/
-#ifndef CachedCSSStyleSheet_h
-#define CachedCSSStyleSheet_h
+#pragma once
#include "CachedResource.h"
-#include <wtf/Vector.h>
namespace WebCore {
- class CachedResourceClient;
- class StyleSheetContents;
- class TextResourceDecoder;
- struct CSSParserContext;
+class StyleSheetContents;
+class TextResourceDecoder;
+
+struct CSSParserContext;
+
+class CachedCSSStyleSheet final : public CachedResource {
+public:
+ CachedCSSStyleSheet(CachedResourceRequest&&, SessionID);
+ virtual ~CachedCSSStyleSheet();
- class CachedCSSStyleSheet final : public CachedResource {
- public:
- CachedCSSStyleSheet(const ResourceRequest&, const String& charset);
- virtual ~CachedCSSStyleSheet();
+ enum class MIMETypeCheck { Strict, Lax };
+ const String sheetText(MIMETypeCheck = MIMETypeCheck::Strict, bool* hasValidMIMEType = nullptr) const;
- const String sheetText(bool enforceMIMEType = true, bool* hasValidMIMEType = 0) const;
+ RefPtr<StyleSheetContents> restoreParsedStyleSheet(const CSSParserContext&, CachePolicy);
+ void saveParsedStyleSheet(Ref<StyleSheetContents>&&);
- PassRefPtr<StyleSheetContents> restoreParsedStyleSheet(const CSSParserContext&);
- void saveParsedStyleSheet(PassRef<StyleSheetContents>);
+private:
+ bool canUseSheet(MIMETypeCheck, bool* hasValidMIMEType) const;
+ bool mayTryReplaceEncodedData() const final { return true; }
- private:
- bool canUseSheet(bool enforceMIMEType, bool* hasValidMIMEType) const;
- virtual PurgePriority purgePriority() const override { return PurgeLast; }
- virtual bool mayTryReplaceEncodedData() const override { return true; }
+ void didAddClient(CachedResourceClient&) final;
- virtual void didAddClient(CachedResourceClient*) override;
+ void setEncoding(const String&) final;
+ String encoding() const final;
+ const TextResourceDecoder* textResourceDecoder() const final { return m_decoder.get(); }
+ void finishLoading(SharedBuffer*) final;
+ void destroyDecodedData() final;
- virtual void setEncoding(const String&) override;
- virtual String encoding() const override;
- virtual void finishLoading(ResourceBuffer*) override;
- virtual void destroyDecodedData() override;
+ void setBodyDataFrom(const CachedResource&) final;
- protected:
- virtual void checkNotify() override;
+protected:
+ void checkNotify() final;
- RefPtr<TextResourceDecoder> m_decoder;
- String m_decodedSheetText;
+ RefPtr<TextResourceDecoder> m_decoder;
+ String m_decodedSheetText;
- RefPtr<StyleSheetContents> m_parsedStyleSheetCache;
- };
+ RefPtr<StyleSheetContents> m_parsedStyleSheetCache;
+};
-}
+} // namespace WebCore
-#endif
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedCSSStyleSheet, CachedResource::CSSStyleSheet)
diff --git a/Source/WebCore/loader/cache/CachedFont.cpp b/Source/WebCore/loader/cache/CachedFont.cpp
index fbf658cc0..91929778b 100644
--- a/Source/WebCore/loader/cache/CachedFont.cpp
+++ b/Source/WebCore/loader/cache/CachedFont.cpp
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -31,27 +31,22 @@
#include "CachedResourceClientWalker.h"
#include "CachedResourceLoader.h"
#include "FontCustomPlatformData.h"
+#include "FontDescription.h"
#include "FontPlatformData.h"
-#include "MemoryCache.h"
-#include "ResourceBuffer.h"
#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
+#include "TypedElementDescendantIterator.h"
#include "WOFFFileFormat.h"
#include <wtf/Vector.h>
-#if ENABLE(SVG_FONTS)
-#include "NodeList.h"
-#include "SVGDocument.h"
-#include "SVGElement.h"
-#include "SVGFontElement.h"
-#include "SVGGElement.h"
-#include "SVGNames.h"
+#if USE(DIRECT2D)
+#include <dwrite.h>
#endif
namespace WebCore {
-CachedFont::CachedFont(const ResourceRequest& resourceRequest)
- : CachedResource(resourceRequest, FontResource)
+CachedFont::CachedFont(CachedResourceRequest&& request, SessionID sessionID, Type type)
+ : CachedResource(WTFMove(request), type, sessionID)
, m_loadInitiated(false)
, m_hasCreatedFontDataWrappingResource(false)
{
@@ -61,21 +56,20 @@ CachedFont::~CachedFont()
{
}
-void CachedFont::load(CachedResourceLoader*, const ResourceLoaderOptions& options)
+void CachedFont::load(CachedResourceLoader&)
{
// Don't load the file yet. Wait for an access before triggering the load.
setLoading(true);
- m_options = options;
}
-void CachedFont::didAddClient(CachedResourceClient* c)
+void CachedFont::didAddClient(CachedResourceClient& client)
{
- ASSERT(c->resourceClientType() == CachedFontClient::expectedType());
+ ASSERT(client.resourceClientType() == CachedFontClient::expectedType());
if (!isLoading())
- static_cast<CachedFontClient*>(c)->fontLoaded(this);
+ static_cast<CachedFontClient&>(client).fontLoaded(*this);
}
-void CachedFont::finishLoading(ResourceBuffer* data)
+void CachedFont::finishLoading(SharedBuffer* data)
{
m_data = data;
setEncodedSize(m_data.get() ? m_data->size() : 0);
@@ -83,103 +77,76 @@ void CachedFont::finishLoading(ResourceBuffer* data)
checkNotify();
}
-void CachedFont::beginLoadIfNeeded(CachedResourceLoader* dl)
+void CachedFont::beginLoadIfNeeded(CachedResourceLoader& loader)
{
if (!m_loadInitiated) {
m_loadInitiated = true;
- CachedResource::load(dl, m_options);
+ CachedResource::load(loader);
}
}
-bool CachedFont::ensureCustomFontData()
+bool CachedFont::ensureCustomFontData(const AtomicString&)
{
- if (!m_fontData && !errorOccurred() && !isLoading() && m_data) {
- SharedBuffer* buffer = m_data.get()->sharedBuffer();
- ASSERT(buffer);
-
- RefPtr<SharedBuffer> sfntBuffer;
-
- bool fontIsWOFF = isWOFF(buffer);
- if (fontIsWOFF) {
- Vector<char> sfnt;
- if (convertWOFFToSfnt(buffer, sfnt)) {
- sfntBuffer = SharedBuffer::adoptVector(sfnt);
- buffer = sfntBuffer.get();
- } else
- buffer = nullptr;
- }
-
- m_fontData = buffer ? createFontCustomPlatformData(*buffer) : nullptr;
- if (m_fontData)
- m_hasCreatedFontDataWrappingResource = !fontIsWOFF;
- else
- setStatus(DecodeError);
- }
- return m_fontData.get();
+ return ensureCustomFontData(m_data.get());
}
-FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant widthVariant, FontRenderingMode renderingMode)
+bool CachedFont::ensureCustomFontData(SharedBuffer* data)
{
-#if ENABLE(SVG_FONTS)
- if (m_externalSVGDocument)
- return FontPlatformData(size, bold, italic);
-#endif
- ASSERT(m_fontData);
- return m_fontData->fontPlatformData(static_cast<int>(size), bold, italic, orientation, widthVariant, renderingMode);
-}
-
-#if ENABLE(SVG_FONTS)
-bool CachedFont::ensureSVGFontData()
-{
- if (!m_externalSVGDocument && !errorOccurred() && !isLoading() && m_data) {
- m_externalSVGDocument = SVGDocument::create(0, URL());
-
- RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
- String svgSource = decoder->decode(m_data->data(), m_data->size());
- svgSource.append(decoder->flush());
-
- m_externalSVGDocument->setContent(svgSource);
-
- if (decoder->sawError())
- m_externalSVGDocument = 0;
+ if (!m_fontCustomPlatformData && !errorOccurred() && !isLoading() && data) {
+ bool wrapping;
+ m_fontCustomPlatformData = createCustomFontData(*data, wrapping);
+ m_hasCreatedFontDataWrappingResource = m_fontCustomPlatformData && wrapping;
+ if (!m_fontCustomPlatformData)
+ setStatus(DecodeError);
}
- return m_externalSVGDocument;
+ return m_fontCustomPlatformData.get();
}
-SVGFontElement* CachedFont::getSVGFontById(const String& fontName) const
+std::unique_ptr<FontCustomPlatformData> CachedFont::createCustomFontData(SharedBuffer& bytes, bool& wrapping)
{
- RefPtr<NodeList> list = m_externalSVGDocument->getElementsByTagNameNS(SVGNames::fontTag.namespaceURI(), SVGNames::fontTag.localName());
- if (!list)
- return 0;
-
- unsigned listLength = list->length();
- if (!listLength)
- return 0;
-
-#ifndef NDEBUG
- for (unsigned i = 0; i < listLength; ++i) {
- ASSERT(list->item(i));
- ASSERT(isSVGFontElement(list->item(i)));
+ wrapping = true;
+
+#if !PLATFORM(COCOA)
+ if (isWOFF(bytes)) {
+ wrapping = false;
+ Vector<char> convertedFont;
+ if (!convertWOFFToSfnt(bytes, convertedFont))
+ return nullptr;
+
+ auto buffer = SharedBuffer::adoptVector(convertedFont);
+ return createFontCustomPlatformData(buffer);
}
#endif
- if (fontName.isEmpty())
- return toSVGFontElement(list->item(0));
+ return createFontCustomPlatformData(bytes);
+}
- for (unsigned i = 0; i < listLength; ++i) {
- SVGFontElement* element = toSVGFontElement(list->item(i));
- if (element->getIdAttribute() == fontName)
- return element;
- }
+RefPtr<Font> CachedFont::createFont(const FontDescription& fontDescription, const AtomicString&, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings)
+{
+ return Font::create(platformDataFromCustomData(fontDescription, syntheticBold, syntheticItalic, fontFaceFeatures, fontFaceVariantSettings), true);
+}
- return 0;
+FontPlatformData CachedFont::platformDataFromCustomData(const FontDescription& fontDescription, bool bold, bool italic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings)
+{
+ ASSERT(m_fontCustomPlatformData);
+ return platformDataFromCustomData(*m_fontCustomPlatformData, fontDescription, bold, italic, fontFaceFeatures, fontFaceVariantSettings);
}
+
+FontPlatformData CachedFont::platformDataFromCustomData(FontCustomPlatformData& fontCustomPlatformData, const FontDescription& fontDescription, bool bold, bool italic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings)
+{
+#if PLATFORM(COCOA)
+ return fontCustomPlatformData.fontPlatformData(fontDescription, bold, italic, fontFaceFeatures, fontFaceVariantSettings);
+#else
+ UNUSED_PARAM(fontFaceFeatures);
+ UNUSED_PARAM(fontFaceVariantSettings);
+ return fontCustomPlatformData.fontPlatformData(fontDescription, bold, italic);
#endif
+}
void CachedFont::allClientsRemoved()
{
- m_fontData = nullptr;
+ m_fontCustomPlatformData = nullptr;
}
void CachedFont::checkNotify()
@@ -187,9 +154,9 @@ void CachedFont::checkNotify()
if (isLoading())
return;
- CachedResourceClientWalker<CachedFontClient> w(m_clients);
- while (CachedFontClient* c = w.next())
- c->fontLoaded(this);
+ CachedResourceClientWalker<CachedFontClient> walker(m_clients);
+ while (CachedFontClient* client = walker.next())
+ client->fontLoaded(*this);
}
bool CachedFont::mayTryReplaceEncodedData() const
diff --git a/Source/WebCore/loader/cache/CachedFont.h b/Source/WebCore/loader/cache/CachedFont.h
index f19582b96..25d292f0f 100644
--- a/Source/WebCore/loader/cache/CachedFont.h
+++ b/Source/WebCore/loader/cache/CachedFont.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,61 +23,63 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedFont_h
-#define CachedFont_h
+#pragma once
#include "CachedResource.h"
#include "CachedResourceClient.h"
-#include "FontOrientation.h"
-#include "FontRenderingMode.h"
-#include "FontWidthVariant.h"
+#include "Font.h"
+#include "TextFlags.h"
namespace WebCore {
class CachedResourceLoader;
+class FontDescription;
class FontPlatformData;
class SVGDocument;
class SVGFontElement;
struct FontCustomPlatformData;
-class CachedFont final : public CachedResource {
+template <typename T> class FontTaggedSettings;
+typedef FontTaggedSettings<int> FontFeatureSettings;
+
+class CachedFont : public CachedResource {
public:
- CachedFont(const ResourceRequest&);
+ CachedFont(CachedResourceRequest&&, SessionID, Type = FontResource);
virtual ~CachedFont();
- void beginLoadIfNeeded(CachedResourceLoader* dl);
- virtual bool stillNeedsLoad() const override { return !m_loadInitiated; }
+ void beginLoadIfNeeded(CachedResourceLoader&);
+ bool stillNeedsLoad() const override { return !m_loadInitiated; }
+
+ virtual bool ensureCustomFontData(const AtomicString& remoteURI);
+ static std::unique_ptr<FontCustomPlatformData> createCustomFontData(SharedBuffer&, bool& wrapping);
+ static FontPlatformData platformDataFromCustomData(FontCustomPlatformData&, const FontDescription&, bool bold, bool italic, const FontFeatureSettings&, const FontVariantSettings&);
- bool ensureCustomFontData();
- FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode);
+ virtual RefPtr<Font> createFont(const FontDescription&, const AtomicString& remoteURI, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings&, const FontVariantSettings&);
-#if ENABLE(SVG_FONTS)
- bool ensureSVGFontData();
- SVGFontElement* getSVGFontById(const String&) const;
-#endif
+protected:
+ FontPlatformData platformDataFromCustomData(const FontDescription&, bool bold, bool italic, const FontFeatureSettings&, const FontVariantSettings&);
+
+ bool ensureCustomFontData(SharedBuffer* data);
private:
- virtual void checkNotify() override;
- virtual bool mayTryReplaceEncodedData() const override;
+ void checkNotify() override;
+ bool mayTryReplaceEncodedData() const override;
- virtual void load(CachedResourceLoader*, const ResourceLoaderOptions&) override;
+ void load(CachedResourceLoader&) override;
+ NO_RETURN_DUE_TO_ASSERT void setBodyDataFrom(const CachedResource&) final { ASSERT_NOT_REACHED(); }
- virtual void didAddClient(CachedResourceClient*) override;
- virtual void finishLoading(ResourceBuffer*) override;
+ void didAddClient(CachedResourceClient&) override;
+ void finishLoading(SharedBuffer*) override;
- virtual void allClientsRemoved() override;
+ void allClientsRemoved() override;
- std::unique_ptr<FontCustomPlatformData> m_fontData;
+ std::unique_ptr<FontCustomPlatformData> m_fontCustomPlatformData;
bool m_loadInitiated;
bool m_hasCreatedFontDataWrappingResource;
-#if ENABLE(SVG_FONTS)
- RefPtr<SVGDocument> m_externalSVGDocument;
-#endif
-
friend class MemoryCache;
};
} // namespace WebCore
-#endif // CachedFont_h
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedFont, CachedResource::FontResource)
diff --git a/Source/WebCore/loader/cache/CachedFontClient.h b/Source/WebCore/loader/cache/CachedFontClient.h
index e87040ea2..a1388fb88 100644
--- a/Source/WebCore/loader/cache/CachedFontClient.h
+++ b/Source/WebCore/loader/cache/CachedFontClient.h
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedFontClient_h
-#define CachedFontClient_h
+#pragma once
#include "CachedResourceClient.h"
@@ -36,10 +35,8 @@ class CachedFontClient : public CachedResourceClient {
public:
virtual ~CachedFontClient() { }
static CachedResourceClientType expectedType() { return FontType; }
- virtual CachedResourceClientType resourceClientType() const override { return expectedType(); }
- virtual void fontLoaded(CachedFont*) { }
+ CachedResourceClientType resourceClientType() const override { return expectedType(); }
+ virtual void fontLoaded(CachedFont&) { }
};
} // namespace WebCore
-
-#endif // CachedFontClient_h
diff --git a/Source/WebCore/loader/cache/CachedImage.cpp b/Source/WebCore/loader/cache/CachedImage.cpp
index 5525fb1f3..65f0bf79c 100644
--- a/Source/WebCore/loader/cache/CachedImage.cpp
+++ b/Source/WebCore/loader/cache/CachedImage.cpp
@@ -35,15 +35,15 @@
#include "FrameLoaderTypes.h"
#include "FrameView.h"
#include "MemoryCache.h"
-#include "Page.h"
#include "RenderElement.h"
-#include "ResourceBuffer.h"
+#include "SVGImage.h"
#include "SecurityOrigin.h"
#include "Settings.h"
+#include "SharedBuffer.h"
#include "SubresourceLoader.h"
#include <wtf/CurrentTime.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
-#include <wtf/Vector.h>
#if PLATFORM(IOS)
#include "SystemMemory.h"
@@ -53,40 +53,28 @@
#include "PDFDocumentImage.h"
#endif
-#if ENABLE(SVG)
-#include "SVGImage.h"
-#endif
-
-#if ENABLE(DISK_IMAGE_CACHE)
-#include "DiskImageCacheIOS.h"
-#endif
-
namespace WebCore {
-CachedImage::CachedImage(const ResourceRequest& resourceRequest)
- : CachedResource(resourceRequest, ImageResource)
- , m_image(0)
- , m_shouldPaintBrokenImage(true)
+CachedImage::CachedImage(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedResource(WTFMove(request), ImageResource, sessionID)
{
setStatus(Unknown);
}
-CachedImage::CachedImage(Image* image)
- : CachedResource(ResourceRequest(), ImageResource)
+CachedImage::CachedImage(Image* image, SessionID sessionID)
+ : CachedResource(URL(), ImageResource, sessionID)
, m_image(image)
- , m_shouldPaintBrokenImage(true)
{
- setStatus(Cached);
- setLoading(false);
}
-CachedImage::CachedImage(const URL& url, Image* image)
- : CachedResource(ResourceRequest(url), ImageResource)
+CachedImage::CachedImage(const URL& url, Image* image, SessionID sessionID)
+ : CachedResource(url, ImageResource, sessionID)
, m_image(image)
- , m_shouldPaintBrokenImage(true)
+ , m_isManuallyCached(true)
{
- setStatus(Cached);
- setLoading(false);
+ // Use the incoming URL in the response field. This ensures that code using the response directly,
+ // such as origin checks for security, actually see something.
+ m_response.setURL(url);
}
CachedImage::~CachedImage()
@@ -94,56 +82,69 @@ CachedImage::~CachedImage()
clearImage();
}
-void CachedImage::load(CachedResourceLoader* cachedResourceLoader, const ResourceLoaderOptions& options)
+void CachedImage::load(CachedResourceLoader& loader)
{
- if (!cachedResourceLoader || cachedResourceLoader->autoLoadImages())
- CachedResource::load(cachedResourceLoader, options);
+ if (loader.shouldPerformImageLoad(url()))
+ CachedResource::load(loader);
else
setLoading(false);
}
-void CachedImage::didAddClient(CachedResourceClient* c)
+void CachedImage::setBodyDataFrom(const CachedResource& resource)
+{
+ ASSERT(resource.type() == type());
+ const CachedImage& image = static_cast<const CachedImage&>(resource);
+
+ CachedResource::setBodyDataFrom(resource);
+
+ m_image = image.m_image;
+ m_imageObserver = image.m_imageObserver;
+ if (m_imageObserver)
+ m_imageObserver->add(*this);
+
+ if (m_image && is<SVGImage>(*m_image))
+ m_svgImageCache = std::make_unique<SVGImageCache>(&downcast<SVGImage>(*m_image));
+}
+
+void CachedImage::didAddClient(CachedResourceClient& client)
{
if (m_data && !m_image && !errorOccurred()) {
createImage();
- m_image->setData(m_data->sharedBuffer(), true);
+ m_image->setData(m_data.copyRef(), true);
}
-
- ASSERT(c->resourceClientType() == CachedImageClient::expectedType());
+
+ ASSERT(client.resourceClientType() == CachedImageClient::expectedType());
if (m_image && !m_image->isNull())
- static_cast<CachedImageClient*>(c)->imageChanged(this);
+ static_cast<CachedImageClient&>(client).imageChanged(this);
- CachedResource::didAddClient(c);
+ CachedResource::didAddClient(client);
}
-void CachedImage::didRemoveClient(CachedResourceClient* c)
+void CachedImage::didRemoveClient(CachedResourceClient& client)
{
- ASSERT(c);
- ASSERT(c->resourceClientType() == CachedImageClient::expectedType());
+ ASSERT(client.resourceClientType() == CachedImageClient::expectedType());
+
+ m_pendingContainerSizeRequests.remove(&static_cast<CachedImageClient&>(client));
- m_pendingContainerSizeRequests.remove(static_cast<CachedImageClient*>(c));
-#if ENABLE(SVG)
if (m_svgImageCache)
- m_svgImageCache->removeClientFromCache(static_cast<CachedImageClient*>(c));
-#endif
+ m_svgImageCache->removeClientFromCache(&static_cast<CachedImageClient&>(client));
- CachedResource::didRemoveClient(c);
+ CachedResource::didRemoveClient(client);
}
void CachedImage::switchClientsToRevalidatedResource()
{
- ASSERT(resourceToRevalidate());
- ASSERT(resourceToRevalidate()->isImage());
+ ASSERT(is<CachedImage>(resourceToRevalidate()));
// Pending container size requests need to be transferred to the revalidated resource.
if (!m_pendingContainerSizeRequests.isEmpty()) {
// A copy of pending size requests is needed as they are deleted during CachedResource::switchClientsToRevalidateResouce().
ContainerSizeRequests switchContainerSizeRequests;
- for (ContainerSizeRequests::iterator it = m_pendingContainerSizeRequests.begin(); it != m_pendingContainerSizeRequests.end(); ++it)
- switchContainerSizeRequests.set(it->key, it->value);
+ for (auto& request : m_pendingContainerSizeRequests)
+ switchContainerSizeRequests.set(request.key, request.value);
CachedResource::switchClientsToRevalidatedResource();
- CachedImage* revalidatedCachedImage = static_cast<CachedImage*>(resourceToRevalidate());
- for (ContainerSizeRequests::iterator it = switchContainerSizeRequests.begin(); it != switchContainerSizeRequests.end(); ++it)
- revalidatedCachedImage->setContainerSizeForRenderer(it->key, it->value.first, it->value.second);
+ CachedImage& revalidatedCachedImage = downcast<CachedImage>(*resourceToRevalidate());
+ for (auto& request : switchContainerSizeRequests)
+ revalidatedCachedImage.setContainerSizeForRenderer(request.key, request.value.first, request.value.second);
return;
}
@@ -159,12 +160,17 @@ void CachedImage::allClientsRemoved()
std::pair<Image*, float> CachedImage::brokenImage(float deviceScaleFactor) const
{
+ if (deviceScaleFactor >= 3) {
+ static NeverDestroyed<Image*> brokenImageVeryHiRes(Image::loadPlatformResource("missingImage@3x").leakRef());
+ return std::make_pair(brokenImageVeryHiRes, 3);
+ }
+
if (deviceScaleFactor >= 2) {
- DEFINE_STATIC_LOCAL(Image*, brokenImageHiRes, (Image::loadPlatformResource("missingImage@2x").leakRef()));
+ static NeverDestroyed<Image*> brokenImageHiRes(Image::loadPlatformResource("missingImage@2x").leakRef());
return std::make_pair(brokenImageHiRes, 2);
}
- DEFINE_STATIC_LOCAL(Image*, brokenImageLoRes, (Image::loadPlatformResource("missingImage").leakRef()));
+ static NeverDestroyed<Image*> brokenImageLoRes(Image::loadPlatformResource("missingImage").leakRef());
return std::make_pair(brokenImageLoRes, 1);
}
@@ -175,8 +181,6 @@ bool CachedImage::willPaintBrokenImage() const
Image* CachedImage::image()
{
- ASSERT(!isPurgeable());
-
if (errorOccurred() && m_shouldPaintBrokenImage) {
// Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
// deviceScaleFactor from here. It is critical that callers use CachedImage::brokenImage()
@@ -192,8 +196,6 @@ Image* CachedImage::image()
Image* CachedImage::imageForRenderer(const RenderObject* renderer)
{
- ASSERT(!isPurgeable());
-
if (errorOccurred() && m_shouldPaintBrokenImage) {
// Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
// deviceScaleFactor from here. It is critical that callers use CachedImage::brokenImage()
@@ -204,19 +206,15 @@ Image* CachedImage::imageForRenderer(const RenderObject* renderer)
if (!m_image)
return Image::nullImage();
-#if ENABLE(SVG)
if (m_image->isSVGImage()) {
Image* image = m_svgImageCache->imageForRenderer(renderer);
if (image != Image::nullImage())
return image;
}
-#else
- UNUSED_PARAM(renderer);
-#endif
return m_image.get();
}
-void CachedImage::setContainerSizeForRenderer(const CachedImageClient* renderer, const IntSize& containerSize, float containerZoom)
+void CachedImage::setContainerSizeForRenderer(const CachedImageClient* renderer, const LayoutSize& containerSize, float containerZoom)
{
if (containerSize.isEmpty())
return;
@@ -226,17 +224,13 @@ void CachedImage::setContainerSizeForRenderer(const CachedImageClient* renderer,
m_pendingContainerSizeRequests.set(renderer, SizeAndZoom(containerSize, containerZoom));
return;
}
-#if ENABLE(SVG)
+
if (!m_image->isSVGImage()) {
m_image->setContainerSize(containerSize);
return;
}
m_svgImageCache->setContainerSizeForRenderer(renderer, containerSize, containerZoom);
-#else
- UNUSED_PARAM(containerZoom);
- m_image->setContainerSize(containerSize);
-#endif
}
bool CachedImage::usesImageContainerSize() const
@@ -263,42 +257,19 @@ bool CachedImage::imageHasRelativeHeight() const
return false;
}
-LayoutSize CachedImage::imageSizeForRenderer(const RenderObject* renderer, float multiplier, SizeType sizeType)
+LayoutSize CachedImage::imageSizeForRenderer(const RenderElement* renderer, float multiplier, SizeType sizeType)
{
- ASSERT(!isPurgeable());
-
if (!m_image)
- return IntSize();
+ return LayoutSize();
- LayoutSize imageSize(m_image->size());
+ LayoutSize imageSize;
-#if ENABLE(CSS_IMAGE_ORIENTATION)
- if (renderer && m_image->isBitmapImage()) {
- ImageOrientationDescription orientationDescription(renderer->shouldRespectImageOrientation(), renderer->style().imageOrientation());
- if (orientationDescription.respectImageOrientation() == RespectImageOrientation)
- imageSize = toBitmapImage(m_image.get())->sizeRespectingOrientation(orientationDescription);
- }
-#else
- if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation))
-#if !PLATFORM(IOS)
- imageSize = toBitmapImage(m_image.get())->sizeRespectingOrientation();
-#else
- {
- // On iOS, the image may have been subsampled to accommodate our size restrictions. However
- // we should tell the renderer what the original size was.
- imageSize = toBitmapImage(m_image.get())->originalSizeRespectingOrientation();
- } else if (m_image->isBitmapImage())
- imageSize = toBitmapImage(m_image.get())->originalSize();
-#endif // !PLATFORM(IOS)
-#endif // ENABLE(CSS_IMAGE_ORIENTATION)
-
-#if ENABLE(SVG)
- else if (m_image->isSVGImage() && sizeType == UsedSize) {
- imageSize = m_svgImageCache->imageSizeForRenderer(renderer);
- }
-#else
- UNUSED_PARAM(sizeType);
-#endif
+ if (is<BitmapImage>(*m_image) && renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation)
+ imageSize = LayoutSize(downcast<BitmapImage>(*m_image).sizeRespectingOrientation());
+ else if (is<SVGImage>(*m_image) && sizeType == UsedSize)
+ imageSize = LayoutSize(m_svgImageCache->imageSizeForRenderer(renderer));
+ else
+ imageSize = LayoutSize(m_image->size());
if (multiplier == 1.0f)
return imageSize;
@@ -331,7 +302,7 @@ void CachedImage::checkShouldPaintBrokenImage()
if (!m_loader || m_loader->reachedTerminalState())
return;
- m_shouldPaintBrokenImage = m_loader->frameLoader()->client().shouldPaintBrokenImage(m_resourceRequest.url());
+ m_shouldPaintBrokenImage = m_loader->frameLoader()->client().shouldPaintBrokenImage(url());
}
void CachedImage::clear()
@@ -347,77 +318,98 @@ inline void CachedImage::createImage()
// Create the image if it doesn't yet exist.
if (m_image)
return;
+
+ m_imageObserver = CachedImageObserver::create(*this);
+
+ if (m_response.mimeType() == "image/svg+xml") {
+ auto svgImage = SVGImage::create(*m_imageObserver, url());
+ m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.ptr());
+ m_image = WTFMove(svgImage);
#if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS)
- else if (m_response.mimeType() == "application/pdf")
- m_image = PDFDocumentImage::create(this);
+ } else if (m_response.mimeType() == "application/pdf") {
+ m_image = PDFDocumentImage::create(m_imageObserver.get());
#endif
-#if ENABLE(SVG)
- else if (m_response.mimeType() == "image/svg+xml") {
- RefPtr<SVGImage> svgImage = SVGImage::create(this);
- m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.get());
- m_image = svgImage.release();
- }
-#endif
- else
- m_image = BitmapImage::create(this);
+ } else
+ m_image = BitmapImage::create(m_imageObserver.get());
if (m_image) {
// Send queued container size requests.
if (m_image->usesContainerSize()) {
- for (ContainerSizeRequests::iterator it = m_pendingContainerSizeRequests.begin(); it != m_pendingContainerSizeRequests.end(); ++it)
- setContainerSizeForRenderer(it->key, it->value.first, it->value.second);
+ for (auto& request : m_pendingContainerSizeRequests)
+ setContainerSizeForRenderer(request.key, request.value.first, request.value.second);
}
m_pendingContainerSizeRequests.clear();
}
}
-inline void CachedImage::clearImage()
+CachedImage::CachedImageObserver::CachedImageObserver(CachedImage& image)
{
- // If our Image has an observer, it's always us so we need to clear the back pointer
- // before dropping our reference.
- if (m_image)
- m_image->setImageObserver(0);
- m_image.clear();
+ m_cachedImages.reserveInitialCapacity(1);
+ m_cachedImages.append(&image);
+ if (auto* loader = image.loader()) {
+ m_allowSubsampling = loader->frameLoader()->frame().settings().imageSubsamplingEnabled();
+ m_allowLargeImageAsyncDecoding = loader->frameLoader()->frame().settings().largeImageAsyncDecodingEnabled();
+ m_allowAnimatedImageAsyncDecoding = loader->frameLoader()->frame().settings().animatedImageAsyncDecodingEnabled();
+ m_showDebugBackground = loader->frameLoader()->frame().settings().showDebugBorders();
+ }
}
-bool CachedImage::canBeDrawn() const
+void CachedImage::CachedImageObserver::decodedSizeChanged(const Image* image, long long delta)
{
- if (!m_image || m_image->isNull())
- return false;
+ for (auto cachedImage : m_cachedImages)
+ cachedImage->decodedSizeChanged(image, delta);
+}
- if (!m_loader || m_loader->reachedTerminalState())
- return true;
+void CachedImage::CachedImageObserver::didDraw(const Image* image)
+{
+ for (auto cachedImage : m_cachedImages)
+ cachedImage->didDraw(image);
+}
- size_t estimatedDecodedImageSize = m_image->width() * m_image->height() * 4; // no overflow check
- return estimatedDecodedImageSize <= m_loader->frameLoader()->frame().settings().maximumDecodedImageSize();
+void CachedImage::CachedImageObserver::animationAdvanced(const Image* image)
+{
+ for (auto cachedImage : m_cachedImages)
+ cachedImage->animationAdvanced(image);
}
-void CachedImage::addIncrementalDataBuffer(ResourceBuffer* data)
+void CachedImage::CachedImageObserver::changedInRect(const Image* image, const IntRect* rect)
{
- m_data = data;
- if (!data)
- return;
+ for (auto cachedImage : m_cachedImages)
+ cachedImage->changedInRect(image, rect);
+}
+
+inline void CachedImage::clearImage()
+{
+ if (m_imageObserver) {
+ m_imageObserver->remove(*this);
+ m_imageObserver = nullptr;
+ }
+ m_image = nullptr;
+}
+
+void CachedImage::addIncrementalDataBuffer(SharedBuffer& data)
+{
+ m_data = &data;
createImage();
// Have the image update its data from its internal buffer.
// It will not do anything now, but will delay decoding until
// queried for info (like size or specific image frames).
- bool sizeAvailable = m_image->setData(m_data->sharedBuffer(), false);
+ bool sizeAvailable = m_image->setData(&data, false);
if (!sizeAvailable)
return;
- if (!canBeDrawn()) {
- // There's no image to draw or its decoded size is bigger than the maximum allowed.
+ if (m_image->isNull()) {
+ // Image decoding failed. Either we need more image data or the image data is malformed.
error(errorOccurred() ? status() : DecodeError);
if (inCache())
- memoryCache()->remove(this);
+ MemoryCache::singleton().remove(*this);
return;
}
- // Go ahead and tell our observers to try to draw.
- // Each chunk from the network causes observers to repaint, which will
- // force that chunk to decode.
+ // Tell our observers to try to draw.
+ // Each chunk from the network causes observers to repaint, which will force that chunk to decode.
// It would be nice to only redraw the decoded band of the image, but with the current design
// (decoding delayed until painting) that seems hard.
notifyObservers();
@@ -425,32 +417,34 @@ void CachedImage::addIncrementalDataBuffer(ResourceBuffer* data)
setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
}
-void CachedImage::addDataBuffer(ResourceBuffer* data)
+void CachedImage::addDataBuffer(SharedBuffer& data)
{
- ASSERT(m_options.dataBufferingPolicy == BufferData);
+ ASSERT(dataBufferingPolicy() == BufferData);
addIncrementalDataBuffer(data);
+ CachedResource::addDataBuffer(data);
}
void CachedImage::addData(const char* data, unsigned length)
{
- ASSERT(m_options.dataBufferingPolicy == DoNotBufferData);
- addIncrementalDataBuffer(ResourceBuffer::create(data, length).get());
+ ASSERT(dataBufferingPolicy() == DoNotBufferData);
+ addIncrementalDataBuffer(SharedBuffer::create(data, length));
+ CachedResource::addData(data, length);
}
-void CachedImage::finishLoading(ResourceBuffer* data)
+void CachedImage::finishLoading(SharedBuffer* data)
{
m_data = data;
if (!m_image && data)
createImage();
if (m_image)
- m_image->setData(m_data->sharedBuffer(), true);
+ m_image->setData(data, true);
- if (!canBeDrawn()) {
- // There's no image to draw or its decoded size is bigger than the maximum allowed.
+ if (!m_image || m_image->isNull()) {
+ // Image decoding failed; the image data is malformed.
error(errorOccurred() ? status() : DecodeError);
if (inCache())
- memoryCache()->remove(this);
+ MemoryCache::singleton().remove(*this);
return;
}
@@ -460,6 +454,16 @@ void CachedImage::finishLoading(ResourceBuffer* data)
CachedResource::finishLoading(data);
}
+void CachedImage::didReplaceSharedBufferContents()
+{
+ if (m_image) {
+ // Let the Image know that the SharedBuffer has been rejigged, so it can let go of any references to the heap-allocated resource buffer.
+ // FIXME(rdar://problem/24275617): It would be better if we could somehow tell the Image's decoder to swap in the new contents without destroying anything.
+ m_image->destroyDecodedData(true);
+ }
+ CachedResource::didReplaceSharedBufferContents();
+}
+
void CachedImage::error(CachedResource::Status status)
{
checkShouldPaintBrokenImage();
@@ -478,23 +482,20 @@ void CachedImage::responseReceived(const ResourceResponse& response)
void CachedImage::destroyDecodedData()
{
bool canDeleteImage = !m_image || (m_image->hasOneRef() && m_image->isBitmapImage());
- if (isSafeToMakePurgeable() && canDeleteImage && !isLoading()) {
- // Image refs the data buffer so we should not make it purgeable while the image is alive.
- // Invoking addClient() will reconstruct the image object.
- m_image = 0;
+ if (canDeleteImage && !isLoading() && !hasClients()) {
+ m_image = nullptr;
setDecodedSize(0);
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
- makePurgeable(true);
} else if (m_image && !errorOccurred())
m_image->destroyDecodedData();
}
-void CachedImage::decodedSizeChanged(const Image* image, int delta)
+void CachedImage::decodedSizeChanged(const Image* image, long long delta)
{
if (!image || image != m_image)
return;
-
- setDecodedSize(decodedSize() + delta);
+
+ ASSERT(delta >= 0 || decodedSize() + delta >= 0);
+ setDecodedSize(static_cast<unsigned>(decodedSize() + delta));
}
void CachedImage::didDraw(const Image* image)
@@ -509,132 +510,47 @@ void CachedImage::didDraw(const Image* image)
CachedResource::didAccessDecodedData(timeStamp);
}
-bool CachedImage::shouldPauseAnimation(const Image* image)
-{
- if (!image || image != m_image)
- return false;
-
- CachedResourceClientWalker<CachedImageClient> w(m_clients);
- while (CachedImageClient* c = w.next()) {
- if (c->willRenderImage(this))
- return false;
- }
-
- return true;
-}
-
void CachedImage::animationAdvanced(const Image* image)
{
if (!image || image != m_image)
return;
- notifyObservers();
+ CachedResourceClientWalker<CachedImageClient> clientWalker(m_clients);
+ while (CachedImageClient* client = clientWalker.next())
+ client->newImageAnimationFrameAvailable(*this);
}
-void CachedImage::changedInRect(const Image* image, const IntRect& rect)
+void CachedImage::changedInRect(const Image* image, const IntRect* rect)
{
if (!image || image != m_image)
return;
- notifyObservers(&rect);
-}
-
-void CachedImage::resumeAnimatingImagesForLoader(CachedResourceLoader* loader)
-{
- const CachedResourceLoader::DocumentResourceMap& resources = loader->allCachedResources();
-
- for (CachedResourceLoader::DocumentResourceMap::const_iterator it = resources.begin(), end = resources.end(); it != end; ++it) {
- const CachedResourceHandle<CachedResource>& resource = it->value;
- if (!resource || !resource->isImage())
- continue;
- CachedImage* cachedImage = static_cast<CachedImage*>(resource.get());
- if (!cachedImage->hasImage())
- continue;
- Image* image = cachedImage->image();
- if (!image->isBitmapImage())
- continue;
- BitmapImage* bitmapImage = toBitmapImage(image);
- if (!bitmapImage->canAnimate())
- continue;
- cachedImage->animationAdvanced(bitmapImage);
- }
+ notifyObservers(rect);
}
bool CachedImage::currentFrameKnownToBeOpaque(const RenderElement* renderer)
{
Image* image = imageForRenderer(renderer);
- if (image->isBitmapImage())
- image->nativeImageForCurrentFrame(); // force decode
return image->currentFrameKnownToBeOpaque();
}
-#if ENABLE(DISK_IMAGE_CACHE)
-bool CachedImage::canUseDiskImageCache() const
-{
- if (isLoading() || errorOccurred())
- return false;
-
- if (!m_data)
- return false;
-
- if (isPurgeable())
- return false;
-
- if (m_data->size() < diskImageCache().minimumImageSize())
- return false;
-
- // "Cache-Control: no-store" resources may be marked as such because they may
- // contain sensitive information. We should not write these resources to disk.
- if (m_response.cacheControlContainsNoStore())
- return false;
-
- // Testing shows that PDF images did not work when memory mapped.
- // However, SVG images and Bitmap images were fine. See:
- // <rdar://problem/8591834> Disk Image Cache should support PDF Images
- if (m_response.mimeType() == "application/pdf")
- return false;
-
- return true;
-}
-
-void CachedImage::useDiskImageCache()
+bool CachedImage::isOriginClean(SecurityOrigin* origin)
{
- ASSERT(canUseDiskImageCache());
- ASSERT(!isUsingDiskImageCache());
- m_data->sharedBuffer()->allowToBeMemoryMapped();
-}
-#endif
-
-bool CachedImage::isOriginClean(SecurityOrigin* securityOrigin)
-{
- if (!image()->hasSingleSecurityOrigin())
- return false;
- if (passesAccessControlCheck(securityOrigin))
- return true;
- return !securityOrigin->taintsCanvas(response().url());
+ ASSERT_UNUSED(origin, origin);
+ ASSERT(this->origin());
+ ASSERT(origin->toString() == this->origin()->toString());
+ return !loadFailedOrCanceled() && isCORSSameOrigin();
}
-#if USE(CF)
-// FIXME: We should look to incorporate the functionality of CachedImageManual
-// into CachedImage or find a better place for this class.
-// FIXME: Remove the USE(CF) once we make MemoryCache::addImageToCache() platform-independent.
-CachedImageManual::CachedImageManual(const URL& url, Image* image)
- : CachedImage(url, image)
- , m_fakeClient(std::make_unique<CachedImageClient>())
+CachedResource::RevalidationDecision CachedImage::makeRevalidationDecision(CachePolicy cachePolicy) const
{
- // Use the incoming URL in the response field. This ensures that code
- // using the response directly, such as origin checks for security,
- // actually see something.
- m_response.setURL(url);
-}
-
-bool CachedImageManual::mustRevalidateDueToCacheHeaders(CachePolicy) const
-{
- // Do not revalidate manually cached images. This mechanism is used as a
- // way to efficiently share an image from the client to content and
- // the URL for that image may not represent a resource that can be
- // retrieved by standard means. If the manual caching SPI is used, it is
- // incumbent on the client to only use valid resources.
- return false;
+ if (UNLIKELY(isManuallyCached())) {
+ // Do not revalidate manually cached images. This mechanism is used as a
+ // way to efficiently share an image from the client to content and
+ // the URL for that image may not represent a resource that can be
+ // retrieved by standard means. If the manual caching SPI is used, it is
+ // incumbent on the client to only use valid resources.
+ return RevalidationDecision::No;
+ }
+ return CachedResource::makeRevalidationDecision(cachePolicy);
}
-#endif
} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedImage.h b/Source/WebCore/loader/cache/CachedImage.h
index 12b77cc46..985aa9749 100644
--- a/Source/WebCore/loader/cache/CachedImage.h
+++ b/Source/WebCore/loader/cache/CachedImage.h
@@ -20,17 +20,16 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedImage_h
-#define CachedImage_h
+#pragma once
#include "CachedResource.h"
+#include "Image.h"
#include "ImageObserver.h"
#include "IntRect.h"
#include "IntSizeHash.h"
#include "LayoutSize.h"
#include "SVGImageCache.h"
#include <wtf/HashMap.h>
-#include <wtf/Vector.h>
namespace WebCore {
@@ -44,124 +43,132 @@ class SecurityOrigin;
struct Length;
-class CachedImage : public CachedResource, public ImageObserver {
+class CachedImage final : public CachedResource {
friend class MemoryCache;
public:
- CachedImage(const ResourceRequest&);
- CachedImage(Image*);
- CachedImage(const URL&, Image*);
+ CachedImage(CachedResourceRequest&&, SessionID);
+ CachedImage(Image*, SessionID);
+ // Constructor to use for manually cached images.
+ CachedImage(const URL&, Image*, SessionID);
virtual ~CachedImage();
- Image* image(); // Returns the nullImage() if the image is not available yet.
- Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet.
+ WEBCORE_EXPORT Image* image(); // Returns the nullImage() if the image is not available yet.
+ WEBCORE_EXPORT Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet.
bool hasImage() const { return m_image.get(); }
- bool currentFrameKnownToBeOpaque(const RenderElement*); // Side effect: ensures decoded image is in cache, therefore should only be called when about to draw the image.
+ bool currentFrameKnownToBeOpaque(const RenderElement*);
std::pair<Image*, float> brokenImage(float deviceScaleFactor) const; // Returns an image and the image's resolution scale factor.
- bool willPaintBrokenImage() const;
+ bool willPaintBrokenImage() const;
- bool canRender(const RenderObject* renderer, float multiplier) { return !errorOccurred() && !imageSizeForRenderer(renderer, multiplier).isEmpty(); }
+ bool canRender(const RenderElement* renderer, float multiplier) { return !errorOccurred() && !imageSizeForRenderer(renderer, multiplier).isEmpty(); }
- void setContainerSizeForRenderer(const CachedImageClient*, const IntSize&, float);
+ void setContainerSizeForRenderer(const CachedImageClient*, const LayoutSize&, float);
bool usesImageContainerSize() const;
bool imageHasRelativeWidth() const;
bool imageHasRelativeHeight() const;
- virtual void addDataBuffer(ResourceBuffer*) override;
- virtual void finishLoading(ResourceBuffer*) override;
+ void addDataBuffer(SharedBuffer&) override;
+ void finishLoading(SharedBuffer*) override;
enum SizeType {
UsedSize,
IntrinsicSize
};
// This method takes a zoom multiplier that can be used to increase the natural size of the image by the zoom.
- LayoutSize imageSizeForRenderer(const RenderObject*, float multiplier, SizeType = UsedSize); // returns the size of the complete image.
+ LayoutSize imageSizeForRenderer(const RenderElement*, float multiplier, SizeType = UsedSize); // returns the size of the complete image.
void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio);
-#if USE(CF)
- // FIXME: Remove the USE(CF) once we make MemoryCache::addImageToCache() platform-independent.
- virtual bool isManual() const { return false; }
-#endif
-
- static void resumeAnimatingImagesForLoader(CachedResourceLoader*);
-
-#if ENABLE(DISK_IMAGE_CACHE)
- virtual bool canUseDiskImageCache() const override;
- virtual void useDiskImageCache() override;
-#endif
+ bool isManuallyCached() const { return m_isManuallyCached; }
+ RevalidationDecision makeRevalidationDecision(CachePolicy) const override;
+ void load(CachedResourceLoader&) override;
bool isOriginClean(SecurityOrigin*);
private:
- virtual void load(CachedResourceLoader*, const ResourceLoaderOptions&) override;
-
void clear();
+ CachedImage(CachedImage&, const ResourceRequest&, SessionID);
+
+ void setBodyDataFrom(const CachedResource&) final;
+
void createImage();
void clearImage();
- bool canBeDrawn() const;
// If not null, changeRect is the changed part of the image.
- void notifyObservers(const IntRect* changeRect = 0);
- virtual PurgePriority purgePriority() const override { return PurgeFirst; }
+ void notifyObservers(const IntRect* changeRect = nullptr);
void checkShouldPaintBrokenImage();
- virtual void switchClientsToRevalidatedResource() override;
- virtual bool mayTryReplaceEncodedData() const override { return true; }
+ void switchClientsToRevalidatedResource() final;
+ bool mayTryReplaceEncodedData() const final { return true; }
- virtual void didAddClient(CachedResourceClient*) override;
- virtual void didRemoveClient(CachedResourceClient*) override;
+ void didAddClient(CachedResourceClient&) final;
+ void didRemoveClient(CachedResourceClient&) final;
- virtual void allClientsRemoved() override;
- virtual void destroyDecodedData() override;
+ void allClientsRemoved() override;
+ void destroyDecodedData() override;
- virtual void addData(const char* data, unsigned length) override;
- virtual void error(CachedResource::Status) override;
- virtual void responseReceived(const ResourceResponse&) override;
+ void addData(const char* data, unsigned length) override;
+ void error(CachedResource::Status) override;
+ void responseReceived(const ResourceResponse&) override;
// For compatibility, images keep loading even if there are HTTP errors.
- virtual bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }
-
- virtual bool isImage() const override { return true; }
- virtual bool stillNeedsLoad() const override { return !errorOccurred() && status() == Unknown && !isLoading(); }
+ bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }
+
+ bool stillNeedsLoad() const override { return !errorOccurred() && status() == Unknown && !isLoading(); }
+
+ class CachedImageObserver final : public RefCounted<CachedImageObserver>, public ImageObserver {
+ public:
+ static Ref<CachedImageObserver> create(CachedImage& image) { return adoptRef(*new CachedImageObserver(image)); }
+ void add(CachedImage& image) { m_cachedImages.append(&image); }
+ void remove(CachedImage& image) { m_cachedImages.removeFirst(&image); }
+
+ private:
+ explicit CachedImageObserver(CachedImage&);
+
+ // ImageObserver API
+ URL sourceUrl() const override { return m_cachedImages[0]->url(); }
+ bool allowSubsampling() const final { return m_allowSubsampling; }
+ bool allowLargeImageAsyncDecoding() const override { return m_allowLargeImageAsyncDecoding; }
+ bool allowAnimatedImageAsyncDecoding() const override { return m_allowAnimatedImageAsyncDecoding; }
+ bool showDebugBackground() const final { return m_showDebugBackground; }
+ void decodedSizeChanged(const Image*, long long delta) final;
+ void didDraw(const Image*) final;
+
+ void animationAdvanced(const Image*) final;
+ void changedInRect(const Image*, const IntRect*) final;
+
+ Vector<CachedImage*> m_cachedImages;
+ // The default value of m_allowSubsampling should be the same as defaultImageSubsamplingEnabled in Settings.cpp
+#if PLATFORM(IOS)
+ bool m_allowSubsampling { true };
+#else
+ bool m_allowSubsampling { false };
+#endif
+ bool m_allowLargeImageAsyncDecoding { true };
+ bool m_allowAnimatedImageAsyncDecoding { true };
+ bool m_showDebugBackground { false };
+ };
- // ImageObserver
- virtual void decodedSizeChanged(const Image*, int delta) override;
- virtual void didDraw(const Image*) override;
+ void decodedSizeChanged(const Image*, long long delta);
+ void didDraw(const Image*);
+ void animationAdvanced(const Image*);
+ void changedInRect(const Image*, const IntRect*);
- virtual bool shouldPauseAnimation(const Image*) override;
- virtual void animationAdvanced(const Image*) override;
- virtual void changedInRect(const Image*, const IntRect&) override;
+ void addIncrementalDataBuffer(SharedBuffer&);
- void addIncrementalDataBuffer(ResourceBuffer*);
+ void didReplaceSharedBufferContents() override;
- typedef std::pair<IntSize, float> SizeAndZoom;
+ typedef std::pair<LayoutSize, float> SizeAndZoom;
typedef HashMap<const CachedImageClient*, SizeAndZoom> ContainerSizeRequests;
ContainerSizeRequests m_pendingContainerSizeRequests;
+ RefPtr<CachedImageObserver> m_imageObserver;
RefPtr<Image> m_image;
-#if ENABLE(SVG)
std::unique_ptr<SVGImageCache> m_svgImageCache;
-#endif
- bool m_shouldPaintBrokenImage;
-};
-
-#if USE(CF)
-// FIXME: We should look to incorporate the functionality of CachedImageManual
-// into CachedImage or find a better place for this class.
-// FIXME: Remove the USE(CF) once we make MemoryCache::addImageToCache() platform-independent.
-class CachedImageManual : public CachedImage {
-public:
- CachedImageManual(const URL&, Image*);
- void addFakeClient() { addClient(m_fakeClient.get()); }
- void removeFakeClient() { removeClient(m_fakeClient.get()); }
- virtual bool isManual() const override { return true; }
- virtual bool mustRevalidateDueToCacheHeaders(CachePolicy) const;
-private:
- std::unique_ptr<CachedResourceClient> m_fakeClient;
+ bool m_isManuallyCached { false };
+ bool m_shouldPaintBrokenImage { true };
};
-#endif
-}
+} // namespace WebCore
-#endif
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedImage, CachedResource::ImageResource)
diff --git a/Source/WebCore/loader/cache/CachedImageClient.h b/Source/WebCore/loader/cache/CachedImageClient.h
index 1c3fac206..e09621ed8 100644
--- a/Source/WebCore/loader/cache/CachedImageClient.h
+++ b/Source/WebCore/loader/cache/CachedImageClient.h
@@ -20,8 +20,7 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedImageClient_h
-#define CachedImageClient_h
+#pragma once
#include "CachedResourceClient.h"
@@ -34,19 +33,14 @@ class CachedImageClient : public CachedResourceClient {
public:
virtual ~CachedImageClient() { }
static CachedResourceClientType expectedType() { return ImageType; }
- virtual CachedResourceClientType resourceClientType() const override { return expectedType(); }
+ CachedResourceClientType resourceClientType() const override { return expectedType(); }
- // Called whenever a frame of an image changes, either because we got more data from the network or
- // because we are animating. If not null, the IntRect is the changed rect of the image.
- virtual void imageChanged(CachedImage*, const IntRect* = 0) { }
+ // Called whenever a frame of an image changes because we got more data from the network.
+ // If not null, the IntRect is the changed rect of the image.
+ virtual void imageChanged(CachedImage*, const IntRect* = nullptr) { }
- // Called to find out if this client wants to actually display the image. Used to tell when we
- // can halt animation. Content nodes that hold image refs for example would not render the image,
- // but RenderImages would (assuming they have visibility: visible and their render tree isn't hidden
- // e.g., in the b/f cache or in a background tab).
- virtual bool willRenderImage(CachedImage*) { return false; }
+ // Called when GIF animation progresses.
+ virtual void newImageAnimationFrameAvailable(CachedImage& image) { imageChanged(&image); }
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedRawResource.cpp b/Source/WebCore/loader/cache/CachedRawResource.cpp
index a6eff5efb..05b9de128 100644
--- a/Source/WebCore/loader/cache/CachedRawResource.cpp
+++ b/Source/WebCore/loader/cache/CachedRawResource.cpp
@@ -29,23 +29,26 @@
#include "CachedRawResourceClient.h"
#include "CachedResourceClientWalker.h"
#include "CachedResourceLoader.h"
-#include "ResourceBuffer.h"
+#include "HTTPHeaderNames.h"
+#include "SharedBuffer.h"
#include "SubresourceLoader.h"
-#include <wtf/PassRefPtr.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
-CachedRawResource::CachedRawResource(ResourceRequest& resourceRequest, Type type)
- : CachedResource(resourceRequest, type)
+CachedRawResource::CachedRawResource(CachedResourceRequest&& request, Type type, SessionID sessionID)
+ : CachedResource(WTFMove(request), type, sessionID)
, m_identifier(0)
+ , m_allowEncodedDataReplacement(true)
{
+ ASSERT(isMainOrMediaOrRawResource());
}
-const char* CachedRawResource::calculateIncrementalDataChunk(ResourceBuffer* data, unsigned& incrementalDataLength)
+const char* CachedRawResource::calculateIncrementalDataChunk(SharedBuffer* data, unsigned& incrementalDataLength)
{
incrementalDataLength = 0;
if (!data)
- return 0;
+ return nullptr;
unsigned previousDataLength = encodedSize();
ASSERT(data->size() >= previousDataLength);
@@ -53,34 +56,37 @@ const char* CachedRawResource::calculateIncrementalDataChunk(ResourceBuffer* dat
return data->data() + previousDataLength;
}
-void CachedRawResource::addDataBuffer(ResourceBuffer* data)
+void CachedRawResource::addDataBuffer(SharedBuffer& data)
{
- CachedResourceHandle<CachedRawResource> protect(this);
- ASSERT(m_options.dataBufferingPolicy == BufferData);
- m_data = data;
+ CachedResourceHandle<CachedRawResource> protectedThis(this);
+ ASSERT(dataBufferingPolicy() == BufferData);
+ m_data = &data;
unsigned incrementalDataLength;
- const char* incrementalData = calculateIncrementalDataChunk(data, incrementalDataLength);
- if (data)
- setEncodedSize(data->size());
+ const char* incrementalData = calculateIncrementalDataChunk(&data, incrementalDataLength);
+ setEncodedSize(data.size());
notifyClientsDataWasReceived(incrementalData, incrementalDataLength);
- if (m_options.dataBufferingPolicy == DoNotBufferData) {
+ if (dataBufferingPolicy() == DoNotBufferData) {
if (m_loader)
m_loader->setDataBufferingPolicy(DoNotBufferData);
clear();
+ return;
}
+
+ CachedResource::addDataBuffer(data);
}
void CachedRawResource::addData(const char* data, unsigned length)
{
- ASSERT(m_options.dataBufferingPolicy == DoNotBufferData);
+ ASSERT(dataBufferingPolicy() == DoNotBufferData);
notifyClientsDataWasReceived(data, length);
+ CachedResource::addData(data, length);
}
-void CachedRawResource::finishLoading(ResourceBuffer* data)
+void CachedRawResource::finishLoading(SharedBuffer* data)
{
- CachedResourceHandle<CachedRawResource> protect(this);
- DataBufferingPolicy dataBufferingPolicy = m_options.dataBufferingPolicy;
+ CachedResourceHandle<CachedRawResource> protectedThis(this);
+ DataBufferingPolicy dataBufferingPolicy = this->dataBufferingPolicy();
if (dataBufferingPolicy == BufferData) {
m_data = data;
@@ -91,8 +97,12 @@ void CachedRawResource::finishLoading(ResourceBuffer* data)
notifyClientsDataWasReceived(incrementalData, incrementalDataLength);
}
+#if USE(QUICK_LOOK)
+ m_allowEncodedDataReplacement = !m_loader->isQuickLookResource();
+#endif
+
CachedResource::finishLoading(data);
- if (dataBufferingPolicy == BufferData && m_options.dataBufferingPolicy == DoNotBufferData) {
+ if (dataBufferingPolicy == BufferData && this->dataBufferingPolicy() == DoNotBufferData) {
if (m_loader)
m_loader->setDataBufferingPolicy(DoNotBufferData);
clear();
@@ -104,37 +114,45 @@ void CachedRawResource::notifyClientsDataWasReceived(const char* data, unsigned
if (!length)
return;
- CachedResourceHandle<CachedRawResource> protect(this);
+ CachedResourceHandle<CachedRawResource> protectedThis(this);
CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
while (CachedRawResourceClient* c = w.next())
- c->dataReceived(this, data, length);
+ c->dataReceived(*this, data, length);
}
-void CachedRawResource::didAddClient(CachedResourceClient* c)
+void CachedRawResource::didAddClient(CachedResourceClient& c)
{
if (!hasClient(c))
return;
// The calls to the client can result in events running, potentially causing
// this resource to be evicted from the cache and all clients to be removed,
// so a protector is necessary.
- CachedResourceHandle<CachedRawResource> protect(this);
- CachedRawResourceClient* client = static_cast<CachedRawResourceClient*>(c);
+ CachedResourceHandle<CachedRawResource> protectedThis(this);
+ CachedRawResourceClient& client = static_cast<CachedRawResourceClient&>(c);
size_t redirectCount = m_redirectChain.size();
for (size_t i = 0; i < redirectCount; i++) {
RedirectPair redirect = m_redirectChain[i];
ResourceRequest request(redirect.m_request);
- client->redirectReceived(this, request, redirect.m_redirectResponse);
+ client.redirectReceived(*this, request, redirect.m_redirectResponse);
if (!hasClient(c))
return;
}
ASSERT(redirectCount == m_redirectChain.size());
- if (!m_response.isNull())
- client->responseReceived(this, m_response);
+ if (!m_response.isNull()) {
+ ResourceResponse response(m_response);
+ if (validationCompleting())
+ response.setSource(ResourceResponse::Source::MemoryCacheAfterValidation);
+ else {
+ ASSERT(!validationInProgress());
+ response.setSource(ResourceResponse::Source::MemoryCache);
+ }
+ client.responseReceived(*this, response);
+ }
if (!hasClient(c))
return;
if (m_data)
- client->dataReceived(this, m_data->data(), m_data->size());
+ client.dataReceived(*this, m_data->data(), m_data->size());
if (!hasClient(c))
return;
CachedResource::didAddClient(client);
@@ -146,34 +164,51 @@ void CachedRawResource::allClientsRemoved()
m_loader->cancelIfNotFinishing();
}
-void CachedRawResource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
+void CachedRawResource::redirectReceived(ResourceRequest& request, const ResourceResponse& response)
{
- CachedResourceHandle<CachedRawResource> protect(this);
+ CachedResourceHandle<CachedRawResource> protectedThis(this);
if (!response.isNull()) {
CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
while (CachedRawResourceClient* c = w.next())
- c->redirectReceived(this, request, response);
+ c->redirectReceived(*this, request, response);
m_redirectChain.append(RedirectPair(request, response));
}
- CachedResource::willSendRequest(request, response);
+ CachedResource::redirectReceived(request, response);
}
void CachedRawResource::responseReceived(const ResourceResponse& response)
{
- CachedResourceHandle<CachedRawResource> protect(this);
+ CachedResourceHandle<CachedRawResource> protectedThis(this);
if (!m_identifier)
m_identifier = m_loader->identifier();
CachedResource::responseReceived(response);
CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
while (CachedRawResourceClient* c = w.next())
- c->responseReceived(this, m_response);
+ c->responseReceived(*this, m_response);
+}
+
+bool CachedRawResource::shouldCacheResponse(const ResourceResponse& response)
+{
+ CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
+ while (CachedRawResourceClient* c = w.next()) {
+ if (!c->shouldCacheResponse(*this, response))
+ return false;
+ }
+ return true;
}
void CachedRawResource::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
while (CachedRawResourceClient* c = w.next())
- c->dataSent(this, bytesSent, totalBytesToBeSent);
+ c->dataSent(*this, bytesSent, totalBytesToBeSent);
+}
+
+void CachedRawResource::finishedTimingForWorkerLoad(ResourceTiming&& resourceTiming)
+{
+ CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
+ while (CachedRawResourceClient* c = w.next())
+ c->finishedTimingForWorkerLoad(*this, resourceTiming);
}
void CachedRawResource::switchClientsToRevalidatedResource()
@@ -181,7 +216,7 @@ void CachedRawResource::switchClientsToRevalidatedResource()
ASSERT(m_loader);
// If we're in the middle of a successful revalidation, responseReceived() hasn't been called, so we haven't set m_identifier.
ASSERT(!m_identifier);
- static_cast<CachedRawResource*>(resourceToRevalidate())->m_identifier = m_loader->identifier();
+ downcast<CachedRawResource>(*resourceToRevalidate()).m_identifier = m_loader->identifier();
CachedResource::switchClientsToRevalidatedResource();
}
@@ -196,25 +231,26 @@ void CachedRawResource::setDataBufferingPolicy(DataBufferingPolicy dataBuffering
m_options.dataBufferingPolicy = dataBufferingPolicy;
}
-static bool shouldIgnoreHeaderForCacheReuse(AtomicString headerName)
+static bool shouldIgnoreHeaderForCacheReuse(HTTPHeaderName name)
{
+ switch (name) {
// FIXME: This list of headers that don't affect cache policy almost certainly isn't complete.
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, m_headers, ());
- if (m_headers.isEmpty()) {
- m_headers.add("Accept");
- m_headers.add("Cache-Control");
- m_headers.add("Origin");
- m_headers.add("Pragma");
- m_headers.add("Purpose");
- m_headers.add("Referer");
- m_headers.add("User-Agent");
+ case HTTPHeaderName::Accept:
+ case HTTPHeaderName::CacheControl:
+ case HTTPHeaderName::Pragma:
+ case HTTPHeaderName::Purpose:
+ case HTTPHeaderName::Referer:
+ case HTTPHeaderName::UserAgent:
+ return true;
+
+ default:
+ return false;
}
- return m_headers.contains(headerName);
}
bool CachedRawResource::canReuse(const ResourceRequest& newRequest) const
{
- if (m_options.dataBufferingPolicy == DoNotBufferData)
+ if (dataBufferingPolicy() == DoNotBufferData)
return false;
if (m_resourceRequest.httpMethod() != newRequest.httpMethod())
@@ -226,6 +262,9 @@ bool CachedRawResource::canReuse(const ResourceRequest& newRequest) const
if (m_resourceRequest.allowCookies() != newRequest.allowCookies())
return false;
+ if (newRequest.isConditional())
+ return false;
+
// Ensure most headers match the existing headers before continuing.
// Note that the list of ignored headers includes some headers explicitly related to caching.
// A more detailed check of caching policy will be performed later, this is simply a list of
@@ -233,22 +272,23 @@ bool CachedRawResource::canReuse(const ResourceRequest& newRequest) const
const HTTPHeaderMap& newHeaders = newRequest.httpHeaderFields();
const HTTPHeaderMap& oldHeaders = m_resourceRequest.httpHeaderFields();
- HTTPHeaderMap::const_iterator end = newHeaders.end();
- for (HTTPHeaderMap::const_iterator i = newHeaders.begin(); i != end; ++i) {
- AtomicString headerName = i->key;
- if (!shouldIgnoreHeaderForCacheReuse(headerName) && i->value != oldHeaders.get(headerName))
- return false;
- }
-
- end = oldHeaders.end();
- for (HTTPHeaderMap::const_iterator i = oldHeaders.begin(); i != end; ++i) {
- AtomicString headerName = i->key;
- if (!shouldIgnoreHeaderForCacheReuse(headerName) && i->value != newHeaders.get(headerName))
+ for (const auto& header : newHeaders) {
+ if (header.keyAsHTTPHeaderName) {
+ if (!shouldIgnoreHeaderForCacheReuse(header.keyAsHTTPHeaderName.value())
+ && header.value != oldHeaders.commonHeaders().get(header.keyAsHTTPHeaderName.value()))
+ return false;
+ } else if (header.value != oldHeaders.uncommonHeaders().get(header.key))
return false;
}
- for (size_t i = 0; i < m_redirectChain.size(); i++) {
- if (m_redirectChain[i].m_redirectResponse.cacheControlContainsNoStore())
+ // For this second loop, we don't actually need to compare values, checking that the
+ // key is contained in newHeaders is sufficient due to the previous loop.
+ for (const auto& header : oldHeaders) {
+ if (header.keyAsHTTPHeaderName) {
+ if (!shouldIgnoreHeaderForCacheReuse(header.keyAsHTTPHeaderName.value())
+ && !newHeaders.commonHeaders().contains(header.keyAsHTTPHeaderName.value()))
+ return false;
+ } else if (!newHeaders.uncommonHeaders().contains(header.key))
return false;
}
@@ -257,7 +297,7 @@ bool CachedRawResource::canReuse(const ResourceRequest& newRequest) const
void CachedRawResource::clear()
{
- m_data.clear();
+ m_data = nullptr;
setEncodedSize(0);
if (m_loader)
m_loader->clearResourceData();
diff --git a/Source/WebCore/loader/cache/CachedRawResource.h b/Source/WebCore/loader/cache/CachedRawResource.h
index 48e04ffec..7d7468c0e 100644
--- a/Source/WebCore/loader/cache/CachedRawResource.h
+++ b/Source/WebCore/loader/cache/CachedRawResource.h
@@ -20,19 +20,19 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedRawResource_h
-#define CachedRawResource_h
+#pragma once
#include "CachedResource.h"
namespace WebCore {
class CachedResourceClient;
+class ResourceTiming;
class SubresourceLoader;
class CachedRawResource final : public CachedResource {
public:
- CachedRawResource(ResourceRequest&, Type);
+ CachedRawResource(CachedResourceRequest&&, Type, SessionID);
// FIXME: AssociatedURLLoader shouldn't be a DocumentThreadableLoader and therefore shouldn't
// use CachedRawResource. However, it is, and it needs to be able to defer loading.
@@ -40,38 +40,44 @@ public:
virtual void setDefersLoading(bool);
virtual void setDataBufferingPolicy(DataBufferingPolicy);
-
- // FIXME: This is exposed for the InpsectorInstrumentation for preflights in DocumentThreadableLoader. It's also really lame.
+
+ // FIXME: This is exposed for the InspectorInstrumentation for preflights in DocumentThreadableLoader. It's also really lame.
unsigned long identifier() const { return m_identifier; }
void clear();
-private:
- virtual void didAddClient(CachedResourceClient*) override;
- virtual void addDataBuffer(ResourceBuffer*) override;
- virtual void addData(const char* data, unsigned length) override;
- virtual void finishLoading(ResourceBuffer*) override;
+ bool canReuse(const ResourceRequest&) const;
+
+ bool wasRedirected() const { return !m_redirectChain.isEmpty(); };
- virtual bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }
- virtual void allClientsRemoved() override;
+ void finishedTimingForWorkerLoad(ResourceTiming&&);
+
+private:
+ void didAddClient(CachedResourceClient&) final;
+ void addDataBuffer(SharedBuffer&) final;
+ void addData(const char* data, unsigned length) final;
+ void finishLoading(SharedBuffer*) final;
- virtual void willSendRequest(ResourceRequest&, const ResourceResponse&) override;
- virtual void responseReceived(const ResourceResponse&) override;
- virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }
+ void allClientsRemoved() override;
- virtual void switchClientsToRevalidatedResource() override;
- virtual bool mayTryReplaceEncodedData() const override { return true; }
+ void redirectReceived(ResourceRequest&, const ResourceResponse&) override;
+ void responseReceived(const ResourceResponse&) override;
+ bool shouldCacheResponse(const ResourceResponse&) override;
+ void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
- virtual bool canReuse(const ResourceRequest&) const override;
+ void switchClientsToRevalidatedResource() override;
+ bool mayTryReplaceEncodedData() const override { return m_allowEncodedDataReplacement; }
- const char* calculateIncrementalDataChunk(ResourceBuffer*, unsigned& incrementalDataLength);
+ const char* calculateIncrementalDataChunk(SharedBuffer*, unsigned& incrementalDataLength);
void notifyClientsDataWasReceived(const char* data, unsigned length);
#if USE(SOUP)
- virtual char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize);
+ char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize) override;
#endif
unsigned long m_identifier;
+ bool m_allowEncodedDataReplacement;
struct RedirectPair {
public:
@@ -88,6 +94,8 @@ private:
Vector<RedirectPair> m_redirectChain;
};
-}
+} // namespace WebCore
-#endif // CachedRawResource_h
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::CachedRawResource)
+ static bool isType(const WebCore::CachedResource& resource) { return resource.isMainOrMediaOrRawResource(); }
+SPECIALIZE_TYPE_TRAITS_END()
diff --git a/Source/WebCore/loader/cache/CachedRawResourceClient.h b/Source/WebCore/loader/cache/CachedRawResourceClient.h
index 3d7fd5e5c..2e9fac591 100644
--- a/Source/WebCore/loader/cache/CachedRawResourceClient.h
+++ b/Source/WebCore/loader/cache/CachedRawResourceClient.h
@@ -20,8 +20,7 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedRawResourceClient_h
-#define CachedRawResourceClient_h
+#pragma once
#include "CachedResourceClient.h"
@@ -30,22 +29,23 @@ namespace WebCore {
class CachedResource;
class ResourceRequest;
class ResourceResponse;
+class ResourceTiming;
class CachedRawResourceClient : public CachedResourceClient {
public:
virtual ~CachedRawResourceClient() { }
static CachedResourceClientType expectedType() { return RawResourceType; }
- virtual CachedResourceClientType resourceClientType() const override { return expectedType(); }
-
- virtual void dataSent(CachedResource*, unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
- virtual void responseReceived(CachedResource*, const ResourceResponse&) { }
- virtual void dataReceived(CachedResource*, const char* /* data */, int /* length */) { }
- virtual void redirectReceived(CachedResource*, ResourceRequest&, const ResourceResponse&) { }
+ CachedResourceClientType resourceClientType() const override { return expectedType(); }
+
+ virtual void dataSent(CachedResource&, unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
+ virtual void responseReceived(CachedResource&, const ResourceResponse&) { }
+ virtual bool shouldCacheResponse(CachedResource&, const ResourceResponse&) { return true; }
+ virtual void dataReceived(CachedResource&, const char* /* data */, int /* length */) { }
+ virtual void redirectReceived(CachedResource&, ResourceRequest&, const ResourceResponse&) { }
+ virtual void finishedTimingForWorkerLoad(CachedResource&, const ResourceTiming&) { }
#if USE(SOUP)
- virtual char* getOrCreateReadBuffer(CachedResource*, size_t /* requestedSize */, size_t& /* actualSize */) { return 0; }
+ virtual char* getOrCreateReadBuffer(CachedResource&, size_t /* requestedSize */, size_t& /* actualSize */) { return nullptr; }
#endif
};
}
-
-#endif // CachedRawResourceClient_h
diff --git a/Source/WebCore/loader/cache/CachedResource.cpp b/Source/WebCore/loader/cache/CachedResource.cpp
index 5f0bc76fa..8b09d3285 100644
--- a/Source/WebCore/loader/cache/CachedResource.cpp
+++ b/Source/WebCore/loader/cache/CachedResource.cpp
@@ -3,7 +3,7 @@
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@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.
+ Copyright (C) 2004-2011, 2014 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
@@ -29,23 +29,23 @@
#include "CachedResourceHandle.h"
#include "CachedResourceLoader.h"
#include "CrossOriginAccessControl.h"
+#include "DiagnosticLoggingClient.h"
+#include "DiagnosticLoggingKeys.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
+#include "HTTPHeaderNames.h"
#include "InspectorInstrumentation.h"
#include "URL.h"
#include "LoaderStrategy.h"
#include "Logging.h"
+#include "MainFrame.h"
#include "MemoryCache.h"
#include "PlatformStrategies.h"
-#include "PurgeableBuffer.h"
-#include "ResourceBuffer.h"
#include "ResourceHandle.h"
-#include "ResourceLoadScheduler.h"
#include "SchemeRegistry.h"
#include "SecurityOrigin.h"
-#include "SecurityPolicy.h"
#include "SubresourceLoader.h"
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
@@ -60,139 +60,99 @@
using namespace WTF;
-namespace WebCore {
+#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(cachedResourceLoader.isAlwaysOnLoggingAllowed(), Network, "%p - CachedResource::" fmt, this, ##__VA_ARGS__)
-// These response headers are not copied from a revalidated response to the
-// cached response headers. For compatibility, this list is based on Chromium's
-// net/http/http_response_headers.cc.
-const char* const headersToIgnoreAfterRevalidation[] = {
- "allow",
- "connection",
- "etag",
- "expires",
- "keep-alive",
- "last-modified"
- "proxy-authenticate",
- "proxy-connection",
- "trailer",
- "transfer-encoding",
- "upgrade",
- "www-authenticate",
- "x-frame-options",
- "x-xss-protection",
-};
-
-// Some header prefixes mean "Don't copy this header from a 304 response.".
-// Rather than listing all the relevant headers, we can consolidate them into
-// this list, also grabbed from Chromium's net/http/http_response_headers.cc.
-const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
- "content-",
- "x-content-",
- "x-webkit-"
-};
-
-static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& header)
-{
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation); i++) {
- if (equalIgnoringCase(header, headersToIgnoreAfterRevalidation[i]))
- return false;
- }
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidation); i++) {
- if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i], false))
- return false;
- }
- return true;
-}
+namespace WebCore {
-static ResourceLoadPriority defaultPriorityForResourceType(CachedResource::Type type)
+ResourceLoadPriority CachedResource::defaultPriorityForResourceType(Type type)
{
switch (type) {
case CachedResource::MainResource:
- return ResourceLoadPriorityVeryHigh;
+ return ResourceLoadPriority::VeryHigh;
case CachedResource::CSSStyleSheet:
- return ResourceLoadPriorityHigh;
case CachedResource::Script:
+ return ResourceLoadPriority::High;
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
+ case CachedResource::MediaResource:
case CachedResource::FontResource:
case CachedResource::RawResource:
- return ResourceLoadPriorityMedium;
+ return ResourceLoadPriority::Medium;
case CachedResource::ImageResource:
- return ResourceLoadPriorityLow;
+ return ResourceLoadPriority::Low;
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
- return ResourceLoadPriorityHigh;
+ return ResourceLoadPriority::High;
#endif
-#if ENABLE(SVG)
case CachedResource::SVGDocumentResource:
- return ResourceLoadPriorityLow;
-#endif
+ return ResourceLoadPriority::Low;
#if ENABLE(LINK_PREFETCH)
case CachedResource::LinkPrefetch:
- return ResourceLoadPriorityVeryLow;
+ return ResourceLoadPriority::VeryLow;
case CachedResource::LinkSubresource:
- return ResourceLoadPriorityVeryLow;
+ return ResourceLoadPriority::VeryLow;
#endif
#if ENABLE(VIDEO_TRACK)
case CachedResource::TextTrackResource:
- return ResourceLoadPriorityLow;
+ return ResourceLoadPriority::Low;
#endif
}
ASSERT_NOT_REACHED();
- return ResourceLoadPriorityLow;
+ return ResourceLoadPriority::Low;
}
-static double deadDecodedDataDeletionIntervalForResourceType(CachedResource::Type type)
+static std::chrono::milliseconds deadDecodedDataDeletionIntervalForResourceType(CachedResource::Type type)
{
if (type == CachedResource::Script)
- return 0;
- return memoryCache()->deadDecodedDataDeletionInterval();
+ return std::chrono::milliseconds { 0 };
+
+ return MemoryCache::singleton().deadDecodedDataDeletionInterval();
}
DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("CachedResource"));
-CachedResource::CachedResource(const ResourceRequest& request, Type type)
- : m_resourceRequest(request)
+CachedResource::CachedResource(CachedResourceRequest&& request, Type type, SessionID sessionID)
+ : m_resourceRequest(request.releaseResourceRequest())
+ , m_options(request.options())
+ , m_decodedDataDeletionTimer(*this, &CachedResource::destroyDecodedData, deadDecodedDataDeletionIntervalForResourceType(type))
+ , m_sessionID(sessionID)
, m_loadPriority(defaultPriorityForResourceType(type))
- , m_responseTimestamp(currentTime())
- , m_decodedDataDeletionTimer(this, &CachedResource::decodedDataDeletionTimerFired, deadDecodedDataDeletionIntervalForResourceType(type))
- , m_lastDecodedAccessTime(0)
- , m_loadFinishTime(0)
- , m_encodedSize(0)
- , m_decodedSize(0)
- , m_accessCount(0)
- , m_handleCount(0)
- , m_preloadCount(0)
- , m_preloadResult(PreloadNotReferenced)
- , m_inLiveDecodedResourcesList(false)
- , m_requestedFromNetworkingLayer(false)
- , m_inCache(false)
- , m_loading(false)
- , m_switchingClientsToRevalidatedResource(false)
+ , m_responseTimestamp(std::chrono::system_clock::now())
+ , m_fragmentIdentifierForRequest(request.releaseFragmentIdentifier())
+ , m_origin(request.releaseOrigin())
+ , m_initiatorName(request.initiatorName())
+ , m_isLinkPreload(request.isLinkPreload())
, m_type(type)
- , m_status(Pending)
+{
+ ASSERT(sessionID.isValid());
+
+ setLoadPriority(request.priority());
#ifndef NDEBUG
- , m_deleted(false)
- , m_lruIndex(0)
+ cachedResourceLeakCounter.increment();
#endif
- , m_nextInAllResourcesList(0)
- , m_prevInAllResourcesList(0)
- , m_nextInLiveResourcesList(0)
- , m_prevInLiveResourcesList(0)
- , m_owningCachedResourceLoader(0)
- , m_resourceToRevalidate(0)
- , m_proxyResource(0)
-{
- ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests careless updates of the enum.
+
+ // FIXME: We should have a better way of checking for Navigation loads, maybe FetchMode::Options::Navigate.
+ ASSERT(m_origin || m_type == CachedResource::MainResource);
+
+ if (isRequestCrossOrigin(m_origin.get(), m_resourceRequest.url(), m_options))
+ setCrossOrigin();
+}
+
+// FIXME: For this constructor, we should probably mandate that the URL has no fragment identifier.
+CachedResource::CachedResource(const URL& url, Type type, SessionID sessionID)
+ : m_resourceRequest(url)
+ , m_decodedDataDeletionTimer(*this, &CachedResource::destroyDecodedData, deadDecodedDataDeletionIntervalForResourceType(type))
+ , m_sessionID(sessionID)
+ , m_responseTimestamp(std::chrono::system_clock::now())
+ , m_fragmentIdentifierForRequest(CachedResourceRequest::splitFragmentIdentifierFromRequestURL(m_resourceRequest))
+ , m_type(type)
+ , m_status(Cached)
+{
+ ASSERT(sessionID.isValid());
#ifndef NDEBUG
cachedResourceLeakCounter.increment();
#endif
-
- if (!m_resourceRequest.url().hasFragmentIdentifier())
- return;
- URL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
- if (urlForCache.hasFragmentIdentifier())
- return;
- m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier();
- m_resourceRequest.setURL(urlForCache);
}
CachedResource::~CachedResource()
@@ -201,7 +161,7 @@ CachedResource::~CachedResource()
ASSERT(canDelete());
ASSERT(!inCache());
ASSERT(!m_deleted);
- ASSERT(url().isNull() || memoryCache()->resourceForRequest(resourceRequest()) != this);
+ ASSERT(url().isNull() || !allowsCaching() || MemoryCache::singleton().resourceForRequest(resourceRequest(), sessionID()) != this);
#ifndef NDEBUG
m_deleted = true;
@@ -209,99 +169,81 @@ CachedResource::~CachedResource()
#endif
if (m_owningCachedResourceLoader)
- m_owningCachedResourceLoader->removeCachedResource(this);
+ m_owningCachedResourceLoader->removeCachedResource(*this);
}
void CachedResource::failBeforeStarting()
{
// FIXME: What if resources in other frames were waiting for this revalidation?
LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1().data());
- if (m_resourceToRevalidate)
- memoryCache()->revalidationFailed(this);
+ if (allowsCaching() && m_resourceToRevalidate)
+ MemoryCache::singleton().revalidationFailed(*this);
error(CachedResource::LoadError);
}
-void CachedResource::addAdditionalRequestHeaders(CachedResourceLoader* cachedResourceLoader)
+void CachedResource::load(CachedResourceLoader& cachedResourceLoader)
{
- // Note: We skip the Content-Security-Policy check here because we check
- // the Content-Security-Policy at the CachedResourceLoader layer so we can
- // handle different resource types differently.
-
- FrameLoader& frameLoader = cachedResourceLoader->frame()->loader();
- String outgoingReferrer;
- String outgoingOrigin;
- if (m_resourceRequest.httpReferrer().isNull()) {
- outgoingReferrer = frameLoader.outgoingReferrer();
- outgoingOrigin = frameLoader.outgoingOrigin();
- } else {
- outgoingReferrer = m_resourceRequest.httpReferrer();
- outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
- }
-
- outgoingReferrer = SecurityPolicy::generateReferrerHeader(cachedResourceLoader->document()->referrerPolicy(), m_resourceRequest.url(), outgoingReferrer);
- if (outgoingReferrer.isEmpty())
- m_resourceRequest.clearHTTPReferrer();
- else if (!m_resourceRequest.httpReferrer())
- m_resourceRequest.setHTTPReferrer(outgoingReferrer);
- FrameLoader::addHTTPOriginIfNeeded(m_resourceRequest, outgoingOrigin);
-
- frameLoader.addExtraFieldsToSubresourceRequest(m_resourceRequest);
-}
-
-void CachedResource::load(CachedResourceLoader* cachedResourceLoader, const ResourceLoaderOptions& options)
-{
- if (!cachedResourceLoader->frame()) {
+ if (!cachedResourceLoader.frame()) {
+ RELEASE_LOG_IF_ALLOWED("load: No associated frame");
failBeforeStarting();
return;
}
+ Frame& frame = *cachedResourceLoader.frame();
+
+ // Prevent new loads if we are in the PageCache or being added to the PageCache.
+ // We query the top document because new frames may be created in pagehide event handlers
+ // and their pageCacheState will not reflect the fact that they are about to enter page
+ // cache.
+ if (auto* topDocument = frame.mainFrame().document()) {
+ if (topDocument->pageCacheState() != Document::NotInPageCache) {
+ RELEASE_LOG_IF_ALLOWED("load: Already in page cache or being added to it (frame = %p)", &frame);
+ failBeforeStarting();
+ return;
+ }
+ }
- FrameLoader& frameLoader = cachedResourceLoader->frame()->loader();
- if (options.securityCheck == DoSecurityCheck && (frameLoader.state() == FrameStateProvisional || !frameLoader.activeDocumentLoader() || frameLoader.activeDocumentLoader()->isStopping())) {
+ FrameLoader& frameLoader = frame.loader();
+ if (m_options.securityCheck == DoSecurityCheck && (frameLoader.state() == FrameStateProvisional || !frameLoader.activeDocumentLoader() || frameLoader.activeDocumentLoader()->isStopping())) {
+ if (frameLoader.state() == FrameStateProvisional)
+ RELEASE_LOG_IF_ALLOWED("load: Failed security check -- state is provisional (frame = %p)", &frame);
+ else if (!frameLoader.activeDocumentLoader())
+ RELEASE_LOG_IF_ALLOWED("load: Failed security check -- not active document (frame = %p)", &frame);
+ else if (frameLoader.activeDocumentLoader()->isStopping())
+ RELEASE_LOG_IF_ALLOWED("load: Failed security check -- active loader is stopping (frame = %p)", &frame);
failBeforeStarting();
return;
}
- m_options = options;
m_loading = true;
-#if USE(QUICK_LOOK)
- if (!m_resourceRequest.isNull() && m_resourceRequest.url().protocolIs(QLPreviewProtocol())) {
- // When QuickLook is invoked to convert a document, it returns a unique URL in the
- // NSURLReponse for the main document. To make safeQLURLForDocumentURLAndResourceURL()
- // work, we need to use the QL URL not the original URL.
- const URL& documentURL = cachedResourceLoader->frame() ? cachedResourceLoader->frame()->loader().documentLoader()->response().url() : cachedResourceLoader->document()->url();
- m_resourceRequest.setURL(safeQLURLForDocumentURLAndResourceURL(documentURL, url()));
- }
-#endif
-
- if (!accept().isEmpty())
- m_resourceRequest.setHTTPAccept(accept());
-
if (isCacheValidator()) {
CachedResource* resourceToRevalidate = m_resourceToRevalidate;
ASSERT(resourceToRevalidate->canUseCacheValidator());
ASSERT(resourceToRevalidate->isLoaded());
- const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified");
- const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag");
+ const String& lastModified = resourceToRevalidate->response().httpHeaderField(HTTPHeaderName::LastModified);
+ const String& eTag = resourceToRevalidate->response().httpHeaderField(HTTPHeaderName::ETag);
if (!lastModified.isEmpty() || !eTag.isEmpty()) {
- ASSERT(cachedResourceLoader->cachePolicy(type()) != CachePolicyReload);
- if (cachedResourceLoader->cachePolicy(type()) == CachePolicyRevalidate)
- m_resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
+ ASSERT(cachedResourceLoader.cachePolicy(type()) != CachePolicyReload);
+ if (cachedResourceLoader.cachePolicy(type()) == CachePolicyRevalidate)
+ m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
if (!lastModified.isEmpty())
- m_resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
+ m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
if (!eTag.isEmpty())
- m_resourceRequest.setHTTPHeaderField("If-None-Match", eTag);
+ m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
}
}
#if ENABLE(LINK_PREFETCH)
if (type() == CachedResource::LinkPrefetch || type() == CachedResource::LinkSubresource)
- m_resourceRequest.setHTTPHeaderField("Purpose", "prefetch");
+ m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::Purpose, "prefetch");
#endif
m_resourceRequest.setPriority(loadPriority());
- if (type() != MainResource)
- addAdditionalRequestHeaders(cachedResourceLoader);
+ // Navigation algorithm is setting up the request before sending it to CachedResourceLoader?CachedResource.
+ // So no need for extra fields for MainResource.
+ if (type() != CachedResource::MainResource)
+ frameLoader.addExtraFieldsToSubresourceRequest(m_resourceRequest);
+
// FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers.
// We should look into removing the expectation of that knowledge from the platform network stacks.
@@ -313,8 +255,9 @@ void CachedResource::load(CachedResourceLoader* cachedResourceLoader, const Reso
m_fragmentIdentifierForRequest = String();
}
- m_loader = platformStrategies()->loaderStrategy()->resourceLoadScheduler()->scheduleSubresourceLoad(cachedResourceLoader->frame(), this, request, request.priority(), options);
+ m_loader = platformStrategies()->loaderStrategy()->loadResource(frame, *this, request, m_options);
if (!m_loader) {
+ RELEASE_LOG_IF_ALLOWED("load: Unable to create SubresourceLoader (frame = %p)", &frame);
failBeforeStarting();
return;
}
@@ -322,27 +265,55 @@ void CachedResource::load(CachedResourceLoader* cachedResourceLoader, const Reso
m_status = Pending;
}
+void CachedResource::loadFrom(const CachedResource& resource)
+{
+ ASSERT(url() == resource.url());
+ ASSERT(type() == resource.type());
+ ASSERT(resource.status() == Status::Cached);
+
+ if (isCrossOrigin() && m_options.mode == FetchOptions::Mode::Cors) {
+ ASSERT(m_origin);
+ String errorMessage;
+ if (!WebCore::passesAccessControlCheck(resource.response(), m_options.allowCredentials, *m_origin, errorMessage)) {
+ setResourceError(ResourceError(String(), 0, url(), errorMessage, ResourceError::Type::AccessControl));
+ return;
+ }
+ }
+
+ setBodyDataFrom(resource);
+ setStatus(Status::Cached);
+ setLoading(false);
+}
+
+void CachedResource::setBodyDataFrom(const CachedResource& resource)
+{
+ m_data = resource.m_data;
+ m_response = resource.m_response;
+ setDecodedSize(resource.decodedSize());
+ setEncodedSize(resource.encodedSize());
+}
+
void CachedResource::checkNotify()
{
- if (isLoading())
+ if (isLoading() || stillNeedsLoad())
return;
- CachedResourceClientWalker<CachedResourceClient> w(m_clients);
- while (CachedResourceClient* c = w.next())
- c->notifyFinished(this);
+ CachedResourceClientWalker<CachedResourceClient> walker(m_clients);
+ while (CachedResourceClient* client = walker.next())
+ client->notifyFinished(*this);
}
-void CachedResource::addDataBuffer(ResourceBuffer*)
+void CachedResource::addDataBuffer(SharedBuffer&)
{
- ASSERT(m_options.dataBufferingPolicy == BufferData);
+ ASSERT(dataBufferingPolicy() == BufferData);
}
void CachedResource::addData(const char*, unsigned)
{
- ASSERT(m_options.dataBufferingPolicy == DoNotBufferData);
+ ASSERT(dataBufferingPolicy() == DoNotBufferData);
}
-void CachedResource::finishLoading(ResourceBuffer*)
+void CachedResource::finishLoading(SharedBuffer*)
{
setLoading(false);
checkNotify();
@@ -352,7 +323,7 @@ void CachedResource::error(CachedResource::Status status)
{
setStatus(status);
ASSERT(errorOccurred());
- m_data.clear();
+ m_data = nullptr;
setLoading(false);
checkNotify();
@@ -360,7 +331,7 @@ void CachedResource::error(CachedResource::Status status)
void CachedResource::cancelLoad()
{
- if (!isLoading())
+ if (!isLoading() && !stillNeedsLoad())
return;
setStatus(LoadError);
@@ -374,10 +345,30 @@ void CachedResource::finish()
m_status = Cached;
}
-bool CachedResource::passesAccessControlCheck(SecurityOrigin* securityOrigin)
+void CachedResource::setCrossOrigin()
{
- String errorDescription;
- return WebCore::passesAccessControlCheck(m_response, resourceRequest().allowCookies() ? AllowStoredCredentials : DoNotAllowStoredCredentials, securityOrigin, errorDescription);
+ ASSERT(m_options.mode != FetchOptions::Mode::SameOrigin);
+ m_responseTainting = (m_options.mode == FetchOptions::Mode::Cors) ? ResourceResponse::Tainting::Cors : ResourceResponse::Tainting::Opaque;
+}
+
+bool CachedResource::isCrossOrigin() const
+{
+ return m_responseTainting != ResourceResponse::Tainting::Basic;
+}
+
+bool CachedResource::isCORSSameOrigin() const
+{
+ // Following resource types do not use CORS
+ ASSERT(type() != CachedResource::Type::FontResource);
+#if ENABLE(SVG_FONTS)
+ ASSERT(type() != CachedResource::Type::SVGFontResource);
+#endif
+#if ENABLE(XSLT)
+ ASSERT(type() != CachedResource::XSLStyleSheet);
+#endif
+
+ // https://html.spec.whatwg.org/multipage/infrastructure.html#cors-same-origin
+ return !loadFailedOrCanceled() && m_responseTainting != ResourceResponse::Tainting::Opaque;
}
bool CachedResource::isExpired() const
@@ -385,53 +376,62 @@ bool CachedResource::isExpired() const
if (m_response.isNull())
return false;
- return currentAge() > freshnessLifetime();
+ return computeCurrentAge(m_response, m_responseTimestamp) > freshnessLifetime(m_response);
}
-double CachedResource::currentAge() const
+static inline bool shouldCacheSchemeIndefinitely(StringView scheme)
{
- // RFC2616 13.2.3
- // No compensation for latency as that is not terribly important in practice
- double dateValue = m_response.date();
- double apparentAge = std::isfinite(dateValue) ? std::max(0., m_responseTimestamp - dateValue) : 0;
- double ageValue = m_response.age();
- double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge, ageValue) : apparentAge;
- double residentTime = currentTime() - m_responseTimestamp;
- return correctedReceivedAge + residentTime;
+#if PLATFORM(COCOA)
+ if (equalLettersIgnoringASCIICase(scheme, "applewebdata"))
+ return true;
+#endif
+#if USE(SOUP)
+ if (equalLettersIgnoringASCIICase(scheme, "resource"))
+ return true;
+#endif
+ return equalLettersIgnoringASCIICase(scheme, "data");
}
-double CachedResource::freshnessLifetime() const
+std::chrono::microseconds CachedResource::freshnessLifetime(const ResourceResponse& response) const
{
- if (!m_response.url().protocolIsInHTTPFamily()) {
- // Don't cache non-HTTP main resources since we can't check for freshness.
- // FIXME: We should not cache subresources either, but when we tried this
- // it caused performance and flakiness issues in our test infrastructure.
- if (m_type == MainResource && !SchemeRegistry::shouldCacheResponsesFromURLSchemeIndefinitely(m_response.url().protocol()))
- return 0;
+ if (!response.url().protocolIsInHTTPFamily()) {
+ StringView protocol = response.url().protocol();
+ if (!shouldCacheSchemeIndefinitely(protocol)) {
+ // Don't cache non-HTTP main resources since we can't check for freshness.
+ // FIXME: We should not cache subresources either, but when we tried this
+ // it caused performance and flakiness issues in our test infrastructure.
+ if (m_type == MainResource || SchemeRegistry::shouldAlwaysRevalidateURLScheme(protocol.toStringWithoutCopying()))
+ return 0us;
+ }
- return std::numeric_limits<double>::max();
+ return std::chrono::microseconds::max();
}
- // RFC2616 13.2.4
- double maxAgeValue = m_response.cacheControlMaxAge();
- if (std::isfinite(maxAgeValue))
- return maxAgeValue;
- double expiresValue = m_response.expires();
- double dateValue = m_response.date();
- double creationTime = std::isfinite(dateValue) ? dateValue : m_responseTimestamp;
- if (std::isfinite(expiresValue))
- return expiresValue - creationTime;
- double lastModifiedValue = m_response.lastModified();
- if (std::isfinite(lastModifiedValue))
- return (creationTime - lastModifiedValue) * 0.1;
- // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
- return 0;
+ return computeFreshnessLifetimeForHTTPFamily(response, m_responseTimestamp);
+}
+
+void CachedResource::redirectReceived(ResourceRequest&, const ResourceResponse& response)
+{
+ m_requestedFromNetworkingLayer = true;
+ if (response.isNull())
+ return;
+
+ updateRedirectChainStatus(m_redirectChainCacheStatus, response);
+}
+
+void CachedResource::setResponse(const ResourceResponse& response)
+{
+ ASSERT(m_response.type() == ResourceResponse::Type::Default);
+ m_response = response;
+ m_response.setRedirected(m_redirectChainCacheStatus.status != RedirectChainCacheStatus::NoRedirection);
+
+ m_varyingHeaderValues = collectVaryingRequestHeaders(m_resourceRequest, m_response, m_sessionID);
}
void CachedResource::responseReceived(const ResourceResponse& response)
{
setResponse(response);
- m_responseTimestamp = currentTime();
+ m_responseTimestamp = std::chrono::system_clock::now();
String encoding = response.textEncodingName();
if (!encoding.isNull())
setEncoding(encoding);
@@ -440,32 +440,30 @@ void CachedResource::responseReceived(const ResourceResponse& response)
void CachedResource::clearLoader()
{
ASSERT(m_loader);
- m_loader = 0;
+ m_identifierForLoadWithoutResourceLoader = m_loader->identifier();
+ m_loader = nullptr;
+ deleteIfPossible();
}
-void CachedResource::addClient(CachedResourceClient* client)
+void CachedResource::addClient(CachedResourceClient& client)
{
if (addClientToSet(client))
didAddClient(client);
}
-void CachedResource::didAddClient(CachedResourceClient* c)
+void CachedResource::didAddClient(CachedResourceClient& client)
{
if (m_decodedDataDeletionTimer.isActive())
m_decodedDataDeletionTimer.stop();
- if (m_clientsAwaitingCallback.contains(c)) {
- m_clients.add(c);
- m_clientsAwaitingCallback.remove(c);
- }
+ if (m_clientsAwaitingCallback.remove(&client))
+ m_clients.add(&client);
if (!isLoading() && !stillNeedsLoad())
- c->notifyFinished(this);
+ client.notifyFinished(*this);
}
-bool CachedResource::addClientToSet(CachedResourceClient* client)
+bool CachedResource::addClientToSet(CachedResourceClient& client)
{
- ASSERT(!isPurgeable());
-
if (m_preloadResult == PreloadNotReferenced) {
if (isLoaded())
m_preloadResult = PreloadReferencedWhileComplete;
@@ -474,78 +472,90 @@ bool CachedResource::addClientToSet(CachedResourceClient* client)
else
m_preloadResult = PreloadReferenced;
}
- if (!hasClients() && inCache())
- memoryCache()->addToLiveResourcesSize(this);
+ if (allowsCaching() && !hasClients() && inCache())
+ MemoryCache::singleton().addToLiveResourcesSize(*this);
if ((m_type == RawResource || m_type == MainResource) && !m_response.isNull() && !m_proxyResource) {
// Certain resources (especially XHRs and main resources) do crazy things if an asynchronous load returns
// synchronously (e.g., scripts may not have set all the state they need to handle the load).
// Therefore, rather than immediately sending callbacks on a cache hit like other CachedResources,
// we schedule the callbacks and ensure we never finish synchronously.
- ASSERT(!m_clientsAwaitingCallback.contains(client));
- m_clientsAwaitingCallback.add(client, CachedResourceCallback::schedule(this, client));
+ ASSERT(!m_clientsAwaitingCallback.contains(&client));
+ m_clientsAwaitingCallback.add(&client, std::make_unique<Callback>(*this, client));
return false;
}
- m_clients.add(client);
+ m_clients.add(&client);
return true;
}
-void CachedResource::removeClient(CachedResourceClient* client)
+void CachedResource::removeClient(CachedResourceClient& client)
{
- OwnPtr<CachedResourceCallback> callback = m_clientsAwaitingCallback.take(client);
+ auto callback = m_clientsAwaitingCallback.take(&client);
if (callback) {
- ASSERT(!m_clients.contains(client));
+ ASSERT(!m_clients.contains(&client));
callback->cancel();
- callback.clear();
+ callback = nullptr;
} else {
- ASSERT(m_clients.contains(client));
- m_clients.remove(client);
+ ASSERT(m_clients.contains(&client));
+ m_clients.remove(&client);
didRemoveClient(client);
}
- bool deleted = deleteIfPossible();
- if (!deleted && !hasClients()) {
- if (inCache()) {
- memoryCache()->removeFromLiveResourcesSize(this);
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- }
- if (!m_switchingClientsToRevalidatedResource)
- allClientsRemoved();
- destroyDecodedDataIfNeeded();
- if (response().cacheControlContainsNoStore()) {
- // RFC2616 14.9.2:
- // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
- // "... History buffers MAY store such responses as part of their normal operation."
- // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
- if (url().protocolIs("https"))
- memoryCache()->remove(this);
- } else
- memoryCache()->prune();
+ if (deleteIfPossible()) {
+ // `this` object is dead here.
+ return;
}
- // This object may be dead here.
+
+ if (hasClients())
+ return;
+
+ auto& memoryCache = MemoryCache::singleton();
+ if (allowsCaching() && inCache()) {
+ memoryCache.removeFromLiveResourcesSize(*this);
+ memoryCache.removeFromLiveDecodedResourcesList(*this);
+ }
+ if (!m_switchingClientsToRevalidatedResource)
+ allClientsRemoved();
+ destroyDecodedDataIfNeeded();
+
+ if (!allowsCaching())
+ return;
+
+ if (response().cacheControlContainsNoStore() && url().protocolIs("https")) {
+ // RFC2616 14.9.2:
+ // "no-store: ... MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible"
+ // "... History buffers MAY store such responses as part of their normal operation."
+ // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
+ memoryCache.remove(*this);
+ }
+ memoryCache.pruneSoon();
}
void CachedResource::destroyDecodedDataIfNeeded()
{
if (!m_decodedSize)
return;
- if (!memoryCache()->deadDecodedDataDeletionInterval())
+ if (!MemoryCache::singleton().deadDecodedDataDeletionInterval().count())
return;
m_decodedDataDeletionTimer.restart();
}
-void CachedResource::decodedDataDeletionTimerFired(DeferrableOneShotTimer<CachedResource>&)
+void CachedResource::decodedDataDeletionTimerFired()
{
destroyDecodedData();
}
bool CachedResource::deleteIfPossible()
{
- if (canDelete() && !inCache()) {
- InspectorInstrumentation::willDestroyCachedResource(this);
- delete this;
- return true;
+ if (canDelete()) {
+ if (!inCache()) {
+ InspectorInstrumentation::willDestroyCachedResource(*this);
+ delete this;
+ return true;
+ }
+ if (m_data)
+ m_data->hintMemoryNotNeededSoon();
}
return false;
}
@@ -555,19 +565,19 @@ void CachedResource::setDecodedSize(unsigned size)
if (size == m_decodedSize)
return;
- int delta = size - m_decodedSize;
+ long long delta = static_cast<long long>(size) - m_decodedSize;
+
+ // The object must be moved to a different queue, since its size has been changed.
+ // Remove before updating m_decodedSize, so we find the resource in the correct LRU list.
+ if (allowsCaching() && inCache())
+ MemoryCache::singleton().removeFromLRUList(*this);
- // The object must now be moved to a different queue, since its size has been changed.
- // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
- // queue.
- if (inCache())
- memoryCache()->removeFromLRUList(this);
-
m_decodedSize = size;
- if (inCache()) {
+ if (allowsCaching() && inCache()) {
+ auto& memoryCache = MemoryCache::singleton();
// Now insert into the new LRU list.
- memoryCache()->insertInLRUList(this);
+ memoryCache.insertInLRUList(*this);
// Insert into or remove from the live decoded list if necessary.
// When inserting into the LiveDecodedResourcesList it is possible
@@ -576,13 +586,14 @@ void CachedResource::setDecodedSize(unsigned size)
// violation of the invariant that the list is to be kept sorted
// by access time. The weakening of the invariant does not pose
// a problem. For more details please see: https://bugs.webkit.org/show_bug.cgi?id=30209
- if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
- memoryCache()->insertInLiveDecodedResourcesList(this);
- else if (!m_decodedSize && m_inLiveDecodedResourcesList)
- memoryCache()->removeFromLiveDecodedResourcesList(this);
+ bool inLiveDecodedResourcesList = memoryCache.inLiveDecodedResourcesList(*this);
+ if (m_decodedSize && !inLiveDecodedResourcesList && hasClients())
+ memoryCache.insertInLiveDecodedResourcesList(*this);
+ else if (!m_decodedSize && inLiveDecodedResourcesList)
+ memoryCache.removeFromLiveDecodedResourcesList(*this);
// Update the cache's size totals.
- memoryCache()->adjustSize(hasClients(), delta);
+ memoryCache.adjustSize(hasClients(), delta);
}
}
@@ -591,25 +602,19 @@ void CachedResource::setEncodedSize(unsigned size)
if (size == m_encodedSize)
return;
- // The size cannot ever shrink (unless it is being nulled out because of an error). If it ever does, assert.
- ASSERT(size == 0 || size >= m_encodedSize);
-
- int delta = size - m_encodedSize;
+ long long delta = static_cast<long long>(size) - m_encodedSize;
+
+ // The object must be moved to a different queue, since its size has been changed.
+ // Remove before updating m_encodedSize, so we find the resource in the correct LRU list.
+ if (allowsCaching() && inCache())
+ MemoryCache::singleton().removeFromLRUList(*this);
- // The object must now be moved to a different queue, since its size has been changed.
- // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
- // queue.
- if (inCache())
- memoryCache()->removeFromLRUList(this);
-
m_encodedSize = size;
-
- if (inCache()) {
- // Now insert into the new LRU list.
- memoryCache()->insertInLRUList(this);
-
- // Update the cache's size totals.
- memoryCache()->adjustSize(hasClients(), delta);
+
+ if (allowsCaching() && inCache()) {
+ auto& memoryCache = MemoryCache::singleton();
+ memoryCache.insertInLRUList(*this);
+ memoryCache.adjustSize(hasClients(), delta);
}
}
@@ -617,12 +622,13 @@ void CachedResource::didAccessDecodedData(double timeStamp)
{
m_lastDecodedAccessTime = timeStamp;
- if (inCache()) {
- if (m_inLiveDecodedResourcesList) {
- memoryCache()->removeFromLiveDecodedResourcesList(this);
- memoryCache()->insertInLiveDecodedResourcesList(this);
+ if (allowsCaching() && inCache()) {
+ auto& memoryCache = MemoryCache::singleton();
+ if (memoryCache.inLiveDecodedResourcesList(*this)) {
+ memoryCache.removeFromLiveDecodedResourcesList(*this);
+ memoryCache.insertInLiveDecodedResourcesList(*this);
}
- memoryCache()->prune();
+ memoryCache.pruneSoon();
}
}
@@ -633,31 +639,27 @@ void CachedResource::setResourceToRevalidate(CachedResource* resource)
ASSERT(resource != this);
ASSERT(m_handlesToRevalidate.isEmpty());
ASSERT(resource->type() == type());
+ ASSERT(!resource->m_proxyResource);
LOG(ResourceLoading, "CachedResource %p setResourceToRevalidate %p", this, resource);
- // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
- // https://bugs.webkit.org/show_bug.cgi?id=28604.
- // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in CachedResource::clearResourceToRevalidate.
- ASSERT(!resource->m_proxyResource);
-
resource->m_proxyResource = this;
m_resourceToRevalidate = resource;
}
void CachedResource::clearResourceToRevalidate()
-{
+{
ASSERT(m_resourceToRevalidate);
+ ASSERT(m_resourceToRevalidate->m_proxyResource == this);
+
if (m_switchingClientsToRevalidatedResource)
return;
- // A resource may start revalidation before this method has been called, so check that this resource is still the proxy resource before clearing it out.
- if (m_resourceToRevalidate->m_proxyResource == this) {
- m_resourceToRevalidate->m_proxyResource = 0;
- m_resourceToRevalidate->deleteIfPossible();
- }
+ m_resourceToRevalidate->m_proxyResource = nullptr;
+ m_resourceToRevalidate->deleteIfPossible();
+
m_handlesToRevalidate.clear();
- m_resourceToRevalidate = 0;
+ m_resourceToRevalidate = nullptr;
deleteIfPossible();
}
@@ -670,9 +672,7 @@ void CachedResource::switchClientsToRevalidatedResource()
LOG(ResourceLoading, "CachedResource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
m_switchingClientsToRevalidatedResource = true;
- HashSet<CachedResourceHandleBase*>::iterator end = m_handlesToRevalidate.end();
- for (HashSet<CachedResourceHandleBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
- CachedResourceHandleBase* handle = *it;
+ for (auto& handle : m_handlesToRevalidate) {
handle->m_resource = m_resourceToRevalidate;
m_resourceToRevalidate->registerHandle(handle);
--m_handleCount;
@@ -681,52 +681,37 @@ void CachedResource::switchClientsToRevalidatedResource()
m_handlesToRevalidate.clear();
Vector<CachedResourceClient*> clientsToMove;
- HashCountedSet<CachedResourceClient*>::iterator end2 = m_clients.end();
- for (HashCountedSet<CachedResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
- CachedResourceClient* client = it->key;
- unsigned count = it->value;
+ for (auto& entry : m_clients) {
+ CachedResourceClient* client = entry.key;
+ unsigned count = entry.value;
while (count) {
clientsToMove.append(client);
--count;
}
}
- unsigned moveCount = clientsToMove.size();
- for (unsigned n = 0; n < moveCount; ++n)
- removeClient(clientsToMove[n]);
+ for (auto& client : clientsToMove)
+ removeClient(*client);
ASSERT(m_clients.isEmpty());
- for (unsigned n = 0; n < moveCount; ++n)
- m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
- for (unsigned n = 0; n < moveCount; ++n) {
+ for (auto& client : clientsToMove)
+ m_resourceToRevalidate->addClientToSet(*client);
+ for (auto& client : clientsToMove) {
// Calling didAddClient may do anything, including trying to cancel revalidation.
// Assert that it didn't succeed.
ASSERT(m_resourceToRevalidate);
// Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
- if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
- m_resourceToRevalidate->didAddClient(clientsToMove[n]);
+ if (m_resourceToRevalidate->m_clients.contains(client))
+ m_resourceToRevalidate->didAddClient(*client);
}
m_switchingClientsToRevalidatedResource = false;
}
void CachedResource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse)
{
- m_responseTimestamp = currentTime();
-
- // RFC2616 10.3.5
- // Update cached headers from the 304 response
- const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
- HTTPHeaderMap::const_iterator end = newHeaders.end();
- for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
- // Entity headers should not be sent by servers when generating a 304
- // response; misconfigured servers send them anyway. We shouldn't allow
- // such headers to update the original request. We'll base this on the
- // list defined by RFC2616 7.1, with a few additions for extension headers
- // we care about.
- if (!shouldUpdateHeaderAfterRevalidation(it->key))
- continue;
- m_response.setHTTPHeaderField(it->key, it->value);
- }
+ m_responseTimestamp = std::chrono::system_clock::now();
+
+ updateResponseHeadersAfterRevalidation(m_response, validatingResponse);
}
void CachedResource::registerHandle(CachedResourceHandleBase* h)
@@ -758,95 +743,50 @@ bool CachedResource::canUseCacheValidator() const
return m_response.hasCacheValidatorFields();
}
-bool CachedResource::mustRevalidateDueToCacheHeaders(CachePolicy cachePolicy) const
+CachedResource::RevalidationDecision CachedResource::makeRevalidationDecision(CachePolicy cachePolicy) const
{
- ASSERT(cachePolicy == CachePolicyRevalidate || cachePolicy == CachePolicyCache || cachePolicy == CachePolicyVerify);
-
- if (cachePolicy == CachePolicyRevalidate)
- return true;
-
- if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
- LOG(ResourceLoading, "CachedResource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
- return true;
- }
-
- if (cachePolicy == CachePolicyCache) {
- if (m_response.cacheControlContainsMustRevalidate() && isExpired()) {
- LOG(ResourceLoading, "CachedResource %p mustRevalidate because of cachePolicy == CachePolicyCache and m_response.cacheControlContainsMustRevalidate() && isExpired()\n", this);
- return true;
- }
- return false;
- }
-
- // CachePolicyVerify
- if (isExpired()) {
- LOG(ResourceLoading, "CachedResource %p mustRevalidate because of isExpired()\n", this);
- return true;
- }
-
- return false;
-}
-
-bool CachedResource::isSafeToMakePurgeable() const
-{
-#if ENABLE(DISK_IMAGE_CACHE)
- // It does not make sense to have a resource in the disk image cache
- // (memory mapped on disk) and purgeable (in memory). So do not allow
- // disk image cached resources to be purgeable.
- if (isUsingDiskImageCache())
- return false;
-#endif
-
- return !hasClients() && !m_proxyResource && !m_resourceToRevalidate;
-}
-
-bool CachedResource::makePurgeable(bool purgeable)
-{
- if (purgeable) {
- ASSERT(isSafeToMakePurgeable());
-
- if (m_purgeableData) {
- ASSERT(!m_data);
- return true;
+ switch (cachePolicy) {
+ case CachePolicyHistoryBuffer:
+ return RevalidationDecision::No;
+
+ case CachePolicyReload:
+ return RevalidationDecision::YesDueToCachePolicy;
+
+ case CachePolicyRevalidate:
+ if (m_response.cacheControlContainsImmutable() && m_response.url().protocolIs("https")) {
+ if (isExpired())
+ return RevalidationDecision::YesDueToExpired;
+ return RevalidationDecision::No;
}
- if (!m_data)
- return false;
-
- // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
- if (!m_data->hasOneRef())
- return false;
+ return RevalidationDecision::YesDueToCachePolicy;
- m_data->createPurgeableBuffer();
- if (!m_data->hasPurgeableBuffer())
- return false;
+ case CachePolicyVerify:
+ if (m_response.cacheControlContainsNoCache())
+ return RevalidationDecision::YesDueToNoCache;
+ // FIXME: Cache-Control:no-store should prevent storing, not reuse.
+ if (m_response.cacheControlContainsNoStore())
+ return RevalidationDecision::YesDueToNoStore;
- m_purgeableData = m_data->releasePurgeableBuffer();
- m_purgeableData->setPurgePriority(purgePriority());
- m_purgeableData->makePurgeable(true);
- m_data.clear();
- return true;
- }
-
- if (!m_purgeableData)
- return true;
- ASSERT(!m_data);
- ASSERT(!hasClients());
+ if (isExpired())
+ return RevalidationDecision::YesDueToExpired;
- if (!m_purgeableData->makePurgeable(false))
- return false;
-
- m_data = ResourceBuffer::adoptSharedBuffer(SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release()));
- return true;
+ return RevalidationDecision::No;
+ };
+ ASSERT_NOT_REACHED();
+ return RevalidationDecision::No;
}
-bool CachedResource::isPurgeable() const
+bool CachedResource::redirectChainAllowsReuse(ReuseExpiredRedirectionOrNot reuseExpiredRedirection) const
{
- return m_purgeableData && m_purgeableData->isPurgeable();
+ return WebCore::redirectChainAllowsReuse(m_redirectChainCacheStatus, reuseExpiredRedirection);
}
-bool CachedResource::wasPurged() const
+bool CachedResource::varyHeaderValuesMatch(const ResourceRequest& request)
{
- return m_purgeableData && m_purgeableData->wasPurged();
+ if (m_varyingHeaderValues.isEmpty())
+ return true;
+
+ return verifyVaryingRequestHeaders(m_varyingHeaderValues, request, m_sessionID);
}
unsigned CachedResource::overheadSize() const
@@ -855,59 +795,65 @@ unsigned CachedResource::overheadSize() const
return sizeof(CachedResource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
}
-void CachedResource::setLoadPriority(ResourceLoadPriority loadPriority)
+bool CachedResource::areAllClientsXMLHttpRequests() const
{
- if (loadPriority == ResourceLoadPriorityUnresolved)
- loadPriority = defaultPriorityForResourceType(type());
- if (loadPriority == m_loadPriority)
- return;
- m_loadPriority = loadPriority;
- if (m_loader)
- m_loader->didChangePriority(loadPriority);
+ if (type() != RawResource)
+ return false;
+
+ for (auto& client : m_clients) {
+ if (!client.key->isXMLHttpRequest())
+ return false;
+ }
+ return true;
}
-CachedResource::CachedResourceCallback::CachedResourceCallback(CachedResource* resource, CachedResourceClient* client)
- : m_resource(resource)
- , m_client(client)
- , m_callbackTimer(this, &CachedResourceCallback::timerFired)
+void CachedResource::setLoadPriority(const std::optional<ResourceLoadPriority>& loadPriority)
{
- m_callbackTimer.startOneShot(0);
+ if (loadPriority)
+ m_loadPriority = loadPriority.value();
+ else
+ m_loadPriority = defaultPriorityForResourceType(type());
}
-void CachedResource::CachedResourceCallback::cancel()
+inline CachedResource::Callback::Callback(CachedResource& resource, CachedResourceClient& client)
+ : m_resource(resource)
+ , m_client(client)
+ , m_timer(*this, &Callback::timerFired)
{
- if (m_callbackTimer.isActive())
- m_callbackTimer.stop();
+ m_timer.startOneShot(0);
}
-void CachedResource::CachedResourceCallback::timerFired(Timer<CachedResourceCallback>&)
+inline void CachedResource::Callback::cancel()
{
- m_resource->didAddClient(m_client);
+ if (m_timer.isActive())
+ m_timer.stop();
}
-#if ENABLE(DISK_IMAGE_CACHE)
-bool CachedResource::isUsingDiskImageCache() const
+void CachedResource::Callback::timerFired()
{
- return m_data && m_data->isUsingDiskImageCache();
+ m_resource.didAddClient(m_client);
}
-#endif
-#if PLATFORM(MAC)
-void CachedResource::tryReplaceEncodedData(PassRefPtr<SharedBuffer> newBuffer)
+#if USE(FOUNDATION) || USE(SOUP)
+
+void CachedResource::tryReplaceEncodedData(SharedBuffer& newBuffer)
{
if (!m_data)
return;
if (!mayTryReplaceEncodedData())
return;
-
- // Because the disk cache is asynchronous and racey with regards to the data we might be asked to replace,
- // we need to verify that the new buffer has the same contents as our old buffer.
- if (m_data->size() != newBuffer->size() || memcmp(m_data->data(), newBuffer->data(), m_data->size()))
+
+ // We have to do the memcmp because we can't tell if the replacement file backed data is for the
+ // same resource or if we made a second request with the same URL which gave us a different
+ // resource. We have seen this happen for cached POST resources.
+ if (m_data->size() != newBuffer.size() || memcmp(m_data->data(), newBuffer.data(), m_data->size()))
return;
- m_data->tryReplaceSharedBufferContents(newBuffer.get());
+ if (m_data->tryReplaceContentsWithPlatformBuffer(newBuffer))
+ didReplaceSharedBufferContents();
}
+
#endif
}
diff --git a/Source/WebCore/loader/cache/CachedResource.h b/Source/WebCore/loader/cache/CachedResource.h
index 8de69cdbf..6f4e0e1b2 100644
--- a/Source/WebCore/loader/cache/CachedResource.h
+++ b/Source/WebCore/loader/cache/CachedResource.h
@@ -20,37 +20,37 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedResource_h
-#define CachedResource_h
+#pragma once
#include "CachePolicy.h"
+#include "CacheValidation.h"
#include "FrameLoaderTypes.h"
-#include "PurgePriority.h"
#include "ResourceError.h"
#include "ResourceLoadPriority.h"
#include "ResourceLoaderOptions.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "SessionID.h"
#include "Timer.h"
#include <time.h>
#include <wtf/HashCountedSet.h>
#include <wtf/HashSet.h>
-#include <wtf/OwnPtr.h>
+#include <wtf/TypeCasts.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-class MemoryCache;
class CachedResourceClient;
class CachedResourceHandleBase;
class CachedResourceLoader;
-class InspectorResource;
-class PurgeableBuffer;
-class ResourceBuffer;
+class CachedResourceRequest;
+class LoadTiming;
+class MemoryCache;
class SecurityOrigin;
class SharedBuffer;
class SubresourceLoader;
+class TextResourceDecoder;
// A resource that is held in the cache. Classes who want to use this object should derive
// from CachedResourceClient, to get the function calls in case the requested data has arrived.
@@ -58,8 +58,7 @@ class SubresourceLoader;
class CachedResource {
WTF_MAKE_NONCOPYABLE(CachedResource); WTF_MAKE_FAST_ALLOCATED;
friend class MemoryCache;
- friend class InspectorResource;
-
+
public:
enum Type {
MainResource,
@@ -67,10 +66,12 @@ public:
CSSStyleSheet,
Script,
FontResource,
- RawResource
-#if ENABLE(SVG)
- , SVGDocumentResource
+#if ENABLE(SVG_FONTS)
+ SVGFontResource,
#endif
+ MediaResource,
+ RawResource,
+ SVGDocumentResource
#if ENABLE(XSLT)
, XSLStyleSheet
#endif
@@ -91,16 +92,17 @@ public:
DecodeError
};
- CachedResource(const ResourceRequest&, Type);
+ CachedResource(CachedResourceRequest&&, Type, SessionID);
virtual ~CachedResource();
- virtual void load(CachedResourceLoader*, const ResourceLoaderOptions&);
+ virtual void load(CachedResourceLoader&);
virtual void setEncoding(const String&) { }
virtual String encoding() const { return String(); }
- virtual void addDataBuffer(ResourceBuffer*);
+ virtual const TextResourceDecoder* textResourceDecoder() const { return nullptr; }
+ virtual void addDataBuffer(SharedBuffer&);
virtual void addData(const char* data, unsigned length);
- virtual void finishLoading(ResourceBuffer*);
+ virtual void finishLoading(SharedBuffer*);
virtual void error(CachedResource::Status);
void setResourceError(const ResourceError& error) { m_error = error; }
@@ -108,20 +110,20 @@ public:
virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; }
+ const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
ResourceRequest& resourceRequest() { return m_resourceRequest; }
const URL& url() const { return m_resourceRequest.url();}
-#if ENABLE(CACHE_PARTITIONING)
const String& cachePartition() const { return m_resourceRequest.cachePartition(); }
-#endif
- Type type() const { return static_cast<Type>(m_type); }
-
+ SessionID sessionID() const { return m_sessionID; }
+ Type type() const { return m_type; }
+
ResourceLoadPriority loadPriority() const { return m_loadPriority; }
- void setLoadPriority(ResourceLoadPriority);
+ void setLoadPriority(const std::optional<ResourceLoadPriority>&);
- void addClient(CachedResourceClient*);
- void removeClient(CachedResourceClient*);
+ WEBCORE_EXPORT void addClient(CachedResourceClient&);
+ WEBCORE_EXPORT void removeClient(CachedResourceClient&);
bool hasClients() const { return !m_clients.isEmpty() || !m_clientsAwaitingCallback.isEmpty(); }
- bool hasClient(CachedResourceClient* client) { return m_clients.contains(client) || m_clientsAwaitingCallback.contains(client); }
+ bool hasClient(CachedResourceClient& client) { return m_clients.contains(&client) || m_clientsAwaitingCallback.contains(&client); }
bool deleteIfPossible();
enum PreloadResult {
@@ -132,8 +134,8 @@ public:
};
PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); }
- virtual void didAddClient(CachedResourceClient*);
- virtual void didRemoveClient(CachedResourceClient*) { }
+ virtual void didAddClient(CachedResourceClient&);
+ virtual void didRemoveClient(CachedResourceClient&) { }
virtual void allClientsRemoved() { }
void destroyDecodedDataIfNeeded();
@@ -146,7 +148,7 @@ public:
unsigned encodedSize() const { return m_encodedSize; }
unsigned decodedSize() const { return m_decodedSize; }
unsigned 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; }
@@ -155,10 +157,15 @@ public:
SubresourceLoader* loader() { return m_loader.get(); }
- virtual bool isImage() const { return false; }
+ bool areAllClientsXMLHttpRequests() const;
+
+ bool isImage() const { return type() == ImageResource; }
+ // FIXME: CachedRawResource could be a main resource, an audio/video resource, or a raw XHR/icon resource.
+ bool isMainOrMediaOrRawResource() const { return type() == MainResource || type() == MediaResource || type() == RawResource; }
bool ignoreForRequestCount() const
{
- return type() == MainResource
+ return m_resourceRequest.ignoreForRequestCount()
+ || type() == MainResource
#if ENABLE(LINK_PREFETCH)
|| type() == LinkPrefetch
|| type() == LinkSubresource
@@ -169,205 +176,220 @@ public:
unsigned accessCount() const { return m_accessCount; }
void increaseAccessCount() { m_accessCount++; }
- // Computes the status of an object after loading.
+ // Computes the status of an object after loading.
// Updates the expire date on the cache entry file
void finish();
- bool passesAccessControlCheck(SecurityOrigin*);
-
// Called by the cache if the object has been removed from the cache
// while still being referenced. This means the object should delete itself
// if the number of clients observing it ever drops to 0.
// The resource can be brought back to cache after successful revalidation.
void setInCache(bool inCache) { m_inCache = inCache; }
bool inCache() const { return m_inCache; }
-
- bool inLiveDecodedResourcesList() { return m_inLiveDecodedResourcesList; }
-
+
void clearLoader();
- ResourceBuffer* resourceBuffer() const { ASSERT(!m_purgeableData); return m_data.get(); }
+ SharedBuffer* resourceBuffer() const { return m_data.get(); }
- virtual void willSendRequest(ResourceRequest&, const ResourceResponse&) { m_requestedFromNetworkingLayer = true; }
+ virtual void redirectReceived(ResourceRequest&, const ResourceResponse&);
virtual void responseReceived(const ResourceResponse&);
- void setResponse(const ResourceResponse& response) { m_response = response; }
+ virtual bool shouldCacheResponse(const ResourceResponse&) { return true; }
+ void setResponse(const ResourceResponse&);
const ResourceResponse& response() const { return m_response; }
+ void setCrossOrigin();
+ bool isCrossOrigin() const;
+ bool isCORSSameOrigin() const;
+ ResourceResponse::Tainting responseTainting() const { return m_responseTainting; }
+
+ void loadFrom(const CachedResource&);
+
+ SecurityOrigin* origin() const { return m_origin.get(); }
+ AtomicString initiatorName() const { return m_initiatorName; }
+
bool canDelete() const { return !hasClients() && !m_loader && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_proxyResource; }
bool hasOneHandle() const { return m_handleCount == 1; }
bool isExpired() const;
- // List of acceptable MIME types separated by ",".
- // A MIME type may contain a wildcard, e.g. "text/*".
- String accept() const { return m_accept; }
- void setAccept(const String& accept) { m_accept = accept; }
-
void cancelLoad();
bool wasCanceled() const { return m_error.isCancellation(); }
bool errorOccurred() const { return m_status == LoadError || m_status == DecodeError; }
- bool loadFailedOrCanceled() { return !m_error.isNull(); }
+ bool loadFailedOrCanceled() const { return !m_error.isNull(); }
bool shouldSendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; }
DataBufferingPolicy dataBufferingPolicy() const { return m_options.dataBufferingPolicy; }
-
+
+ bool allowsCaching() const { return m_options.cachingPolicy == CachingPolicy::AllowCaching; }
+ const FetchOptions& options() const { return m_options; }
+
virtual void destroyDecodedData() { }
void setOwningCachedResourceLoader(CachedResourceLoader* cachedResourceLoader) { m_owningCachedResourceLoader = cachedResourceLoader; }
-
+
bool isPreloaded() const { return m_preloadCount; }
void increasePreloadCount() { ++m_preloadCount; }
void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
-
- void registerHandle(CachedResourceHandleBase* h);
- void unregisterHandle(CachedResourceHandleBase* h);
-
+ bool isLinkPreload() { return m_isLinkPreload; }
+ void setLinkPreload() { m_isLinkPreload = true; }
+
+ void registerHandle(CachedResourceHandleBase*);
+ WEBCORE_EXPORT void unregisterHandle(CachedResourceHandleBase*);
+
bool canUseCacheValidator() const;
- virtual bool mustRevalidateDueToCacheHeaders(CachePolicy) const;
+ enum class RevalidationDecision { No, YesDueToCachePolicy, YesDueToNoStore, YesDueToNoCache, YesDueToExpired };
+ virtual RevalidationDecision makeRevalidationDecision(CachePolicy) const;
+ bool redirectChainAllowsReuse(ReuseExpiredRedirectionOrNot) const;
+ bool hasRedirections() const { return m_redirectChainCacheStatus.status != RedirectChainCacheStatus::Status::NoRedirection; }
+
+ bool varyHeaderValuesMatch(const ResourceRequest&);
bool isCacheValidator() const { return m_resourceToRevalidate; }
CachedResource* resourceToRevalidate() const { return m_resourceToRevalidate; }
-
- bool isPurgeable() const;
- bool wasPurged() const;
-
- // This is used by the archive machinery to get at a purged resource without
- // triggering a load. We should make it protected again if we can find a
- // better way to handle the archive case.
- bool makePurgeable(bool purgeable);
-
+
// HTTP revalidation support methods for CachedResourceLoader.
void setResourceToRevalidate(CachedResource*);
virtual void switchClientsToRevalidatedResource();
void clearResourceToRevalidate();
void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse);
-
+ bool validationInProgress() const { return m_proxyResource; }
+ bool validationCompleting() const { return m_proxyResource && m_proxyResource->m_switchingClientsToRevalidatedResource; }
+
virtual void didSendData(unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
+ virtual void didRetrieveDerivedDataFromCache(const String& /* type */, SharedBuffer&) { }
+
void setLoadFinishTime(double finishTime) { m_loadFinishTime = finishTime; }
double loadFinishTime() const { return m_loadFinishTime; }
-#if ENABLE(DISK_IMAGE_CACHE)
- bool isUsingDiskImageCache() const;
- virtual bool canUseDiskImageCache() const { return false; }
- virtual void useDiskImageCache() { ASSERT(canUseDiskImageCache()); }
-#endif
-
- virtual bool canReuse(const ResourceRequest&) const { return true; }
-
-#if PLATFORM(MAC)
- void tryReplaceEncodedData(PassRefPtr<SharedBuffer>);
+#if USE(FOUNDATION) || USE(SOUP)
+ WEBCORE_EXPORT void tryReplaceEncodedData(SharedBuffer&);
#endif
#if USE(SOUP)
- virtual char* getOrCreateReadBuffer(size_t /* requestedSize */, size_t& /* actualSize */) { return 0; }
+ virtual char* getOrCreateReadBuffer(size_t /* requestedSize */, size_t& /* actualSize */) { return nullptr; }
#endif
+ unsigned long identifierForLoadWithoutResourceLoader() const { return m_identifierForLoadWithoutResourceLoader; }
+ static ResourceLoadPriority defaultPriorityForResourceType(Type);
+
protected:
- virtual void checkNotify();
+ // CachedResource constructor that may be used when the CachedResource can already be filled with response data.
+ CachedResource(const URL&, Type, SessionID);
void setEncodedSize(unsigned);
void setDecodedSize(unsigned);
void didAccessDecodedData(double timeStamp);
- bool isSafeToMakePurgeable() const;
-
- HashCountedSet<CachedResourceClient*> m_clients;
+ virtual void didReplaceSharedBufferContents() { }
- class CachedResourceCallback {
- public:
- static PassOwnPtr<CachedResourceCallback> schedule(CachedResource* resource, CachedResourceClient* client) { return adoptPtr(new CachedResourceCallback(resource, client)); }
- void cancel();
- private:
- CachedResourceCallback(CachedResource*, CachedResourceClient*);
- void timerFired(Timer<CachedResourceCallback>&);
-
- CachedResource* m_resource;
- CachedResourceClient* m_client;
- Timer<CachedResourceCallback> m_callbackTimer;
- };
- HashMap<CachedResourceClient*, OwnPtr<CachedResourceCallback>> m_clientsAwaitingCallback;
+ virtual void setBodyDataFrom(const CachedResource&);
+ // FIXME: Make the rest of these data members private and use functions in derived classes instead.
+ HashCountedSet<CachedResourceClient*> m_clients;
ResourceRequest m_resourceRequest;
- String m_accept;
RefPtr<SubresourceLoader> m_loader;
ResourceLoaderOptions m_options;
- ResourceLoadPriority m_loadPriority;
-
ResourceResponse m_response;
- double m_responseTimestamp;
-
- RefPtr<ResourceBuffer> m_data;
- OwnPtr<PurgeableBuffer> m_purgeableData;
- DeferrableOneShotTimer<CachedResource> m_decodedDataDeletionTimer;
+ ResourceResponse::Tainting m_responseTainting { ResourceResponse::Tainting::Basic };
+ RefPtr<SharedBuffer> m_data;
+ DeferrableOneShotTimer m_decodedDataDeletionTimer;
private:
- bool addClientToSet(CachedResourceClient*);
+ class Callback;
+
+ bool addClientToSet(CachedResourceClient&);
- void decodedDataDeletionTimerFired(DeferrableOneShotTimer<CachedResource>&);
+ void decodedDataDeletionTimerFired();
- virtual PurgePriority purgePriority() const { return PurgeDefault; }
+ virtual void checkNotify();
virtual bool mayTryReplaceEncodedData() const { return false; }
- double currentAge() const;
- double freshnessLifetime() const;
+ std::chrono::microseconds freshnessLifetime(const ResourceResponse&) const;
- void addAdditionalRequestHeaders(CachedResourceLoader*);
+ void addAdditionalRequestHeaders(CachedResourceLoader&);
void failBeforeStarting();
+ HashMap<CachedResourceClient*, std::unique_ptr<Callback>> m_clientsAwaitingCallback;
+ SessionID m_sessionID;
+ ResourceLoadPriority m_loadPriority;
+ std::chrono::system_clock::time_point m_responseTimestamp;
+
String m_fragmentIdentifierForRequest;
ResourceError m_error;
+ RefPtr<SecurityOrigin> m_origin;
+ AtomicString m_initiatorName;
- double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache
- double m_loadFinishTime;
+ double m_lastDecodedAccessTime { 0 }; // Used as a "thrash guard" in the cache
+ double m_loadFinishTime { 0 };
- unsigned m_encodedSize;
- unsigned m_decodedSize;
- unsigned m_accessCount;
- unsigned m_handleCount;
- unsigned m_preloadCount;
+ unsigned m_encodedSize { 0 };
+ unsigned m_decodedSize { 0 };
+ unsigned m_accessCount { 0 };
+ unsigned m_handleCount { 0 };
+ unsigned m_preloadCount { 0 };
- unsigned m_preloadResult : 2; // PreloadResult
+ PreloadResult m_preloadResult { PreloadNotReferenced };
- bool m_inLiveDecodedResourcesList : 1;
- bool m_requestedFromNetworkingLayer : 1;
+ bool m_requestedFromNetworkingLayer { false };
- bool m_inCache : 1;
- bool m_loading : 1;
+ bool m_inCache { false };
+ bool m_loading { false };
+ bool m_isLinkPreload { false };
- bool m_switchingClientsToRevalidatedResource : 1;
+ bool m_switchingClientsToRevalidatedResource { false };
- unsigned m_type : 4; // Type
- unsigned m_status : 3; // Status
+ Type m_type; // Type
+ unsigned m_status { Pending }; // Status
#ifndef NDEBUG
- bool m_deleted;
- unsigned m_lruIndex;
+ bool m_deleted { false };
+ unsigned m_lruIndex { 0 };
#endif
- CachedResource* m_nextInAllResourcesList;
- CachedResource* m_prevInAllResourcesList;
-
- CachedResource* m_nextInLiveResourcesList;
- CachedResource* m_prevInLiveResourcesList;
+ CachedResourceLoader* m_owningCachedResourceLoader { nullptr }; // only non-null for resources that are not in the cache
- CachedResourceLoader* m_owningCachedResourceLoader; // only non-0 for resources that are not in the cache
-
// 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.
- CachedResource* m_resourceToRevalidate;
+ CachedResource* m_resourceToRevalidate { nullptr };
// If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate).
- CachedResource* m_proxyResource;
+ CachedResource* m_proxyResource { nullptr };
// These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response.
HashSet<CachedResourceHandleBase*> m_handlesToRevalidate;
-};
-}
+ RedirectChainCacheStatus m_redirectChainCacheStatus;
+
+ Vector<std::pair<String, String>> m_varyingHeaderValues;
+
+ unsigned long m_identifierForLoadWithoutResourceLoader { 0 };
+};
+class CachedResource::Callback {
+#if !COMPILER(MSVC)
+ WTF_MAKE_FAST_ALLOCATED;
#endif
+public:
+ Callback(CachedResource&, CachedResourceClient&);
+
+ void cancel();
+
+private:
+ void timerFired();
+
+ CachedResource& m_resource;
+ CachedResourceClient& m_client;
+ Timer m_timer;
+};
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(ToClassName, CachedResourceType) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToClassName) \
+ static bool isType(const WebCore::CachedResource& resource) { return resource.type() == WebCore::CachedResourceType; } \
+SPECIALIZE_TYPE_TRAITS_END()
diff --git a/Source/WebCore/loader/cache/CachedResourceClient.h b/Source/WebCore/loader/cache/CachedResourceClient.h
index 402ff91a1..17c361d71 100644
--- a/Source/WebCore/loader/cache/CachedResourceClient.h
+++ b/Source/WebCore/loader/cache/CachedResourceClient.h
@@ -21,39 +21,33 @@
This class provides all functionality needed for loading images, style sheets and html
pages from the web. It has a memory cache for these objects.
*/
-
-#ifndef CachedResourceClient_h
-#define CachedResourceClient_h
-
-#include <wtf/FastMalloc.h>
+#pragma once
namespace WebCore {
+
class CachedResource;
class CachedResourceClient {
- WTF_MAKE_FAST_ALLOCATED;
public:
enum CachedResourceClientType {
BaseResourceType,
ImageType,
FontType,
StyleSheetType,
-#if ENABLE(SVG)
SVGDocumentType,
-#endif
RawResourceType
};
virtual ~CachedResourceClient() { }
- virtual void notifyFinished(CachedResource*) { }
- virtual void deprecatedDidReceiveCachedResource(CachedResource*) { }
-
+ virtual void notifyFinished(CachedResource&) { }
+ virtual void deprecatedDidReceiveCachedResource(CachedResource&) { }
+ virtual bool isXMLHttpRequest() const { return false; }
+
static CachedResourceClientType expectedType() { return BaseResourceType; }
virtual CachedResourceClientType resourceClientType() const { return expectedType(); }
protected:
CachedResourceClient() { }
};
-}
-#endif
+}
diff --git a/Source/WebCore/loader/cache/CachedResourceClientWalker.h b/Source/WebCore/loader/cache/CachedResourceClientWalker.h
index de352f037..39ee0234f 100644
--- a/Source/WebCore/loader/cache/CachedResourceClientWalker.h
+++ b/Source/WebCore/loader/cache/CachedResourceClientWalker.h
@@ -22,8 +22,7 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef CachedResourceClientWalker_h
-#define CachedResourceClientWalker_h
+#pragma once
#include "CachedResourceClient.h"
#include <wtf/HashCountedSet.h>
@@ -56,7 +55,7 @@ public:
}
}
- return 0;
+ return nullptr;
}
private:
const HashCountedSet<CachedResourceClient*>& m_clientSet;
@@ -64,6 +63,4 @@ private:
size_t m_index;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedResourceHandle.cpp b/Source/WebCore/loader/cache/CachedResourceHandle.cpp
index 07c84ed70..097276e93 100644
--- a/Source/WebCore/loader/cache/CachedResourceHandle.cpp
+++ b/Source/WebCore/loader/cache/CachedResourceHandle.cpp
@@ -31,7 +31,7 @@
namespace WebCore {
CachedResourceHandleBase::CachedResourceHandleBase()
- : m_resource(0)
+ : m_resource(nullptr)
{
}
diff --git a/Source/WebCore/loader/cache/CachedResourceHandle.h b/Source/WebCore/loader/cache/CachedResourceHandle.h
index 5b6b42540..3dbbda6c1 100644
--- a/Source/WebCore/loader/cache/CachedResourceHandle.h
+++ b/Source/WebCore/loader/cache/CachedResourceHandle.h
@@ -23,9 +23,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedResourceHandle_h
-#define CachedResourceHandle_h
+#pragma once
+#include "PlatformExportMacros.h"
#include <wtf/Forward.h>
namespace WebCore {
@@ -49,7 +49,7 @@ protected:
CachedResourceHandleBase(CachedResource*);
CachedResourceHandleBase(const CachedResourceHandleBase&);
- void setResource(CachedResource*);
+ WEBCORE_EXPORT void setResource(CachedResource*);
private:
CachedResourceHandleBase& operator=(const CachedResourceHandleBase&) { return *this; }
@@ -68,6 +68,7 @@ public:
R* get() const { return reinterpret_cast<R*>(CachedResourceHandleBase::get()); }
R* operator->() const { return get(); }
+ R& operator*() const { ASSERT(get()); return *get(); }
CachedResourceHandle& operator=(R* res) { setResource(res); return *this; }
CachedResourceHandle& operator=(const CachedResourceHandle& o) { setResource(o.get()); return *this; }
@@ -95,5 +96,3 @@ template <class R, class RR> bool operator!=(const RR* res, const CachedResource
}
} // namespace WebCore
-
-#endif // CachedResourceHandle
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;
+}
+
}
diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.h b/Source/WebCore/loader/cache/CachedResourceLoader.h
index bcc793e0c..23eb1dd6f 100644
--- a/Source/WebCore/loader/cache/CachedResourceLoader.h
+++ b/Source/WebCore/loader/cache/CachedResourceLoader.h
@@ -23,14 +23,15 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef CachedResourceLoader_h
-#define CachedResourceLoader_h
+#pragma once
#include "CachePolicy.h"
#include "CachedResource.h"
#include "CachedResourceHandle.h"
#include "CachedResourceRequest.h"
+#include "ContentSecurityPolicy.h"
#include "ResourceLoadPriority.h"
+#include "ResourceTimingInformation.h"
#include "Timer.h"
#include <wtf/Deque.h>
#include <wtf/HashMap.h>
@@ -68,28 +69,26 @@ friend class ImageLoader;
friend class ResourceCacheValidationSuppressor;
public:
- static PassRef<CachedResourceLoader> create(DocumentLoader* documentLoader) { return adoptRef(*new CachedResourceLoader(documentLoader)); }
+ static Ref<CachedResourceLoader> create(DocumentLoader* documentLoader) { return adoptRef(*new CachedResourceLoader(documentLoader)); }
~CachedResourceLoader();
- CachedResourceHandle<CachedImage> requestImage(CachedResourceRequest&);
- CachedResourceHandle<CachedCSSStyleSheet> requestCSSStyleSheet(CachedResourceRequest&);
- CachedResourceHandle<CachedCSSStyleSheet> requestUserCSSStyleSheet(CachedResourceRequest&);
- CachedResourceHandle<CachedScript> requestScript(CachedResourceRequest&);
- CachedResourceHandle<CachedFont> requestFont(CachedResourceRequest&);
- CachedResourceHandle<CachedRawResource> requestRawResource(CachedResourceRequest&);
- CachedResourceHandle<CachedRawResource> requestMainResource(CachedResourceRequest&);
-
-#if ENABLE(SVG)
- CachedResourceHandle<CachedSVGDocument> requestSVGDocument(CachedResourceRequest&);
-#endif
+ CachedResourceHandle<CachedImage> requestImage(CachedResourceRequest&&);
+ CachedResourceHandle<CachedCSSStyleSheet> requestCSSStyleSheet(CachedResourceRequest&&);
+ CachedResourceHandle<CachedCSSStyleSheet> requestUserCSSStyleSheet(CachedResourceRequest&&);
+ CachedResourceHandle<CachedScript> requestScript(CachedResourceRequest&&);
+ CachedResourceHandle<CachedFont> requestFont(CachedResourceRequest&&, bool isSVG);
+ CachedResourceHandle<CachedRawResource> requestMedia(CachedResourceRequest&&);
+ CachedResourceHandle<CachedRawResource> requestRawResource(CachedResourceRequest&&);
+ CachedResourceHandle<CachedRawResource> requestMainResource(CachedResourceRequest&&);
+ CachedResourceHandle<CachedSVGDocument> requestSVGDocument(CachedResourceRequest&&);
#if ENABLE(XSLT)
- CachedResourceHandle<CachedXSLStyleSheet> requestXSLStyleSheet(CachedResourceRequest&);
+ CachedResourceHandle<CachedXSLStyleSheet> requestXSLStyleSheet(CachedResourceRequest&&);
#endif
#if ENABLE(LINK_PREFETCH)
- CachedResourceHandle<CachedResource> requestLinkResource(CachedResource::Type, CachedResourceRequest&);
+ CachedResourceHandle<CachedResource> requestLinkResource(CachedResource::Type, CachedResourceRequest&&);
#endif
#if ENABLE(VIDEO_TRACK)
- CachedResourceHandle<CachedTextTrack> requestTextTrack(CachedResourceRequest&);
+ CachedResourceHandle<CachedTextTrack> requestTextTrack(CachedResourceRequest&&);
#endif
// Logs an access denied message to the console for the specified URL.
@@ -97,67 +96,89 @@ public:
CachedResource* cachedResource(const String& url) const;
CachedResource* cachedResource(const URL& url) const;
-
+
typedef HashMap<String, CachedResourceHandle<CachedResource>> DocumentResourceMap;
const DocumentResourceMap& allCachedResources() const { return m_documentResources; }
bool autoLoadImages() const { return m_autoLoadImages; }
void setAutoLoadImages(bool);
+ bool imagesEnabled() const { return m_imagesEnabled; }
void setImagesEnabled(bool);
bool shouldDeferImageLoad(const URL&) const;
+ bool shouldPerformImageLoad(const URL&) const;
CachePolicy cachePolicy(CachedResource::Type) const;
Frame* frame() const; // Can be null
Document* document() const { return m_document; } // Can be null
void setDocument(Document* document) { m_document = document; }
- void clearDocumentLoader() { m_documentLoader = 0; }
+ void clearDocumentLoader() { m_documentLoader = nullptr; }
+ SessionID sessionID() const;
- void removeCachedResource(CachedResource*) const;
+ void removeCachedResource(CachedResource&);
- void loadDone(CachedResource*, bool shouldPerformPostLoadActions = true);
+ void loadDone(bool shouldPerformPostLoadActions = true);
- void garbageCollectDocumentResources();
-
- void incrementRequestCount(const CachedResource*);
- void decrementRequestCount(const CachedResource*);
+ WEBCORE_EXPORT void garbageCollectDocumentResources();
+
+ void incrementRequestCount(const CachedResource&);
+ void decrementRequestCount(const CachedResource&);
int requestCount() const { return m_requestCount; }
- bool isPreloaded(const String& urlString) const;
- void clearPreloads();
- void clearPendingPreloads();
- void preload(CachedResource::Type, CachedResourceRequest&, const String& charset);
- void checkForPendingPreloads();
+ WEBCORE_EXPORT bool isPreloaded(const String& urlString) const;
+ enum class ClearPreloadsMode { ClearSpeculativePreloads, ClearAllPreloads };
+ void clearPreloads(ClearPreloadsMode);
+ CachedResourceHandle<CachedResource> preload(CachedResource::Type, CachedResourceRequest&&);
void printPreloadStats();
- bool canRequest(CachedResource::Type, const URL&, const ResourceLoaderOptions&, bool forPreload = false);
+
+ bool updateRequestAfterRedirection(CachedResource::Type, ResourceRequest&, const ResourceLoaderOptions&);
static const ResourceLoaderOptions& defaultCachedResourceOptions();
+ void documentDidFinishLoadEvent();
+
+#if ENABLE(WEB_TIMING)
+ ResourceTimingInformation& resourceTimingInformation() { return m_resourceTimingInfo; }
+#endif
+
+ bool isAlwaysOnLoggingAllowed() const;
+
private:
explicit CachedResourceLoader(DocumentLoader*);
- CachedResourceHandle<CachedResource> requestResource(CachedResource::Type, CachedResourceRequest&);
- CachedResourceHandle<CachedResource> revalidateResource(const CachedResourceRequest&, CachedResource*);
- CachedResourceHandle<CachedResource> loadResource(CachedResource::Type, CachedResourceRequest&, const String& charset);
-#if ENABLE(RESOURCE_TIMING)
- void storeResourceTimingInitiatorInformation(const CachedResourceHandle<CachedResource>&, const CachedResourceRequest&);
-#endif
- void requestPreload(CachedResource::Type, CachedResourceRequest&, const String& charset);
+ enum class ForPreload { Yes, No };
+ enum class DeferOption { NoDefer, DeferredByClient };
+
+ CachedResourceHandle<CachedResource> requestResource(CachedResource::Type, CachedResourceRequest&&, ForPreload = ForPreload::No, DeferOption = DeferOption::NoDefer);
+ CachedResourceHandle<CachedResource> revalidateResource(CachedResourceRequest&&, CachedResource&);
+ CachedResourceHandle<CachedResource> loadResource(CachedResource::Type, CachedResourceRequest&&);
+
+ void prepareFetch(CachedResource::Type, CachedResourceRequest&);
+ void updateHTTPRequestHeaders(CachedResource::Type, CachedResourceRequest&);
+ void updateReferrerOriginAndUserAgentHeaders(CachedResourceRequest&);
+
+ bool canRequest(CachedResource::Type, const URL&, const CachedResourceRequest&, ForPreload);
enum RevalidationPolicy { Use, Revalidate, Reload, Load };
- RevalidationPolicy determineRevalidationPolicy(CachedResource::Type, ResourceRequest&, bool forPreload, CachedResource* existingResource, CachedResourceRequest::DeferOption) const;
-
- bool shouldContinueAfterNotifyingLoadedFromMemoryCache(CachedResource*);
+ RevalidationPolicy determineRevalidationPolicy(CachedResource::Type, CachedResourceRequest&, CachedResource* existingResource, ForPreload, DeferOption) const;
+
+ bool shouldUpdateCachedResourceWithCurrentRequest(const CachedResource&, const CachedResourceRequest&);
+ CachedResourceHandle<CachedResource> updateCachedResourceWithCurrentRequest(const CachedResource&, CachedResourceRequest&&);
+
+ bool shouldContinueAfterNotifyingLoadedFromMemoryCache(const CachedResourceRequest&, CachedResource*);
bool checkInsecureContent(CachedResource::Type, const URL&) const;
+ bool allowedByContentSecurityPolicy(CachedResource::Type, const URL&, const ResourceLoaderOptions&, ContentSecurityPolicy::RedirectResponseReceived) const;
- void garbageCollectDocumentResourcesTimerFired(Timer<CachedResourceLoader>&);
void performPostLoadActions();
bool clientDefersImage(const URL&) const;
void reloadImagesIfNotDeferred();
-
+
+ bool canRequestAfterRedirection(CachedResource::Type, const URL&, const ResourceLoaderOptions&) const;
+ bool canRequestInContentDispositionAttachmentSandbox(CachedResource::Type, const URL&) const;
+
HashSet<String> m_validatedURLs;
mutable DocumentResourceMap m_documentResources;
Document* m_document;
@@ -165,22 +186,12 @@ private:
int m_requestCount;
- OwnPtr<ListHashSet<CachedResource*>> m_preloads;
- struct PendingPreload {
- CachedResource::Type m_type;
- CachedResourceRequest m_request;
- String m_charset;
- };
- Deque<PendingPreload> m_pendingPreloads;
-
- Timer<CachedResourceLoader> m_garbageCollectDocumentResourcesTimer;
-
-#if ENABLE(RESOURCE_TIMING)
- struct InitiatorInfo {
- AtomicString name;
- double startTime;
- };
- HashMap<CachedResource*, InitiatorInfo> m_initiatorMap;
+ std::unique_ptr<ListHashSet<CachedResource*>> m_preloads;
+
+ Timer m_garbageCollectDocumentResourcesTimer;
+
+#if ENABLE(WEB_TIMING)
+ ResourceTimingInformation m_resourceTimingInfo;
#endif
// 29 bits left
@@ -193,25 +204,19 @@ class ResourceCacheValidationSuppressor {
WTF_MAKE_NONCOPYABLE(ResourceCacheValidationSuppressor);
WTF_MAKE_FAST_ALLOCATED;
public:
- ResourceCacheValidationSuppressor(CachedResourceLoader* loader)
+ ResourceCacheValidationSuppressor(CachedResourceLoader& loader)
: m_loader(loader)
- , m_previousState(false)
+ , m_previousState(m_loader.m_allowStaleResources)
{
- if (m_loader) {
- m_previousState = m_loader->m_allowStaleResources;
- m_loader->m_allowStaleResources = true;
- }
+ m_loader.m_allowStaleResources = true;
}
~ResourceCacheValidationSuppressor()
{
- if (m_loader)
- m_loader->m_allowStaleResources = m_previousState;
+ m_loader.m_allowStaleResources = m_previousState;
}
private:
- CachedResourceLoader* m_loader;
+ CachedResourceLoader& m_loader;
bool m_previousState;
};
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/cache/CachedResourceRequest.cpp b/Source/WebCore/loader/cache/CachedResourceRequest.cpp
index 55a493859..a5ac5637a 100644
--- a/Source/WebCore/loader/cache/CachedResourceRequest.cpp
+++ b/Source/WebCore/loader/cache/CachedResourceRequest.cpp
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -27,52 +27,49 @@
#include "CachedResourceRequest.h"
#include "CachedResourceLoader.h"
+#include "ContentExtensionActions.h"
+#include "CrossOriginAccessControl.h"
#include "Document.h"
#include "Element.h"
+#include "FrameLoader.h"
+#include "HTTPHeaderValues.h"
+#include "MemoryCache.h"
+#include "SecurityPolicy.h"
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
-CachedResourceRequest::CachedResourceRequest(const ResourceRequest& resourceRequest, const String& charset, ResourceLoadPriority priority)
- : m_resourceRequest(resourceRequest)
- , m_charset(charset)
- , m_options(CachedResourceLoader::defaultCachedResourceOptions())
- , m_priority(priority)
- , m_forPreload(false)
- , m_defer(NoDefer)
-{
-}
-
-CachedResourceRequest::CachedResourceRequest(const ResourceRequest& resourceRequest, const ResourceLoaderOptions& options)
- : m_resourceRequest(resourceRequest)
+CachedResourceRequest::CachedResourceRequest(ResourceRequest&& resourceRequest, const ResourceLoaderOptions& options, std::optional<ResourceLoadPriority> priority, String&& charset)
+ : m_resourceRequest(WTFMove(resourceRequest))
+ , m_charset(WTFMove(charset))
, m_options(options)
- , m_priority(ResourceLoadPriorityUnresolved)
- , m_forPreload(false)
- , m_defer(NoDefer)
-{
-}
-
-CachedResourceRequest::CachedResourceRequest(const ResourceRequest& resourceRequest, ResourceLoadPriority priority)
- : m_resourceRequest(resourceRequest)
- , m_options(CachedResourceLoader::defaultCachedResourceOptions())
, m_priority(priority)
- , m_forPreload(false)
- , m_defer(NoDefer)
+ , m_fragmentIdentifier(splitFragmentIdentifierFromRequestURL(m_resourceRequest))
{
}
-CachedResourceRequest::~CachedResourceRequest()
+String CachedResourceRequest::splitFragmentIdentifierFromRequestURL(ResourceRequest& request)
{
+ if (!MemoryCache::shouldRemoveFragmentIdentifier(request.url()))
+ return { };
+ URL url = request.url();
+ String fragmentIdentifier = url.fragmentIdentifier();
+ url.removeFragmentIdentifier();
+ request.setURL(url);
+ return fragmentIdentifier;
}
-void CachedResourceRequest::setInitiator(PassRefPtr<Element> element)
+void CachedResourceRequest::setInitiator(Element& element)
{
- ASSERT(!m_initiatorElement && m_initiatorName.isEmpty());
- m_initiatorElement = element;
+ ASSERT(!m_initiatorElement);
+ ASSERT(m_initiatorName.isEmpty());
+ m_initiatorElement = &element;
}
void CachedResourceRequest::setInitiator(const AtomicString& name)
{
- ASSERT(!m_initiatorElement && m_initiatorName.isEmpty());
+ ASSERT(!m_initiatorElement);
+ ASSERT(m_initiatorName.isEmpty());
m_initiatorName = name;
}
@@ -83,8 +80,198 @@ const AtomicString& CachedResourceRequest::initiatorName() const
if (!m_initiatorName.isEmpty())
return m_initiatorName;
- DEFINE_STATIC_LOCAL(AtomicString, defaultName, ("resource", AtomicString::ConstructFromLiteral));
+ static NeverDestroyed<AtomicString> defaultName("other", AtomicString::ConstructFromLiteral);
return defaultName;
}
+void CachedResourceRequest::setAsPotentiallyCrossOrigin(const String& mode, Document& document)
+{
+ ASSERT(m_options.mode == FetchOptions::Mode::NoCors);
+
+ m_origin = &document.securityOrigin();
+
+ if (mode.isNull())
+ return;
+
+ m_options.mode = FetchOptions::Mode::Cors;
+
+ FetchOptions::Credentials credentials = equalLettersIgnoringASCIICase(mode, "omit")
+ ? FetchOptions::Credentials::Omit : equalLettersIgnoringASCIICase(mode, "use-credentials")
+ ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin;
+ m_options.credentials = credentials;
+ m_options.allowCredentials = credentials == FetchOptions::Credentials::Include ? AllowStoredCredentials : DoNotAllowStoredCredentials;
+ WebCore::updateRequestForAccessControl(m_resourceRequest, document.securityOrigin(), m_options.allowCredentials);
+}
+
+void CachedResourceRequest::updateForAccessControl(Document& document)
+{
+ ASSERT(m_options.mode == FetchOptions::Mode::Cors);
+
+ m_origin = &document.securityOrigin();
+ WebCore::updateRequestForAccessControl(m_resourceRequest, *m_origin, m_options.allowCredentials);
+}
+
+void upgradeInsecureResourceRequestIfNeeded(ResourceRequest& request, Document& document)
+{
+ URL url = request.url();
+
+ ASSERT(document.contentSecurityPolicy());
+ document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(url, ContentSecurityPolicy::InsecureRequestType::Load);
+
+ if (url == request.url())
+ return;
+
+ request.setURL(url);
+}
+
+void CachedResourceRequest::upgradeInsecureRequestIfNeeded(Document& document)
+{
+ upgradeInsecureResourceRequestIfNeeded(m_resourceRequest, document);
+}
+
+void CachedResourceRequest::setDomainForCachePartition(Document& document)
+{
+ m_resourceRequest.setDomainForCachePartition(document.topOrigin().domainForCachePartition());
+}
+
+static inline String acceptHeaderValueFromType(CachedResource::Type type)
+{
+ switch (type) {
+ case CachedResource::Type::MainResource:
+ return ASCIILiteral("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+ case CachedResource::Type::ImageResource:
+ return ASCIILiteral("image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5");
+ case CachedResource::Type::CSSStyleSheet:
+ return ASCIILiteral("text/css,*/*;q=0.1");
+ case CachedResource::Type::SVGDocumentResource:
+ return ASCIILiteral("image/svg+xml");
+#if ENABLE(XSLT)
+ case CachedResource::Type::XSLStyleSheet:
+ // FIXME: This should accept more general xml formats */*+xml, image/svg+xml for example.
+ return ASCIILiteral("text/xml,application/xml,application/xhtml+xml,text/xsl,application/rss+xml,application/atom+xml");
+#endif
+ default:
+ return ASCIILiteral("*/*");
+ }
+}
+
+void CachedResourceRequest::setAcceptHeaderIfNone(CachedResource::Type type)
+{
+ if (!m_resourceRequest.hasHTTPHeader(HTTPHeaderName::Accept))
+ m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::Accept, acceptHeaderValueFromType(type));
+}
+
+void CachedResourceRequest::updateAccordingCacheMode()
+{
+ if (m_options.cache == FetchOptions::Cache::Default
+ && (m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfModifiedSince)
+ || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfNoneMatch)
+ || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfUnmodifiedSince)
+ || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfMatch)
+ || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfRange)))
+ m_options.cache = FetchOptions::Cache::NoStore;
+
+ switch (m_options.cache) {
+ case FetchOptions::Cache::NoCache:
+ m_resourceRequest.setCachePolicy(RefreshAnyCacheData);
+ m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::CacheControl, HTTPHeaderValues::maxAge0());
+ break;
+ case FetchOptions::Cache::NoStore:
+ m_options.cachingPolicy = CachingPolicy::DisallowCaching;
+ m_resourceRequest.setCachePolicy(DoNotUseAnyCache);
+ m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::Pragma, HTTPHeaderValues::noCache());
+ m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::CacheControl, HTTPHeaderValues::noCache());
+ break;
+ case FetchOptions::Cache::Reload:
+ m_resourceRequest.setCachePolicy(ReloadIgnoringCacheData);
+ m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::Pragma, HTTPHeaderValues::noCache());
+ m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::CacheControl, HTTPHeaderValues::noCache());
+ break;
+ case FetchOptions::Cache::Default:
+ break;
+ case FetchOptions::Cache::ForceCache:
+ m_resourceRequest.setCachePolicy(ReturnCacheDataElseLoad);
+ break;
+ case FetchOptions::Cache::OnlyIfCached:
+ m_resourceRequest.setCachePolicy(ReturnCacheDataDontLoad);
+ break;
+ }
+}
+
+void CachedResourceRequest::removeFragmentIdentifierIfNeeded()
+{
+ URL url = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
+ if (url.string() != m_resourceRequest.url())
+ m_resourceRequest.setURL(url);
+}
+
+#if ENABLE(CONTENT_EXTENSIONS)
+
+void CachedResourceRequest::applyBlockedStatus(const ContentExtensions::BlockedStatus& blockedStatus)
+{
+ ContentExtensions::applyBlockedStatusToRequest(blockedStatus, m_resourceRequest);
+}
+
+#endif
+
+void CachedResourceRequest::updateReferrerOriginAndUserAgentHeaders(FrameLoader& frameLoader, ReferrerPolicy defaultPolicy)
+{
+ // Implementing step 7 to 9 of https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
+
+ String outgoingOrigin;
+ String outgoingReferrer = m_resourceRequest.httpReferrer();
+ if (!outgoingReferrer.isNull())
+ outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
+ else {
+ outgoingReferrer = frameLoader.outgoingReferrer();
+ outgoingOrigin = frameLoader.outgoingOrigin();
+ }
+
+ // FIXME: Refactor SecurityPolicy::generateReferrerHeader to align with new terminology used in https://w3c.github.io/webappsec-referrer-policy.
+ switch (m_options.referrerPolicy) {
+ case FetchOptions::ReferrerPolicy::EmptyString: {
+ outgoingReferrer = SecurityPolicy::generateReferrerHeader(defaultPolicy, m_resourceRequest.url(), outgoingReferrer);
+ break; }
+ case FetchOptions::ReferrerPolicy::NoReferrerWhenDowngrade:
+ outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Default, m_resourceRequest.url(), outgoingReferrer);
+ break;
+ case FetchOptions::ReferrerPolicy::NoReferrer:
+ outgoingReferrer = String();
+ break;
+ case FetchOptions::ReferrerPolicy::Origin:
+ outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Origin, m_resourceRequest.url(), outgoingReferrer);
+ break;
+ case FetchOptions::ReferrerPolicy::OriginWhenCrossOrigin:
+ if (isRequestCrossOrigin(m_origin.get(), m_resourceRequest.url(), m_options))
+ outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Origin, m_resourceRequest.url(), outgoingReferrer);
+ break;
+ case FetchOptions::ReferrerPolicy::UnsafeUrl:
+ break;
+ };
+
+ if (outgoingReferrer.isEmpty())
+ m_resourceRequest.clearHTTPReferrer();
+ else
+ m_resourceRequest.setHTTPReferrer(outgoingReferrer);
+ FrameLoader::addHTTPOriginIfNeeded(m_resourceRequest, outgoingOrigin);
+
+ frameLoader.applyUserAgent(m_resourceRequest);
+}
+
+bool isRequestCrossOrigin(SecurityOrigin* origin, const URL& requestURL, const ResourceLoaderOptions& options)
+{
+ if (!origin)
+ return false;
+
+ // Using same origin mode guarantees the loader will not do a cross-origin load, so we let it take care of it and just return false.
+ if (options.mode == FetchOptions::Mode::SameOrigin)
+ return false;
+
+ // FIXME: We should remove options.sameOriginDataURLFlag once https://github.com/whatwg/fetch/issues/393 is fixed.
+ if (requestURL.protocolIsData() && options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set)
+ return false;
+
+ return !origin->canRequest(requestURL);
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedResourceRequest.h b/Source/WebCore/loader/cache/CachedResourceRequest.h
index 0122c9958..1030b3660 100644
--- a/Source/WebCore/loader/cache/CachedResourceRequest.h
+++ b/Source/WebCore/loader/cache/CachedResourceRequest.h
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,55 +23,83 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedResourceRequest_h
-#define CachedResourceRequest_h
+#pragma once
+#include "CachedResource.h"
+#include "DocumentLoader.h"
#include "Element.h"
#include "ResourceLoadPriority.h"
#include "ResourceLoaderOptions.h"
#include "ResourceRequest.h"
+#include "SecurityOrigin.h"
#include <wtf/RefPtr.h>
#include <wtf/text/AtomicString.h>
namespace WebCore {
+
+namespace ContentExtensions {
+struct BlockedStatus;
+}
+
class Document;
+class FrameLoader;
+enum class ReferrerPolicy;
+
+bool isRequestCrossOrigin(SecurityOrigin*, const URL& requestURL, const ResourceLoaderOptions&);
class CachedResourceRequest {
public:
- enum DeferOption { NoDefer, DeferredByClient };
-
- explicit CachedResourceRequest(const ResourceRequest&, const String& charset = String(), ResourceLoadPriority = ResourceLoadPriorityUnresolved);
- CachedResourceRequest(const ResourceRequest&, const ResourceLoaderOptions&);
- CachedResourceRequest(const ResourceRequest&, ResourceLoadPriority);
- ~CachedResourceRequest();
+ CachedResourceRequest(ResourceRequest&&, const ResourceLoaderOptions&, std::optional<ResourceLoadPriority> = std::nullopt, String&& charset = String());
- ResourceRequest& mutableResourceRequest() { return m_resourceRequest; }
+ ResourceRequest&& releaseResourceRequest() { return WTFMove(m_resourceRequest); }
const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
const String& charset() const { return m_charset; }
void setCharset(const String& charset) { m_charset = charset; }
const ResourceLoaderOptions& options() const { return m_options; }
void setOptions(const ResourceLoaderOptions& options) { m_options = options; }
- void setPriority(ResourceLoadPriority priority) { m_priority = priority; }
- ResourceLoadPriority priority() const { return m_priority; }
- bool forPreload() const { return m_forPreload; }
- void setForPreload(bool forPreload) { m_forPreload = forPreload; }
- DeferOption defer() const { return m_defer; }
- void setDefer(DeferOption defer) { m_defer = defer; }
- void setInitiator(PassRefPtr<Element>);
+ const std::optional<ResourceLoadPriority>& priority() const { return m_priority; }
+ void setInitiator(Element&);
void setInitiator(const AtomicString& name);
const AtomicString& initiatorName() const;
+ bool allowsCaching() const { return m_options.cachingPolicy == CachingPolicy::AllowCaching; }
+ void setCachingPolicy(CachingPolicy policy) { m_options.cachingPolicy = policy; }
+
+ void setAsPotentiallyCrossOrigin(const String&, Document&);
+ void updateForAccessControl(Document&);
+
+ void updateReferrerOriginAndUserAgentHeaders(FrameLoader&, ReferrerPolicy);
+ void upgradeInsecureRequestIfNeeded(Document&);
+ void setAcceptHeaderIfNone(CachedResource::Type);
+ void updateAccordingCacheMode();
+ void removeFragmentIdentifierIfNeeded();
+#if ENABLE(CONTENT_EXTENSIONS)
+ void applyBlockedStatus(const ContentExtensions::BlockedStatus&);
+#endif
+ void setDomainForCachePartition(Document&);
+ bool isLinkPreload() const { return m_isLinkPreload; }
+ void setIsLinkPreload() { m_isLinkPreload = true; }
+
+ void setOrigin(Ref<SecurityOrigin>&& origin) { m_origin = WTFMove(origin); }
+ RefPtr<SecurityOrigin> releaseOrigin() { return WTFMove(m_origin); }
+ SecurityOrigin* origin() const { return m_origin.get(); }
+
+ String&& releaseFragmentIdentifier() { return WTFMove(m_fragmentIdentifier); }
+ void clearFragmentIdentifier() { m_fragmentIdentifier = { }; }
+
+ static String splitFragmentIdentifierFromRequestURL(ResourceRequest&);
private:
ResourceRequest m_resourceRequest;
String m_charset;
ResourceLoaderOptions m_options;
- ResourceLoadPriority m_priority;
- bool m_forPreload;
- DeferOption m_defer;
+ std::optional<ResourceLoadPriority> m_priority;
RefPtr<Element> m_initiatorElement;
AtomicString m_initiatorName;
+ RefPtr<SecurityOrigin> m_origin;
+ String m_fragmentIdentifier;
+ bool m_isLinkPreload { false };
};
-} // namespace WebCore
+void upgradeInsecureResourceRequestIfNeeded(ResourceRequest&, Document&);
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedResourceRequestInitiators.cpp b/Source/WebCore/loader/cache/CachedResourceRequestInitiators.cpp
index 91a17b66b..b339a8e58 100644
--- a/Source/WebCore/loader/cache/CachedResourceRequestInitiators.cpp
+++ b/Source/WebCore/loader/cache/CachedResourceRequestInitiators.cpp
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -30,6 +30,7 @@ namespace WebCore {
CachedResourceRequestInitiators::CachedResourceRequestInitiators()
: css("css", AtomicString::ConstructFromLiteral)
+ , fetch("fetch", AtomicString::ConstructFromLiteral)
, icon("icon", AtomicString::ConstructFromLiteral)
, xmlhttprequest("xmlhttprequest", AtomicString::ConstructFromLiteral)
{
diff --git a/Source/WebCore/loader/cache/CachedResourceRequestInitiators.h b/Source/WebCore/loader/cache/CachedResourceRequestInitiators.h
index 24ac2387d..50538cafd 100644
--- a/Source/WebCore/loader/cache/CachedResourceRequestInitiators.h
+++ b/Source/WebCore/loader/cache/CachedResourceRequestInitiators.h
@@ -13,7 +13,7 @@
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedResourceRequestInitiators_h
-#define CachedResourceRequestInitiators_h
+#pragma once
#include "ThreadGlobalData.h"
#include <wtf/text/AtomicString.h>
@@ -32,12 +31,14 @@
namespace WebCore {
struct CachedResourceRequestInitiators {
+ CachedResourceRequestInitiators();
+
const AtomicString css;
+ const AtomicString fetch;
const AtomicString icon;
const AtomicString xmlhttprequest;
WTF_MAKE_NONCOPYABLE(CachedResourceRequestInitiators); WTF_MAKE_FAST_ALLOCATED;
private:
- CachedResourceRequestInitiators();
friend class ThreadGlobalData;
};
@@ -47,5 +48,3 @@ inline const CachedResourceRequestInitiators& cachedResourceRequestInitiators()
}
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/cache/CachedSVGDocument.cpp b/Source/WebCore/loader/cache/CachedSVGDocument.cpp
index 15946263f..08b40169d 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocument.cpp
+++ b/Source/WebCore/loader/cache/CachedSVGDocument.cpp
@@ -21,22 +21,16 @@
*/
#include "config.h"
-
-#if ENABLE(SVG)
#include "CachedSVGDocument.h"
-#include "CachedResourceClient.h"
-#include "CachedResourceHandle.h"
-#include "ResourceBuffer.h"
-#include <wtf/text/StringBuilder.h>
+#include "SharedBuffer.h"
namespace WebCore {
-CachedSVGDocument::CachedSVGDocument(const ResourceRequest& request)
- : CachedResource(request, SVGDocumentResource)
+CachedSVGDocument::CachedSVGDocument(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedResource(WTFMove(request), SVGDocumentResource, sessionID)
, m_decoder(TextResourceDecoder::create("application/xml"))
{
- setAccept("image/svg+xml");
}
CachedSVGDocument::~CachedSVGDocument()
@@ -53,20 +47,14 @@ String CachedSVGDocument::encoding() const
return m_decoder->encoding().name();
}
-void CachedSVGDocument::finishLoading(ResourceBuffer* data)
+void CachedSVGDocument::finishLoading(SharedBuffer* data)
{
if (data) {
- StringBuilder decodedText;
- decodedText.append(m_decoder->decode(data->data(), data->size()));
- decodedText.append(m_decoder->flush());
// We don't need to create a new frame because the new document belongs to the parent UseElement.
- m_document = SVGDocument::create(0, response().url());
- m_document->setContent(decodedText.toString());
+ m_document = SVGDocument::create(nullptr, response().url());
+ m_document->setContent(m_decoder->decodeAndFlush(data->data(), data->size()));
}
CachedResource::finishLoading(data);
}
}
-
-#endif
-
diff --git a/Source/WebCore/loader/cache/CachedSVGDocument.h b/Source/WebCore/loader/cache/CachedSVGDocument.h
index d6a6f5d4e..7981f1de0 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocument.h
+++ b/Source/WebCore/loader/cache/CachedSVGDocument.h
@@ -20,10 +20,8 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedSVGDocument_h
-#define CachedSVGDocument_h
+#pragma once
-#if ENABLE(SVG)
#include "CachedResource.h"
#include "CachedResourceHandle.h"
#include "SVGDocument.h"
@@ -33,24 +31,22 @@ namespace WebCore {
class CachedSVGDocument final : public CachedResource {
public:
- explicit CachedSVGDocument(const ResourceRequest&);
+ explicit CachedSVGDocument(CachedResourceRequest&&, SessionID);
virtual ~CachedSVGDocument();
SVGDocument* document() const { return m_document.get(); }
-protected:
+private:
+ bool mayTryReplaceEncodedData() const override { return true; }
+ void setEncoding(const String&) override;
+ String encoding() const override;
+ const TextResourceDecoder* textResourceDecoder() const override { return m_decoder.get(); }
+ void finishLoading(SharedBuffer*) override;
+
RefPtr<SVGDocument> m_document;
RefPtr<TextResourceDecoder> m_decoder;
-
-private:
- virtual bool mayTryReplaceEncodedData() const override { return true; }
- virtual void setEncoding(const String&) override;
- virtual String encoding() const override;
- virtual void finishLoading(ResourceBuffer*) override;
};
} // namespace WebCore
-#endif // USE(SVG)
-
-#endif // CachedSVGDocument_h
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedSVGDocument, CachedResource::SVGDocumentResource)
diff --git a/Source/WebCore/loader/cache/CachedSVGDocumentClient.h b/Source/WebCore/loader/cache/CachedSVGDocumentClient.h
index a01e0aee9..499dcd10e 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocumentClient.h
+++ b/Source/WebCore/loader/cache/CachedSVGDocumentClient.h
@@ -20,26 +20,17 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef CachedSVGDocumentClient_h
-#define CachedSVGDocumentClient_h
-
-#if ENABLE(SVG)
+#pragma once
#include "CachedResourceClient.h"
namespace WebCore {
-class CachedSVGDocument;
-
class CachedSVGDocumentClient : public CachedResourceClient {
public:
virtual ~CachedSVGDocumentClient() { }
static CachedResourceClientType expectedType() { return SVGDocumentType; }
- virtual CachedResourceClientType resourceClientType() const override { return expectedType(); }
+ CachedResourceClientType resourceClientType() const override { return expectedType(); }
};
} // namespace WebCore
-
-#endif // ENABLE(SVG)
-
-#endif // CachedSVGDocumentClient_h
diff --git a/Source/WebCore/loader/cache/CachedSVGDocumentReference.cpp b/Source/WebCore/loader/cache/CachedSVGDocumentReference.cpp
index 116f20e88..a9bf7c66e 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocumentReference.cpp
+++ b/Source/WebCore/loader/cache/CachedSVGDocumentReference.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "CachedSVGDocumentReference.h"
-#if ENABLE(SVG) && ENABLE(CSS_FILTERS)
#include "CachedResourceHandle.h"
#include "CachedResourceLoader.h"
#include "CachedResourceRequest.h"
@@ -37,7 +36,7 @@ namespace WebCore {
CachedSVGDocumentReference::CachedSVGDocumentReference(const String& url)
: m_url(url)
- , m_document(0)
+ , m_document(nullptr)
, m_loadRequested(false)
{
}
@@ -45,24 +44,23 @@ CachedSVGDocumentReference::CachedSVGDocumentReference(const String& url)
CachedSVGDocumentReference::~CachedSVGDocumentReference()
{
if (m_document)
- m_document->removeClient(this);
+ m_document->removeClient(*this);
}
-void CachedSVGDocumentReference::load(CachedResourceLoader* loader)
+void CachedSVGDocumentReference::load(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
{
- ASSERT(loader);
if (m_loadRequested)
return;
- CachedResourceRequest request(ResourceRequest(loader->document()->completeURL(m_url)));
+ auto fetchOptions = options;
+ fetchOptions.mode = FetchOptions::Mode::SameOrigin;
+ CachedResourceRequest request(ResourceRequest(loader.document()->completeURL(m_url)), fetchOptions);
request.setInitiator(cachedResourceRequestInitiators().css);
- m_document = loader->requestSVGDocument(request);
+ m_document = loader.requestSVGDocument(WTFMove(request));
if (m_document)
- m_document->addClient(this);
+ m_document->addClient(*this);
m_loadRequested = true;
}
}
-
-#endif
diff --git a/Source/WebCore/loader/cache/CachedSVGDocumentReference.h b/Source/WebCore/loader/cache/CachedSVGDocumentReference.h
index a297abcf8..70cb1afa4 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocumentReference.h
+++ b/Source/WebCore/loader/cache/CachedSVGDocumentReference.h
@@ -23,10 +23,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedSVGDocumentReference_h
-#define CachedSVGDocumentReference_h
+#pragma once
-#if ENABLE(SVG) && ENABLE(CSS_FILTERS)
#include "CachedResourceHandle.h"
#include "CachedSVGDocumentClient.h"
#include <wtf/text/WTFString.h>
@@ -35,6 +33,7 @@ namespace WebCore {
class CachedSVGDocument;
class CachedResourceLoader;
+struct ResourceLoaderOptions;
class CachedSVGDocumentReference : public CachedSVGDocumentClient {
public:
@@ -42,7 +41,7 @@ public:
virtual ~CachedSVGDocumentReference();
- void load(CachedResourceLoader*);
+ void load(CachedResourceLoader&, const ResourceLoaderOptions&);
bool loadRequested() const { return m_loadRequested; }
CachedSVGDocument* document() { return m_document.get(); }
@@ -53,8 +52,4 @@ private:
bool m_loadRequested;
};
-};
-
-#endif // ENABLE(SVG) && ENABLE(CSS_FILTERS)
-
-#endif // CachedSVGDocumentReference_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/cache/CachedSVGFont.cpp b/Source/WebCore/loader/cache/CachedSVGFont.cpp
new file mode 100644
index 000000000..a06641256
--- /dev/null
+++ b/Source/WebCore/loader/cache/CachedSVGFont.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CachedSVGFont.h"
+
+#if ENABLE(SVG_FONTS)
+
+#include "FontDescription.h"
+#include "FontPlatformData.h"
+#include "NoEventDispatchAssertion.h"
+#include "SVGDocument.h"
+#include "SVGFontElement.h"
+#include "SVGFontFaceElement.h"
+#include "SharedBuffer.h"
+#include "TextResourceDecoder.h"
+#include "TypedElementDescendantIterator.h"
+#include "SVGToOTFFontConversion.h"
+
+#if USE(DIRECT2D)
+#include <dwrite.h>
+#endif
+
+namespace WebCore {
+
+CachedSVGFont::CachedSVGFont(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedFont(WTFMove(request), sessionID, SVGFontResource)
+ , m_externalSVGFontElement(nullptr)
+{
+}
+
+RefPtr<Font> CachedSVGFont::createFont(const FontDescription& fontDescription, const AtomicString& remoteURI, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings)
+{
+ if (firstFontFace(remoteURI))
+ return CachedFont::createFont(fontDescription, remoteURI, syntheticBold, syntheticItalic, fontFaceFeatures, fontFaceVariantSettings);
+ return nullptr;
+}
+
+FontPlatformData CachedSVGFont::platformDataFromCustomData(const FontDescription& fontDescription, bool bold, bool italic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings)
+{
+ if (m_externalSVGDocument)
+ return FontPlatformData(fontDescription.computedPixelSize(), bold, italic);
+ return CachedFont::platformDataFromCustomData(fontDescription, bold, italic, fontFaceFeatures, fontFaceVariantSettings);
+}
+
+bool CachedSVGFont::ensureCustomFontData(const AtomicString& remoteURI)
+{
+ if (!m_externalSVGDocument && !errorOccurred() && !isLoading() && m_data) {
+ bool sawError = false;
+ {
+ // We may get here during render tree updates when events are forbidden.
+ // Frameless document can't run scripts or call back to the client so this is safe.
+ m_externalSVGDocument = SVGDocument::create(nullptr, URL());
+ auto decoder = TextResourceDecoder::create("application/xml");
+
+ NoEventDispatchAssertion::EventAllowedScope allowedScope(*m_externalSVGDocument);
+
+ m_externalSVGDocument->setContent(decoder->decodeAndFlush(m_data->data(), m_data->size()));
+ sawError = decoder->sawError();
+ }
+
+ if (sawError)
+ m_externalSVGDocument = nullptr;
+ if (m_externalSVGDocument)
+ maybeInitializeExternalSVGFontElement(remoteURI);
+ if (!m_externalSVGFontElement)
+ return false;
+ if (auto convertedFont = convertSVGToOTFFont(*m_externalSVGFontElement))
+ m_convertedFont = SharedBuffer::adoptVector(convertedFont.value());
+ else {
+ m_externalSVGDocument = nullptr;
+ m_externalSVGFontElement = nullptr;
+ return false;
+ }
+ }
+
+ return m_externalSVGDocument && CachedFont::ensureCustomFontData(m_convertedFont.get());
+}
+
+SVGFontElement* CachedSVGFont::getSVGFontById(const String& fontName) const
+{
+ ASSERT(m_externalSVGDocument);
+ auto elements = descendantsOfType<SVGFontElement>(*m_externalSVGDocument);
+
+ if (fontName.isEmpty())
+ return elements.first();
+
+ for (auto& element : elements) {
+ if (element.getIdAttribute() == fontName)
+ return &element;
+ }
+ return nullptr;
+}
+
+SVGFontElement* CachedSVGFont::maybeInitializeExternalSVGFontElement(const AtomicString& remoteURI)
+{
+ if (m_externalSVGFontElement)
+ return m_externalSVGFontElement;
+ String fragmentIdentifier;
+ size_t start = remoteURI.find('#');
+ if (start != notFound)
+ fragmentIdentifier = remoteURI.string().substring(start + 1);
+ m_externalSVGFontElement = getSVGFontById(fragmentIdentifier);
+ return m_externalSVGFontElement;
+}
+
+SVGFontFaceElement* CachedSVGFont::firstFontFace(const AtomicString& remoteURI)
+{
+ if (!maybeInitializeExternalSVGFontElement(remoteURI))
+ return nullptr;
+
+ if (auto* firstFontFace = childrenOfType<SVGFontFaceElement>(*m_externalSVGFontElement).first())
+ return firstFontFace;
+ return nullptr;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/loader/cache/CachedSVGFont.h b/Source/WebCore/loader/cache/CachedSVGFont.h
new file mode 100644
index 000000000..93ed7a0c4
--- /dev/null
+++ b/Source/WebCore/loader/cache/CachedSVGFont.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(SVG_FONTS)
+
+#include "CachedFont.h"
+
+namespace WebCore {
+
+class SVGFontFaceElement;
+
+class CachedSVGFont final : public CachedFont {
+public:
+ CachedSVGFont(CachedResourceRequest&&, SessionID);
+
+ bool ensureCustomFontData(const AtomicString& remoteURI) override;
+
+ RefPtr<Font> createFont(const FontDescription&, const AtomicString& remoteURI, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings&, const FontVariantSettings&) override;
+
+private:
+ FontPlatformData platformDataFromCustomData(const FontDescription&, bool bold, bool italic, const FontFeatureSettings&, const FontVariantSettings&);
+
+ SVGFontElement* getSVGFontById(const String&) const;
+
+ SVGFontElement* maybeInitializeExternalSVGFontElement(const AtomicString& remoteURI);
+ SVGFontFaceElement* firstFontFace(const AtomicString& remoteURI);
+
+ RefPtr<SharedBuffer> m_convertedFont;
+ RefPtr<SVGDocument> m_externalSVGDocument;
+ SVGFontElement* m_externalSVGFontElement;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedSVGFont, CachedResource::SVGFontResource)
+
+#endif // ENABLE(SVG_FONTS)
diff --git a/Source/WebCore/loader/cache/CachedScript.cpp b/Source/WebCore/loader/cache/CachedScript.cpp
index 48facd7bc..84de38ebe 100644
--- a/Source/WebCore/loader/cache/CachedScript.cpp
+++ b/Source/WebCore/loader/cache/CachedScript.cpp
@@ -29,24 +29,20 @@
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
+#include "CachedResourceRequest.h"
+#include "HTTPHeaderNames.h"
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
-#include "MemoryCache.h"
-#include "ResourceBuffer.h"
#include "RuntimeApplicationChecks.h"
+#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
-#include <wtf/Vector.h>
namespace WebCore {
-CachedScript::CachedScript(const ResourceRequest& resourceRequest, const String& charset)
- : CachedResource(resourceRequest, Script)
- , m_decoder(TextResourceDecoder::create(ASCIILiteral("application/javascript"), charset))
+CachedScript::CachedScript(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedResource(WTFMove(request), Script, sessionID)
+ , m_decoder(TextResourceDecoder::create(ASCIILiteral("application/javascript"), request.charset()))
{
- // It's javascript we want.
- // But some websites think their scripts are <some wrong mimetype here>
- // and refuse to serve them if we only accept application/x-javascript.
- setAccept("*/*");
}
CachedScript::~CachedScript()
@@ -65,27 +61,55 @@ String CachedScript::encoding() const
String CachedScript::mimeType() const
{
- return extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type")).lower();
+ return extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType)).convertToASCIILowercase();
}
-const String& CachedScript::script()
+StringView CachedScript::script()
{
- ASSERT(!isPurgeable());
+ if (!m_data)
+ return { };
- if (!m_script && m_data) {
- m_script = m_decoder->decode(m_data->data(), encodedSize());
- m_script.append(m_decoder->flush());
+ if (m_decodingState == NeverDecoded
+ && TextEncoding(encoding()).isByteBasedEncoding()
+ && m_data->size()
+ && charactersAreAllASCII(reinterpret_cast<const LChar*>(m_data->data()), m_data->size())) {
+
+ m_decodingState = DataAndDecodedStringHaveSameBytes;
+
+ // If the encoded and decoded data are the same, there is no decoded data cost!
+ setDecodedSize(0);
+ m_decodedDataDeletionTimer.stop();
+
+ m_scriptHash = StringHasher::computeHashAndMaskTop8Bits(reinterpret_cast<const LChar*>(m_data->data()), m_data->size());
+ }
+
+ if (m_decodingState == DataAndDecodedStringHaveSameBytes)
+ return { reinterpret_cast<const LChar*>(m_data->data()), m_data->size() };
+
+ if (!m_script) {
+ m_script = m_decoder->decodeAndFlush(m_data->data(), encodedSize());
+ ASSERT(!m_scriptHash || m_scriptHash == m_script.impl()->hash());
+ if (m_decodingState == NeverDecoded)
+ m_scriptHash = m_script.impl()->hash();
+ m_decodingState = DataAndDecodedStringHaveDifferentBytes;
setDecodedSize(m_script.sizeInBytes());
}
+
m_decodedDataDeletionTimer.restart();
-
return m_script;
}
-void CachedScript::finishLoading(ResourceBuffer* data)
+unsigned CachedScript::scriptHash()
+{
+ if (m_decodingState == NeverDecoded)
+ script();
+ return m_scriptHash;
+}
+
+void CachedScript::finishLoading(SharedBuffer* data)
{
m_data = data;
- setEncodedSize(m_data.get() ? m_data->size() : 0);
+ setEncodedSize(data ? data->size() : 0);
CachedResource::finishLoading(data);
}
@@ -93,27 +117,40 @@ void CachedScript::destroyDecodedData()
{
m_script = String();
setDecodedSize(0);
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
- makePurgeable(true);
+}
+
+void CachedScript::setBodyDataFrom(const CachedResource& resource)
+{
+ ASSERT(resource.type() == type());
+ auto& script = static_cast<const CachedScript&>(resource);
+
+ CachedResource::setBodyDataFrom(resource);
+
+ m_script = script.m_script;
+ m_scriptHash = script.m_scriptHash;
+ m_decodingState = script.m_decodingState;
+ m_decoder = script.m_decoder;
}
#if ENABLE(NOSNIFF)
bool CachedScript::mimeTypeAllowedByNosniff() const
{
- return !parseContentTypeOptionsHeader(m_response.httpHeaderField("X-Content-Type-Options")) == ContentTypeOptionsNosniff || MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType());
+ return parseContentTypeOptionsHeader(m_response.httpHeaderField(HTTPHeaderName::XContentTypeOptions)) != ContentTypeOptionsNosniff || MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType());
}
#endif
bool CachedScript::shouldIgnoreHTTPStatusCodeErrors() const
{
+#if PLATFORM(MAC)
// This is a workaround for <rdar://problem/13916291>
// REGRESSION (r119759): Adobe Flash Player "smaller" installer relies on the incorrect firing
// of a load event and needs an app-specific hack for compatibility.
// The installer in question tries to load .js file that doesn't exist, causing the server to
// return a 404 response. Normally, this would trigger an error event to be dispatched, but the
// installer expects a load event instead so we work around it here.
- if (applicationIsSolidStateNetworksDownloader())
+ if (MacApplication::isSolidStateNetworksDownloader())
return true;
+#endif
return CachedResource::shouldIgnoreHTTPStatusCodeErrors();
}
diff --git a/Source/WebCore/loader/cache/CachedScript.h b/Source/WebCore/loader/cache/CachedScript.h
index 80b073c2a..f8898d378 100644
--- a/Source/WebCore/loader/cache/CachedScript.h
+++ b/Source/WebCore/loader/cache/CachedScript.h
@@ -23,44 +23,51 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef CachedScript_h
-#define CachedScript_h
+#pragma once
#include "CachedResource.h"
namespace WebCore {
- class CachedResourceLoader;
- class TextResourceDecoder;
+class TextResourceDecoder;
- class CachedScript final : public CachedResource {
- public:
- CachedScript(const ResourceRequest&, const String& charset);
- virtual ~CachedScript();
+class CachedScript final : public CachedResource {
+public:
+ CachedScript(CachedResourceRequest&&, SessionID);
+ virtual ~CachedScript();
- const String& script();
+ StringView script();
+ unsigned scriptHash();
- String mimeType() const;
+ String mimeType() const;
#if ENABLE(NOSNIFF)
- bool mimeTypeAllowedByNosniff() const;
+ bool mimeTypeAllowedByNosniff() const;
#endif
- private:
- virtual PurgePriority purgePriority() const override { return PurgeLast; }
- virtual bool mayTryReplaceEncodedData() const override { return true; }
+private:
+ bool mayTryReplaceEncodedData() const final { return true; }
- virtual bool shouldIgnoreHTTPStatusCodeErrors() const override;
+ bool shouldIgnoreHTTPStatusCodeErrors() const final;
- virtual void setEncoding(const String&) override;
- virtual String encoding() const override;
- virtual void finishLoading(ResourceBuffer*) override;
+ void setEncoding(const String&) final;
+ String encoding() const final;
+ const TextResourceDecoder* textResourceDecoder() const final { return m_decoder.get(); }
+ void finishLoading(SharedBuffer*) final;
- virtual void destroyDecodedData() override;
+ void destroyDecodedData() final;
- String m_script;
- RefPtr<TextResourceDecoder> m_decoder;
- };
-}
+ void setBodyDataFrom(const CachedResource&) final;
-#endif
+ String m_script;
+ unsigned m_scriptHash { 0 };
+
+ enum DecodingState { NeverDecoded, DataAndDecodedStringHaveSameBytes, DataAndDecodedStringHaveDifferentBytes };
+ DecodingState m_decodingState { NeverDecoded };
+
+ RefPtr<TextResourceDecoder> m_decoder;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedScript, CachedResource::Script)
diff --git a/Source/WebCore/loader/cache/CachedStyleSheetClient.h b/Source/WebCore/loader/cache/CachedStyleSheetClient.h
index eed2d3a3e..c2f187389 100644
--- a/Source/WebCore/loader/cache/CachedStyleSheetClient.h
+++ b/Source/WebCore/loader/cache/CachedStyleSheetClient.h
@@ -23,8 +23,7 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef CachedStyleSheetClient_h
-#define CachedStyleSheetClient_h
+#pragma once
#include "CachedResourceClient.h"
#include <wtf/Forward.h>
@@ -38,11 +37,9 @@ class CachedStyleSheetClient : public CachedResourceClient {
public:
virtual ~CachedStyleSheetClient() { }
static CachedResourceClientType expectedType() { return StyleSheetType; }
- virtual CachedResourceClientType resourceClientType() const override { return expectedType(); }
+ CachedResourceClientType resourceClientType() const override { return expectedType(); }
virtual void setCSSStyleSheet(const String& /* href */, const URL& /* baseURL */, const String& /* charset */, const CachedCSSStyleSheet*) { }
virtual void setXSLStyleSheet(const String& /* href */, const URL& /* baseURL */, const String& /* sheet */) { }
};
} // namespace WebCore
-
-#endif // CachedStyleSheetClient_h
diff --git a/Source/WebCore/loader/cache/CachedTextTrack.cpp b/Source/WebCore/loader/cache/CachedTextTrack.cpp
index 94974a591..1d82bd71b 100644
--- a/Source/WebCore/loader/cache/CachedTextTrack.cpp
+++ b/Source/WebCore/loader/cache/CachedTextTrack.cpp
@@ -32,36 +32,36 @@
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
#include "CachedResourceLoader.h"
-#include "ResourceBuffer.h"
#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
-#include <wtf/Vector.h>
namespace WebCore {
-CachedTextTrack::CachedTextTrack(const ResourceRequest& resourceRequest)
- : CachedResource(resourceRequest, TextTrackResource)
+CachedTextTrack::CachedTextTrack(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedResource(WTFMove(request), TextTrackResource, sessionID)
{
}
-CachedTextTrack::~CachedTextTrack()
+void CachedTextTrack::updateData(SharedBuffer* data)
{
-}
-
-void CachedTextTrack::addDataBuffer(ResourceBuffer* data)
-{
- ASSERT(m_options.dataBufferingPolicy == BufferData);
+ ASSERT(dataBufferingPolicy() == BufferData);
m_data = data;
- setEncodedSize(m_data.get() ? m_data->size() : 0);
+ setEncodedSize(data ? data->size() : 0);
CachedResourceClientWalker<CachedResourceClient> walker(m_clients);
- while (CachedResourceClient *client = walker.next())
- client->deprecatedDidReceiveCachedResource(this);
+ while (CachedResourceClient* client = walker.next())
+ client->deprecatedDidReceiveCachedResource(*this);
+}
+
+void CachedTextTrack::addDataBuffer(SharedBuffer& data)
+{
+ updateData(&data);
+ CachedResource::addDataBuffer(data);
}
-void CachedTextTrack::finishLoading(ResourceBuffer* data)
+void CachedTextTrack::finishLoading(SharedBuffer* data)
{
- addDataBuffer(data);
+ updateData(data);
CachedResource::finishLoading(data);
}
diff --git a/Source/WebCore/loader/cache/CachedTextTrack.h b/Source/WebCore/loader/cache/CachedTextTrack.h
index 0df56e2d3..adf544a1b 100644
--- a/Source/WebCore/loader/cache/CachedTextTrack.h
+++ b/Source/WebCore/loader/cache/CachedTextTrack.h
@@ -23,28 +23,29 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedTextTrack_h
-#define CachedTextTrack_h
+#pragma once
#if ENABLE(VIDEO_TRACK)
#include "CachedResource.h"
-#include "FontOrientation.h"
+#include "TextFlags.h"
namespace WebCore {
class CachedTextTrack final : public CachedResource {
public:
- CachedTextTrack(const ResourceRequest&);
- virtual ~CachedTextTrack();
+ CachedTextTrack(CachedResourceRequest&&, SessionID);
private:
- virtual bool mayTryReplaceEncodedData() const override { return true; }
- virtual void addDataBuffer(ResourceBuffer*) override;
- virtual void finishLoading(ResourceBuffer*) override;
+ bool mayTryReplaceEncodedData() const override { return true; }
+ void addDataBuffer(SharedBuffer&) override;
+ void finishLoading(SharedBuffer*) override;
+
+ void updateData(SharedBuffer*);
};
-}
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedTextTrack, CachedResource::TextTrackResource)
-#endif
-#endif
+#endif // ENABLE(VIDEO_TRACK)
diff --git a/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp b/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
index eb6c8e1fe..c9f0dc87a 100644
--- a/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
+++ b/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
@@ -29,28 +29,28 @@
#include "CachedResourceClientWalker.h"
#include "CachedStyleSheetClient.h"
-#include "ResourceBuffer.h"
+#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
-#include <wtf/Vector.h>
namespace WebCore {
#if ENABLE(XSLT)
-CachedXSLStyleSheet::CachedXSLStyleSheet(const ResourceRequest& resourceRequest)
- : CachedResource(resourceRequest, XSLStyleSheet)
+CachedXSLStyleSheet::CachedXSLStyleSheet(CachedResourceRequest&& request, SessionID sessionID)
+ : CachedResource(WTFMove(request), XSLStyleSheet, sessionID)
, m_decoder(TextResourceDecoder::create("text/xsl"))
{
- // It's XML we want.
- // FIXME: This should accept more general xml formats */*+xml, image/svg+xml for example.
- setAccept("text/xml, application/xml, application/xhtml+xml, text/xsl, application/rss+xml, application/atom+xml");
}
-void CachedXSLStyleSheet::didAddClient(CachedResourceClient* c)
-{
- ASSERT(c->resourceClientType() == CachedStyleSheetClient::expectedType());
+CachedXSLStyleSheet::~CachedXSLStyleSheet()
+{
+}
+
+void CachedXSLStyleSheet::didAddClient(CachedResourceClient& client)
+{
+ ASSERT(client.resourceClientType() == CachedStyleSheetClient::expectedType());
if (!isLoading())
- static_cast<CachedStyleSheetClient*>(c)->setXSLStyleSheet(m_resourceRequest.url(), m_response.url(), m_sheet);
+ static_cast<CachedStyleSheetClient&>(client).setXSLStyleSheet(m_resourceRequest.url(), m_response.url(), m_sheet);
}
void CachedXSLStyleSheet::setEncoding(const String& chs)
@@ -63,14 +63,12 @@ String CachedXSLStyleSheet::encoding() const
return m_decoder->encoding().name();
}
-void CachedXSLStyleSheet::finishLoading(ResourceBuffer* data)
+void CachedXSLStyleSheet::finishLoading(SharedBuffer* data)
{
m_data = data;
- setEncodedSize(m_data.get() ? m_data->size() : 0);
- if (m_data.get()) {
- m_sheet = m_decoder->decode(m_data->data(), encodedSize());
- m_sheet.append(m_decoder->flush());
- }
+ setEncodedSize(data ? data->size() : 0);
+ if (data)
+ m_sheet = m_decoder->decodeAndFlush(data->data(), encodedSize());
setLoading(false);
checkNotify();
}
diff --git a/Source/WebCore/loader/cache/CachedXSLStyleSheet.h b/Source/WebCore/loader/cache/CachedXSLStyleSheet.h
index 307bda691..3ef0f600e 100644
--- a/Source/WebCore/loader/cache/CachedXSLStyleSheet.h
+++ b/Source/WebCore/loader/cache/CachedXSLStyleSheet.h
@@ -23,42 +23,38 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef CachedXSLStyleSheet_h
-#define CachedXSLStyleSheet_h
+#pragma once
+
+#if ENABLE(XSLT)
#include "CachedResource.h"
-#include <wtf/Vector.h>
namespace WebCore {
- class CachedResourceLoader;
- class TextResourceDecoder;
-
-#if ENABLE(XSLT)
- class CachedXSLStyleSheet final : public CachedResource {
- public:
- CachedXSLStyleSheet(const ResourceRequest&);
-
- const String& sheet() const { return m_sheet; }
-
- protected:
- virtual void checkNotify() override;
+class TextResourceDecoder;
- String m_sheet;
- RefPtr<TextResourceDecoder> m_decoder;
+class CachedXSLStyleSheet final : public CachedResource {
+public:
+ CachedXSLStyleSheet(CachedResourceRequest&&, SessionID);
+ virtual ~CachedXSLStyleSheet();
- private:
- virtual bool mayTryReplaceEncodedData() const override { return true; }
+ const String& sheet() const { return m_sheet; }
- virtual void didAddClient(CachedResourceClient*) override;
+private:
+ void checkNotify() final;
+ bool mayTryReplaceEncodedData() const final { return true; }
+ void didAddClient(CachedResourceClient&) final;
+ void setEncoding(const String&) final;
+ String encoding() const final;
+ const TextResourceDecoder* textResourceDecoder() const final { return m_decoder.get(); }
+ void finishLoading(SharedBuffer*) final;
- virtual void setEncoding(const String&) override;
- virtual String encoding() const override;
- virtual void finishLoading(ResourceBuffer*) override;
- };
+ String m_sheet;
+ RefPtr<TextResourceDecoder> m_decoder;
+};
-#endif
+} // namespace WebCore
-}
+SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedXSLStyleSheet, CachedResource::XSLStyleSheet)
-#endif
+#endif // ENABLE(XSLT)
diff --git a/Source/WebCore/loader/cache/MemoryCache.cpp b/Source/WebCore/loader/cache/MemoryCache.cpp
index 652422cf6..75ee84bb7 100644
--- a/Source/WebCore/loader/cache/MemoryCache.cpp
+++ b/Source/WebCore/loader/cache/MemoryCache.cpp
@@ -25,9 +25,9 @@
#include "BitmapImage.h"
#include "CachedImage.h"
+#include "CachedImageClient.h"
#include "CachedResource.h"
#include "CachedResourceHandle.h"
-#include "CrossThreadTask.h"
#include "Document.h"
#include "FrameLoader.h"
#include "FrameLoaderTypes.h"
@@ -35,166 +35,156 @@
#include "Image.h"
#include "Logging.h"
#include "PublicSuffix.h"
-#include "SecurityOrigin.h"
-#include "SecurityOriginHash.h"
+#include "SharedBuffer.h"
#include "WorkerGlobalScope.h"
#include "WorkerLoaderProxy.h"
#include "WorkerThread.h"
#include <stdio.h>
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
-#include <wtf/TemporaryChange.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/SetForScope.h>
#include <wtf/text/CString.h>
-#if ENABLE(DISK_IMAGE_CACHE)
-#include "DiskImageCacheIOS.h"
-#include "ResourceBuffer.h"
-#endif
-
namespace WebCore {
static const int cDefaultCacheCapacity = 8192 * 1024;
static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
static const float cTargetPrunePercentage = .95f; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
-static const double cDefaultDecodedDataDeletionInterval = 0;
+static const auto defaultDecodedDataDeletionInterval = std::chrono::seconds { 0 };
-MemoryCache* memoryCache()
+MemoryCache& MemoryCache::singleton()
{
- static MemoryCache* staticCache = new MemoryCache;
ASSERT(WTF::isMainThread());
-
- return staticCache;
+ static NeverDestroyed<MemoryCache> memoryCache;
+ return memoryCache;
}
MemoryCache::MemoryCache()
: m_disabled(false)
- , m_pruneEnabled(true)
, m_inPruneResources(false)
, m_capacity(cDefaultCacheCapacity)
, m_minDeadCapacity(0)
, m_maxDeadCapacity(cDefaultCacheCapacity)
- , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval)
+ , m_deadDecodedDataDeletionInterval(defaultDecodedDataDeletionInterval)
, m_liveSize(0)
, m_deadSize(0)
+ , m_pruneTimer(*this, &MemoryCache::prune)
{
+ static_assert(sizeof(long long) > sizeof(unsigned), "Numerical overflow can happen when adjusting the size of the cached memory.");
}
-URL MemoryCache::removeFragmentIdentifierIfNeeded(const URL& originalURL)
+auto MemoryCache::sessionResourceMap(SessionID sessionID) const -> CachedResourceMap*
+{
+ ASSERT(sessionID.isValid());
+ return m_sessionResources.get(sessionID);
+}
+
+auto MemoryCache::ensureSessionResourceMap(SessionID sessionID) -> CachedResourceMap&
+{
+ ASSERT(sessionID.isValid());
+ auto& map = m_sessionResources.add(sessionID, nullptr).iterator->value;
+ if (!map)
+ map = std::make_unique<CachedResourceMap>();
+ return *map;
+}
+
+bool MemoryCache::shouldRemoveFragmentIdentifier(const URL& originalURL)
{
if (!originalURL.hasFragmentIdentifier())
- return originalURL;
+ return false;
// Strip away fragment identifier from HTTP URLs.
- // Data URLs must be unmodified. For file and custom URLs clients may expect resources
+ // Data URLs must be unmodified. For file and custom URLs clients may expect resources
// to be unique even when they differ by the fragment identifier only.
- if (!originalURL.protocolIsInHTTPFamily())
+ return originalURL.protocolIsInHTTPFamily();
+}
+
+URL MemoryCache::removeFragmentIdentifierIfNeeded(const URL& originalURL)
+{
+ if (!shouldRemoveFragmentIdentifier(originalURL))
return originalURL;
URL url = originalURL;
url.removeFragmentIdentifier();
return url;
}
-bool MemoryCache::add(CachedResource* resource)
+bool MemoryCache::add(CachedResource& resource)
{
if (disabled())
return false;
ASSERT(WTF::isMainThread());
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem* originMap = m_resources.get(resource->url());
- if (!originMap) {
- originMap = new CachedResourceItem;
- m_resources.set(resource->url(), adoptPtr(originMap));
- }
- originMap->set(resource->cachePartition(), resource);
-#else
- m_resources.set(resource->url(), resource);
-#endif
- resource->setInCache(true);
+ auto key = std::make_pair(resource.url(), resource.cachePartition());
+
+ ensureSessionResourceMap(resource.sessionID()).set(key, &resource);
+ resource.setInCache(true);
resourceAccessed(resource);
- LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource->url().string().latin1().data(), resource);
+ LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource.url().string().latin1().data(), &resource);
return true;
}
-void MemoryCache::revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse& response)
+void MemoryCache::revalidationSucceeded(CachedResource& revalidatingResource, const ResourceResponse& response)
{
- CachedResource* resource = revalidatingResource->resourceToRevalidate();
- ASSERT(resource);
- ASSERT(!resource->inCache());
- ASSERT(resource->isLoaded());
- ASSERT(revalidatingResource->inCache());
+ ASSERT(revalidatingResource.resourceToRevalidate());
+ CachedResource& resource = *revalidatingResource.resourceToRevalidate();
+ ASSERT(!resource.inCache());
+ ASSERT(resource.isLoaded());
- // Calling evict() can potentially delete revalidatingResource, which we use
+ // Calling remove() can potentially delete revalidatingResource, which we use
// below. This mustn't be the case since revalidation means it is loaded
// and so canDelete() is false.
- ASSERT(!revalidatingResource->canDelete());
+ ASSERT(!revalidatingResource.canDelete());
- evict(revalidatingResource);
+ remove(revalidatingResource);
-#if ENABLE(CACHE_PARTITIONING)
- ASSERT(!m_resources.get(resource->url()) || !m_resources.get(resource->url())->get(resource->cachePartition()));
- CachedResourceItem* originMap = m_resources.get(resource->url());
- if (!originMap) {
- originMap = new CachedResourceItem;
- m_resources.set(resource->url(), adoptPtr(originMap));
- }
- originMap->set(resource->cachePartition(), resource);
-#else
- ASSERT(!m_resources.get(resource->url()));
- m_resources.set(resource->url(), resource);
-#endif
- resource->setInCache(true);
- resource->updateResponseAfterRevalidation(response);
+ auto& resources = ensureSessionResourceMap(resource.sessionID());
+ auto key = std::make_pair(resource.url(), resource.cachePartition());
+
+ ASSERT(!resources.get(key));
+ resources.set(key, &resource);
+ resource.setInCache(true);
+ resource.updateResponseAfterRevalidation(response);
insertInLRUList(resource);
- int delta = resource->size();
- if (resource->decodedSize() && resource->hasClients())
+ long long delta = resource.size();
+ if (resource.decodedSize() && resource.hasClients())
insertInLiveDecodedResourcesList(resource);
if (delta)
- adjustSize(resource->hasClients(), delta);
-
- revalidatingResource->switchClientsToRevalidatedResource();
- ASSERT(!revalidatingResource->m_deleted);
+ adjustSize(resource.hasClients(), delta);
+
+ revalidatingResource.switchClientsToRevalidatedResource();
+ ASSERT(!revalidatingResource.m_deleted);
// this deletes the revalidating resource
- revalidatingResource->clearResourceToRevalidate();
+ revalidatingResource.clearResourceToRevalidate();
}
-void MemoryCache::revalidationFailed(CachedResource* revalidatingResource)
+void MemoryCache::revalidationFailed(CachedResource& revalidatingResource)
{
ASSERT(WTF::isMainThread());
- LOG(ResourceLoading, "Revalidation failed for %p", revalidatingResource);
- ASSERT(revalidatingResource->resourceToRevalidate());
- revalidatingResource->clearResourceToRevalidate();
+ LOG(ResourceLoading, "Revalidation failed for %p", &revalidatingResource);
+ ASSERT(revalidatingResource.resourceToRevalidate());
+ revalidatingResource.clearResourceToRevalidate();
}
-CachedResource* MemoryCache::resourceForURL(const URL& resourceURL)
+CachedResource* MemoryCache::resourceForRequest(const ResourceRequest& request, SessionID sessionID)
{
- return resourceForRequest(ResourceRequest(resourceURL));
+ // FIXME: Change all clients to make sure HTTP(s) URLs have no fragment identifiers before calling here.
+ // CachedResourceLoader is now doing this. Add an assertion once all other clients are doing it too.
+ auto* resources = sessionResourceMap(sessionID);
+ if (!resources)
+ return nullptr;
+ return resourceForRequestImpl(request, *resources);
}
-CachedResource* MemoryCache::resourceForRequest(const ResourceRequest& request)
+CachedResource* MemoryCache::resourceForRequestImpl(const ResourceRequest& request, CachedResourceMap& resources)
{
ASSERT(WTF::isMainThread());
URL url = removeFragmentIdentifierIfNeeded(request.url());
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem* item = m_resources.get(url);
- CachedResource* resource = 0;
- if (item)
- resource = item->get(request.cachePartition());
-#else
- CachedResource* resource = m_resources.get(url);
-#endif
- bool wasPurgeable = MemoryCache::shouldMakeResourcePurgeableOnEviction() && resource && resource->isPurgeable();
- if (resource && !resource->makePurgeable(false)) {
- ASSERT(!resource->hasClients());
- evict(resource);
- return 0;
- }
- // Add the size back since we had subtracted it when we marked the memory as purgeable.
- if (wasPurgeable)
- adjustSize(resource->hasClients(), resource->size());
- return resource;
+
+ auto key = std::make_pair(url, request.cachePartition());
+ return resources.get(key);
}
unsigned MemoryCache::deadCapacity() const
@@ -212,51 +202,46 @@ unsigned MemoryCache::liveCapacity() const
return m_capacity - deadCapacity();
}
-#if USE(CG)
-// FIXME: Remove the USE(CG) once we either make NativeImagePtr a smart pointer on all platforms or
-// remove the usage of CFRetain() in MemoryCache::addImageToCache() so as to make the code platform-independent.
-bool MemoryCache::addImageToCache(NativeImagePtr image, const URL& url, const String& cachePartition)
+static CachedImageClient& dummyCachedImageClient()
+{
+ static NeverDestroyed<CachedImageClient> client;
+ return client;
+}
+
+bool MemoryCache::addImageToCache(NativeImagePtr&& image, const URL& url, const String& domainForCachePartition)
{
ASSERT(image);
- removeImageFromCache(url, cachePartition); // Remove cache entry if it already exists.
+ SessionID sessionID = SessionID::defaultSessionID();
+ removeImageFromCache(url, domainForCachePartition); // Remove cache entry if it already exists.
- RefPtr<BitmapImage> bitmapImage = BitmapImage::create(image, nullptr);
+ RefPtr<BitmapImage> bitmapImage = BitmapImage::create(WTFMove(image), nullptr);
if (!bitmapImage)
return false;
- CachedImageManual* cachedImage = new CachedImageManual(url, bitmapImage.get());
- if (!cachedImage)
- return false;
+ auto cachedImage = std::make_unique<CachedImage>(url, bitmapImage.get(), sessionID);
- // Actual release of the CGImageRef is done in BitmapImage.
- CFRetain(image);
- cachedImage->addFakeClient();
+ cachedImage->addClient(dummyCachedImageClient());
cachedImage->setDecodedSize(bitmapImage->decodedSize());
-#if ENABLE(CACHE_PARTITIONING)
- cachedImage->resourceRequest().setCachePartition(cachePartition);
-#endif
- add(cachedImage);
- return true;
+ cachedImage->resourceRequest().setDomainForCachePartition(domainForCachePartition);
+
+ return add(*cachedImage.release());
}
-void MemoryCache::removeImageFromCache(const URL& url, const String& cachePartition)
+void MemoryCache::removeImageFromCache(const URL& url, const String& domainForCachePartition)
{
-#if ENABLE(CACHE_PARTITIONING)
- CachedResource* resource;
- if (CachedResourceItem* item = m_resources.get(url))
- resource = item->get(ResourceRequest::partitionName(cachePartition));
- else
- resource = nullptr;
-#else
- UNUSED_PARAM(cachePartition);
- CachedResource* resource = m_resources.get(url);
-#endif
+ auto* resources = sessionResourceMap(SessionID::defaultSessionID());
+ if (!resources)
+ return;
+
+ auto key = std::make_pair(url, ResourceRequest::partitionName(domainForCachePartition));
+
+ CachedResource* resource = resources->get(key);
if (!resource)
return;
// A resource exists and is not a manually cached image, so just remove it.
- if (!resource->isImage() || !static_cast<CachedImage*>(resource)->isManual()) {
- evict(resource);
+ if (!is<CachedImage>(*resource) || !downcast<CachedImage>(*resource).isManuallyCached()) {
+ remove(*resource);
return;
}
@@ -265,15 +250,11 @@ void MemoryCache::removeImageFromCache(const URL& url, const String& cachePartit
// dead resources are pruned. That might be immediately since
// removing the last client triggers a MemoryCache::prune, so the
// resource may be deleted after this call.
- static_cast<CachedImageManual*>(resource)->removeFakeClient();
+ downcast<CachedImage>(*resource).removeClient(dummyCachedImageClient());
}
-#endif
void MemoryCache::pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveResources)
{
- if (!m_pruneEnabled)
- return;
-
unsigned capacity = shouldDestroyDecodedDataForAllLiveResources ? 0 : liveCapacity();
if (capacity && m_liveSize <= capacity)
return;
@@ -283,41 +264,67 @@ void MemoryCache::pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveReso
pruneLiveResourcesToSize(targetSize, shouldDestroyDecodedDataForAllLiveResources);
}
-void MemoryCache::pruneLiveResourcesToPercentage(float prunePercentage)
+void MemoryCache::forEachResource(const std::function<void(CachedResource&)>& function)
{
- if (!m_pruneEnabled)
- return;
+ for (auto& unprotectedLRUList : m_allResources) {
+ Vector<CachedResourceHandle<CachedResource>> lruList;
+ copyToVector(*unprotectedLRUList, lruList);
+ for (auto& resource : lruList)
+ function(*resource);
+ }
+}
- if (prunePercentage < 0.0f || prunePercentage > 0.95f)
+void MemoryCache::forEachSessionResource(SessionID sessionID, const std::function<void (CachedResource&)>& function)
+{
+ auto it = m_sessionResources.find(sessionID);
+ if (it == m_sessionResources.end())
return;
- unsigned currentSize = m_liveSize + m_deadSize;
- unsigned targetSize = static_cast<unsigned>(currentSize * prunePercentage);
+ Vector<CachedResourceHandle<CachedResource>> resourcesForSession;
+ copyValuesToVector(*it->value, resourcesForSession);
+
+ for (auto& resource : resourcesForSession)
+ function(*resource);
+}
- pruneLiveResourcesToSize(targetSize);
+void MemoryCache::destroyDecodedDataForAllImages()
+{
+ MemoryCache::singleton().forEachResource([](CachedResource& resource) {
+ if (resource.isImage())
+ resource.destroyDecodedData();
+ });
}
void MemoryCache::pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestroyDecodedDataForAllLiveResources)
{
if (m_inPruneResources)
return;
- TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true);
+ SetForScope<bool> reentrancyProtector(m_inPruneResources, true);
double currentTime = FrameView::currentPaintTimeStamp();
if (!currentTime) // In case prune is called directly, outside of a Frame paint.
currentTime = monotonicallyIncreasingTime();
// Destroy any decoded data in live objects that we can.
- // Start from the tail, since this is the least recently accessed of the objects.
+ // Start from the head, since this is the least recently accessed of the objects.
// The list might not be sorted by the m_lastDecodedAccessTime. The impact
// of this weaker invariant is minor as the below if statement to check the
// elapsedTime will evaluate to false as the currentTime will be a lot
// greater than the current->m_lastDecodedAccessTime.
// For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209
- CachedResource* current = m_liveDecodedResources.m_tail;
- while (current) {
- CachedResource* prev = current->m_prevInLiveResourcesList;
+ auto it = m_liveDecodedResources.begin();
+ while (it != m_liveDecodedResources.end()) {
+ auto* current = *it;
+
+ // Increment the iterator now because the call to destroyDecodedData() below
+ // may cause a call to ListHashSet::remove() and invalidate the current
+ // iterator. Note that this is safe because unlike iteration of most
+ // WTF Hash data structures, iteration is guaranteed safe against mutation
+ // of the ListHashSet, except for removal of the item currently pointed to
+ // by a given iterator.
+ ++it;
+
ASSERT(current->hasClients());
if (current->isLoaded() && current->decodedSize()) {
// Check to see if the remaining resources are too new to prune.
@@ -325,23 +332,18 @@ void MemoryCache::pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestr
if (!shouldDestroyDecodedDataForAllLiveResources && elapsedTime < cMinDelayBeforeLiveDecodedPrune)
return;
- // Destroy our decoded data. This will remove us from
- // m_liveDecodedResources, and possibly move us to a different LRU
- // list in m_allResources.
+ // Destroy our decoded data. This will remove us from m_liveDecodedResources, and possibly move us
+ // to a different LRU list in m_allResources.
current->destroyDecodedData();
if (targetSize && m_liveSize <= targetSize)
return;
}
- current = prev;
}
}
void MemoryCache::pruneDeadResources()
{
- if (!m_pruneEnabled)
- return;
-
unsigned capacity = deadCapacity();
if (capacity && m_deadSize <= capacity)
return;
@@ -350,135 +352,61 @@ void MemoryCache::pruneDeadResources()
pruneDeadResourcesToSize(targetSize);
}
-void MemoryCache::pruneDeadResourcesToPercentage(float prunePercentage)
-{
- if (!m_pruneEnabled)
- return;
-
- if (prunePercentage < 0.0f || prunePercentage > 0.95f)
- return;
-
- unsigned currentSize = m_liveSize + m_deadSize;
- unsigned targetSize = static_cast<unsigned>(currentSize * prunePercentage);
-
- pruneDeadResourcesToSize(targetSize);
-}
-
void MemoryCache::pruneDeadResourcesToSize(unsigned targetSize)
{
if (m_inPruneResources)
return;
- TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true);
-
- int size = m_allResources.size();
+ SetForScope<bool> reentrancyProtector(m_inPruneResources, true);
- // See if we have any purged resources we can evict.
- for (int i = 0; i < size; i++) {
- CachedResource* current = m_allResources[i].m_tail;
- while (current) {
- CachedResource* prev = current->m_prevInAllResourcesList;
- if (current->wasPurged()) {
- ASSERT(!current->hasClients());
- ASSERT(!current->isPreloaded());
- evict(current);
- }
- current = prev;
- }
- }
if (targetSize && m_deadSize <= targetSize)
return;
bool canShrinkLRULists = true;
- for (int i = size - 1; i >= 0; i--) {
- // Remove from the tail, since this is the least frequently accessed of the objects.
- CachedResource* current = m_allResources[i].m_tail;
-
+ for (int i = m_allResources.size() - 1; i >= 0; i--) {
+ // Make a copy of the LRUList first (and ref the resources) as calling
+ // destroyDecodedData() can alter the LRUList.
+ Vector<CachedResourceHandle<CachedResource>> lruList;
+ copyToVector(*m_allResources[i], lruList);
+
// First flush all the decoded data in this queue.
- while (current) {
- // Protect 'previous' so it can't get deleted during destroyDecodedData().
- CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList;
- ASSERT(!previous || previous->inCache());
- if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) {
+ // Remove from the head, since this is the least frequently accessed of the objects.
+ for (auto& resource : lruList) {
+ if (!resource->inCache())
+ continue;
+
+ if (!resource->hasClients() && !resource->isPreloaded() && resource->isLoaded()) {
// Destroy our decoded data. This will remove us from
// m_liveDecodedResources, and possibly move us to a different
// LRU list in m_allResources.
- current->destroyDecodedData();
+ resource->destroyDecodedData();
if (targetSize && m_deadSize <= targetSize)
return;
}
- // Decoded data may reference other resources. Stop iterating if 'previous' somehow got
- // kicked out of cache during destroyDecodedData().
- if (previous && !previous->inCache())
- break;
- current = previous.get();
}
- // Now evict objects from this queue.
- current = m_allResources[i].m_tail;
- while (current) {
- CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList;
- ASSERT(!previous || previous->inCache());
- if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) {
- if (!makeResourcePurgeable(current))
- evict(current);
+ // Now evict objects from this list.
+ // Remove from the head, since this is the least frequently accessed of the objects.
+ for (auto& resource : lruList) {
+ if (!resource->inCache())
+ continue;
+ if (!resource->hasClients() && !resource->isPreloaded() && !resource->isCacheValidator()) {
+ remove(*resource);
if (targetSize && m_deadSize <= targetSize)
return;
}
- if (previous && !previous->inCache())
- break;
- current = previous.get();
}
// Shrink the vector back down so we don't waste time inspecting
// empty LRU lists on future prunes.
- if (m_allResources[i].m_head)
+ if (!m_allResources[i]->isEmpty())
canShrinkLRULists = false;
else if (canShrinkLRULists)
- m_allResources.resize(i);
+ m_allResources.shrink(i);
}
}
-#if ENABLE(DISK_IMAGE_CACHE)
-void MemoryCache::flushCachedImagesToDisk()
-{
- if (!diskImageCache().isEnabled())
- return;
-
-#ifndef NDEBUG
- double start = WTF::currentTimeMS();
- unsigned resourceCount = 0;
- unsigned cachedSize = 0;
-#endif
-
- for (size_t i = m_allResources.size(); i; ) {
- --i;
- CachedResource* current = m_allResources[i].m_tail;
- while (current) {
- CachedResource* previous = current->m_prevInAllResourcesList;
-
- if (!current->isUsingDiskImageCache() && current->canUseDiskImageCache()) {
- current->useDiskImageCache();
- current->destroyDecodedData();
-#ifndef NDEBUG
- LOG(DiskImageCache, "Cache::diskCacheResources(): attempting to save (%d) bytes", current->resourceBuffer()->sharedBuffer()->size());
- ++resourceCount;
- cachedSize += current->resourceBuffer()->sharedBuffer()->size();
-#endif
- }
-
- current = previous;
- }
- }
-
-#ifndef NDEBUG
- double end = WTF::currentTimeMS();
- LOG(DiskImageCache, "DiskImageCache: took (%f) ms to cache (%d) bytes for (%d) resources", end - start, cachedSize, resourceCount);
-#endif
-}
-#endif // ENABLE(DISK_IMAGE_CACHE)
-
void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes)
{
ASSERT(minDeadBytes <= maxDeadBytes);
@@ -489,400 +417,269 @@ void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, un
prune();
}
-bool MemoryCache::makeResourcePurgeable(CachedResource* resource)
-{
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
- return false;
-
- if (!resource->inCache())
- return false;
-
- if (resource->isPurgeable())
- return true;
-
- if (!resource->isSafeToMakePurgeable())
- return false;
-
- if (!resource->makePurgeable(true))
- return false;
-
- adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
-
- return true;
-}
-
-void MemoryCache::evict(CachedResource* resource)
+void MemoryCache::remove(CachedResource& resource)
{
ASSERT(WTF::isMainThread());
- LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", resource, resource->url().string().latin1().data());
+ LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", &resource, resource.url().string().latin1().data());
// The resource may have already been removed by someone other than our caller,
// who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bug.cgi?id=12479#c6>.
- if (resource->inCache()) {
- // Remove from the resource map.
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem* item = m_resources.get(resource->url());
- if (item) {
- item->remove(resource->cachePartition());
- if (!item->size())
- m_resources.remove(resource->url());
- }
-#else
- m_resources.remove(resource->url());
-#endif
- resource->setInCache(false);
-
- // Remove from the appropriate LRU list.
- removeFromLRUList(resource);
- removeFromLiveDecodedResourcesList(resource);
-
- // If the resource was purged, it means we had already decremented the size when we made the
- // resource purgeable in makeResourcePurgeable(). So adjust the size if we are evicting a
- // resource that was not marked as purgeable.
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() || !resource->isPurgeable())
- adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
- } else
-#if ENABLE(CACHE_PARTITIONING)
- ASSERT(!m_resources.get(resource->url()) || m_resources.get(resource->url())->get(resource->cachePartition()) != resource);
-#else
- ASSERT(m_resources.get(resource->url()) != resource);
-#endif
+ if (auto* resources = sessionResourceMap(resource.sessionID())) {
+ auto key = std::make_pair(resource.url(), resource.cachePartition());
+
+ if (resource.inCache()) {
+ // Remove resource from the resource map.
+ resources->remove(key);
+ resource.setInCache(false);
+
+ // If the resource map is now empty, remove it from m_sessionResources.
+ if (resources->isEmpty())
+ m_sessionResources.remove(resource.sessionID());
+
+ // Remove from the appropriate LRU list.
+ removeFromLRUList(resource);
+ removeFromLiveDecodedResourcesList(resource);
+ adjustSize(resource.hasClients(), -static_cast<long long>(resource.size()));
+ } else
+ ASSERT(resources->get(key) != &resource);
+ }
- resource->deleteIfPossible();
+ resource.deleteIfPossible();
}
-MemoryCache::LRUList* MemoryCache::lruListFor(CachedResource* resource)
+auto MemoryCache::lruListFor(CachedResource& resource) -> LRUList&
{
- unsigned accessCount = std::max(resource->accessCount(), 1U);
- unsigned queueIndex = WTF::fastLog2(resource->size() / accessCount);
+ unsigned accessCount = std::max(resource.accessCount(), 1U);
+ unsigned queueIndex = WTF::fastLog2(resource.size() / accessCount);
#ifndef NDEBUG
- resource->m_lruIndex = queueIndex;
+ resource.m_lruIndex = queueIndex;
#endif
- if (m_allResources.size() <= queueIndex)
- m_allResources.grow(queueIndex + 1);
- return &m_allResources[queueIndex];
+
+ m_allResources.reserveCapacity(queueIndex + 1);
+ while (m_allResources.size() <= queueIndex)
+ m_allResources.uncheckedAppend(std::make_unique<LRUList>());
+ return *m_allResources[queueIndex];
}
-void MemoryCache::removeFromLRUList(CachedResource* resource)
+void MemoryCache::removeFromLRUList(CachedResource& resource)
{
// If we've never been accessed, then we're brand new and not in any list.
- if (resource->accessCount() == 0)
+ if (!resource.accessCount())
return;
#if !ASSERT_DISABLED
- unsigned oldListIndex = resource->m_lruIndex;
+ unsigned oldListIndex = resource.m_lruIndex;
#endif
- LRUList* list = lruListFor(resource);
+ LRUList& list = lruListFor(resource);
-#if !ASSERT_DISABLED
// Verify that the list we got is the list we want.
- ASSERT(resource->m_lruIndex == oldListIndex);
-
- // Verify that we are in fact in this list.
- bool found = false;
- for (CachedResource* current = list->m_head; current; current = current->m_nextInAllResourcesList) {
- if (current == resource) {
- found = true;
- break;
- }
- }
- ASSERT(found);
-#endif
-
- CachedResource* next = resource->m_nextInAllResourcesList;
- CachedResource* prev = resource->m_prevInAllResourcesList;
-
- if (next == 0 && prev == 0 && list->m_head != resource)
- return;
-
- resource->m_nextInAllResourcesList = 0;
- resource->m_prevInAllResourcesList = 0;
-
- if (next)
- next->m_prevInAllResourcesList = prev;
- else if (list->m_tail == resource)
- list->m_tail = prev;
+ ASSERT(resource.m_lruIndex == oldListIndex);
- if (prev)
- prev->m_nextInAllResourcesList = next;
- else if (list->m_head == resource)
- list->m_head = next;
+ bool removed = list.remove(&resource);
+ ASSERT_UNUSED(removed, removed);
}
-void MemoryCache::insertInLRUList(CachedResource* resource)
+void MemoryCache::insertInLRUList(CachedResource& resource)
{
- // Make sure we aren't in some list already.
- ASSERT(!resource->m_nextInAllResourcesList && !resource->m_prevInAllResourcesList);
- ASSERT(resource->inCache());
- ASSERT(resource->accessCount() > 0);
-
- LRUList* list = lruListFor(resource);
-
- resource->m_nextInAllResourcesList = list->m_head;
- if (list->m_head)
- list->m_head->m_prevInAllResourcesList = resource;
- list->m_head = resource;
+ ASSERT(resource.inCache());
+ ASSERT(resource.accessCount() > 0);
- if (!resource->m_nextInAllResourcesList)
- list->m_tail = resource;
-
-#if !ASSERT_DISABLED
- // Verify that we are in now in the list like we should be.
- list = lruListFor(resource);
- bool found = false;
- for (CachedResource* current = list->m_head; current; current = current->m_nextInAllResourcesList) {
- if (current == resource) {
- found = true;
- break;
- }
- }
- ASSERT(found);
-#endif
-
+ auto addResult = lruListFor(resource).add(&resource);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
}
-void MemoryCache::resourceAccessed(CachedResource* resource)
+void MemoryCache::resourceAccessed(CachedResource& resource)
{
- ASSERT(resource->inCache());
+ ASSERT(resource.inCache());
// Need to make sure to remove before we increase the access count, since
// the queue will possibly change.
removeFromLRUList(resource);
// If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
- if (!resource->accessCount())
- adjustSize(resource->hasClients(), resource->size());
+ if (!resource.accessCount())
+ adjustSize(resource.hasClients(), resource.size());
// Add to our access count.
- resource->increaseAccessCount();
+ resource.increaseAccessCount();
// Now insert into the new queue.
insertInLRUList(resource);
}
-void MemoryCache::removeResourcesWithOrigin(SecurityOrigin* origin)
+void MemoryCache::removeResourcesWithOrigin(SecurityOrigin& origin)
{
- Vector<CachedResource*> resourcesWithOrigin;
-
- CachedResourceMap::iterator e = m_resources.end();
-#if ENABLE(CACHE_PARTITIONING)
- String originPartition = ResourceRequest::partitionName(origin->host());
-#endif
+ String originPartition = ResourceRequest::partitionName(origin.host());
- for (CachedResourceMap::iterator it = m_resources.begin(); it != e; ++it) {
-#if ENABLE(CACHE_PARTITIONING)
- for (CachedResourceItem::iterator itemIterator = it->value->begin(); itemIterator != it->value->end(); ++itemIterator) {
- CachedResource* resource = itemIterator->value;
- String partition = itemIterator->key;
- if (partition == originPartition) {
- resourcesWithOrigin.append(resource);
+ Vector<CachedResource*> resourcesWithOrigin;
+ for (auto& resources : m_sessionResources.values()) {
+ for (auto& keyValue : *resources) {
+ auto& resource = *keyValue.value;
+ auto& partitionName = keyValue.key.second;
+ if (partitionName == originPartition) {
+ resourcesWithOrigin.append(&resource);
continue;
}
-#else
- CachedResource* resource = it->value;
-#endif
- RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::createFromString(resource->url());
- if (!resourceOrigin)
- continue;
- if (resourceOrigin->equal(origin))
- resourcesWithOrigin.append(resource);
-#if ENABLE(CACHE_PARTITIONING)
+ RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::create(resource.url());
+ if (resourceOrigin->equal(&origin))
+ resourcesWithOrigin.append(&resource);
}
-#endif
}
- for (size_t i = 0; i < resourcesWithOrigin.size(); ++i)
- remove(resourcesWithOrigin[i]);
+ for (auto* resource : resourcesWithOrigin)
+ remove(*resource);
+}
+
+void MemoryCache::removeResourcesWithOrigins(SessionID sessionID, const HashSet<RefPtr<SecurityOrigin>>& origins)
+{
+ auto* resourceMap = sessionResourceMap(sessionID);
+ if (!resourceMap)
+ return;
+
+ HashSet<String> originPartitions;
+
+ for (auto& origin : origins)
+ originPartitions.add(ResourceRequest::partitionName(origin->host()));
+
+ Vector<CachedResource*> resourcesToRemove;
+ for (auto& keyValuePair : *resourceMap) {
+ auto& resource = *keyValuePair.value;
+ auto& partitionName = keyValuePair.key.second;
+ if (originPartitions.contains(partitionName)) {
+ resourcesToRemove.append(&resource);
+ continue;
+ }
+ if (origins.contains(SecurityOrigin::create(resource.url()).ptr()))
+ resourcesToRemove.append(&resource);
+ }
+
+ for (auto& resource : resourcesToRemove)
+ remove(*resource);
}
void MemoryCache::getOriginsWithCache(SecurityOriginSet& origins)
{
-#if ENABLE(CACHE_PARTITIONING)
- DEFINE_STATIC_LOCAL(String, httpString, ("http"));
-#endif
- CachedResourceMap::iterator e = m_resources.end();
- for (CachedResourceMap::iterator it = m_resources.begin(); it != e; ++it) {
-#if ENABLE(CACHE_PARTITIONING)
- if (it->value->begin()->key == emptyString())
- origins.add(SecurityOrigin::createFromString(it->value->begin()->value->url()));
- else
- origins.add(SecurityOrigin::create(httpString, it->value->begin()->key, 0));
-#else
- origins.add(SecurityOrigin::createFromString(it->value->url()));
-#endif
+ for (auto& resources : m_sessionResources.values()) {
+ for (auto& keyValue : *resources) {
+ auto& resource = *keyValue.value;
+ auto& partitionName = keyValue.key.second;
+ if (!partitionName.isEmpty())
+ origins.add(SecurityOrigin::create(ASCIILiteral("http"), partitionName, 0));
+ else
+ origins.add(SecurityOrigin::create(resource.url()));
+ }
}
}
-void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource)
+HashSet<RefPtr<SecurityOrigin>> MemoryCache::originsWithCache(SessionID sessionID) const
{
- // If we've never been accessed, then we're brand new and not in any list.
- if (!resource->m_inLiveDecodedResourcesList)
- return;
- resource->m_inLiveDecodedResourcesList = false;
+ HashSet<RefPtr<SecurityOrigin>> origins;
-#if !ASSERT_DISABLED
- // Verify that we are in fact in this list.
- bool found = false;
- for (CachedResource* current = m_liveDecodedResources.m_head; current; current = current->m_nextInLiveResourcesList) {
- if (current == resource) {
- found = true;
- break;
+ auto it = m_sessionResources.find(sessionID);
+ if (it != m_sessionResources.end()) {
+ for (auto& keyValue : *it->value) {
+ auto& resource = *keyValue.value;
+ auto& partitionName = keyValue.key.second;
+ if (!partitionName.isEmpty())
+ origins.add(SecurityOrigin::create("http", partitionName, 0));
+ else
+ origins.add(SecurityOrigin::create(resource.url()));
}
}
- ASSERT(found);
-#endif
- CachedResource* next = resource->m_nextInLiveResourcesList;
- CachedResource* prev = resource->m_prevInLiveResourcesList;
-
- if (next == 0 && prev == 0 && m_liveDecodedResources.m_head != resource)
- return;
-
- resource->m_nextInLiveResourcesList = 0;
- resource->m_prevInLiveResourcesList = 0;
-
- if (next)
- next->m_prevInLiveResourcesList = prev;
- else if (m_liveDecodedResources.m_tail == resource)
- m_liveDecodedResources.m_tail = prev;
+ return origins;
+}
- if (prev)
- prev->m_nextInLiveResourcesList = next;
- else if (m_liveDecodedResources.m_head == resource)
- m_liveDecodedResources.m_head = next;
+void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource& resource)
+{
+ m_liveDecodedResources.remove(&resource);
}
-void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource)
+void MemoryCache::insertInLiveDecodedResourcesList(CachedResource& resource)
{
// Make sure we aren't in the list already.
- ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResourcesList && !resource->m_inLiveDecodedResourcesList);
- resource->m_inLiveDecodedResourcesList = true;
-
- resource->m_nextInLiveResourcesList = m_liveDecodedResources.m_head;
- if (m_liveDecodedResources.m_head)
- m_liveDecodedResources.m_head->m_prevInLiveResourcesList = resource;
- m_liveDecodedResources.m_head = resource;
-
- if (!resource->m_nextInLiveResourcesList)
- m_liveDecodedResources.m_tail = resource;
-
-#if !ASSERT_DISABLED
- // Verify that we are in now in the list like we should be.
- bool found = false;
- for (CachedResource* current = m_liveDecodedResources.m_head; current; current = current->m_nextInLiveResourcesList) {
- if (current == resource) {
- found = true;
- break;
- }
- }
- ASSERT(found);
-#endif
-
+ ASSERT(!m_liveDecodedResources.contains(&resource));
+ m_liveDecodedResources.add(&resource);
}
-void MemoryCache::addToLiveResourcesSize(CachedResource* resource)
+void MemoryCache::addToLiveResourcesSize(CachedResource& resource)
{
- m_liveSize += resource->size();
- m_deadSize -= resource->size();
+ m_liveSize += resource.size();
+ m_deadSize -= resource.size();
}
-void MemoryCache::removeFromLiveResourcesSize(CachedResource* resource)
+void MemoryCache::removeFromLiveResourcesSize(CachedResource& resource)
{
- m_liveSize -= resource->size();
- m_deadSize += resource->size();
+ m_liveSize -= resource.size();
+ m_deadSize += resource.size();
}
-void MemoryCache::adjustSize(bool live, int delta)
+void MemoryCache::adjustSize(bool live, long long delta)
{
if (live) {
- ASSERT(delta >= 0 || ((int)m_liveSize + delta >= 0));
+ ASSERT(delta >= 0 || (static_cast<long long>(m_liveSize) + delta >= 0));
m_liveSize += delta;
} else {
- ASSERT(delta >= 0 || ((int)m_deadSize + delta >= 0));
+ ASSERT(delta >= 0 || (static_cast<long long>(m_deadSize) + delta >= 0));
m_deadSize += delta;
}
}
-void MemoryCache::removeUrlFromCache(ScriptExecutionContext* context, const String& urlString)
-{
- removeRequestFromCache(context, ResourceRequest(urlString));
-}
-
-void MemoryCache::removeRequestFromCache(ScriptExecutionContext* context, const ResourceRequest& request)
+void MemoryCache::removeRequestFromSessionCaches(ScriptExecutionContext& context, const ResourceRequest& request)
{
- if (context->isWorkerGlobalScope()) {
- WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context);
- workerGlobalScope->thread()->workerLoaderProxy().postTaskToLoader(createCallbackTask(&crossThreadRemoveRequestFromCache, request));
+ if (is<WorkerGlobalScope>(context)) {
+ downcast<WorkerGlobalScope>(context).thread().workerLoaderProxy().postTaskToLoader([request = request.isolatedCopy()] (ScriptExecutionContext& context) {
+ MemoryCache::removeRequestFromSessionCaches(context, request);
+ });
return;
}
- removeRequestFromCacheImpl(context, request);
-}
-
-void MemoryCache::removeRequestFromCacheImpl(ScriptExecutionContext*, const ResourceRequest& request)
-{
- if (CachedResource* resource = memoryCache()->resourceForRequest(request))
- memoryCache()->remove(resource);
-}
-
-void MemoryCache::crossThreadRemoveRequestFromCache(ScriptExecutionContext* context, PassOwnPtr<WebCore::CrossThreadResourceRequestData> requestData)
-{
- OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData));
- MemoryCache::removeRequestFromCacheImpl(context, *request);
+ auto& memoryCache = MemoryCache::singleton();
+ for (auto& resources : memoryCache.m_sessionResources) {
+ if (CachedResource* resource = memoryCache.resourceForRequestImpl(request, *resources.value))
+ memoryCache.remove(*resource);
+ }
}
-void MemoryCache::TypeStatistic::addResource(CachedResource* o)
+void MemoryCache::TypeStatistic::addResource(CachedResource& resource)
{
- bool purged = o->wasPurged();
- bool purgeable = o->isPurgeable() && !purged;
- int pageSize = (o->encodedSize() + o->overheadSize() + 4095) & ~4095;
count++;
- size += purged ? 0 : o->size();
- liveSize += o->hasClients() ? o->size() : 0;
- decodedSize += o->decodedSize();
- purgeableSize += purgeable ? pageSize : 0;
- purgedSize += purged ? pageSize : 0;
-#if ENABLE(DISK_IMAGE_CACHE)
- // Only the data inside the resource was mapped, not the entire resource.
- mappedSize += o->isUsingDiskImageCache() ? o->resourceBuffer()->sharedBuffer()->size() : 0;
-#endif
+ size += resource.size();
+ liveSize += resource.hasClients() ? resource.size() : 0;
+ decodedSize += resource.decodedSize();
}
MemoryCache::Statistics MemoryCache::getStatistics()
{
Statistics stats;
- CachedResourceMap::iterator e = m_resources.end();
- for (CachedResourceMap::iterator i = m_resources.begin(); i != e; ++i) {
-#if ENABLE(CACHE_PARTITIONING)
- for (CachedResourceItem::iterator itemIterator = i->value->begin(); itemIterator != i->value->end(); ++itemIterator) {
- CachedResource* resource = itemIterator->value;
-#else
- CachedResource* resource = i->value;
-#endif
+
+ for (auto& resources : m_sessionResources.values()) {
+ for (auto* resource : resources->values()) {
switch (resource->type()) {
case CachedResource::ImageResource:
- stats.images.addResource(resource);
+ stats.images.addResource(*resource);
break;
case CachedResource::CSSStyleSheet:
- stats.cssStyleSheets.addResource(resource);
+ stats.cssStyleSheets.addResource(*resource);
break;
case CachedResource::Script:
- stats.scripts.addResource(resource);
+ stats.scripts.addResource(*resource);
break;
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
- stats.xslStyleSheets.addResource(resource);
+ stats.xslStyleSheets.addResource(*resource);
break;
#endif
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
case CachedResource::FontResource:
- stats.fonts.addResource(resource);
+ stats.fonts.addResource(*resource);
break;
default:
break;
}
-#if ENABLE(CACHE_PARTITIONING)
}
-#endif
}
return stats;
}
@@ -893,16 +690,10 @@ void MemoryCache::setDisabled(bool disabled)
if (!m_disabled)
return;
- for (;;) {
- CachedResourceMap::iterator outerIterator = m_resources.begin();
- if (outerIterator == m_resources.end())
- break;
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem::iterator innerIterator = outerIterator->value->begin();
- evict(innerIterator->value);
-#else
- evict(outerIterator->value);
-#endif
+ while (!m_sessionResources.isEmpty()) {
+ auto& resources = *m_sessionResources.begin()->value;
+ ASSERT(!resources.isEmpty());
+ remove(*resources.begin()->value);
}
}
@@ -915,66 +706,65 @@ void MemoryCache::evictResources()
setDisabled(false);
}
+void MemoryCache::evictResources(SessionID sessionID)
+{
+ if (disabled())
+ return;
+
+ forEachSessionResource(sessionID, [this] (CachedResource& resource) { remove(resource); });
+
+ ASSERT(!m_sessionResources.contains(sessionID));
+}
+
+bool MemoryCache::needsPruning() const
+{
+ return m_liveSize + m_deadSize > m_capacity || m_deadSize > m_maxDeadCapacity;
+}
+
void MemoryCache::prune()
{
- if (m_liveSize + m_deadSize <= m_capacity && m_deadSize <= m_maxDeadCapacity) // Fast path.
+ if (!needsPruning())
return;
pruneDeadResources(); // Prune dead first, in case it was "borrowing" capacity from live.
pruneLiveResources();
}
-void MemoryCache::pruneToPercentage(float targetPercentLive)
+void MemoryCache::pruneSoon()
{
- pruneDeadResourcesToPercentage(targetPercentLive); // Prune dead first, in case it was "borrowing" capacity from live.
- pruneLiveResourcesToPercentage(targetPercentLive);
+ if (m_pruneTimer.isActive())
+ return;
+ if (!needsPruning())
+ return;
+ m_pruneTimer.startOneShot(0);
}
-
#ifndef NDEBUG
void MemoryCache::dumpStats()
{
Statistics s = getStatistics();
-#if ENABLE(DISK_IMAGE_CACHE)
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize", "Mapped", "\"Real\"");
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
- printf("%-13s %13d %13d %13d %13d %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize, s.images.mappedSize, s.images.size - s.images.mappedSize);
-#else
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize");
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize);
-#endif
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize, s.cssStyleSheets.purgeableSize, s.cssStyleSheets.purgedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize");
+ printf("%-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------");
+ printf("%-13s %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize);
+ printf("%-13s %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize);
#if ENABLE(XSLT)
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize, s.xslStyleSheets.purgeableSize, s.xslStyleSheets.purgedSize);
+ printf("%-13s %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize);
#endif
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize, s.scripts.purgeableSize, s.scripts.purgedSize);
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize, s.fonts.purgeableSize, s.fonts.purgedSize);
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
+ printf("%-13s %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize);
+ printf("%-13s %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------");
}
void MemoryCache::dumpLRULists(bool includeLive) const
{
-#if ENABLE(DISK_IMAGE_CACHE)
- printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged, isMemoryMapped):\n");
-#else
- printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n");
-#endif
+ printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n");
int size = m_allResources.size();
for (int i = size - 1; i >= 0; i--) {
printf("\n\nList %d: ", i);
- CachedResource* current = m_allResources[i].m_tail;
- while (current) {
- CachedResource* prev = current->m_prevInAllResourcesList;
- if (includeLive || !current->hasClients())
-#if ENABLE(DISK_IMAGE_CACHE)
- printf("(%.1fK, %.1fK, %uA, %dR, %d, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged(), current->isUsingDiskImageCache());
-#else
- printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged());
-#endif
-
- current = prev;
+ for (auto* resource : *m_allResources[i]) {
+ if (includeLive || !resource->hasClients())
+ printf("(%.1fK, %.1fK, %uA, %dR); ", resource->decodedSize() / 1024.0f, (resource->encodedSize() + resource->overheadSize()) / 1024.0f, resource->accessCount(), resource->hasClients());
}
}
}
diff --git a/Source/WebCore/loader/cache/MemoryCache.h b/Source/WebCore/loader/cache/MemoryCache.h
index c023a9725..c5d97e1d3 100644
--- a/Source/WebCore/loader/cache/MemoryCache.h
+++ b/Source/WebCore/loader/cache/MemoryCache.h
@@ -22,13 +22,16 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef Cache_h
-#define Cache_h
+#pragma once
-#include "NativeImagePtr.h"
+#include "NativeImage.h"
#include "SecurityOriginHash.h"
+#include "SessionID.h"
+#include "Timer.h"
+#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
#include <wtf/text/StringHash.h>
@@ -36,16 +39,12 @@
namespace WebCore {
-class CachedCSSStyleSheet;
class CachedResource;
-class CachedResourceLoader;
class URL;
class ResourceRequest;
class ResourceResponse;
class ScriptExecutionContext;
class SecurityOrigin;
-struct CrossThreadResourceRequestData;
-struct SecurityOriginHash;
// This cache holds subresources used by Web pages: images, scripts, stylesheets, etc.
@@ -60,54 +59,26 @@ struct SecurityOriginHash;
// -------|-----+++++++++++++++|
// -------|-----+++++++++++++++|+++++
-// The behavior of the cache changes in the following way if shouldMakeResourcePurgeableOnEviction
-// returns true.
-//
-// 1. Dead resources in the cache are kept in non-purgeable memory.
-// 2. When we prune dead resources, instead of freeing them, we mark their memory as purgeable and
-// keep the resources until the kernel reclaims the purgeable memory.
-//
-// By leaving the in-cache dead resources in dirty resident memory, we decrease the likelihood of
-// the kernel claiming that memory and forcing us to refetch the resource (for example when a user
-// presses back).
-//
-// And by having an unbounded number of resource objects using purgeable memory, we can use as much
-// memory as is available on the machine. The trade-off here is that the CachedResource object (and
-// its member variables) are allocated in non-purgeable TC-malloc'd memory so we would see slightly
-// more memory use due to this.
-
class MemoryCache {
WTF_MAKE_NONCOPYABLE(MemoryCache); WTF_MAKE_FAST_ALLOCATED;
+ friend NeverDestroyed<MemoryCache>;
+ friend class Internals;
public:
- friend MemoryCache* memoryCache();
-
-#if ENABLE(CACHE_PARTITIONING)
- typedef HashMap<String, CachedResource*> CachedResourceItem;
- typedef HashMap<String, OwnPtr<CachedResourceItem>> CachedResourceMap;
-#else
- typedef HashMap<String, CachedResource*> CachedResourceMap;
-#endif
-
- struct LRUList {
- CachedResource* m_head;
- CachedResource* m_tail;
- LRUList() : m_head(0), m_tail(0) { }
- };
-
struct TypeStatistic {
int count;
int size;
int liveSize;
int decodedSize;
- int purgeableSize;
- int purgedSize;
-#if ENABLE(DISK_IMAGE_CACHE)
- int mappedSize;
- TypeStatistic() : count(0), size(0), liveSize(0), decodedSize(0), purgeableSize(0), purgedSize(0), mappedSize(0) { }
-#else
- TypeStatistic() : count(0), size(0), liveSize(0), decodedSize(0), purgeableSize(0), purgedSize(0) { }
-#endif
- void addResource(CachedResource*);
+
+ TypeStatistic()
+ : count(0)
+ , size(0)
+ , liveSize(0)
+ , decodedSize(0)
+ {
+ }
+
+ void addResource(CachedResource&);
};
struct Statistics {
@@ -118,98 +89,92 @@ public:
TypeStatistic fonts;
};
- CachedResource* resourceForURL(const URL&);
- CachedResource* resourceForRequest(const ResourceRequest&);
-
- bool add(CachedResource* resource);
- void remove(CachedResource* resource) { evict(resource); }
+ WEBCORE_EXPORT static MemoryCache& singleton();
- static URL removeFragmentIdentifierIfNeeded(const URL& originalURL);
-
- void revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse&);
- void revalidationFailed(CachedResource* revalidatingResource);
-
- // Sets the cache's memory capacities, in bytes. These will hold only approximately,
+ WEBCORE_EXPORT CachedResource* resourceForRequest(const ResourceRequest&, SessionID);
+
+ bool add(CachedResource&);
+ void remove(CachedResource&);
+
+ static bool shouldRemoveFragmentIdentifier(const URL&);
+ static URL removeFragmentIdentifierIfNeeded(const URL&);
+
+ void revalidationSucceeded(CachedResource& revalidatingResource, const ResourceResponse&);
+ void revalidationFailed(CachedResource& revalidatingResource);
+
+ void forEachResource(const std::function<void(CachedResource&)>&);
+ void forEachSessionResource(SessionID, const std::function<void(CachedResource&)>&);
+ void destroyDecodedDataForAllImages();
+
+ // Sets the cache's memory capacities, in bytes. These will hold only approximately,
// since the decoded cost of resources like scripts and stylesheets is not known.
// - minDeadBytes: The maximum number of bytes that dead resources should consume when the cache is under pressure.
// - maxDeadBytes: The maximum number of bytes that dead resources should consume when the cache is not under pressure.
// - totalBytes: The maximum number of bytes that the cache should consume overall.
- void setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes);
+ WEBCORE_EXPORT void setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes);
// Turn the cache on and off. Disabling the cache will remove all resources from the cache. They may
// still live on if they are referenced by some Web page though.
- void setDisabled(bool);
+ WEBCORE_EXPORT void setDisabled(bool);
bool disabled() const { return m_disabled; }
- void evictResources();
-
- void setPruneEnabled(bool enabled) { m_pruneEnabled = enabled; }
+ WEBCORE_EXPORT void evictResources();
+ WEBCORE_EXPORT void evictResources(SessionID);
+
void prune();
- void pruneToPercentage(float targetPercentLive);
+ void pruneSoon();
+ unsigned size() const { return m_liveSize + m_deadSize; }
- void setDeadDecodedDataDeletionInterval(double interval) { m_deadDecodedDataDeletionInterval = interval; }
- double deadDecodedDataDeletionInterval() const { return m_deadDecodedDataDeletionInterval; }
+ void setDeadDecodedDataDeletionInterval(std::chrono::milliseconds interval) { m_deadDecodedDataDeletionInterval = interval; }
+ std::chrono::milliseconds deadDecodedDataDeletionInterval() const { return m_deadDecodedDataDeletionInterval; }
// Calls to put the cached resource into and out of LRU lists.
- void insertInLRUList(CachedResource*);
- void removeFromLRUList(CachedResource*);
+ void insertInLRUList(CachedResource&);
+ void removeFromLRUList(CachedResource&);
// Called to adjust the cache totals when a resource changes size.
- void adjustSize(bool live, int delta);
+ void adjustSize(bool live, long long delta);
// Track decoded resources that are in the cache and referenced by a Web page.
- void insertInLiveDecodedResourcesList(CachedResource*);
- void removeFromLiveDecodedResourcesList(CachedResource*);
-
- void addToLiveResourcesSize(CachedResource*);
- void removeFromLiveResourcesSize(CachedResource*);
+ void insertInLiveDecodedResourcesList(CachedResource&);
+ void removeFromLiveDecodedResourcesList(CachedResource&);
- static bool shouldMakeResourcePurgeableOnEviction();
+ void addToLiveResourcesSize(CachedResource&);
+ void removeFromLiveResourcesSize(CachedResource&);
-#if ENABLE(DISK_IMAGE_CACHE)
- void flushCachedImagesToDisk(); // Flush encoded data from resources still referenced by web pages.
-#endif
-
- static void removeUrlFromCache(ScriptExecutionContext*, const String& urlString);
- static void removeRequestFromCache(ScriptExecutionContext*, const ResourceRequest&);
+ static void removeRequestFromSessionCaches(ScriptExecutionContext&, const ResourceRequest&);
// Function to collect cache statistics for the caches window in the Safari Debug menu.
- Statistics getStatistics();
+ WEBCORE_EXPORT Statistics getStatistics();
- void resourceAccessed(CachedResource*);
+ void resourceAccessed(CachedResource&);
+ bool inLiveDecodedResourcesList(CachedResource& resource) const { return m_liveDecodedResources.contains(&resource); }
typedef HashSet<RefPtr<SecurityOrigin>> SecurityOriginSet;
- void removeResourcesWithOrigin(SecurityOrigin*);
- void getOriginsWithCache(SecurityOriginSet& origins);
-
- unsigned minDeadCapacity() const { return m_minDeadCapacity; }
- unsigned maxDeadCapacity() const { return m_maxDeadCapacity; }
- unsigned capacity() const { return m_capacity; }
- unsigned liveSize() const { return m_liveSize; }
- unsigned deadSize() const { return m_deadSize; }
-
-#if USE(CG)
- // FIXME: Remove the USE(CG) once we either make NativeImagePtr a smart pointer on all platforms or
- // remove the usage of CFRetain() in MemoryCache::addImageToCache() so as to make the code platform-independent.
- bool addImageToCache(NativeImagePtr, const URL&, const String& cachePartition);
- void removeImageFromCache(const URL&, const String& cachePartition);
-#endif
+ WEBCORE_EXPORT void removeResourcesWithOrigin(SecurityOrigin&);
+ WEBCORE_EXPORT void removeResourcesWithOrigins(SessionID, const HashSet<RefPtr<SecurityOrigin>>&);
+ WEBCORE_EXPORT void getOriginsWithCache(SecurityOriginSet& origins);
+ WEBCORE_EXPORT HashSet<RefPtr<SecurityOrigin>> originsWithCache(SessionID) const;
+
+ WEBCORE_EXPORT bool addImageToCache(NativeImagePtr&&, const URL&, const String& domainForCachePartition);
+ WEBCORE_EXPORT void removeImageFromCache(const URL&, const String& domainForCachePartition);
// pruneDead*() - Flush decoded and encoded data from resources not referenced by Web pages.
// pruneLive*() - Flush decoded data from resources still referenced by Web pages.
- void pruneDeadResources(); // Automatically decide how much to prune.
- void pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveResources = false);
+ WEBCORE_EXPORT void pruneDeadResources(); // Automatically decide how much to prune.
+ WEBCORE_EXPORT void pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveResources = false);
+
+ WEBCORE_EXPORT void pruneDeadResourcesToSize(unsigned targetSize);
+ WEBCORE_EXPORT void pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestroyDecodedDataForAllLiveResources = false);
private:
- void pruneDeadResourcesToPercentage(float prunePercentage); // Prune to % current size
- void pruneLiveResourcesToPercentage(float prunePercentage);
- void pruneDeadResourcesToSize(unsigned targetSize);
- void pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestroyDecodedDataForAllLiveResources = false);
+ typedef HashMap<std::pair<URL, String /* partitionName */>, CachedResource*> CachedResourceMap;
+ typedef ListHashSet<CachedResource*> LRUList;
MemoryCache();
~MemoryCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons.
- LRUList* lruListFor(CachedResource*);
+ LRUList& lruListFor(CachedResource&);
#ifndef NDEBUG
void dumpStats();
void dumpLRULists(bool includeLive) const;
@@ -217,21 +182,20 @@ private:
unsigned liveCapacity() const;
unsigned deadCapacity() const;
+ bool needsPruning() const;
- bool makeResourcePurgeable(CachedResource*);
- void evict(CachedResource*);
+ CachedResource* resourceForRequestImpl(const ResourceRequest&, CachedResourceMap&);
- static void removeRequestFromCacheImpl(ScriptExecutionContext*, const ResourceRequest&);
- static void crossThreadRemoveRequestFromCache(ScriptExecutionContext*, PassOwnPtr<CrossThreadResourceRequestData>);
+ CachedResourceMap& ensureSessionResourceMap(SessionID);
+ CachedResourceMap* sessionResourceMap(SessionID) const;
bool m_disabled; // Whether or not the cache is enabled.
- bool m_pruneEnabled;
bool m_inPruneResources;
unsigned m_capacity;
unsigned m_minDeadCapacity;
unsigned m_maxDeadCapacity;
- double m_deadDecodedDataDeletionInterval;
+ std::chrono::milliseconds m_deadDecodedDataDeletionInterval;
unsigned m_liveSize; // The number of bytes currently consumed by "live" resources in the cache.
unsigned m_deadSize; // The number of bytes currently consumed by "dead" resources in the cache.
@@ -239,28 +203,17 @@ private:
// Size-adjusted and popularity-aware LRU list collection for cache objects. This collection can hold
// more resources than the cached resource map, since it can also hold "stale" multiple versions of objects that are
// waiting to die when the clients referencing them go away.
- Vector<LRUList, 32> m_allResources;
+ Vector<std::unique_ptr<LRUList>, 32> m_allResources;
// List just for live resources with decoded data. Access to this list is based off of painting the resource.
LRUList m_liveDecodedResources;
// A URL-based map of all resources that are in the cache (including the freshest version of objects that are currently being
// referenced by a Web page).
- CachedResourceMap m_resources;
-};
-
-inline bool MemoryCache::shouldMakeResourcePurgeableOnEviction()
-{
-#if PLATFORM(IOS)
- return true;
-#else
- return false;
-#endif
-}
+ typedef HashMap<SessionID, std::unique_ptr<CachedResourceMap>> SessionCachedResourceMap;
+ SessionCachedResourceMap m_sessionResources;
-// Function to obtain the global cache.
-MemoryCache* memoryCache();
-
-}
+ Timer m_pruneTimer;
+};
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/loader/icon/IconController.cpp b/Source/WebCore/loader/icon/IconController.cpp
index 06c7a5e45..9a1a93148 100644
--- a/Source/WebCore/loader/icon/IconController.cpp
+++ b/Source/WebCore/loader/icon/IconController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2011, 2015 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
@@ -16,7 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -37,12 +37,14 @@
#include "Document.h"
#include "DocumentLoader.h"
+#include "ElementChildIterator.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
+#include "HTMLHeadElement.h"
+#include "HTMLLinkElement.h"
#include "IconDatabase.h"
-#include "IconDatabaseBase.h"
#include "IconLoader.h"
-#include "IconURL.h"
+#include "LinkIconType.h"
#include "Logging.h"
#include "MainFrame.h"
#include "Page.h"
@@ -53,7 +55,6 @@ namespace WebCore {
IconController::IconController(Frame& frame)
: m_frame(frame)
- , m_waitingForLoadDecision(false)
{
}
@@ -61,63 +62,57 @@ IconController::~IconController()
{
}
-URL IconController::url()
+static URL iconFromLinkElements(Frame& frame)
{
- IconURLs iconURLs = urlsForTypes(Favicon);
- return iconURLs.isEmpty() ? URL() : iconURLs[0].m_iconURL;
-}
-
-IconURL IconController::iconURL(IconType iconType) const
-{
- IconURL result;
- const Vector<IconURL>& iconURLs = m_frame.document()->iconURLs(iconType);
- Vector<IconURL>::const_iterator iter(iconURLs.begin());
- for (; iter != iconURLs.end(); ++iter) {
- if (result.m_iconURL.isEmpty() || !iter->m_mimeType.isEmpty())
- result = *iter;
+ // This function returns the first icon with a mime type.
+ // If no icon with mime type exists, the last icon is returned.
+ // It may make more sense to always return the last icon,
+ // but this implementation is consistent with previous behavior.
+
+ URL result;
+
+ auto* document = frame.document();
+ if (!document)
+ return result;
+
+ auto* head = document->head();
+ if (!head)
+ return result;
+
+ for (auto& linkElement : childrenOfType<HTMLLinkElement>(*head)) {
+ if (!linkElement.iconType())
+ continue;
+ if (*linkElement.iconType() != LinkIconType::Favicon)
+ continue;
+ if (linkElement.href().isEmpty())
+ continue;
+ result = linkElement.href();
+ if (!linkElement.type().isEmpty())
+ break;
}
return result;
}
-IconURLs IconController::urlsForTypes(int iconTypesMask)
+URL IconController::url()
{
- IconURLs iconURLs;
- if (m_frame.tree().parent())
- return iconURLs;
-
- if (iconTypesMask & Favicon && !appendToIconURLs(Favicon, &iconURLs))
- iconURLs.append(defaultURL(Favicon));
-
-#if ENABLE(TOUCH_ICON_LOADING)
- int missedIcons = 0;
- if (iconTypesMask & TouchPrecomposedIcon)
- missedIcons += appendToIconURLs(TouchPrecomposedIcon, &iconURLs) ? 0:1;
-
- if (iconTypesMask & TouchIcon)
- missedIcons += appendToIconURLs(TouchIcon, &iconURLs) ? 0:1;
-
- // Only return the default touch icons when the both were required and neither was gotten.
- if (missedIcons == 2) {
- iconURLs.append(defaultURL(TouchPrecomposedIcon));
- iconURLs.append(defaultURL(TouchIcon));
- }
-#endif
-
- // Finally, append all remaining icons of this type.
- const Vector<IconURL>& allIconURLs = m_frame.document()->iconURLs(iconTypesMask);
- for (Vector<IconURL>::const_iterator iter = allIconURLs.begin(); iter != allIconURLs.end(); ++iter) {
- int i;
- int iconCount = iconURLs.size();
- for (i = 0; i < iconCount; ++i) {
- if (*iter == iconURLs.at(i))
- break;
- }
- if (i == iconCount)
- iconURLs.append(*iter);
+ if (!m_frame.isMainFrame())
+ return URL();
+
+ auto icon = iconFromLinkElements(m_frame);
+ if (!icon.isEmpty())
+ return icon;
+
+ icon = m_frame.document()->completeURL(ASCIILiteral("/favicon.ico"));
+ if (icon.protocolIsInHTTPFamily()) {
+ // FIXME: Not sure we need to remove credentials like this.
+ // However this preserves behavior this code path has historically had.
+ icon.setUser(String());
+ icon.setPass(String());
+ return icon;
}
- return iconURLs;
+ return URL();
}
void IconController::commitToDatabase(const URL& icon)
@@ -142,9 +137,8 @@ void IconController::startLoader()
if (!documentCanHaveIcon(m_frame.document()->url()))
return;
- URL iconURL(url());
- String urlString(iconURL.string());
- if (urlString.isEmpty())
+ URL iconURL = url();
+ if (iconURL.isEmpty())
return;
// People who want to avoid loading images generally want to avoid loading all images, unless an exception has been made for site icons.
@@ -154,30 +148,30 @@ void IconController::startLoader()
// If we're reloading the page, always start the icon load now.
// FIXME: How can this condition ever be true?
- if (m_frame.loader().loadType() == FrameLoadTypeReload && m_frame.loader().loadType() == FrameLoadTypeReloadFromOrigin) {
+ if (m_frame.loader().loadType() == FrameLoadType::Reload && m_frame.loader().loadType() == FrameLoadType::ReloadFromOrigin) {
continueLoadWithDecision(IconLoadYes);
return;
}
if (iconDatabase().supportsAsynchronousMode()) {
// FIXME (<rdar://problem/9168605>) - We should support in-memory-only private browsing icons in asynchronous icon database mode.
- if (m_frame.page() && m_frame.page()->settings().privateBrowsingEnabled())
+ if (m_frame.page() && m_frame.page()->usesEphemeralSession())
return;
- m_frame.loader().documentLoader()->getIconLoadDecisionForIconURL(urlString);
+ m_frame.loader().documentLoader()->getIconLoadDecisionForIconURL(iconURL.string());
// Commit the icon url mapping to the database just in case we don't end up loading later.
commitToDatabase(iconURL);
return;
}
- IconLoadDecision decision = iconDatabase().synchronousLoadDecisionForIconURL(urlString, m_frame.loader().documentLoader());
+ IconLoadDecision decision = iconDatabase().synchronousLoadDecisionForIconURL(iconURL.string(), m_frame.loader().documentLoader());
if (decision == IconLoadUnknown) {
// In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
// just in case we don't end up loading later - if we commit the mapping a second time after the load, that's no big deal
// We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
// icon is later read in from disk
- LOG(IconDatabase, "IconController %p might load icon %s later", this, urlString.ascii().data());
+ LOG(IconDatabase, "IconController %p might load icon %s later", this, iconURL.string().utf8().data());
m_waitingForLoadDecision = true;
m_frame.loader().client().registerForIconNotification();
commitToDatabase(iconURL);
@@ -208,16 +202,15 @@ void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision)
ASSERT(iconLoadDecision != IconLoadUnknown);
if (iconLoadDecision == IconLoadNo) {
- URL iconURL(url());
- String urlString(iconURL.string());
- if (urlString.isEmpty())
+ URL iconURL = url();
+ if (iconURL.isEmpty())
return;
- LOG(IconDatabase, "IconController::startLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
+ LOG(IconDatabase, "IconController::startLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", iconURL.string().utf8().data());
commitToDatabase(iconURL);
if (iconDatabase().supportsAsynchronousMode()) {
- m_frame.loader().documentLoader()->getIconDataForIconURL(urlString);
+ m_frame.loader().documentLoader()->getIconDataForIconURL(iconURL.string());
return;
}
@@ -225,8 +218,8 @@ void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision)
// If the icon data hasn't been read in from disk yet, kick off the read of the icon from the database to make sure someone
// has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
// Otherwise if the icon data *is* available, notify the delegate
- if (!iconDatabase().synchronousIconDataKnownForIconURL(urlString)) {
- LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data());
+ if (!iconDatabase().synchronousIconDataKnownForIconURL(iconURL.string())) {
+ LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", iconURL.string().ascii().data());
m_frame.loader().client().registerForIconNotification();
iconDatabase().synchronousIconForPageURL(m_frame.document()->url().string(), IntSize(0, 0));
iconDatabase().synchronousIconForPageURL(m_frame.loader().initialRequest().url().string(), IntSize(0, 0));
@@ -242,45 +235,4 @@ void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision)
m_iconLoader->startLoading();
}
-bool IconController::appendToIconURLs(IconType iconType, IconURLs* iconURLs)
-{
- IconURL faviconURL = iconURL(iconType);
- if (faviconURL.m_iconURL.isEmpty())
- return false;
-
- iconURLs->append(faviconURL);
- return true;
-}
-
-IconURL IconController::defaultURL(IconType iconType)
-{
- // Don't return a favicon iconURL unless we're http or https
- URL documentURL = m_frame.document()->url();
- if (!documentURL.protocolIsInHTTPFamily())
- return IconURL();
-
- URL url;
- bool couldSetProtocol = url.setProtocol(documentURL.protocol());
- ASSERT_UNUSED(couldSetProtocol, couldSetProtocol);
- url.setHost(documentURL.host());
- if (documentURL.hasPort())
- url.setPort(documentURL.port());
-
- if (iconType == Favicon) {
- url.setPath("/favicon.ico");
- return IconURL::defaultIconURL(url, Favicon);
- }
-#if ENABLE(TOUCH_ICON_LOADING)
- if (iconType == TouchPrecomposedIcon) {
- url.setPath("/apple-touch-icon-precomposed.png");
- return IconURL::defaultIconURL(url, TouchPrecomposedIcon);
- }
- if (iconType == TouchIcon) {
- url.setPath("/apple-touch-icon.png");
- return IconURL::defaultIconURL(url, TouchIcon);
- }
-#endif
- return IconURL();
-}
-
}
diff --git a/Source/WebCore/loader/icon/IconController.h b/Source/WebCore/loader/icon/IconController.h
index 83844b9d4..31b1562a1 100644
--- a/Source/WebCore/loader/icon/IconController.h
+++ b/Source/WebCore/loader/icon/IconController.h
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -28,28 +28,23 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IconController_h
-#define IconController_h
+#pragma once
#include "IconDatabaseBase.h"
-#include "IconURL.h"
-#include "URL.h"
namespace WebCore {
class Frame;
class IconLoader;
+class URL;
class IconController {
- WTF_MAKE_NONCOPYABLE(IconController);
WTF_MAKE_FAST_ALLOCATED;
public:
explicit IconController(Frame&);
~IconController();
- URL url();
- IconURLs urlsForTypes(int iconTypesMask);
- IconURL iconURL(IconType) const;
+ WEBCORE_EXPORT URL url();
void startLoader();
void stopLoader();
@@ -60,15 +55,9 @@ public:
void commitToDatabase(const URL& icon);
private:
- bool appendToIconURLs(IconType, IconURLs*);
- IconURL defaultURL(IconType);
-
Frame& m_frame;
-
std::unique_ptr<IconLoader> m_iconLoader;
- bool m_waitingForLoadDecision;
+ bool m_waitingForLoadDecision { false };
};
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/icon/IconDatabase.cpp b/Source/WebCore/loader/icon/IconDatabase.cpp
index 39272e4d6..4cdcfaad6 100644
--- a/Source/WebCore/loader/icon/IconDatabase.cpp
+++ b/Source/WebCore/loader/icon/IconDatabase.cpp
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -34,16 +34,14 @@
#include "IconDatabaseClient.h"
#include "IconRecord.h"
#include "Image.h"
-#include "IntSize.h"
#include "Logging.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
#include "SuddenTermination.h"
#include <wtf/AutodrainedPool.h>
-#include <wtf/CurrentTime.h>
#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
-#include <wtf/text/CString.h>
// For methods that are meant to support API from the main thread - should not be called internally
#define ASSERT_NOT_SYNC_THREAD() ASSERT(!m_syncThreadRunning || !IS_ICON_SYNC_THREAD())
@@ -82,7 +80,7 @@ static const int notUsedIconExpirationTime = 60*60*24*30;
#if !LOG_DISABLED || !ERROR_DISABLED
static String urlForLogging(const String& url)
{
- static unsigned urlTruncationLength = 120;
+ static const unsigned urlTruncationLength = 120;
if (url.length() < urlTruncationLength)
return url;
@@ -90,19 +88,19 @@ static String urlForLogging(const String& url)
}
#endif
-class DefaultIconDatabaseClient : public IconDatabaseClient {
+class DefaultIconDatabaseClient final : public IconDatabaseClient {
WTF_MAKE_FAST_ALLOCATED;
public:
- virtual void didImportIconURLForPageURL(const String&) { }
- virtual void didImportIconDataForPageURL(const String&) { }
- virtual void didChangeIconForPageURL(const String&) { }
- virtual void didRemoveAllIcons() { }
- virtual void didFinishURLImport() { }
+ void didImportIconURLForPageURL(const String&) override { }
+ void didImportIconDataForPageURL(const String&) override { }
+ void didChangeIconForPageURL(const String&) override { }
+ void didRemoveAllIcons() override { }
+ void didFinishURLImport() override { }
};
static IconDatabaseClient* defaultClient()
{
- static IconDatabaseClient* defaultClient = new DefaultIconDatabaseClient();
+ static IconDatabaseClient* defaultClient = new DefaultIconDatabaseClient;
return defaultClient;
}
@@ -171,7 +169,11 @@ void IconDatabase::close()
m_removeIconsRequested = false;
m_syncDB.close();
- ASSERT(!isOpen());
+
+ // If there are still main thread callbacks in flight then the database might not actually be closed yet.
+ // But if it is closed, notify the client now.
+ if (!isOpen() && m_client)
+ m_client->didClose();
}
void IconDatabase::removeAllIcons()
@@ -185,28 +187,26 @@ void IconDatabase::removeAllIcons()
// Clear the in-memory record of every IconRecord, anything waiting to be read from disk, and anything waiting to be written to disk
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
// Clear the IconRecords for every page URL - RefCounting will cause the IconRecords themselves to be deleted
// We don't delete the actual PageRecords because we have the "retain icon for url" count to keep track of
- HashMap<String, PageURLRecord*>::iterator iter = m_pageURLToRecordMap.begin();
- HashMap<String, PageURLRecord*>::iterator end = m_pageURLToRecordMap.end();
- for (; iter != end; ++iter)
- (*iter).value->setIconRecord(0);
-
+ for (auto& pageURL : m_pageURLToRecordMap.values())
+ pageURL->setIconRecord(nullptr);
+
// Clear the iconURL -> IconRecord map
m_iconURLToRecordMap.clear();
// Clear all in-memory records of things that need to be synced out to disk
{
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
m_pageURLsPendingSync.clear();
m_iconsPendingSync.clear();
}
// Clear all in-memory records of things that need to be read in from disk
{
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
m_pageURLsPendingImport.clear();
m_pageURLsInterestedInIcons.clear();
m_iconsPendingReading.clear();
@@ -226,9 +226,9 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co
// We should go our of our way to only copy it if we have to store it
if (!isOpen() || !documentCanHaveIcon(pageURLOriginal))
- return 0;
+ return nullptr;
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
performPendingRetainAndReleaseOperations();
@@ -244,14 +244,14 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co
// 1 - The initial url import is incomplete and this pageURL was marked to be notified once it is complete if an iconURL exists
// 2 - The initial url import IS complete and this pageURL has no icon
if (!pageRecord) {
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
// Import is ongoing, there might be an icon. In this case, register to be notified when the icon comes in
// If we ever reach this condition, we know we've already made the pageURL copy
if (!m_iconURLImportComplete)
m_pageURLsInterestedInIcons.add(pageURLCopy);
- return 0;
+ return nullptr;
}
IconRecord* iconRecord = pageRecord->iconRecord();
@@ -260,14 +260,14 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co
// In this case, the pageURL is already in the set to alert the client when the iconURL mapping is complete so
// we can just bail now
if (!m_iconURLImportComplete && !iconRecord)
- return 0;
+ return nullptr;
// Assuming we're done initializing and cleanup is allowed,
// the only way we should *not* have an icon record is if this pageURL is retained but has no icon yet.
ASSERT(iconRecord || databaseCleanupCounter || m_retainedPageURLs.contains(pageURLOriginal));
if (!iconRecord)
- return 0;
+ return nullptr;
// If it's a new IconRecord object that doesn't have its imageData set yet,
// mark it to be read by the background thread
@@ -275,17 +275,17 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co
if (pageURLCopy.isNull())
pageURLCopy = pageURLOriginal.isolatedCopy();
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
m_pageURLsInterestedInIcons.add(pageURLCopy);
m_iconsPendingReading.add(iconRecord);
wakeSyncThread();
- return 0;
+ return nullptr;
}
// If the size parameter was (0, 0) that means the caller of this method just wanted the read from disk to be kicked off
// and isn't actually interested in the image return value
if (size == IntSize(0, 0))
- return 0;
+ return nullptr;
// PARANOID DISCUSSION: This method makes some assumptions. It returns a WebCore::image which the icon database might dispose of at anytime in the future,
// and Images aren't ref counted. So there is no way for the client to guarantee continued existence of the image.
@@ -300,13 +300,13 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co
return iconRecord->image(size);
}
-PassNativeImagePtr IconDatabase::synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize& size)
+NativeImagePtr IconDatabase::synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize& size)
{
Image* icon = synchronousIconForPageURL(pageURLOriginal, size);
if (!icon)
- return 0;
+ return nullptr;
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
return icon->nativeImageForCurrentFrame();
}
@@ -328,7 +328,7 @@ String IconDatabase::synchronousIconURLForPageURL(const String& pageURLOriginal)
if (!isOpen() || !documentCanHaveIcon(pageURLOriginal))
return String();
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal);
if (!pageRecord)
@@ -390,8 +390,8 @@ static inline void loadDefaultIconRecord(IconRecord* defaultIconRecord)
0x00, 0x00, 0x01, 0x52, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A,
0xFC, 0x80, 0x00, 0x00, 0x27, 0x10, 0x00, 0x0A, 0xFC, 0x80, 0x00, 0x00, 0x27, 0x10 };
- static SharedBuffer* defaultIconBuffer = SharedBuffer::create(defaultIconData, sizeof(defaultIconData)).leakRef();
- defaultIconRecord->setImageData(defaultIconBuffer);
+ static auto& defaultIconBuffer = SharedBuffer::create(defaultIconData, sizeof(defaultIconData)).leakRef();
+ defaultIconRecord->setImageData(&defaultIconBuffer);
}
#endif
@@ -416,7 +416,7 @@ void IconDatabase::retainIconForPageURL(const String& pageURL)
return;
{
- MutexLocker locker(m_urlsToRetainOrReleaseLock);
+ LockHolder locker(m_urlsToRetainOrReleaseLock);
m_urlsToRetain.add(pageURL.isolatedCopy());
m_retainOrReleaseIconRequested = true;
}
@@ -449,7 +449,7 @@ void IconDatabase::performRetainIconForPageURL(const String& pageURLOriginal, in
if (!m_iconURLImportComplete)
return;
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
// If this pageURL waiting to be sync'ed, update the sync record
// This saves us in the case where a page was ready to be deleted from the database but was just retained - so theres no need to delete it!
if (!m_privateBrowsingEnabled && m_pageURLsPendingSync.contains(pageURL)) {
@@ -469,7 +469,7 @@ void IconDatabase::releaseIconForPageURL(const String& pageURL)
return;
{
- MutexLocker locker(m_urlsToRetainOrReleaseLock);
+ LockHolder locker(m_urlsToRetainOrReleaseLock);
m_urlsToRelease.add(pageURL.isolatedCopy());
m_retainOrReleaseIconRequested = true;
}
@@ -505,7 +505,7 @@ void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, i
ASSERT(!iconRecord || (iconRecord && m_iconURLToRecordMap.get(iconRecord->iconURL()) == iconRecord));
{
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
// Since this pageURL is going away, there's no reason anyone would ever be interested in its read results
if (!m_iconURLImportComplete)
@@ -521,7 +521,7 @@ void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, i
// Mark stuff for deletion from the database only if we're not in private browsing
if (!m_privateBrowsingEnabled) {
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
m_pageURLsPendingSync.set(pageURLOriginal.isolatedCopy(), pageRecord->snapshot(true));
// If this page is the last page to refer to a particular IconRecord, that IconRecord needs to
@@ -533,7 +533,7 @@ void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, i
delete pageRecord;
}
-void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal, const String& iconURLOriginal)
+void IconDatabase::setIconDataForIconURL(SharedBuffer* dataOriginal, const String& iconURLOriginal)
{
ASSERT_NOT_SYNC_THREAD();
@@ -542,23 +542,23 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal,
if (!isOpen() || iconURLOriginal.isEmpty())
return;
- RefPtr<SharedBuffer> data = dataOriginal ? dataOriginal->copy() : PassRefPtr<SharedBuffer>(0);
+ auto data = dataOriginal ? RefPtr<SharedBuffer> { dataOriginal->copy() } : nullptr;
String iconURL = iconURLOriginal.isolatedCopy();
Vector<String> pageURLs;
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
// If this icon was pending a read, remove it from that set because this new data should override what is on disk
RefPtr<IconRecord> icon = m_iconURLToRecordMap.get(iconURL);
if (icon) {
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
m_iconsPendingReading.remove(icon.get());
} else
icon = getOrCreateIconRecord(iconURL);
// Update the data and set the time stamp
- icon->setImageData(data.release());
+ icon->setImageData(WTFMove(data));
icon->setTimestamp((int)currentTime());
// Copy the current retaining pageURLs - if any - to notify them of the change
@@ -566,7 +566,7 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal,
// Mark the IconRecord as requiring an update to the database only if private browsing is disabled
if (!m_privateBrowsingEnabled) {
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
m_iconsPendingSync.set(iconURL, icon->snapshot());
}
@@ -584,11 +584,11 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal,
// Start the timer to commit this change - or further delay the timer if it was already started
scheduleOrDeferSyncTimer();
- for (unsigned i = 0; i < pageURLs.size(); ++i) {
+ for (auto& pageURL : pageURLs) {
AutodrainedPool pool;
- LOG(IconDatabase, "Dispatching notification that retaining pageURL %s has a new icon", urlForLogging(pageURLs[i]).ascii().data());
- m_client->didChangeIconForPageURL(pageURLs[i]);
+ LOG(IconDatabase, "Dispatching notification that retaining pageURL %s has a new icon", urlForLogging(pageURL).ascii().data());
+ m_client->didChangeIconForPageURL(pageURL);
}
}
}
@@ -607,7 +607,7 @@ void IconDatabase::setIconURLForPageURL(const String& iconURLOriginal, const Str
String iconURL, pageURL;
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal);
@@ -635,13 +635,13 @@ void IconDatabase::setIconURLForPageURL(const String& iconURLOriginal, const Str
ASSERT(iconRecord->retainingPageURLs().size() == 0);
LOG(IconDatabase, "Icon for icon url %s is about to be destroyed - removing mapping for it", urlForLogging(iconRecord->iconURL()).ascii().data());
m_iconURLToRecordMap.remove(iconRecord->iconURL());
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
m_iconsPendingReading.remove(iconRecord.get());
}
// And mark this mapping to be added to the database
if (!m_privateBrowsingEnabled) {
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
m_pageURLsPendingSync.set(pageURL, pageRecord->snapshot());
// If the icon is on its last ref, mark it for deletion
@@ -673,7 +673,7 @@ IconLoadDecision IconDatabase::synchronousLoadDecisionForIconURL(const String& i
// 1 - When we read the icon urls from disk, getting the timeStamp at the same time
// 2 - When we get a new icon from the loader, in which case the timestamp is set at that time
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
if (IconRecord* icon = m_iconURLToRecordMap.get(iconURL)) {
LOG(IconDatabase, "Found expiration time on a present icon based on existing IconRecord");
return static_cast<int>(currentTime()) - static_cast<int>(icon->getTimestamp()) > iconExpirationTime ? IconLoadYes : IconLoadNo;
@@ -681,7 +681,7 @@ IconLoadDecision IconDatabase::synchronousLoadDecisionForIconURL(const String& i
}
// If we don't have a record for it, but we *have* imported all iconURLs from disk, then we should load it now
- MutexLocker readingLocker(m_pendingReadingLock);
+ LockHolder readingLocker(m_pendingReadingLock);
if (m_iconURLImportComplete)
return IconLoadYes;
@@ -698,7 +698,7 @@ bool IconDatabase::synchronousIconDataKnownForIconURL(const String& iconURL)
{
ASSERT_NOT_SYNC_THREAD();
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
if (IconRecord* icon = m_iconURLToRecordMap.get(iconURL))
return icon->imageDataStatus() != ImageDataStatusUnknown;
@@ -753,39 +753,36 @@ void IconDatabase::checkIntegrityBeforeOpening()
size_t IconDatabase::pageURLMappingCount()
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
return m_pageURLToRecordMap.size();
}
size_t IconDatabase::retainedPageURLCount()
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
performPendingRetainAndReleaseOperations();
return m_retainedPageURLs.size();
}
size_t IconDatabase::iconRecordCount()
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
return m_iconURLToRecordMap.size();
}
size_t IconDatabase::iconRecordCountWithData()
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
size_t result = 0;
-
- HashMap<String, IconRecord*>::iterator i = m_iconURLToRecordMap.begin();
- HashMap<String, IconRecord*>::iterator end = m_iconURLToRecordMap.end();
-
- for (; i != end; ++i)
- result += ((*i).value->imageDataStatus() == ImageDataStatusPresent);
-
+
+ for (auto& iconRecord : m_iconURLToRecordMap.values())
+ result += (iconRecord->imageDataStatus() == ImageDataStatusPresent);
+
return result;
}
IconDatabase::IconDatabase()
- : m_syncTimer(this, &IconDatabase::syncTimerFired)
+ : m_syncTimer(*this, &IconDatabase::syncTimerFired)
, m_syncThreadRunning(false)
, m_scheduleOrDeferSyncTimerRequested(false)
, m_isEnabled(false)
@@ -796,6 +793,7 @@ IconDatabase::IconDatabase()
, m_syncThreadHasWorkToDo(false)
, m_retainOrReleaseIconRequested(false)
, m_initialPruningComplete(false)
+ , m_mainThreadCallbackCount(0)
, m_client(defaultClient())
{
LOG(IconDatabase, "Creating IconDatabase %p", this);
@@ -807,11 +805,6 @@ IconDatabase::~IconDatabase()
ASSERT(!isOpen());
}
-void IconDatabase::notifyPendingLoadDecisionsOnMainThread(void* context)
-{
- static_cast<IconDatabase*>(context)->notifyPendingLoadDecisions();
-}
-
void IconDatabase::notifyPendingLoadDecisions()
{
ASSERT_NOT_SYNC_THREAD();
@@ -819,37 +812,24 @@ void IconDatabase::notifyPendingLoadDecisions()
// This method should only be called upon completion of the initial url import from the database
ASSERT(m_iconURLImportComplete);
LOG(IconDatabase, "Notifying all DocumentLoaders that were waiting on a load decision for their icons");
-
- HashSet<RefPtr<DocumentLoader>>::iterator i = m_loadersPendingDecision.begin();
- HashSet<RefPtr<DocumentLoader>>::iterator end = m_loadersPendingDecision.end();
-
- for (; i != end; ++i)
- if ((*i)->refCount() > 1)
- (*i)->iconLoadDecisionAvailable();
-
+
+ for (auto& loader : m_loadersPendingDecision) {
+ if (loader->refCount() > 1)
+ loader->iconLoadDecisionAvailable();
+ }
+
m_loadersPendingDecision.clear();
}
void IconDatabase::wakeSyncThread()
{
- MutexLocker locker(m_syncLock);
+ LockHolder locker(m_syncLock);
if (!m_disableSuddenTerminationWhileSyncThreadHasWorkToDo)
m_disableSuddenTerminationWhileSyncThreadHasWorkToDo = std::make_unique<SuddenTerminationDisabler>();
m_syncThreadHasWorkToDo = true;
- m_syncCondition.signal();
-}
-
-void IconDatabase::performScheduleOrDeferSyncTimer()
-{
- m_syncTimer.startOneShot(updateTimerDelay);
- m_scheduleOrDeferSyncTimerRequested = false;
-}
-
-void IconDatabase::performScheduleOrDeferSyncTimerOnMainThread(void* context)
-{
- static_cast<IconDatabase*>(context)->performScheduleOrDeferSyncTimer();
+ m_syncCondition.notifyOne();
}
void IconDatabase::scheduleOrDeferSyncTimer()
@@ -863,10 +843,13 @@ void IconDatabase::scheduleOrDeferSyncTimer()
m_disableSuddenTerminationWhileSyncTimerScheduled = std::make_unique<SuddenTerminationDisabler>();
m_scheduleOrDeferSyncTimerRequested = true;
- callOnMainThread(performScheduleOrDeferSyncTimerOnMainThread, this);
+ callOnMainThread([this] {
+ m_syncTimer.startOneShot(updateTimerDelay);
+ m_scheduleOrDeferSyncTimerRequested = false;
+ });
}
-void IconDatabase::syncTimerFired(Timer<IconDatabase>&)
+void IconDatabase::syncTimerFired()
{
ASSERT_NOT_SYNC_THREAD();
wakeSyncThread();
@@ -880,35 +863,39 @@ void IconDatabase::syncTimerFired(Timer<IconDatabase>&)
bool IconDatabase::isOpen() const
{
- MutexLocker locker(m_syncLock);
- return m_syncDB.isOpen();
+ return isOpenBesidesMainThreadCallbacks() || m_mainThreadCallbackCount;
+}
+
+bool IconDatabase::isOpenBesidesMainThreadCallbacks() const
+{
+ LockHolder locker(m_syncLock);
+ return m_syncThreadRunning || m_syncDB.isOpen();
}
String IconDatabase::databasePath() const
{
- MutexLocker locker(m_syncLock);
+ LockHolder locker(m_syncLock);
return m_completeDatabasePath.isolatedCopy();
}
String IconDatabase::defaultDatabaseFilename()
{
- DEFINE_STATIC_LOCAL(String, defaultDatabaseFilename, (ASCIILiteral("WebpageIcons.db")));
- return defaultDatabaseFilename.isolatedCopy();
+ static NeverDestroyed<String> defaultDatabaseFilename(ASCIILiteral("WebpageIcons.db"));
+ return defaultDatabaseFilename.get().isolatedCopy();
}
// Unlike getOrCreatePageURLRecord(), getOrCreateIconRecord() does not mark the icon as "interested in import"
-PassRefPtr<IconRecord> IconDatabase::getOrCreateIconRecord(const String& iconURL)
+Ref<IconRecord> IconDatabase::getOrCreateIconRecord(const String& iconURL)
{
// Clients of getOrCreateIconRecord() are required to acquire the m_urlAndIconLock before calling this method
ASSERT(!m_urlAndIconLock.tryLock());
- if (IconRecord* icon = m_iconURLToRecordMap.get(iconURL))
- return icon;
+ if (auto* icon = m_iconURLToRecordMap.get(iconURL))
+ return *icon;
- RefPtr<IconRecord> newIcon = IconRecord::create(iconURL);
- m_iconURLToRecordMap.set(iconURL, newIcon.get());
-
- return newIcon.release();
+ auto newIcon = IconRecord::create(iconURL);
+ m_iconURLToRecordMap.set(iconURL, newIcon.ptr());
+ return newIcon;
}
// This method retrieves the existing PageURLRecord, or creates a new one and marks it as "interested in the import" for later notification
@@ -918,11 +905,11 @@ PageURLRecord* IconDatabase::getOrCreatePageURLRecord(const String& pageURL)
ASSERT(!m_urlAndIconLock.tryLock());
if (!documentCanHaveIcon(pageURL))
- return 0;
+ return nullptr;
PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURL);
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
if (!m_iconURLImportComplete) {
// If the initial import of all URLs hasn't completed and we have no page record, we assume we *might* know about this later and create a record for it
if (!pageRecord) {
@@ -935,7 +922,7 @@ PageURLRecord* IconDatabase::getOrCreatePageURLRecord(const String& pageURL)
// Mark the URL as "interested in the result of the import" then bail
if (!pageRecord->iconRecord()) {
m_pageURLsPendingImport.add(pageURL);
- return 0;
+ return nullptr;
}
}
@@ -991,7 +978,7 @@ void IconDatabase::iconDatabaseSyncThread()
}
{
- MutexLocker locker(m_syncLock);
+ LockHolder locker(m_syncLock);
if (!m_syncDB.open(m_completeDatabasePath)) {
LOG_ERROR("Unable to open icon database at path %s - %s", m_completeDatabasePath.ascii().data(), m_syncDB.lastErrorMsg());
return;
@@ -1119,7 +1106,7 @@ void IconDatabase::performOpenInitialization()
m_syncDB.close();
{
- MutexLocker locker(m_syncLock);
+ LockHolder locker(m_syncLock);
// Should've been consumed by SQLite, delete just to make sure we don't see it again in the future;
deleteFile(m_completeDatabasePath + "-journal");
deleteFile(m_completeDatabasePath);
@@ -1165,16 +1152,16 @@ bool IconDatabase::checkIntegrity()
ASSERT_ICON_SYNC_THREAD();
SQLiteStatement integrity(m_syncDB, "PRAGMA integrity_check;");
- if (integrity.prepare() != SQLResultOk) {
+ if (integrity.prepare() != SQLITE_OK) {
LOG_ERROR("checkIntegrity failed to execute");
return false;
}
int resultCode = integrity.step();
- if (resultCode == SQLResultOk)
+ if (resultCode == SQLITE_OK)
return true;
-
- if (resultCode != SQLResultRow)
+
+ if (resultCode != SQLITE_ROW)
return false;
int columns = integrity.columnCount();
@@ -1209,25 +1196,25 @@ void IconDatabase::performURLImport()
SQLiteStatement query(m_syncDB, importQuery);
- if (query.prepare() != SQLResultOk) {
+ if (query.prepare() != SQLITE_OK) {
LOG_ERROR("Unable to prepare icon url import query");
return;
}
int result = query.step();
- while (result == SQLResultRow) {
+ while (result == SQLITE_ROW) {
AutodrainedPool pool;
String pageURL = query.getColumnText(0);
String iconURL = query.getColumnText(1);
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURL);
// If the pageRecord doesn't exist in this map, then no one has retained this pageURL
// If the s_databaseCleanupCounter count is non-zero, then we're not supposed to be pruning the database in any manner,
- // so go ahead and actually create a pageURLRecord for this url even though it's not retained.
+ // so actually create a pageURLRecord for this url even though it's not retained.
// If database cleanup *is* allowed, we don't want to bother pulling in a page url from disk that noone is actually interested
// in - we'll prune it later instead!
if (!pageRecord && databaseCleanupCounter && documentCanHaveIcon(pageURL)) {
@@ -1254,7 +1241,7 @@ void IconDatabase::performURLImport()
// one for the URL and one for the Image itself
// Note that WebIconDatabase is not neccessarily API so we might be able to make this change
{
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
if (m_pageURLsPendingImport.contains(pageURL)) {
dispatchDidImportIconURLForPageURLOnMainThread(pageURL);
m_pageURLsPendingImport.remove(pageURL);
@@ -1270,14 +1257,14 @@ void IconDatabase::performURLImport()
result = query.step();
}
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG(IconDatabase, "Error reading page->icon url mappings from database");
// Clear the m_pageURLsPendingImport set - either the page URLs ended up with an iconURL (that we'll notify about) or not,
// but after m_iconURLImportComplete is set to true, we don't care about this set anymore
Vector<String> urls;
{
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
urls.appendRange(m_pageURLsPendingImport.begin(), m_pageURLsPendingImport.end());
m_pageURLsPendingImport.clear();
@@ -1290,15 +1277,15 @@ void IconDatabase::performURLImport()
// Remove unretained ones if database cleanup is allowed
// Keep a set of ones that are retained and pending notification
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
performPendingRetainAndReleaseOperations();
- for (unsigned i = 0; i < urls.size(); ++i) {
- if (!m_retainedPageURLs.contains(urls[i])) {
- PageURLRecord* record = m_pageURLToRecordMap.get(urls[i]);
+ for (auto& url : urls) {
+ if (!m_retainedPageURLs.contains(url)) {
+ PageURLRecord* record = m_pageURLToRecordMap.get(url);
if (record && !databaseCleanupCounter) {
- m_pageURLToRecordMap.remove(urls[i]);
+ m_pageURLToRecordMap.remove(url);
IconRecord* iconRecord = record->iconRecord();
// If this page is the only remaining retainer of its icon, mark that icon for deletion and don't bother
@@ -1307,12 +1294,12 @@ void IconDatabase::performURLImport()
m_iconURLToRecordMap.remove(iconRecord->iconURL());
{
- MutexLocker locker(m_pendingReadingLock);
- m_pageURLsInterestedInIcons.remove(urls[i]);
+ LockHolder locker(m_pendingReadingLock);
+ m_pageURLsInterestedInIcons.remove(url);
m_iconsPendingReading.remove(iconRecord);
}
{
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
m_iconsPendingSync.set(iconRecord->iconURL(), iconRecord->snapshot(true));
}
}
@@ -1320,18 +1307,18 @@ void IconDatabase::performURLImport()
delete record;
}
} else {
- urlsToNotify.append(urls[i]);
+ urlsToNotify.append(url);
}
}
}
LOG(IconDatabase, "Notifying %lu interested page URLs that their icon URL is known due to the import", static_cast<unsigned long>(urlsToNotify.size()));
// Now that we don't hold any locks, perform the actual notifications
- for (unsigned i = 0; i < urlsToNotify.size(); ++i) {
+ for (auto& url : urlsToNotify) {
AutodrainedPool pool;
- LOG(IconDatabase, "Notifying icon info known for pageURL %s", urlsToNotify[i].ascii().data());
- dispatchDidImportIconURLForPageURLOnMainThread(urlsToNotify[i]);
+ LOG(IconDatabase, "Notifying icon info known for pageURL %s", url.ascii().data());
+ dispatchDidImportIconURLForPageURLOnMainThread(url);
if (shouldStopThreadActivity())
return;
}
@@ -1340,7 +1327,9 @@ void IconDatabase::performURLImport()
dispatchDidFinishURLImportOnMainThread();
// Notify all DocumentLoaders that were waiting for an icon load decision on the main thread
- callOnMainThread(notifyPendingLoadDecisionsOnMainThread, this);
+ callOnMainThread([this] {
+ notifyPendingLoadDecisions();
+ });
}
void IconDatabase::syncThreadMainLoop()
@@ -1349,7 +1338,7 @@ void IconDatabase::syncThreadMainLoop()
m_syncLock.lock();
- std::unique_ptr<SuddenTerminationDisabler> disableSuddenTermination = std::move(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo);
+ std::unique_ptr<SuddenTerminationDisabler> disableSuddenTermination = WTFMove(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo);
// We'll either do any pending work on our first pass through the loop, or we'll terminate
// without doing any work. Either way we're dealing with any currently-pending work.
@@ -1371,11 +1360,13 @@ void IconDatabase::syncThreadMainLoop()
}
// Then, if the thread should be quitting, quit now!
- if (m_threadTerminationRequested)
- break;
+ if (m_threadTerminationRequested) {
+ cleanupSyncThread();
+ return;
+ }
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
performPendingRetainAndReleaseOperations();
}
@@ -1437,7 +1428,7 @@ void IconDatabase::syncThreadMainLoop()
m_syncThreadHasWorkToDo = false;
ASSERT(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo);
- disableSuddenTermination = std::move(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo);
+ disableSuddenTermination = WTFMove(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo);
}
m_syncLock.unlock();
@@ -1455,7 +1446,7 @@ void IconDatabase::performPendingRetainAndReleaseOperations()
HashCountedSet<String> toRelease;
{
- MutexLocker pendingWorkLocker(m_urlsToRetainOrReleaseLock);
+ LockHolder pendingWorkLocker(m_urlsToRetainOrReleaseLock);
if (!m_retainOrReleaseIconRequested)
return;
@@ -1467,14 +1458,14 @@ void IconDatabase::performPendingRetainAndReleaseOperations()
m_retainOrReleaseIconRequested = false;
}
- for (HashCountedSet<String>::const_iterator it = toRetain.begin(), end = toRetain.end(); it != end; ++it) {
- ASSERT(!it->key.impl() || it->key.impl()->hasOneRef());
- performRetainIconForPageURL(it->key, it->value);
+ for (auto& entry : toRetain) {
+ ASSERT(!entry.key.impl() || entry.key.impl()->hasOneRef());
+ performRetainIconForPageURL(entry.key, entry.value);
}
- for (HashCountedSet<String>::const_iterator it = toRelease.begin(), end = toRelease.end(); it != end; ++it) {
- ASSERT(!it->key.impl() || it->key.impl()->hasOneRef());
- performReleaseIconForPageURL(it->key, it->value);
+ for (auto& entry : toRelease) {
+ ASSERT(!entry.key.impl() || entry.key.impl()->hasOneRef());
+ performReleaseIconForPageURL(entry.key, entry.value);
}
}
@@ -1492,7 +1483,7 @@ bool IconDatabase::readFromDatabase()
// This way we won't hold the lock for a long period of time
Vector<IconRecord*> icons;
{
- MutexLocker locker(m_pendingReadingLock);
+ LockHolder locker(m_pendingReadingLock);
icons.appendRange(m_iconsPendingReading.begin(), m_iconsPendingReading.end());
}
@@ -1501,17 +1492,17 @@ bool IconDatabase::readFromDatabase()
for (unsigned i = 0; i < icons.size(); ++i) {
didAnyWork = true;
- RefPtr<SharedBuffer> imageData = getImageDataForIconURLFromSQLDatabase(icons[i]->iconURL());
+ auto imageData = getImageDataForIconURLFromSQLDatabase(icons[i]->iconURL());
// Verify this icon still wants to be read from disk
{
- MutexLocker urlLocker(m_urlAndIconLock);
+ LockHolder urlLocker(m_urlAndIconLock);
{
- MutexLocker readLocker(m_pendingReadingLock);
+ LockHolder readLocker(m_pendingReadingLock);
if (m_iconsPendingReading.contains(icons[i])) {
// Set the new data
- icons[i]->setImageData(imageData.release());
+ icons[i]->setImageData(WTFMove(imageData));
// Remove this icon from the set that needs to be read
m_iconsPendingReading.remove(icons[i]);
@@ -1530,12 +1521,10 @@ bool IconDatabase::readFromDatabase()
outerHash = &(icons[i]->retainingPageURLs());
}
- HashSet<String>::const_iterator iter = outerHash->begin();
- HashSet<String>::const_iterator end = outerHash->end();
- for (; iter != end; ++iter) {
- if (innerHash->contains(*iter)) {
- LOG(IconDatabase, "%s is interested in the icon we just read. Adding it to the notification list and removing it from the interested set", urlForLogging(*iter).ascii().data());
- urlsToNotify.add(*iter);
+ for (auto& outer : *outerHash) {
+ if (innerHash->contains(outer)) {
+ LOG(IconDatabase, "%s is interested in the icon we just read. Adding it to the notification list and removing it from the interested set", urlForLogging(outer).ascii().data());
+ urlsToNotify.add(outer);
}
// If we ever get to the point were we've seen every url interested in this icon, break early
@@ -1547,10 +1536,8 @@ bool IconDatabase::readFromDatabase()
if (urlsToNotify.size() == m_pageURLsInterestedInIcons.size())
m_pageURLsInterestedInIcons.clear();
else {
- iter = urlsToNotify.begin();
- end = urlsToNotify.end();
- for (; iter != end; ++iter)
- m_pageURLsInterestedInIcons.remove(*iter);
+ for (auto& url : urlsToNotify)
+ m_pageURLsInterestedInIcons.remove(url);
}
}
}
@@ -1595,11 +1582,11 @@ bool IconDatabase::writeToDatabase()
// we'll pick it up on the next pass. This greatly simplifies the locking strategy for this method and remains cohesive with changes
// asked for by the database on the main thread
{
- MutexLocker locker(m_urlAndIconLock);
+ LockHolder locker(m_urlAndIconLock);
Vector<IconSnapshot> iconSnapshots;
Vector<PageURLSnapshot> pageSnapshots;
{
- MutexLocker locker(m_pendingSyncLock);
+ LockHolder locker(m_pendingSyncLock);
iconSnapshots.appendRange(m_iconsPendingSync.begin().values(), m_iconsPendingSync.end().values());
m_iconsPendingSync.clear();
@@ -1614,19 +1601,19 @@ bool IconDatabase::writeToDatabase()
SQLiteTransaction syncTransaction(m_syncDB);
syncTransaction.begin();
- for (unsigned i = 0; i < iconSnapshots.size(); ++i) {
- writeIconSnapshotToSQLDatabase(iconSnapshots[i]);
- LOG(IconDatabase, "Wrote IconRecord for IconURL %s with timeStamp of %i to the DB", urlForLogging(iconSnapshots[i].iconURL()).ascii().data(), iconSnapshots[i].timestamp());
+ for (auto& snapshot : iconSnapshots) {
+ writeIconSnapshotToSQLDatabase(snapshot);
+ LOG(IconDatabase, "Wrote IconRecord for IconURL %s with timeStamp of %i to the DB", urlForLogging(snapshot.iconURL()).ascii().data(), snapshot.timestamp());
}
- for (unsigned i = 0; i < pageSnapshots.size(); ++i) {
+ for (auto& snapshot : pageSnapshots) {
// If the icon URL is empty, this page is meant to be deleted
// ASSERTs are sanity checks to make sure the mappings exist if they should and don't if they shouldn't
- if (pageSnapshots[i].iconURL().isEmpty())
- removePageURLFromSQLDatabase(pageSnapshots[i].pageURL());
+ if (snapshot.iconURL().isEmpty())
+ removePageURLFromSQLDatabase(snapshot.pageURL());
else
- setIconURLForPageURLInSQLDatabase(pageSnapshots[i].iconURL(), pageSnapshots[i].pageURL());
- LOG(IconDatabase, "Committed IconURL for PageURL %s to database", urlForLogging(pageSnapshots[i].pageURL()).ascii().data());
+ setIconURLForPageURLInSQLDatabase(snapshot.iconURL(), snapshot.pageURL());
+ LOG(IconDatabase, "Committed IconURL for PageURL %s to database", urlForLogging(snapshot.pageURL()).ascii().data());
}
syncTransaction.commit();
@@ -1661,13 +1648,13 @@ void IconDatabase::pruneUnretainedIcons()
pageSQL.prepare();
int result;
- while ((result = pageSQL.step()) == SQLResultRow) {
- MutexLocker locker(m_urlAndIconLock);
+ while ((result = pageSQL.step()) == SQLITE_ROW) {
+ LockHolder locker(m_urlAndIconLock);
if (!m_pageURLToRecordMap.contains(pageSQL.getColumnText(1)))
pageIDsToDelete.append(pageSQL.getColumnInt64(0));
}
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Error reading PageURL table from on-disk DB");
pageSQL.finalize();
@@ -1683,7 +1670,7 @@ void IconDatabase::pruneUnretainedIcons()
LOG(IconDatabase, "Pruning page with rowid %lli from disk", static_cast<long long>(pageIDsToDelete[i]));
pageDeleteSQL.bindInt64(1, pageIDsToDelete[i]);
int result = pageDeleteSQL.step();
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("Unabled to delete page with id %lli from disk", static_cast<long long>(pageIDsToDelete[i]));
pageDeleteSQL.reset();
@@ -1762,20 +1749,20 @@ void IconDatabase::deleteAllPreparedStatements()
{
ASSERT_ICON_SYNC_THREAD();
- m_setIconIDForPageURLStatement.clear();
- m_removePageURLStatement.clear();
- m_getIconIDForIconURLStatement.clear();
- m_getImageDataForIconURLStatement.clear();
- m_addIconToIconInfoStatement.clear();
- m_addIconToIconDataStatement.clear();
- m_getImageDataStatement.clear();
- m_deletePageURLsForIconURLStatement.clear();
- m_deleteIconFromIconInfoStatement.clear();
- m_deleteIconFromIconDataStatement.clear();
- m_updateIconInfoStatement.clear();
- m_updateIconDataStatement.clear();
- m_setIconInfoStatement.clear();
- m_setIconDataStatement.clear();
+ m_setIconIDForPageURLStatement = nullptr;
+ m_removePageURLStatement = nullptr;
+ m_getIconIDForIconURLStatement = nullptr;
+ m_getImageDataForIconURLStatement = nullptr;
+ m_addIconToIconInfoStatement = nullptr;
+ m_addIconToIconDataStatement = nullptr;
+ m_getImageDataStatement = nullptr;
+ m_deletePageURLsForIconURLStatement = nullptr;
+ m_deleteIconFromIconInfoStatement = nullptr;
+ m_deleteIconFromIconDataStatement = nullptr;
+ m_updateIconInfoStatement = nullptr;
+ m_updateIconDataStatement = nullptr;
+ m_setIconInfoStatement = nullptr;
+ m_setIconDataStatement = nullptr;
}
void* IconDatabase::cleanupSyncThread()
@@ -1795,7 +1782,7 @@ void* IconDatabase::cleanupSyncThread()
writeToDatabase();
// Close the database
- MutexLocker locker(m_syncLock);
+ LockHolder locker(m_syncLock);
m_databaseDirectory = String();
m_completeDatabasePath = String();
@@ -1807,23 +1794,23 @@ void* IconDatabase::cleanupSyncThread()
#endif
m_syncThreadRunning = false;
- return 0;
+ return nullptr;
}
// readySQLiteStatement() handles two things
// 1 - If the SQLDatabase& argument is different, the statement must be destroyed and remade. This happens when the user
// switches to and from private browsing
// 2 - Lazy construction of the Statement in the first place, in case we've never made this query before
-inline void readySQLiteStatement(OwnPtr<SQLiteStatement>& statement, SQLiteDatabase& db, const String& str)
+inline void readySQLiteStatement(std::unique_ptr<SQLiteStatement>& statement, SQLiteDatabase& db, const String& str)
{
- if (statement && (statement->database() != &db || statement->isExpired())) {
+ if (statement && (&statement->database() != &db || statement->isExpired())) {
if (statement->isExpired())
LOG(IconDatabase, "SQLiteStatement associated with %s is expired", str.ascii().data());
- statement.clear();
+ statement = nullptr;
}
if (!statement) {
- statement = adoptPtr(new SQLiteStatement(db, str));
- if (statement->prepare() != SQLResultOk)
+ statement = std::make_unique<SQLiteStatement>(db, str);
+ if (statement->prepare() != SQLITE_OK)
LOG_ERROR("Preparing statement %s failed", str.ascii().data());
}
}
@@ -1855,7 +1842,7 @@ void IconDatabase::setIconIDForPageURLInSQLDatabase(int64_t iconID, const String
m_setIconIDForPageURLStatement->bindInt64(2, iconID);
int result = m_setIconIDForPageURLStatement->step();
- if (result != SQLResultDone) {
+ if (result != SQLITE_DONE) {
ASSERT_NOT_REACHED();
LOG_ERROR("setIconIDForPageURLQuery failed for url %s", urlForLogging(pageURL).ascii().data());
}
@@ -1870,7 +1857,7 @@ void IconDatabase::removePageURLFromSQLDatabase(const String& pageURL)
readySQLiteStatement(m_removePageURLStatement, m_syncDB, "DELETE FROM PageURL WHERE url = (?);");
m_removePageURLStatement->bindText(1, pageURL);
- if (m_removePageURLStatement->step() != SQLResultDone)
+ if (m_removePageURLStatement->step() != SQLITE_DONE)
LOG_ERROR("removePageURLFromSQLDatabase failed for url %s", urlForLogging(pageURL).ascii().data());
m_removePageURLStatement->reset();
@@ -1885,10 +1872,10 @@ int64_t IconDatabase::getIconIDForIconURLFromSQLDatabase(const String& iconURL)
m_getIconIDForIconURLStatement->bindText(1, iconURL);
int64_t result = m_getIconIDForIconURLStatement->step();
- if (result == SQLResultRow)
+ if (result == SQLITE_ROW)
result = m_getIconIDForIconURLStatement->getColumnInt64(0);
else {
- if (result != SQLResultDone)
+ if (result != SQLITE_DONE)
LOG_ERROR("getIconIDForIconURLFromSQLDatabase failed for url %s", urlForLogging(iconURL).ascii().data());
result = 0;
}
@@ -1910,7 +1897,7 @@ int64_t IconDatabase::addIconURLToSQLDatabase(const String& iconURL)
int result = m_addIconToIconInfoStatement->step();
m_addIconToIconInfoStatement->reset();
- if (result != SQLResultDone) {
+ if (result != SQLITE_DONE) {
LOG_ERROR("addIconURLToSQLDatabase failed to insert %s into IconInfo", urlForLogging(iconURL).ascii().data());
return 0;
}
@@ -1921,7 +1908,7 @@ int64_t IconDatabase::addIconURLToSQLDatabase(const String& iconURL)
result = m_addIconToIconDataStatement->step();
m_addIconToIconDataStatement->reset();
- if (result != SQLResultDone) {
+ if (result != SQLITE_DONE) {
LOG_ERROR("addIconURLToSQLDatabase failed to insert %s into IconData", urlForLogging(iconURL).ascii().data());
return 0;
}
@@ -1929,7 +1916,7 @@ int64_t IconDatabase::addIconURLToSQLDatabase(const String& iconURL)
return iconID;
}
-PassRefPtr<SharedBuffer> IconDatabase::getImageDataForIconURLFromSQLDatabase(const String& iconURL)
+RefPtr<SharedBuffer> IconDatabase::getImageDataForIconURLFromSQLDatabase(const String& iconURL)
{
ASSERT_ICON_SYNC_THREAD();
@@ -1939,16 +1926,16 @@ PassRefPtr<SharedBuffer> IconDatabase::getImageDataForIconURLFromSQLDatabase(con
m_getImageDataForIconURLStatement->bindText(1, iconURL);
int result = m_getImageDataForIconURLStatement->step();
- if (result == SQLResultRow) {
+ if (result == SQLITE_ROW) {
Vector<char> data;
m_getImageDataForIconURLStatement->getColumnBlobAsVector(0, data);
imageData = SharedBuffer::create(data.data(), data.size());
- } else if (result != SQLResultDone)
+ } else if (result != SQLITE_DONE)
LOG_ERROR("getImageDataForIconURLFromSQLDatabase failed for url %s", urlForLogging(iconURL).ascii().data());
m_getImageDataForIconURLStatement->reset();
- return imageData.release();
+ return imageData;
}
void IconDatabase::removeIconFromSQLDatabase(const String& iconURL)
@@ -1970,21 +1957,21 @@ void IconDatabase::removeIconFromSQLDatabase(const String& iconURL)
readySQLiteStatement(m_deletePageURLsForIconURLStatement, m_syncDB, "DELETE FROM PageURL WHERE PageURL.iconID = (?);");
m_deletePageURLsForIconURLStatement->bindInt64(1, iconID);
- if (m_deletePageURLsForIconURLStatement->step() != SQLResultDone)
+ if (m_deletePageURLsForIconURLStatement->step() != SQLITE_DONE)
LOG_ERROR("m_deletePageURLsForIconURLStatement failed for url %s", urlForLogging(iconURL).ascii().data());
readySQLiteStatement(m_deleteIconFromIconInfoStatement, m_syncDB, "DELETE FROM IconInfo WHERE IconInfo.iconID = (?);");
m_deleteIconFromIconInfoStatement->bindInt64(1, iconID);
- if (m_deleteIconFromIconInfoStatement->step() != SQLResultDone)
+ if (m_deleteIconFromIconInfoStatement->step() != SQLITE_DONE)
LOG_ERROR("m_deleteIconFromIconInfoStatement failed for url %s", urlForLogging(iconURL).ascii().data());
-
+
readySQLiteStatement(m_deleteIconFromIconDataStatement, m_syncDB, "DELETE FROM IconData WHERE IconData.iconID = (?);");
m_deleteIconFromIconDataStatement->bindInt64(1, iconID);
- if (m_deleteIconFromIconDataStatement->step() != SQLResultDone)
+ if (m_deleteIconFromIconDataStatement->step() != SQLITE_DONE)
LOG_ERROR("m_deleteIconFromIconDataStatement failed for url %s", urlForLogging(iconURL).ascii().data());
-
+
m_deletePageURLsForIconURLStatement->reset();
m_deleteIconFromIconInfoStatement->reset();
m_deleteIconFromIconDataStatement->reset();
@@ -2018,7 +2005,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot)
m_updateIconInfoStatement->bindText(2, snapshot.iconURL());
m_updateIconInfoStatement->bindInt64(3, iconID);
- if (m_updateIconInfoStatement->step() != SQLResultDone)
+ if (m_updateIconInfoStatement->step() != SQLITE_DONE)
LOG_ERROR("Failed to update icon info for url %s", urlForLogging(snapshot.iconURL()).ascii().data());
m_updateIconInfoStatement->reset();
@@ -2033,7 +2020,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot)
else
m_updateIconDataStatement->bindNull(1);
- if (m_updateIconDataStatement->step() != SQLResultDone)
+ if (m_updateIconDataStatement->step() != SQLITE_DONE)
LOG_ERROR("Failed to update icon data for url %s", urlForLogging(snapshot.iconURL()).ascii().data());
m_updateIconDataStatement->reset();
@@ -2042,7 +2029,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot)
m_setIconInfoStatement->bindText(1, snapshot.iconURL());
m_setIconInfoStatement->bindInt64(2, snapshot.timestamp());
- if (m_setIconInfoStatement->step() != SQLResultDone)
+ if (m_setIconInfoStatement->step() != SQLITE_DONE)
LOG_ERROR("Failed to set icon info for url %s", urlForLogging(snapshot.iconURL()).ascii().data());
m_setIconInfoStatement->reset();
@@ -2059,7 +2046,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot)
else
m_setIconDataStatement->bindNull(2);
- if (m_setIconDataStatement->step() != SQLResultDone)
+ if (m_setIconDataStatement->step() != SQLITE_DONE)
LOG_ERROR("Failed to set icon data for url %s", urlForLogging(snapshot.iconURL()).ascii().data());
m_setIconDataStatement->reset();
@@ -2080,133 +2067,71 @@ void IconDatabase::setWasExcludedFromBackup()
SQLiteStatement(m_syncDB, "INSERT INTO IconDatabaseInfo (key, value) VALUES ('ExcludedFromBackup', 1)").executeCommand();
}
-class ClientWorkItem {
- WTF_MAKE_FAST_ALLOCATED;
-public:
- ClientWorkItem(IconDatabaseClient* client)
- : m_client(client)
- { }
- virtual void performWork() = 0;
- virtual ~ClientWorkItem() { }
-
-protected:
- IconDatabaseClient* m_client;
-};
-
-class ImportedIconURLForPageURLWorkItem : public ClientWorkItem {
-public:
- ImportedIconURLForPageURLWorkItem(IconDatabaseClient* client, const String& pageURL)
- : ClientWorkItem(client)
- , m_pageURL(new String(pageURL.isolatedCopy()))
- { }
-
- virtual ~ImportedIconURLForPageURLWorkItem()
- {
- delete m_pageURL;
- }
-
- virtual void performWork()
- {
- ASSERT(m_client);
- m_client->didImportIconURLForPageURL(*m_pageURL);
- m_client = 0;
- }
-
-private:
- String* m_pageURL;
-};
-
-class ImportedIconDataForPageURLWorkItem : public ClientWorkItem {
-public:
- ImportedIconDataForPageURLWorkItem(IconDatabaseClient* client, const String& pageURL)
- : ClientWorkItem(client)
- , m_pageURL(new String(pageURL.isolatedCopy()))
- { }
-
- virtual ~ImportedIconDataForPageURLWorkItem()
- {
- delete m_pageURL;
- }
-
- virtual void performWork()
- {
- ASSERT(m_client);
- m_client->didImportIconDataForPageURL(*m_pageURL);
- m_client = 0;
- }
-
-private:
- String* m_pageURL;
-};
-
-class RemovedAllIconsWorkItem : public ClientWorkItem {
-public:
- RemovedAllIconsWorkItem(IconDatabaseClient* client)
- : ClientWorkItem(client)
- { }
-
- virtual void performWork()
- {
- ASSERT(m_client);
- m_client->didRemoveAllIcons();
- m_client = 0;
- }
-};
+void IconDatabase::checkClosedAfterMainThreadCallback()
+{
+ ASSERT_NOT_SYNC_THREAD();
-class FinishedURLImport : public ClientWorkItem {
-public:
- FinishedURLImport(IconDatabaseClient* client)
- : ClientWorkItem(client)
- { }
+ // If there are still callbacks in flight from the sync thread we cannot possibly be closed.
+ if (--m_mainThreadCallbackCount)
+ return;
- virtual void performWork()
- {
- ASSERT(m_client);
- m_client->didFinishURLImport();
- m_client = 0;
- }
-};
+ // Even if there's no more pending callbacks the database might otherwise still be open.
+ if (isOpenBesidesMainThreadCallbacks())
+ return;
-static void performWorkItem(void* context)
-{
- ClientWorkItem* item = static_cast<ClientWorkItem*>(context);
- item->performWork();
- delete item;
+ // This database is now actually closed! But first notify the client.
+ if (m_client)
+ m_client->didClose();
}
void IconDatabase::dispatchDidImportIconURLForPageURLOnMainThread(const String& pageURL)
{
ASSERT_ICON_SYNC_THREAD();
+ ++m_mainThreadCallbackCount;
- ImportedIconURLForPageURLWorkItem* work = new ImportedIconURLForPageURLWorkItem(m_client, pageURL);
- callOnMainThread(performWorkItem, work);
+ callOnMainThread([this, pageURL = pageURL.isolatedCopy()] {
+ if (m_client)
+ m_client->didImportIconURLForPageURL(pageURL);
+ checkClosedAfterMainThreadCallback();
+ });
}
void IconDatabase::dispatchDidImportIconDataForPageURLOnMainThread(const String& pageURL)
{
ASSERT_ICON_SYNC_THREAD();
+ ++m_mainThreadCallbackCount;
- ImportedIconDataForPageURLWorkItem* work = new ImportedIconDataForPageURLWorkItem(m_client, pageURL);
- callOnMainThread(performWorkItem, work);
+ callOnMainThread([this, pageURL = pageURL.isolatedCopy()] {
+ if (m_client)
+ m_client->didImportIconDataForPageURL(pageURL);
+ checkClosedAfterMainThreadCallback();
+ });
}
void IconDatabase::dispatchDidRemoveAllIconsOnMainThread()
{
ASSERT_ICON_SYNC_THREAD();
+ ++m_mainThreadCallbackCount;
- RemovedAllIconsWorkItem* work = new RemovedAllIconsWorkItem(m_client);
- callOnMainThread(performWorkItem, work);
+ callOnMainThread([this] {
+ if (m_client)
+ m_client->didRemoveAllIcons();
+ checkClosedAfterMainThreadCallback();
+ });
}
void IconDatabase::dispatchDidFinishURLImportOnMainThread()
{
ASSERT_ICON_SYNC_THREAD();
+ ++m_mainThreadCallbackCount;
- FinishedURLImport* work = new FinishedURLImport(m_client);
- callOnMainThread(performWorkItem, work);
+ callOnMainThread([this] {
+ if (m_client)
+ m_client->didFinishURLImport();
+ checkClosedAfterMainThreadCallback();
+ });
}
-
} // namespace WebCore
#endif // ENABLE(ICONDATABASE)
diff --git a/Source/WebCore/loader/icon/IconDatabase.h b/Source/WebCore/loader/icon/IconDatabase.h
index 04db323a7..061af4a12 100644
--- a/Source/WebCore/loader/icon/IconDatabase.h
+++ b/Source/WebCore/loader/icon/IconDatabase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,113 +24,101 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IconDatabase_h
-#define IconDatabase_h
+#pragma once
#include "IconDatabaseBase.h"
-#include "Timer.h"
-#include <wtf/HashCountedSet.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>
#if ENABLE(ICONDATABASE)
#include "SQLiteDatabase.h"
-#include <wtf/Threading.h>
-#endif // ENABLE(ICONDATABASE)
+#include "Timer.h"
+#include <wtf/Condition.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#endif
namespace WebCore {
-class DocumentLoader;
-class Image;
-class IntSize;
-class IconDatabaseClient;
-class IconRecord;
-class IconSnapshot;
-class URL;
-class PageURLRecord;
-class PageURLSnapshot;
-class SharedBuffer;
-class SuddenTerminationDisabler;
+#if !ENABLE(ICONDATABASE)
-#if ENABLE(ICONDATABASE)
-class SQLTransaction;
-#endif
+// Dummy version of IconDatabase that does nothing.
+class IconDatabase final : public IconDatabaseBase {
+ WTF_MAKE_FAST_ALLOCATED;
-#if !ENABLE(ICONDATABASE)
-// For builds with IconDatabase disabled, they'll just use a default derivation of IconDatabaseBase. Which does nothing.
-class IconDatabase : public IconDatabaseBase {
public:
- static PassOwnPtr<IconDatabase> create() { return adoptPtr(new IconDatabase); }
static void delayDatabaseCleanup() { }
static void allowDatabaseCleanup() { }
static void checkIntegrityBeforeOpening() { }
- static String defaultDatabaseFilename() { return "WebpageIcons.db"; }
+
+ // FIXME: Is it really helpful to return a filename here rather than just the null string?
+ static String defaultDatabaseFilename() { return ASCIILiteral("WebpageIcons.db"); }
};
-#else
-class IconDatabase : public IconDatabaseBase {
+#else
+
+class IconRecord;
+class IconSnapshot;
+class PageURLRecord;
+class PageURLSnapshot;
+class SuddenTerminationDisabler;
+
+class IconDatabase final : public IconDatabaseBase {
WTF_MAKE_FAST_ALLOCATED;
// *** Main Thread Only ***
public:
- static PassOwnPtr<IconDatabase> create() { return adoptPtr(new IconDatabase); }
+ WEBCORE_EXPORT IconDatabase();
~IconDatabase();
- virtual void setClient(IconDatabaseClient*);
+ WEBCORE_EXPORT void setClient(IconDatabaseClient*) final;
- virtual bool open(const String& directory, const String& filename);
- virtual void close();
+ WEBCORE_EXPORT bool open(const String& directory, const String& filename) final;
+ WEBCORE_EXPORT void close() final;
- virtual void removeAllIcons();
+ WEBCORE_EXPORT void removeAllIcons() final;
void readIconForPageURLFromDisk(const String&);
- virtual Image* defaultIcon(const IntSize&);
+ WEBCORE_EXPORT Image* defaultIcon(const IntSize&) final;
- virtual void retainIconForPageURL(const String&);
- virtual void releaseIconForPageURL(const String&);
- virtual void setIconDataForIconURL(PassRefPtr<SharedBuffer> data, const String&);
- virtual void setIconURLForPageURL(const String& iconURL, const String& pageURL);
+ WEBCORE_EXPORT void retainIconForPageURL(const String&) final;
+ WEBCORE_EXPORT void releaseIconForPageURL(const String&) final;
+ WEBCORE_EXPORT void setIconDataForIconURL(SharedBuffer* data, const String& iconURL) final;
+ WEBCORE_EXPORT void setIconURLForPageURL(const String& iconURL, const String& pageURL) final;
- virtual Image* synchronousIconForPageURL(const String&, const IntSize&);
- virtual PassNativeImagePtr synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize&);
- virtual String synchronousIconURLForPageURL(const String&);
- virtual bool synchronousIconDataKnownForIconURL(const String&);
- virtual IconLoadDecision synchronousLoadDecisionForIconURL(const String&, DocumentLoader*);
-
- virtual void setEnabled(bool);
- virtual bool isEnabled() const;
-
- virtual void setPrivateBrowsingEnabled(bool flag);
+ WEBCORE_EXPORT Image* synchronousIconForPageURL(const String&, const IntSize&) final;
+ NativeImagePtr synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize&) final;
+ WEBCORE_EXPORT String synchronousIconURLForPageURL(const String&) final;
+ bool synchronousIconDataKnownForIconURL(const String&) final;
+ WEBCORE_EXPORT IconLoadDecision synchronousLoadDecisionForIconURL(const String&, DocumentLoader*) final;
+
+ WEBCORE_EXPORT void setEnabled(bool);
+ WEBCORE_EXPORT bool isEnabled() const final;
+
+ WEBCORE_EXPORT void setPrivateBrowsingEnabled(bool flag) final;
bool isPrivateBrowsingEnabled() const;
-
- static void delayDatabaseCleanup();
- static void allowDatabaseCleanup();
- static void checkIntegrityBeforeOpening();
-
+
+ WEBCORE_EXPORT static void delayDatabaseCleanup();
+ WEBCORE_EXPORT static void allowDatabaseCleanup();
+ WEBCORE_EXPORT static void checkIntegrityBeforeOpening();
+
// Support for WebCoreStatistics in WebKit
- virtual size_t pageURLMappingCount();
- virtual size_t retainedPageURLCount();
- virtual size_t iconRecordCount();
- virtual size_t iconRecordCountWithData();
+ WEBCORE_EXPORT size_t pageURLMappingCount() final;
+ WEBCORE_EXPORT size_t retainedPageURLCount() final;
+ WEBCORE_EXPORT size_t iconRecordCount() final;
+ WEBCORE_EXPORT size_t iconRecordCountWithData() final;
private:
- IconDatabase();
friend IconDatabaseBase& iconDatabase();
- static void notifyPendingLoadDecisionsOnMainThread(void*);
void notifyPendingLoadDecisions();
void wakeSyncThread();
void scheduleOrDeferSyncTimer();
- void syncTimerFired(Timer<IconDatabase>&);
+ void syncTimerFired();
- Timer<IconDatabase> m_syncTimer;
+ Timer m_syncTimer;
ThreadIdentifier m_syncThread;
bool m_syncThreadRunning;
@@ -138,27 +126,24 @@ private:
RefPtr<IconRecord> m_defaultIconRecord;
- static void performScheduleOrDeferSyncTimerOnMainThread(void*);
- void performScheduleOrDeferSyncTimer();
-
bool m_scheduleOrDeferSyncTimerRequested;
std::unique_ptr<SuddenTerminationDisabler> m_disableSuddenTerminationWhileSyncTimerScheduled;
// *** Any Thread ***
public:
- virtual bool isOpen() const;
- virtual String databasePath() const;
- static String defaultDatabaseFilename();
+ WEBCORE_EXPORT bool isOpen() const final;
+ WEBCORE_EXPORT String databasePath() const final;
+ WEBCORE_EXPORT static String defaultDatabaseFilename();
private:
- PassRefPtr<IconRecord> getOrCreateIconRecord(const String& iconURL);
+ Ref<IconRecord> getOrCreateIconRecord(const String& iconURL);
PageURLRecord* getOrCreatePageURLRecord(const String& pageURL);
bool m_isEnabled;
bool m_privateBrowsingEnabled;
- mutable Mutex m_syncLock;
- ThreadCondition m_syncCondition;
+ mutable Lock m_syncLock;
+ Condition m_syncCondition;
String m_databaseDirectory;
// Holding m_syncLock is required when accessing m_completeDatabasePath
String m_completeDatabasePath;
@@ -169,24 +154,24 @@ private:
bool m_syncThreadHasWorkToDo;
std::unique_ptr<SuddenTerminationDisabler> m_disableSuddenTerminationWhileSyncThreadHasWorkToDo;
- Mutex m_urlAndIconLock;
+ Lock m_urlAndIconLock;
// Holding m_urlAndIconLock is required when accessing any of the following data structures or the objects they contain
HashMap<String, IconRecord*> m_iconURLToRecordMap;
HashMap<String, PageURLRecord*> m_pageURLToRecordMap;
HashSet<String> m_retainedPageURLs;
- Mutex m_pendingSyncLock;
+ Lock m_pendingSyncLock;
// Holding m_pendingSyncLock is required when accessing any of the following data structures
HashMap<String, PageURLSnapshot> m_pageURLsPendingSync;
HashMap<String, IconSnapshot> m_iconsPendingSync;
- Mutex m_pendingReadingLock;
+ Lock m_pendingReadingLock;
// Holding m_pendingSyncLock is required when accessing any of the following data structures - when dealing with IconRecord*s, holding m_urlAndIconLock is also required
HashSet<String> m_pageURLsPendingImport;
HashSet<String> m_pageURLsInterestedInIcons;
HashSet<IconRecord*> m_iconsPendingReading;
- Mutex m_urlsToRetainOrReleaseLock;
+ Lock m_urlsToRetainOrReleaseLock;
// Holding m_urlsToRetainOrReleaseLock is required when accessing any of the following data structures.
HashCountedSet<String> m_urlsToRetain;
HashCountedSet<String> m_urlsToRelease;
@@ -194,7 +179,7 @@ private:
// *** Sync Thread Only ***
public:
- virtual bool shouldStopThreadActivity() const;
+ WEBCORE_EXPORT bool shouldStopThreadActivity() const final;
private:
static void iconDatabaseSyncThreadStart(void *);
@@ -219,6 +204,9 @@ private:
bool wasExcludedFromBackup();
void setWasExcludedFromBackup();
+ bool isOpenBesidesMainThreadCallbacks() const;
+ void checkClosedAfterMainThreadCallback();
+
bool m_initialPruningComplete;
void setIconURLForPageURLInSQLDatabase(const String&, const String&);
@@ -226,7 +214,7 @@ private:
void removePageURLFromSQLDatabase(const String& pageURL);
int64_t getIconIDForIconURLFromSQLDatabase(const String& iconURL);
int64_t addIconURLToSQLDatabase(const String&);
- PassRefPtr<SharedBuffer> getImageDataForIconURLFromSQLDatabase(const String& iconURL);
+ RefPtr<SharedBuffer> getImageDataForIconURLFromSQLDatabase(const String& iconURL);
void removeIconFromSQLDatabase(const String& iconURL);
void writeIconSnapshotToSQLDatabase(const IconSnapshot&);
@@ -237,30 +225,29 @@ private:
void dispatchDidImportIconDataForPageURLOnMainThread(const String&);
void dispatchDidRemoveAllIconsOnMainThread();
void dispatchDidFinishURLImportOnMainThread();
+ std::atomic<uint32_t> m_mainThreadCallbackCount;
// The client is set by the main thread before the thread starts, and from then on is only used by the sync thread
IconDatabaseClient* m_client;
SQLiteDatabase m_syncDB;
- OwnPtr<SQLiteStatement> m_setIconIDForPageURLStatement;
- OwnPtr<SQLiteStatement> m_removePageURLStatement;
- OwnPtr<SQLiteStatement> m_getIconIDForIconURLStatement;
- OwnPtr<SQLiteStatement> m_getImageDataForIconURLStatement;
- OwnPtr<SQLiteStatement> m_addIconToIconInfoStatement;
- OwnPtr<SQLiteStatement> m_addIconToIconDataStatement;
- OwnPtr<SQLiteStatement> m_getImageDataStatement;
- OwnPtr<SQLiteStatement> m_deletePageURLsForIconURLStatement;
- OwnPtr<SQLiteStatement> m_deleteIconFromIconInfoStatement;
- OwnPtr<SQLiteStatement> m_deleteIconFromIconDataStatement;
- OwnPtr<SQLiteStatement> m_updateIconInfoStatement;
- OwnPtr<SQLiteStatement> m_updateIconDataStatement;
- OwnPtr<SQLiteStatement> m_setIconInfoStatement;
- OwnPtr<SQLiteStatement> m_setIconDataStatement;
+ std::unique_ptr<SQLiteStatement> m_setIconIDForPageURLStatement;
+ std::unique_ptr<SQLiteStatement> m_removePageURLStatement;
+ std::unique_ptr<SQLiteStatement> m_getIconIDForIconURLStatement;
+ std::unique_ptr<SQLiteStatement> m_getImageDataForIconURLStatement;
+ std::unique_ptr<SQLiteStatement> m_addIconToIconInfoStatement;
+ std::unique_ptr<SQLiteStatement> m_addIconToIconDataStatement;
+ std::unique_ptr<SQLiteStatement> m_getImageDataStatement;
+ std::unique_ptr<SQLiteStatement> m_deletePageURLsForIconURLStatement;
+ std::unique_ptr<SQLiteStatement> m_deleteIconFromIconInfoStatement;
+ std::unique_ptr<SQLiteStatement> m_deleteIconFromIconDataStatement;
+ std::unique_ptr<SQLiteStatement> m_updateIconInfoStatement;
+ std::unique_ptr<SQLiteStatement> m_updateIconDataStatement;
+ std::unique_ptr<SQLiteStatement> m_setIconInfoStatement;
+ std::unique_ptr<SQLiteStatement> m_setIconDataStatement;
};
#endif // !ENABLE(ICONDATABASE)
} // namespace WebCore
-
-#endif // IconDatabase_h
diff --git a/Source/WebCore/loader/icon/IconDatabaseBase.cpp b/Source/WebCore/loader/icon/IconDatabaseBase.cpp
index 51ccb3b27..4c6931071 100644
--- a/Source/WebCore/loader/icon/IconDatabaseBase.cpp
+++ b/Source/WebCore/loader/icon/IconDatabaseBase.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -47,7 +47,7 @@ bool IconDatabaseBase::open(const String&, const String&)
return false;
}
-static IconDatabaseBase* vmbase = 0;
+static IconDatabaseBase* vmbase = nullptr;
// Functions to get/set the global icon database.
IconDatabaseBase& iconDatabase()
@@ -55,7 +55,7 @@ IconDatabaseBase& iconDatabase()
if (vmbase)
return *vmbase;
- static IconDatabaseBase* defaultDatabase = 0;
+ static IconDatabaseBase* defaultDatabase = nullptr;
if (!defaultDatabase)
defaultDatabase = new IconDatabase;
diff --git a/Source/WebCore/loader/icon/IconDatabaseBase.h b/Source/WebCore/loader/icon/IconDatabaseBase.h
index e1f63af94..d4051b936 100644
--- a/Source/WebCore/loader/icon/IconDatabaseBase.h
+++ b/Source/WebCore/loader/icon/IconDatabaseBase.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,15 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IconDatabaseBase_h
-#define IconDatabaseBase_h
-
-#include "ImageSource.h"
-#include "SharedBuffer.h"
+#pragma once
+#include "NativeImage.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
-#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
namespace WebCore {
@@ -39,12 +36,9 @@ class DocumentLoader;
class IconDatabaseClient;
class Image;
class IntSize;
+class SharedBuffer;
-enum IconLoadDecision {
- IconLoadYes,
- IconLoadNo,
- IconLoadUnknown
-};
+enum IconLoadDecision { IconLoadYes, IconLoadNo, IconLoadUnknown };
class CallbackBase : public RefCounted<CallbackBase> {
public:
@@ -79,9 +73,9 @@ class EnumCallback : public CallbackBase {
public:
typedef void (*CallbackFunction)(EnumType, void*);
- static PassRefPtr<EnumCallback> create(void* context, CallbackFunction callback)
+ static Ref<EnumCallback> create(void* context, CallbackFunction callback)
{
- return adoptRef(new EnumCallback(context, callback));
+ return adoptRef(*new EnumCallback(context, callback));
}
virtual ~EnumCallback()
@@ -94,12 +88,12 @@ public:
if (!m_callback)
return;
m_callback(result, context());
- m_callback = 0;
+ m_callback = nullptr;
}
void invalidate()
{
- m_callback = 0;
+ m_callback = nullptr;
}
private:
@@ -118,9 +112,9 @@ class ObjectCallback : public CallbackBase {
public:
typedef void (*CallbackFunction)(ObjectType, void*);
- static PassRefPtr<ObjectCallback> create(void* context, CallbackFunction callback)
+ static Ref<ObjectCallback> create(void* context, CallbackFunction callback)
{
- return adoptRef(new ObjectCallback(context, callback));
+ return adoptRef(*new ObjectCallback(context, callback));
}
virtual ~ObjectCallback()
@@ -133,12 +127,12 @@ public:
if (!m_callback)
return;
m_callback(result, context());
- m_callback = 0;
+ m_callback = nullptr;
}
-
+
void invalidate()
{
- m_callback = 0;
+ m_callback = nullptr;
}
private:
@@ -152,46 +146,42 @@ private:
CallbackFunction m_callback;
};
-typedef EnumCallback<IconLoadDecision> IconLoadDecisionCallback;
-typedef ObjectCallback<SharedBuffer*> IconDataCallback;
+using IconLoadDecisionCallback = EnumCallback<IconLoadDecision>;
+using IconDataCallback = ObjectCallback<SharedBuffer*>;
-class IconDatabaseBase {
+class WEBCORE_EXPORT IconDatabaseBase {
WTF_MAKE_NONCOPYABLE(IconDatabaseBase);
-protected:
- IconDatabaseBase() { }
-
public:
virtual ~IconDatabaseBase() { }
- // Used internally by WebCore
virtual bool isEnabled() const { return false; }
-
+
virtual void retainIconForPageURL(const String&) { }
virtual void releaseIconForPageURL(const String&) { }
- virtual void setIconURLForPageURL(const String&, const String&) { }
- virtual void setIconDataForIconURL(PassRefPtr<SharedBuffer>, const String&) { }
+ virtual void setIconURLForPageURL(const String& /*iconURL*/, const String& /*pageURL*/) { }
+ virtual void setIconDataForIconURL(SharedBuffer*, const String& /*iconURL*/) { }
// Synchronous calls used internally by WebCore.
// Usage should be replaced by asynchronous calls.
virtual String synchronousIconURLForPageURL(const String&);
virtual bool synchronousIconDataKnownForIconURL(const String&) { return false; }
virtual IconLoadDecision synchronousLoadDecisionForIconURL(const String&, DocumentLoader*) { return IconLoadNo; }
- virtual Image* synchronousIconForPageURL(const String&, const IntSize&) { return 0; }
- virtual PassNativeImagePtr synchronousNativeIconForPageURL(const String&, const IntSize&) { return 0; }
+ virtual Image* synchronousIconForPageURL(const String&, const IntSize&) { return nullptr; }
+ virtual NativeImagePtr synchronousNativeIconForPageURL(const String&, const IntSize&) { return nullptr; }
// Asynchronous calls we should use to replace the above when supported.
virtual bool supportsAsynchronousMode() { return false; }
- virtual void loadDecisionForIconURL(const String&, PassRefPtr<IconLoadDecisionCallback>) { }
- virtual void iconDataForIconURL(const String&, PassRefPtr<IconDataCallback>) { }
-
+ virtual void loadDecisionForIconURL(const String&, IconLoadDecisionCallback&) { }
+ virtual void iconDataForIconURL(const String&, IconDataCallback&) { }
// Used within one or more WebKit ports.
// We should try to remove these dependencies from the IconDatabaseBase class.
+
virtual void setEnabled(bool) { }
- virtual Image* defaultIcon(const IntSize&) { return 0; }
+ virtual Image* defaultIcon(const IntSize&) { return nullptr; }
virtual size_t pageURLMappingCount() { return 0; }
virtual size_t retainedPageURLCount() { return 0; }
@@ -206,17 +196,17 @@ public:
virtual void setPrivateBrowsingEnabled(bool) { }
virtual void setClient(IconDatabaseClient*) { }
-
+
virtual bool isOpen() const { return false; }
virtual String databasePath() const;
+protected:
+ IconDatabaseBase() = default;
};
// Functions to get/set the global icon database.
-IconDatabaseBase& iconDatabase();
-void setGlobalIconDatabase(IconDatabaseBase*);
+WEBCORE_EXPORT IconDatabaseBase& iconDatabase();
+WEBCORE_EXPORT void setGlobalIconDatabase(IconDatabaseBase*);
bool documentCanHaveIcon(const String&);
} // namespace WebCore
-
-#endif // IconDatabaseBase_h
diff --git a/Source/WebCore/loader/icon/IconDatabaseClient.h b/Source/WebCore/loader/icon/IconDatabaseClient.h
index 70494ec11..33e5413a8 100644
--- a/Source/WebCore/loader/icon/IconDatabaseClient.h
+++ b/Source/WebCore/loader/icon/IconDatabaseClient.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IconDatabaseClient_h
-#define IconDatabaseClient_h
+#pragma once
#include <wtf/Forward.h>
@@ -42,8 +41,7 @@ public:
virtual void didChangeIconForPageURL(const String&) = 0;
virtual void didRemoveAllIcons() = 0;
virtual void didFinishURLImport() = 0;
+ virtual void didClose() { }
};
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/icon/IconLoader.cpp b/Source/WebCore/loader/icon/IconLoader.cpp
index 819bfb7e6..ab6385e55 100644
--- a/Source/WebCore/loader/icon/IconLoader.cpp
+++ b/Source/WebCore/loader/icon/IconLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -37,14 +37,21 @@
#include "IconController.h"
#include "IconDatabase.h"
#include "Logging.h"
-#include "ResourceBuffer.h"
#include "ResourceRequest.h"
+#include "SharedBuffer.h"
#include <wtf/text/CString.h>
namespace WebCore {
IconLoader::IconLoader(Frame& frame)
- : m_frame(frame)
+ : m_frame(&frame)
+ , m_url(frame.loader().icon().url())
+{
+}
+
+IconLoader::IconLoader(DocumentLoader& documentLoader, const URL& url)
+ : m_documentLoader(&documentLoader)
+ , m_url(url)
{
}
@@ -55,54 +62,83 @@ IconLoader::~IconLoader()
void IconLoader::startLoading()
{
- if (m_resource || !m_frame.document())
+ ASSERT(m_frame || m_documentLoader);
+
+ if (m_resource)
return;
- CachedResourceRequest request(ResourceRequest(m_frame.loader().icon().url()), ResourceLoaderOptions(SendCallbacks, SniffContent, BufferData, DoNotAllowStoredCredentials, DoNotAskClientForAnyCredentials, DoSecurityCheck, UseDefaultOriginRestrictionsForType));
+ if (m_frame && !m_frame->document())
+ return;
+
+
+ if (m_documentLoader && !m_documentLoader->frame())
+ return;
+
+ ResourceRequest resourceRequest = m_documentLoader ? m_url : m_frame->loader().icon().url();
+ resourceRequest.setPriority(ResourceLoadPriority::Low);
+#if !ERROR_DISABLED
+ // Copy this because we may want to access it after transferring the
+ // `resourceRequest` to the `request`. If we don't, then the LOG_ERROR
+ // below won't print a URL.
+ auto resourceRequestURL = resourceRequest.url();
+#endif
+
+ // ContentSecurityPolicyImposition::DoPolicyCheck is a placeholder value. It does not affect the request since Content Security Policy does not apply to raw resources.
+ CachedResourceRequest request(WTFMove(resourceRequest), ResourceLoaderOptions(SendCallbacks, SniffContent, BufferData, DoNotAllowStoredCredentials, ClientCredentialPolicy::CannotAskClientForCredentials, FetchOptions::Credentials::Omit, DoSecurityCheck, FetchOptions::Mode::NoCors, DoNotIncludeCertificateInfo, ContentSecurityPolicyImposition::DoPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching));
- request.mutableResourceRequest().setPriority(ResourceLoadPriorityLow);
request.setInitiator(cachedResourceRequestInitiators().icon);
- m_resource = m_frame.document()->cachedResourceLoader()->requestRawResource(request);
+ auto* frame = m_frame ? m_frame : m_documentLoader->frame();
+ m_resource = frame->document()->cachedResourceLoader().requestRawResource(WTFMove(request));
if (m_resource)
- m_resource->addClient(this);
+ m_resource->addClient(*this);
else
- LOG_ERROR("Failed to start load for icon at url %s", m_frame.loader().icon().url().string().ascii().data());
+ LOG_ERROR("Failed to start load for icon at url %s", resourceRequestURL.string().ascii().data());
}
void IconLoader::stopLoading()
{
if (m_resource) {
- m_resource->removeClient(this);
- m_resource = 0;
+ m_resource->removeClient(*this);
+ m_resource = nullptr;
}
}
-void IconLoader::notifyFinished(CachedResource* resource)
+void IconLoader::notifyFinished(CachedResource& resource)
{
- ASSERT(resource == m_resource);
+ ASSERT_UNUSED(resource, &resource == m_resource);
// If we got a status code indicating an invalid response, then lets
// ignore the data and not try to decode the error page as an icon.
- RefPtr<ResourceBuffer> data = resource->resourceBuffer();
- int status = resource->response().httpStatusCode();
+ auto* data = m_resource->resourceBuffer();
+ int status = m_resource->response().httpStatusCode();
if (status && (status < 200 || status > 299))
- data = 0;
+ data = nullptr;
static const char pdfMagicNumber[] = "%PDF";
static unsigned pdfMagicNumberLength = sizeof(pdfMagicNumber) - 1;
if (data && data->size() >= pdfMagicNumberLength && !memcmp(data->data(), pdfMagicNumber, pdfMagicNumberLength)) {
- LOG(IconDatabase, "IconLoader::finishLoading() - Ignoring icon at %s because it appears to be a PDF", resource->url().string().ascii().data());
- data = 0;
+ LOG(IconDatabase, "IconLoader::finishLoading() - Ignoring icon at %s because it appears to be a PDF", m_resource->url().string().ascii().data());
+ data = nullptr;
+ }
+
+ LOG(IconDatabase, "IconLoader::finishLoading() - Committing iconURL %s to database", m_resource->url().string().ascii().data());
+
+ if (!m_frame) {
+ // DocumentLoader::finishedLoadingIcon destroys this IconLoader as it finishes. This will automatically
+ // trigger IconLoader::stopLoading() during destruction, so we should just return here.
+ m_documentLoader->finishedLoadingIcon(*this, data);
+ return;
}
- LOG(IconDatabase, "IconLoader::finishLoading() - Committing iconURL %s to database", resource->url().string().ascii().data());
- m_frame.loader().icon().commitToDatabase(resource->url());
+ m_frame->loader().icon().commitToDatabase(m_resource->url());
+
// Setting the icon data only after committing to the database ensures that the data is
// kept in memory (so it does not have to be read from the database asynchronously), since
// there is a page URL referencing it.
- iconDatabase().setIconDataForIconURL(data ? data->sharedBuffer() : 0, resource->url().string());
- m_frame.loader().client().dispatchDidReceiveIcon();
+ iconDatabase().setIconDataForIconURL(data, m_resource->url().string());
+ m_frame->loader().client().dispatchDidReceiveIcon();
+
stopLoading();
}
diff --git a/Source/WebCore/loader/icon/IconLoader.h b/Source/WebCore/loader/icon/IconLoader.h
index 2fb79dc34..2de53e8e2 100644
--- a/Source/WebCore/loader/icon/IconLoader.h
+++ b/Source/WebCore/loader/icon/IconLoader.h
@@ -10,49 +10,50 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IconLoader_h
-#define IconLoader_h
+#pragma once
#include "CachedRawResourceClient.h"
#include "CachedResourceHandle.h"
+#include "URL.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
-#include <wtf/RefPtr.h>
namespace WebCore {
class CachedRawResource;
+class DocumentLoader;
class Frame;
class IconLoader final : private CachedRawResourceClient {
WTF_MAKE_NONCOPYABLE(IconLoader); WTF_MAKE_FAST_ALLOCATED;
public:
explicit IconLoader(Frame&);
+ IconLoader(DocumentLoader&, const URL&);
virtual ~IconLoader();
void startLoading();
void stopLoading();
private:
- virtual void notifyFinished(CachedResource*) override;
+ void notifyFinished(CachedResource&) final;
- Frame& m_frame;
+ Frame* m_frame { nullptr };
+ DocumentLoader* m_documentLoader { nullptr };
+ URL m_url;
CachedResourceHandle<CachedRawResource> m_resource;
};
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/icon/IconRecord.cpp b/Source/WebCore/loader/icon/IconRecord.cpp
index 7e90d8e8c..b20c26a32 100644
--- a/Source/WebCore/loader/icon/IconRecord.cpp
+++ b/Source/WebCore/loader/icon/IconRecord.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -62,16 +62,16 @@ Image* IconRecord::image(const IntSize&)
return m_image.get();
}
-void IconRecord::setImageData(PassRefPtr<SharedBuffer> data)
+void IconRecord::setImageData(RefPtr<SharedBuffer>&& data)
{
// It's okay to delete the raw image here. Any existing clients using this icon will be
// managing an image that was created with a copy of this raw image data.
m_image = BitmapImage::create();
// Copy the provided data into the buffer of the new Image object.
- if (!m_image->setData(data, true)) {
+ if (!m_image->setData(WTFMove(data), true)) {
LOG(IconDatabase, "Manual image data for iconURL '%s' FAILED - it was probably invalid image data", m_iconURL.ascii().data());
- m_image.clear();
+ m_image = nullptr;
}
m_dataSet = true;
diff --git a/Source/WebCore/loader/icon/IconRecord.h b/Source/WebCore/loader/icon/IconRecord.h
index e5a47f76e..f2105a39a 100644
--- a/Source/WebCore/loader/icon/IconRecord.h
+++ b/Source/WebCore/loader/icon/IconRecord.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,13 +26,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IconRecord_h
-#define IconRecord_h
+#pragma once
#include "PageURLRecord.h"
#include "SharedBuffer.h"
#include <wtf/HashSet.h>
-#include <wtf/OwnPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>
@@ -75,16 +73,16 @@ private:
class IconRecord : public RefCounted<IconRecord> {
friend class PageURLRecord;
public:
- static PassRefPtr<IconRecord> create(const String& url)
+ static Ref<IconRecord> create(const String& url)
{
- return adoptRef(new IconRecord(url));
+ return adoptRef(*new IconRecord(url));
}
~IconRecord();
time_t getTimestamp() { return m_stamp; }
void setTimestamp(time_t stamp) { m_stamp = stamp; }
- void setImageData(PassRefPtr<SharedBuffer> data);
+ void setImageData(RefPtr<SharedBuffer>&&);
Image* image(const IntSize&);
String iconURL() { return m_iconURL; }
@@ -119,7 +117,4 @@ private:
// SizeImageMap m_images;
};
-
} //namespace WebCore
-
-#endif
diff --git a/Source/WebCore/loader/icon/PageURLRecord.cpp b/Source/WebCore/loader/icon/PageURLRecord.cpp
index 09d649f83..99dded8f2 100644
--- a/Source/WebCore/loader/icon/PageURLRecord.cpp
+++ b/Source/WebCore/loader/icon/PageURLRecord.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -35,29 +35,29 @@ namespace WebCore {
PageURLRecord::PageURLRecord(const String& pageURL)
: m_pageURL(pageURL)
- , m_retainCount(0)
{
}
PageURLRecord::~PageURLRecord()
{
- setIconRecord(0);
+ if (m_iconRecord)
+ m_iconRecord->m_retainingPageURLs.remove(m_pageURL);
}
-void PageURLRecord::setIconRecord(PassRefPtr<IconRecord> icon)
+void PageURLRecord::setIconRecord(RefPtr<IconRecord>&& icon)
{
if (m_iconRecord)
m_iconRecord->m_retainingPageURLs.remove(m_pageURL);
-
- m_iconRecord = icon;
-
+
+ m_iconRecord = WTFMove(icon);
+
if (m_iconRecord)
m_iconRecord->m_retainingPageURLs.add(m_pageURL);
}
PageURLSnapshot PageURLRecord::snapshot(bool forDeletion) const
{
- return PageURLSnapshot(m_pageURL, (m_iconRecord && !forDeletion) ? m_iconRecord->iconURL() : String());
+ return { m_pageURL, (m_iconRecord && !forDeletion) ? m_iconRecord->iconURL() : String() };
}
} // namespace WebCore
diff --git a/Source/WebCore/loader/icon/PageURLRecord.h b/Source/WebCore/loader/icon/PageURLRecord.h
index 2b33808d3..189875e32 100644
--- a/Source/WebCore/loader/icon/PageURLRecord.h
+++ b/Source/WebCore/loader/icon/PageURLRecord.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PageURLRecord_h
-#define PageURLRecord_h
+#pragma once
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
@@ -62,7 +61,7 @@ public:
inline String url() const { return m_pageURL; }
- void setIconRecord(PassRefPtr<IconRecord>);
+ void setIconRecord(RefPtr<IconRecord>&&);
IconRecord* iconRecord() { return m_iconRecord.get(); }
PageURLSnapshot snapshot(bool forDeletion = false) const;
@@ -83,13 +82,12 @@ public:
return m_retainCount > 0;
}
- inline int retainCount() const { return m_retainCount; }
+ int retainCount() const { return m_retainCount; }
+
private:
String m_pageURL;
RefPtr<IconRecord> m_iconRecord;
- int m_retainCount;
+ int m_retainCount { 0 };
};
-}
-
-#endif // PageURLRecord_h
+} // namespace WebCore
diff --git a/Source/WebCore/loader/soup/CachedRawResourceSoup.cpp b/Source/WebCore/loader/soup/CachedRawResourceSoup.cpp
index 4934e9df5..5492d2147 100644
--- a/Source/WebCore/loader/soup/CachedRawResourceSoup.cpp
+++ b/Source/WebCore/loader/soup/CachedRawResourceSoup.cpp
@@ -17,6 +17,9 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "CachedRawResource.h"
#include "CachedRawResourceClient.h"
@@ -28,11 +31,13 @@ char* CachedRawResource::getOrCreateReadBuffer(size_t requestedSize, size_t& act
{
CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
while (CachedRawResourceClient* c = w.next()) {
- if (char* bufferPtr = c->getOrCreateReadBuffer(this, requestedSize, actualSize))
+ if (char* bufferPtr = c->getOrCreateReadBuffer(*this, requestedSize, actualSize))
return bufferPtr;
}
- return 0;
+ return nullptr;
}
} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/loader/soup/SubresourceLoaderSoup.cpp b/Source/WebCore/loader/soup/SubresourceLoaderSoup.cpp
index b7670a06d..f86bd55ba 100644
--- a/Source/WebCore/loader/soup/SubresourceLoaderSoup.cpp
+++ b/Source/WebCore/loader/soup/SubresourceLoaderSoup.cpp
@@ -17,6 +17,9 @@
*/
#include "config.h"
+
+#if USE(SOUP)
+
#include "SubresourceLoader.h"
#include "CachedResource.h"
@@ -29,3 +32,5 @@ char* SubresourceLoader::getOrCreateReadBuffer(size_t requestedLength, size_t& a
}
} // namespace WebCore
+
+#endif