summaryrefslogtreecommitdiff
path: root/Source/WebKit2/NetworkProcess
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/NetworkProcess')
-rw-r--r--Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.h121
-rw-r--r--Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.messages.in32
-rw-r--r--Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerImpl.h36
-rw-r--r--Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerQt.cpp78
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/Download.cpp172
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/Download.h162
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.cpp (renamed from Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.h)61
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.h72
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/DownloadID.h96
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/DownloadManager.cpp161
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/DownloadManager.h112
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/PendingDownload.cpp84
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h78
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/qt/DownloadQt.cpp81
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp231
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h79
-rw-r--r--Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/Info.plist34
-rw-r--r--Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService.Development/Info.plist45
-rw-r--r--Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService/Info.plist50
-rw-r--r--Source/WebKit2/NetworkProcess/EntryPoint/qt/NetworkProcessMain.cpp35
-rw-r--r--Source/WebKit2/NetworkProcess/EntryPoint/unix/NetworkProcessMain.cpp45
-rw-r--r--Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp114
-rw-r--r--Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h27
-rw-r--r--Source/WebKit2/NetworkProcess/HostRecord.cpp231
-rw-r--r--Source/WebKit2/NetworkProcess/HostRecord.h86
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp192
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.h77
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.messages.in38
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkDataTask.h149
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkLoad.cpp440
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkLoad.h140
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkLoadClient.h69
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkLoadParameters.cpp (renamed from Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.cpp)63
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkLoadParameters.h56
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcess.cpp403
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcess.h153
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcess.messages.in45
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.cpp168
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.h104
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.cpp48
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.h22
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkProcessSupplement.h (renamed from Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/NetworkProcessMain.mm)25
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.cpp160
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.h69
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.cpp228
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.h108
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp654
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoader.h170
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkResourceLoader.messages.in2
-rw-r--r--Source/WebKit2/NetworkProcess/NetworkSession.h76
-rw-r--r--Source/WebKit2/NetworkProcess/RemoteNetworkingContext.h (renamed from Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.h)53
-rw-r--r--Source/WebKit2/NetworkProcess/SchedulableLoader.cpp118
-rw-r--r--Source/WebKit2/NetworkProcess/SchedulableLoader.h102
-rw-r--r--Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.cpp87
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp656
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCache.h145
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.cpp151
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.h74
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheCoder.h53
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.cpp182
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.h264
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheData.cpp130
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheData.h163
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp142
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.cpp137
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.h103
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp128
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.h118
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp242
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h99
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.cpp131
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.h (renamed from Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm)39
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannel.h84
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp290
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp156
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h120
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp148
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h88
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp453
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h86
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp462
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h96
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp1051
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h178
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp95
-rw-r--r--Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h73
-rw-r--r--Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.mm109
-rw-r--r--Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm231
-rw-r--r--Source/WebKit2/NetworkProcess/mac/NetworkResourceLoadSchedulerMac.mm76
-rw-r--r--Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm116
-rw-r--r--Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.mm135
-rw-r--r--Source/WebKit2/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in148
-rw-r--r--Source/WebKit2/NetworkProcess/qt/NetworkProcessMainQt.cpp125
-rw-r--r--Source/WebKit2/NetworkProcess/qt/NetworkProcessQt.cpp77
-rw-r--r--Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.cpp136
-rw-r--r--Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.h58
-rw-r--r--Source/WebKit2/NetworkProcess/qt/RemoteNetworkingContextQt.cpp (renamed from Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h)55
-rw-r--r--Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.h8
98 files changed, 11291 insertions, 2662 deletions
diff --git a/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.h b/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.h
new file mode 100644
index 000000000..bf2bd4720
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012, 2013 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.
+ */
+
+#ifndef CustomProtocolManager_h
+#define CustomProtocolManager_h
+
+#include "Connection.h"
+#include "NetworkProcessSupplement.h"
+#include <wtf/WorkQueue.h>
+#include <wtf/text/WTFString.h>
+
+#if PLATFORM(COCOA)
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Threading.h>
+#include <wtf/text/StringHash.h>
+OBJC_CLASS NSURLSessionConfiguration;
+OBJC_CLASS WKCustomProtocol;
+#else
+#include "CustomProtocolManagerImpl.h"
+#endif
+
+
+namespace IPC {
+class DataReference;
+} // namespace IPC
+
+namespace WebCore {
+class ResourceError;
+class ResourceRequest;
+class ResourceResponse;
+} // namespace WebCore
+
+namespace WebKit {
+
+class ChildProcess;
+struct NetworkProcessCreationParameters;
+
+class CustomProtocolManager : public NetworkProcessSupplement, public IPC::Connection::WorkQueueMessageReceiver {
+ WTF_MAKE_NONCOPYABLE(CustomProtocolManager);
+public:
+ explicit CustomProtocolManager(ChildProcess*);
+
+ static const char* supplementName();
+
+ ChildProcess* childProcess() const { return m_childProcess; }
+
+ void registerScheme(const String&);
+ void unregisterScheme(const String&);
+ bool supportsScheme(const String&);
+
+#if PLATFORM(COCOA)
+ void addCustomProtocol(WKCustomProtocol *);
+ void removeCustomProtocol(WKCustomProtocol *);
+#if USE(NETWORK_SESSION)
+ void registerProtocolClass(NSURLSessionConfiguration *);
+#endif
+#endif
+
+private:
+ // ChildProcessSupplement
+ void initializeConnection(IPC::Connection*) override;
+
+ // NetworkProcessSupplement
+ void initialize(const NetworkProcessCreationParameters&) override;
+
+ // IPC::MessageReceiver
+ virtual void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
+
+ void didFailWithError(uint64_t customProtocolID, const WebCore::ResourceError&);
+ void didLoadData(uint64_t customProtocolID, const IPC::DataReference&);
+ void didReceiveResponse(uint64_t customProtocolID, const WebCore::ResourceResponse&, uint32_t cacheStoragePolicy);
+ void didFinishLoading(uint64_t customProtocolID);
+ void wasRedirectedToRequest(uint64_t customProtocolID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse);
+
+ ChildProcess* m_childProcess;
+ RefPtr<WorkQueue> m_messageQueue;
+
+#if PLATFORM(COCOA)
+ HashSet<String, ASCIICaseInsensitiveHash> m_registeredSchemes;
+ Lock m_registeredSchemesMutex;
+
+ typedef HashMap<uint64_t, RetainPtr<WKCustomProtocol>> CustomProtocolMap;
+ CustomProtocolMap m_customProtocolMap;
+ Lock m_customProtocolMapMutex;
+
+ // WKCustomProtocol objects can be removed from the m_customProtocolMap from multiple threads.
+ // We return a RetainPtr here because it is unsafe to return a raw pointer since the object might immediately be destroyed from a different thread.
+ RetainPtr<WKCustomProtocol> protocolForID(uint64_t customProtocolID);
+#else
+ // FIXME: Move mac specific code to CustomProtocolManagerImpl.
+ std::unique_ptr<CustomProtocolManagerImpl> m_impl;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // CustomProtocolManager_h
diff --git a/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.messages.in b/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.messages.in
new file mode 100644
index 000000000..0f55eceb1
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.messages.in
@@ -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. 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.
+
+messages -> CustomProtocolManager {
+ DidFailWithError(uint64_t customProtocolID, WebCore::ResourceError error)
+ DidLoadData(uint64_t customProtocolID, IPC::DataReference data)
+ DidReceiveResponse(uint64_t customProtocolID, WebCore::ResourceResponse response, uint32_t cacheStoragePolicy)
+ DidFinishLoading(uint64_t customProtocolID)
+ WasRedirectedToRequest(uint64_t customProtocolID, WebCore::ResourceRequest request, WebCore::ResourceResponse redirectResponse);
+
+ RegisterScheme(String name)
+ UnregisterScheme(String name)
+}
diff --git a/Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerImpl.h b/Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerImpl.h
new file mode 100644
index 000000000..a115e40eb
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerImpl.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 Konstantin Tokarev <annulen@yandex.ru>
+ *
+ * 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/Noncopyable.h>
+
+namespace WebKit {
+
+class CustomProtocolManagerImpl {
+ WTF_MAKE_NONCOPYABLE(CustomProtocolManagerImpl);
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerQt.cpp b/Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerQt.cpp
new file mode 100644
index 000000000..9e79503c4
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/CustomProtocols/qt/CustomProtocolManagerQt.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 Konstantin Tokarev <annulen@yandex.ru>
+ *
+ * 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 "CustomProtocolManager.h"
+
+namespace WebKit {
+
+const char* CustomProtocolManager::supplementName()
+{
+ return "";
+}
+
+CustomProtocolManager::CustomProtocolManager(ChildProcess*)
+ : m_impl(nullptr)
+{
+}
+
+void CustomProtocolManager::initializeConnection(IPC::Connection*)
+{
+}
+
+void CustomProtocolManager::initialize(const NetworkProcessCreationParameters&)
+{
+}
+
+void CustomProtocolManager::registerScheme(const String&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void CustomProtocolManager::unregisterScheme(const String&)
+{
+}
+
+bool CustomProtocolManager::supportsScheme(const String&)
+{
+ return false;
+}
+
+void CustomProtocolManager::didFailWithError(uint64_t, const WebCore::ResourceError&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void CustomProtocolManager::didLoadData(uint64_t, const IPC::DataReference&)
+{
+}
+
+void CustomProtocolManager::didReceiveResponse(uint64_t, const WebCore::ResourceResponse&, uint32_t)
+{
+}
+
+void CustomProtocolManager::didFinishLoading(uint64_t)
+{
+}
+
+void CustomProtocolManager::wasRedirectedToRequest(uint64_t, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&)
+{
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/Downloads/Download.cpp b/Source/WebKit2/NetworkProcess/Downloads/Download.cpp
new file mode 100644
index 000000000..4d2398a54
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/Download.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2010, 2011 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 "Download.h"
+
+#include "AuthenticationManager.h"
+#include "Connection.h"
+#include "DataReference.h"
+#include "DownloadManager.h"
+#include "DownloadProxyMessages.h"
+#include "SandboxExtension.h"
+#include "WebCoreArgumentCoders.h"
+#include <WebCore/NotImplemented.h>
+
+#if !USE(NETWORK_SESSION)
+#include "DownloadAuthenticationClient.h"
+#endif
+
+using namespace WebCore;
+
+namespace WebKit {
+
+#if USE(NETWORK_SESSION)
+Download::Download(DownloadManager& downloadManager, DownloadID downloadID)
+#else
+Download::Download(DownloadManager& downloadManager, DownloadID downloadID, const ResourceRequest& request)
+#endif
+ : m_downloadManager(downloadManager)
+ , m_downloadID(downloadID)
+#if !USE(NETWORK_SESSION)
+ , m_request(request)
+#endif
+{
+ ASSERT(m_downloadID.downloadID());
+
+ m_downloadManager.didCreateDownload();
+}
+
+Download::~Download()
+{
+ platformInvalidate();
+
+ m_downloadManager.didDestroyDownload();
+}
+
+#if USE(NETWORK_SESSION)
+void Download::didStart(const ResourceRequest& request)
+{
+ send(Messages::DownloadProxy::DidStart(request));
+}
+#else
+void Download::didStart()
+{
+ send(Messages::DownloadProxy::DidStart(m_request));
+}
+#endif
+
+#if !USE(NETWORK_SESSION)
+void Download::didReceiveAuthenticationChallenge(const AuthenticationChallenge& authenticationChallenge)
+{
+ m_downloadManager.downloadsAuthenticationManager().didReceiveAuthenticationChallenge(*this, authenticationChallenge);
+}
+#endif
+
+void Download::didReceiveResponse(const ResourceResponse& response)
+{
+ send(Messages::DownloadProxy::DidReceiveResponse(response));
+}
+
+void Download::didReceiveData(uint64_t length)
+{
+ send(Messages::DownloadProxy::DidReceiveData(length));
+}
+
+bool Download::shouldDecodeSourceDataOfMIMEType(const String& mimeType)
+{
+ bool result;
+ if (!sendSync(Messages::DownloadProxy::ShouldDecodeSourceDataOfMIMEType(mimeType), Messages::DownloadProxy::ShouldDecodeSourceDataOfMIMEType::Reply(result)))
+ return true;
+
+ return result;
+}
+
+String Download::decideDestinationWithSuggestedFilename(const String& filename, bool& allowOverwrite)
+{
+ String destination;
+ SandboxExtension::Handle sandboxExtensionHandle;
+ if (!sendSync(Messages::DownloadProxy::DecideDestinationWithSuggestedFilename(filename), Messages::DownloadProxy::DecideDestinationWithSuggestedFilename::Reply(destination, allowOverwrite, sandboxExtensionHandle)))
+ return String();
+
+ m_sandboxExtension = SandboxExtension::create(sandboxExtensionHandle);
+ if (m_sandboxExtension)
+ m_sandboxExtension->consume();
+
+ return destination;
+}
+
+void Download::didCreateDestination(const String& path)
+{
+ send(Messages::DownloadProxy::DidCreateDestination(path));
+}
+
+void Download::didFinish()
+{
+ platformDidFinish();
+
+ send(Messages::DownloadProxy::DidFinish());
+
+ if (m_sandboxExtension) {
+ m_sandboxExtension->revoke();
+ m_sandboxExtension = nullptr;
+ }
+
+ m_downloadManager.downloadFinished(this);
+}
+
+void Download::didFail(const ResourceError& error, const IPC::DataReference& resumeData)
+{
+ send(Messages::DownloadProxy::DidFail(error, resumeData));
+
+ if (m_sandboxExtension) {
+ m_sandboxExtension->revoke();
+ m_sandboxExtension = nullptr;
+ }
+ m_downloadManager.downloadFinished(this);
+}
+
+void Download::didCancel(const IPC::DataReference& resumeData)
+{
+ send(Messages::DownloadProxy::DidCancel(resumeData));
+
+ if (m_sandboxExtension) {
+ m_sandboxExtension->revoke();
+ m_sandboxExtension = nullptr;
+ }
+ m_downloadManager.downloadFinished(this);
+}
+
+IPC::Connection* Download::messageSenderConnection()
+{
+ return m_downloadManager.downloadProxyConnection();
+}
+
+uint64_t Download::messageSenderDestinationID()
+{
+ return m_downloadID.downloadID();
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/Downloads/Download.h b/Source/WebKit2/NetworkProcess/Downloads/Download.h
new file mode 100644
index 000000000..2c5a3a83d
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/Download.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2010, 2011 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.
+ */
+
+#ifndef Download_h
+#define Download_h
+
+#include "DownloadID.h"
+#include "MessageSender.h"
+#include "SandboxExtension.h"
+#include <WebCore/ResourceRequest.h>
+#include <wtf/Noncopyable.h>
+
+#if PLATFORM(COCOA)
+#include <wtf/RetainPtr.h>
+
+#if USE(NETWORK_SESSION)
+OBJC_CLASS NSURLSessionDownloadTask;
+#else
+OBJC_CLASS NSURLDownload;
+OBJC_CLASS WKDownloadAsDelegate;
+#endif
+#endif
+
+#if PLATFORM(GTK) || PLATFORM(EFL)
+#include <WebCore/ResourceHandle.h>
+#include <WebCore/ResourceHandleClient.h>
+#include <memory>
+#endif
+
+#if USE(CFNETWORK)
+#include <CFNetwork/CFURLDownloadPriv.h>
+#endif
+
+namespace IPC {
+class DataReference;
+}
+
+namespace WebCore {
+class AuthenticationChallenge;
+class Credential;
+class ResourceError;
+class ResourceHandle;
+class ResourceResponse;
+}
+
+namespace WebKit {
+
+class DownloadAuthenticationClient;
+class DownloadManager;
+class NetworkSession;
+class WebPage;
+
+#if PLATFORM(QT)
+class QtFileDownloader;
+#endif
+
+class Download : public IPC::MessageSender {
+ WTF_MAKE_NONCOPYABLE(Download);
+public:
+#if USE(NETWORK_SESSION)
+ Download(DownloadManager&, DownloadID);
+#else
+ Download(DownloadManager&, DownloadID, const WebCore::ResourceRequest&);
+#endif
+ ~Download();
+
+#if USE(NETWORK_SESSION) && PLATFORM(COCOA)
+ void dataTaskDidBecomeDownloadTask(const NetworkSession&, RetainPtr<NSURLSessionDownloadTask>&&);
+#else
+ void start();
+ void startWithHandle(WebCore::ResourceHandle*, const WebCore::ResourceResponse&);
+#endif
+ void resume(const IPC::DataReference& resumeData, const String& path, const SandboxExtension::Handle&);
+ void cancel();
+
+ DownloadID downloadID() const { return m_downloadID; }
+
+#if USE(NETWORK_SESSION)
+ void didStart(const WebCore::ResourceRequest&);
+#else
+ void didStart();
+ void didReceiveAuthenticationChallenge(const WebCore::AuthenticationChallenge&);
+#endif
+ void didReceiveResponse(const WebCore::ResourceResponse&);
+ void didReceiveData(uint64_t length);
+ bool shouldDecodeSourceDataOfMIMEType(const String& mimeType);
+ String decideDestinationWithSuggestedFilename(const String& filename, bool& allowOverwrite);
+ void didCreateDestination(const String& path);
+ void didFinish();
+ void platformDidFinish();
+ void didFail(const WebCore::ResourceError&, const IPC::DataReference& resumeData);
+ void didCancel(const IPC::DataReference& resumeData);
+
+#if PLATFORM(QT)
+ void startTransfer(const String& destination);
+#endif
+
+#if USE(CFNETWORK)
+ DownloadAuthenticationClient* authenticationClient();
+#endif
+
+private:
+ // IPC::MessageSender
+ virtual IPC::Connection* messageSenderConnection() override;
+ virtual uint64_t messageSenderDestinationID() override;
+
+ void platformInvalidate();
+
+ DownloadManager& m_downloadManager;
+ DownloadID m_downloadID;
+#if !USE(NETWORK_SESSION)
+ WebCore::ResourceRequest m_request;
+#endif
+
+ RefPtr<SandboxExtension> m_sandboxExtension;
+
+#if PLATFORM(COCOA)
+#if USE(NETWORK_SESSION)
+ RetainPtr<NSURLSessionDownloadTask> m_download;
+#else
+ RetainPtr<NSURLDownload> m_nsURLDownload;
+ RetainPtr<WKDownloadAsDelegate> m_delegate;
+#endif
+#endif
+#if USE(CFNETWORK)
+ RetainPtr<CFURLDownloadRef> m_download;
+ RefPtr<DownloadAuthenticationClient> m_authenticationClient;
+#endif
+#if PLATFORM(QT)
+ QtFileDownloader* m_qtDownloader { nullptr };
+#endif
+#if PLATFORM(GTK) || PLATFORM(EFL)
+ std::unique_ptr<WebCore::ResourceHandleClient> m_downloadClient;
+ RefPtr<WebCore::ResourceHandle> m_resourceHandle;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // Download_h
diff --git a/Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.h b/Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.cpp
index a60929b76..ba122642c 100644
--- a/Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.h
+++ b/Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 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,39 +23,48 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SyncNetworkResourceLoader_h
-#define SyncNetworkResourceLoader_h
+#include "config.h"
+#include "DownloadAuthenticationClient.h"
-#include "NetworkConnectionToWebProcessMessages.h"
-#include "SchedulableLoader.h"
-#include <wtf/RefCounted.h>
+#if !USE(NETWORK_SESSION)
-#if ENABLE(NETWORK_PROCESS)
+#include "Download.h"
+
+using namespace WebCore;
namespace WebKit {
-class SyncNetworkResourceLoader : public SchedulableLoader {
-public:
- static PassRefPtr<SyncNetworkResourceLoader> create(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> reply)
- {
- return adoptRef(new SyncNetworkResourceLoader(parameters, connection, reply));
- }
+DownloadAuthenticationClient::DownloadAuthenticationClient(Download* download)
+ : m_download(download)
+{
+ ASSERT_ARG(download, download);
+}
- virtual void start() OVERRIDE;
- virtual void abort() OVERRIDE;
+void DownloadAuthenticationClient::receivedCredential(const AuthenticationChallenge&, const Credential&)
+{
+ // FIXME (119667): This can probably be just removed.
+}
- virtual bool isSynchronous() OVERRIDE { return true; }
+void DownloadAuthenticationClient::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
+{
+ // FIXME (119667): This can probably be just removed.
+}
-private:
- SyncNetworkResourceLoader(const NetworkResourceLoadParameters&, NetworkConnectionToWebProcess*, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>);
-
- void cleanup();
-
- RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> m_delayedReply;
-};
+void DownloadAuthenticationClient::receivedCancellation(const AuthenticationChallenge&)
+{
+ // FIXME (119667): This can probably be just removed.
+}
-} // namespace WebKit
+void DownloadAuthenticationClient::receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&)
+{
+ // FIXME (119667): This can probably be just removed.
+}
-#endif // ENABLE(NETWORK_PROCESS)
+void DownloadAuthenticationClient::receivedChallengeRejection(const AuthenticationChallenge&)
+{
+ // FIXME (119667): This can probably be just removed.
+}
+
+} // namespace WebKit
-#endif // SyncNetworkResourceLoader_h
+#endif
diff --git a/Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.h b/Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.h
new file mode 100644
index 000000000..9cfc7c693
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/DownloadAuthenticationClient.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef DownloadAuthenticationClient_h
+#define DownloadAuthenticationClient_h
+
+#if !USE(NETWORK_SESSION)
+
+#include <WebCore/AuthenticationClient.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+ class AuthenticationChallenge;
+ class Credential;
+}
+
+namespace WebKit {
+
+class Download;
+
+class DownloadAuthenticationClient : public RefCounted<DownloadAuthenticationClient>, public WebCore::AuthenticationClient {
+public:
+ static Ref<DownloadAuthenticationClient> create(Download* download) { return adoptRef(*new DownloadAuthenticationClient(download)); }
+
+ void detach() { m_download = 0; }
+
+ using RefCounted<DownloadAuthenticationClient>::ref;
+ using RefCounted<DownloadAuthenticationClient>::deref;
+
+private:
+ DownloadAuthenticationClient(Download*);
+
+ virtual void receivedCredential(const WebCore::AuthenticationChallenge&, const WebCore::Credential&) override;
+ virtual void receivedRequestToContinueWithoutCredential(const WebCore::AuthenticationChallenge&) override;
+ virtual void receivedCancellation(const WebCore::AuthenticationChallenge&) override;
+ virtual void receivedRequestToPerformDefaultHandling(const WebCore::AuthenticationChallenge&) override;
+ virtual void receivedChallengeRejection(const WebCore::AuthenticationChallenge&) override;
+
+ virtual void refAuthenticationClient() override { ref(); }
+ virtual void derefAuthenticationClient() override { deref(); }
+
+ Download* m_download;
+};
+
+} // namespace WebKit
+
+#endif // !USE(NETWORK_SESSION)
+
+#endif // DownloadAuthenticationClient_h
diff --git a/Source/WebKit2/NetworkProcess/Downloads/DownloadID.h b/Source/WebKit2/NetworkProcess/Downloads/DownloadID.h
new file mode 100644
index 000000000..37e68c3e9
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/DownloadID.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef DownloadID_h
+#define DownloadID_h
+
+#include "ArgumentCoder.h"
+#include "ArgumentDecoder.h"
+#include "ArgumentEncoder.h"
+#include <wtf/HashTraits.h>
+
+namespace WebKit {
+
+class DownloadID {
+public:
+ DownloadID()
+ {
+ }
+
+ explicit DownloadID(uint64_t downloadID)
+ : m_downloadID(downloadID)
+ {
+ }
+
+ bool operator==(DownloadID other) const { return m_downloadID == other.m_downloadID; }
+ bool operator!=(DownloadID other) const { return m_downloadID != other.m_downloadID; }
+
+ uint64_t downloadID() const { return m_downloadID; }
+private:
+ uint64_t m_downloadID { 0 };
+};
+
+}
+
+namespace IPC {
+
+template<> struct ArgumentCoder<WebKit::DownloadID> {
+ static void encode(ArgumentEncoder& encoder, const WebKit::DownloadID& downloadID)
+ {
+ encoder << downloadID.downloadID();
+ }
+ static bool decode(ArgumentDecoder& decoder, WebKit::DownloadID& downloadID)
+ {
+ uint64_t id;
+ if (!decoder.decode(id))
+ return false;
+
+ downloadID = WebKit::DownloadID(id);
+
+ return true;
+ }
+};
+
+}
+
+namespace WTF {
+
+struct DownloadIDHash {
+ static unsigned hash(const WebKit::DownloadID& d) { return intHash(d.downloadID()); }
+ static bool equal(const WebKit::DownloadID& a, const WebKit::DownloadID& b) { return a.downloadID() == b.downloadID(); }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+template<> struct HashTraits<WebKit::DownloadID> : GenericHashTraits<WebKit::DownloadID> {
+ static WebKit::DownloadID emptyValue() { return { }; }
+
+ static void constructDeletedValue(WebKit::DownloadID& slot) { slot = WebKit::DownloadID(std::numeric_limits<uint64_t>::max()); }
+ static bool isDeletedValue(const WebKit::DownloadID& slot) { return slot.downloadID() == std::numeric_limits<uint64_t>::max(); }
+};
+template<> struct DefaultHash<WebKit::DownloadID> {
+ typedef DownloadIDHash Hash;
+};
+
+}
+#endif /* DownloadID_h */
diff --git a/Source/WebKit2/NetworkProcess/Downloads/DownloadManager.cpp b/Source/WebKit2/NetworkProcess/Downloads/DownloadManager.cpp
new file mode 100644
index 000000000..f05aa645c
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/DownloadManager.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010 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 "DownloadManager.h"
+
+#include "Download.h"
+#include "NetworkLoad.h"
+#include "NetworkSession.h"
+#include "PendingDownload.h"
+#include "SessionTracker.h"
+#include <WebCore/NotImplemented.h>
+#include <WebCore/SessionID.h>
+#include <wtf/StdLibExtras.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+DownloadManager::DownloadManager(Client& client)
+ : m_client(client)
+{
+}
+
+void DownloadManager::startDownload(SessionID sessionID, DownloadID downloadID, const ResourceRequest& request)
+{
+#if USE(NETWORK_SESSION)
+ auto* networkSession = SessionTracker::networkSession(sessionID);
+ if (!networkSession)
+ return;
+ NetworkLoadParameters parameters;
+ parameters.sessionID = sessionID;
+ parameters.request = request;
+ parameters.clientCredentialPolicy = AskClientForAllCredentials;
+ m_pendingDownloads.add(downloadID, std::make_unique<PendingDownload>(parameters, downloadID));
+#else
+ auto download = std::make_unique<Download>(*this, downloadID, request);
+ download->start();
+
+ ASSERT(!m_downloads.contains(downloadID));
+ m_downloads.add(downloadID, WTFMove(download));
+#endif
+}
+
+#if USE(NETWORK_SESSION)
+std::unique_ptr<PendingDownload> DownloadManager::dataTaskBecameDownloadTask(DownloadID downloadID, std::unique_ptr<Download>&& download)
+{
+ // This is needed for downloads started with startDownload, otherwise it will return nullptr.
+ auto pendingDownload = m_pendingDownloads.take(downloadID);
+
+ m_downloads.add(downloadID, WTFMove(download));
+ return pendingDownload;
+}
+
+void DownloadManager::continueCanAuthenticateAgainstProtectionSpace(DownloadID downloadID, bool canAuthenticate)
+{
+ auto* pendingDownload = m_pendingDownloads.get(downloadID);
+ ASSERT(pendingDownload);
+ if (pendingDownload)
+ pendingDownload->continueCanAuthenticateAgainstProtectionSpace(canAuthenticate);
+}
+
+void DownloadManager::continueWillSendRequest(DownloadID downloadID, const WebCore::ResourceRequest& request)
+{
+ auto* pendingDownload = m_pendingDownloads.get(downloadID);
+ ASSERT(pendingDownload);
+ if (pendingDownload)
+ pendingDownload->continueWillSendRequest(request);
+}
+#else
+void DownloadManager::convertHandleToDownload(DownloadID downloadID, ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& response)
+{
+ auto download = std::make_unique<Download>(*this, downloadID, request);
+
+ download->startWithHandle(handle, response);
+ ASSERT(!m_downloads.contains(downloadID));
+ m_downloads.add(downloadID, WTFMove(download));
+}
+#endif
+
+void DownloadManager::resumeDownload(SessionID, DownloadID downloadID, const IPC::DataReference& resumeData, const String& path, const SandboxExtension::Handle& sandboxExtensionHandle)
+{
+#if USE(NETWORK_SESSION)
+ notImplemented();
+#else
+ // Download::resume() is responsible for setting the Download's resource request.
+ auto download = std::make_unique<Download>(*this, downloadID, ResourceRequest());
+
+ download->resume(resumeData, path, sandboxExtensionHandle);
+ ASSERT(!m_downloads.contains(downloadID));
+ m_downloads.add(downloadID, WTFMove(download));
+#endif
+}
+
+void DownloadManager::cancelDownload(DownloadID downloadID)
+{
+ Download* download = m_downloads.get(downloadID);
+ if (!download)
+ return;
+
+ download->cancel();
+}
+
+void DownloadManager::downloadFinished(Download* download)
+{
+ ASSERT(m_downloads.contains(download->downloadID()));
+ m_downloads.remove(download->downloadID());
+}
+
+void DownloadManager::didCreateDownload()
+{
+ m_client.didCreateDownload();
+}
+
+void DownloadManager::didDestroyDownload()
+{
+ m_client.didDestroyDownload();
+}
+
+IPC::Connection* DownloadManager::downloadProxyConnection()
+{
+ return m_client.downloadProxyConnection();
+}
+
+AuthenticationManager& DownloadManager::downloadsAuthenticationManager()
+{
+ return m_client.downloadsAuthenticationManager();
+}
+
+#if PLATFORM(QT)
+void DownloadManager::startTransfer(DownloadID downloadID, const String& destination)
+{
+ ASSERT(m_downloads.contains(downloadID));
+ Download* download = m_downloads.get(downloadID);
+ download->startTransfer(destination);
+}
+#endif
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/Downloads/DownloadManager.h b/Source/WebKit2/NetworkProcess/Downloads/DownloadManager.h
new file mode 100644
index 000000000..53c8d3bb9
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/DownloadManager.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef DownloadManager_h
+#define DownloadManager_h
+
+#include "DownloadID.h"
+#include "PendingDownload.h"
+#include "SandboxExtension.h"
+#include <WebCore/NotImplemented.h>
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+#if !USE(NETWORK_SESSION)
+class ResourceHandle;
+#endif
+class ResourceRequest;
+class ResourceResponse;
+class SessionID;
+}
+
+namespace IPC {
+class Connection;
+class DataReference;
+}
+
+namespace WebKit {
+
+class AuthenticationManager;
+class Download;
+class PendingDownload;
+
+class DownloadManager {
+ WTF_MAKE_NONCOPYABLE(DownloadManager);
+
+public:
+ class Client {
+ public:
+ virtual ~Client() { }
+
+ virtual void didCreateDownload() = 0;
+ virtual void didDestroyDownload() = 0;
+ virtual IPC::Connection* downloadProxyConnection() = 0;
+ virtual AuthenticationManager& downloadsAuthenticationManager() = 0;
+ };
+
+ explicit DownloadManager(Client&);
+
+ void startDownload(WebCore::SessionID, DownloadID, const WebCore::ResourceRequest&);
+#if USE(NETWORK_SESSION)
+ std::unique_ptr<PendingDownload> dataTaskBecameDownloadTask(DownloadID, std::unique_ptr<Download>&&);
+ void continueCanAuthenticateAgainstProtectionSpace(DownloadID, bool canAuthenticate);
+ void continueWillSendRequest(DownloadID, const WebCore::ResourceRequest&);
+#else
+ void convertHandleToDownload(DownloadID, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
+#endif
+
+ void resumeDownload(WebCore::SessionID, DownloadID, const IPC::DataReference& resumeData, const String& path, const SandboxExtension::Handle&);
+
+ void cancelDownload(DownloadID);
+
+ Download* download(DownloadID downloadID) { return m_downloads.get(downloadID); }
+
+ void downloadFinished(Download*);
+ bool isDownloading() const { return !m_downloads.isEmpty(); }
+ uint64_t activeDownloadCount() const { return m_downloads.size(); }
+
+ void didCreateDownload();
+ void didDestroyDownload();
+
+ IPC::Connection* downloadProxyConnection();
+ AuthenticationManager& downloadsAuthenticationManager();
+
+#if PLATFORM(QT)
+ void startTransfer(DownloadID, const String& destination);
+#endif
+
+private:
+ Client& m_client;
+#if USE(NETWORK_SESSION)
+ HashMap<DownloadID, std::unique_ptr<PendingDownload>> m_pendingDownloads;
+#endif
+ HashMap<DownloadID, std::unique_ptr<Download>> m_downloads;
+};
+
+} // namespace WebKit
+
+#endif // DownloadManager_h
diff --git a/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.cpp b/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.cpp
new file mode 100644
index 000000000..62e3799d2
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "PendingDownload.h"
+
+#if USE(NETWORK_SESSION)
+
+#include "DownloadProxyMessages.h"
+#include "NetworkLoad.h"
+#include "NetworkProcess.h"
+#include "WebCoreArgumentCoders.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+PendingDownload::PendingDownload(const NetworkLoadParameters& parameters, DownloadID downloadID)
+ : m_networkLoad(std::make_unique<NetworkLoad>(*this, parameters))
+{
+ m_networkLoad->setPendingDownloadID(downloadID);
+ m_networkLoad->setPendingDownload(*this);
+}
+
+void PendingDownload::willSendRedirectedRequest(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse)
+{
+ send(Messages::DownloadProxy::WillSendRequest(redirectRequest, redirectResponse));
+};
+
+void PendingDownload::continueWillSendRequest(const WebCore::ResourceRequest& newRequest)
+{
+ m_networkLoad->continueWillSendRequest(newRequest);
+}
+
+void PendingDownload::canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace& protectionSpace)
+{
+ send(Messages::DownloadProxy::CanAuthenticateAgainstProtectionSpace(protectionSpace));
+}
+
+void PendingDownload::continueCanAuthenticateAgainstProtectionSpace(bool canAuthenticate)
+{
+ m_networkLoad->continueCanAuthenticateAgainstProtectionSpace(canAuthenticate);
+}
+
+void PendingDownload::didConvertToDownload()
+{
+ m_networkLoad = nullptr;
+}
+
+IPC::Connection* PendingDownload::messageSenderConnection()
+{
+ return NetworkProcess::singleton().parentProcessConnection();
+}
+
+uint64_t PendingDownload::messageSenderDestinationID()
+{
+ return m_networkLoad->pendingDownloadID().downloadID();
+}
+
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h b/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h
new file mode 100644
index 000000000..72a744cb2
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#ifndef PendingDownload_h
+#define PendingDownload_h
+
+#if USE(NETWORK_SESSION)
+
+#include "MessageSender.h"
+#include "NetworkLoadClient.h"
+
+namespace WebCore {
+class ResourceResponse;
+}
+
+namespace WebKit {
+
+class DownloadID;
+class NetworkLoad;
+class NetworkLoadParameters;
+
+class PendingDownload : public NetworkLoadClient, public IPC::MessageSender {
+public:
+ PendingDownload(const NetworkLoadParameters&, DownloadID);
+
+ void continueWillSendRequest(const WebCore::ResourceRequest&);
+ void continueCanAuthenticateAgainstProtectionSpace(bool canAuthenticate);
+
+private:
+ // NetworkLoadClient.
+ virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override { }
+ virtual void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) override;
+ virtual bool isSynchronous() const override { return false; }
+ virtual void willSendRedirectedRequest(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse) override;
+ virtual ShouldContinueDidReceiveResponse didReceiveResponse(const WebCore::ResourceResponse&) override { return ShouldContinueDidReceiveResponse::No; };
+ virtual void didReceiveBuffer(RefPtr<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) override { };
+ virtual void didFinishLoading(double finishTime) override { };
+ virtual void didFailLoading(const WebCore::ResourceError&) override { };
+ virtual void didConvertToDownload() override;
+#if PLATFORM(COCOA)
+ virtual void willCacheResponseAsync(CFCachedURLResponseRef) override { }
+#endif
+
+ // MessageSender.
+ virtual IPC::Connection* messageSenderConnection() override;
+ virtual uint64_t messageSenderDestinationID() override;
+
+private:
+ std::unique_ptr<NetworkLoad> m_networkLoad;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/Downloads/qt/DownloadQt.cpp b/Source/WebKit2/NetworkProcess/Downloads/qt/DownloadQt.cpp
new file mode 100644
index 000000000..3db5ecdfb
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/qt/DownloadQt.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "Download.h"
+
+#include "QtFileDownloader.h"
+#include <WebCore/NotImplemented.h>
+#include <WebCore/QNetworkReplyHandler.h>
+#include <WebCore/ResourceHandle.h>
+#include <WebCore/ResourceHandleInternal.h>
+#include <WebCore/ResourceResponse.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+void Download::start()
+{
+ ASSERT(!m_qtDownloader);
+ m_qtDownloader = new QtFileDownloader(*this, m_request.toNetworkRequest());
+}
+
+void Download::startWithHandle(ResourceHandle* handle, const ResourceResponse& resp)
+{
+ ASSERT(!m_qtDownloader);
+ m_qtDownloader = new QtFileDownloader(*this, handle->getInternal()->m_job->release());
+}
+
+void Download::resume(const IPC::DataReference&, const WTF::String&, const SandboxExtension::Handle&)
+{
+ notImplemented();
+}
+
+void Download::cancel()
+{
+ ASSERT(m_qtDownloader);
+ m_qtDownloader->cancel();
+}
+
+void Download::platformInvalidate()
+{
+ ASSERT(m_qtDownloader);
+ m_qtDownloader->deleteLater();
+ m_qtDownloader = nullptr;
+}
+
+void Download::startTransfer(const String& destination)
+{
+ m_qtDownloader->startTransfer(destination);
+}
+
+void Download::platformDidFinish()
+{
+ notImplemented();
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp
new file mode 100644
index 000000000..2eaed702d
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This program 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 program 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 program; 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 "QtFileDownloader.h"
+
+#include "DataReference.h"
+#include "Download.h"
+#include "HTTPParsers.h"
+#include "MIMETypeRegistry.h"
+#include "NetworkProcess.h"
+#include <QCoreApplication>
+#include <QFile>
+#include <QFileInfo>
+#include <QNetworkAccessManager>
+#include <WebCore/QNetworkReplyHandler.h>
+#include <WebCore/ResourceError.h>
+#include <WebCore/ResourceResponse.h>
+
+using namespace WebCore;
+using namespace WTF;
+
+namespace WebKit {
+
+QtFileDownloader::QtFileDownloader(Download& download, const QNetworkRequest& request)
+ : m_download(download)
+ , m_reply(NetworkProcess::singleton().networkAccessManager().get(request))
+ , m_error(QNetworkReply::NoError)
+{
+ makeConnections();
+}
+
+QtFileDownloader::QtFileDownloader(Download& download, QNetworkReply* reply)
+ : m_download(download)
+ , m_reply(reply)
+ , m_error(reply->error())
+{
+ makeConnections();
+
+ if (reply->isFinished())
+ onFinished();
+ else if (reply->isReadable())
+ onReadyRead();
+}
+
+QtFileDownloader::~QtFileDownloader()
+{
+ if (!m_destinationFile)
+ return;
+
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorAborted);
+}
+
+void QtFileDownloader::makeConnections()
+{
+ connect(m_reply.get(), SIGNAL(readyRead()), SLOT(onReadyRead()));
+ connect(m_reply.get(), SIGNAL(finished()), SLOT(onFinished()));
+ connect(m_reply.get(), SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onError(QNetworkReply::NetworkError)));
+}
+
+void QtFileDownloader::startTransfer(const QString& decidedFilePath)
+{
+ ASSERT(!m_destinationFile);
+
+ // Error might have occured during destination query.
+ if (m_error != QNetworkReply::NoError) {
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorNetworkFailure);
+ return;
+ }
+
+ if (decidedFilePath.isEmpty()) {
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCancelled);
+ return;
+ }
+
+ auto downloadFile = std::make_unique<QFile>(decidedFilePath);
+
+ if (!downloadFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotOpenFile);
+ return;
+ }
+
+ // Assigning to m_destinationFile flags that either error or
+ // finished shall be called in the end.
+ m_destinationFile = WTFMove(downloadFile);
+
+ m_download.didCreateDestination(m_destinationFile->fileName());
+
+ // We might have gotten readyRead already even before this function
+ // was called.
+ if (m_reply->bytesAvailable())
+ onReadyRead();
+
+ // We might have gotten finished already even before this
+ // function was called.
+ if (m_reply->isFinished())
+ onFinished();
+}
+
+void QtFileDownloader::abortDownloadWritingAndEmitError(QtFileDownloader::DownloadError errorCode)
+{
+ m_reply->abort();
+
+ // On network failures it's QNetworkReplyHandler::errorForReply who will handle errors.
+ if (errorCode == QtFileDownloader::DownloadErrorNetworkFailure) {
+ m_download.didFail(QNetworkReplyHandler::errorForReply(m_reply.get()), IPC::DataReference(0, 0));
+ return;
+ }
+
+ QString translatedErrorMessage;
+ switch (errorCode) {
+ case QtFileDownloader::DownloadErrorAborted:
+ translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Download aborted");
+ break;
+ case QtFileDownloader::DownloadErrorCannotWriteToFile:
+ translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Cannot write to file");
+ break;
+ case QtFileDownloader::DownloadErrorCannotOpenFile:
+ translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Cannot open file for writing");
+ break;
+ case QtFileDownloader::DownloadErrorDestinationAlreadyExists:
+ translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Destination already exists");
+ break;
+ case QtFileDownloader::DownloadErrorCancelled:
+ translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Download cancelled by caller");
+ break;
+ case QtFileDownloader::DownloadErrorCannotDetermineFilename:
+ translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Cannot determine filename");
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ ResourceError downloadError("Download", errorCode, m_reply->url(), translatedErrorMessage);
+
+ m_download.didFail(downloadError, IPC::DataReference(0, 0));
+}
+
+void QtFileDownloader::handleDownloadResponse()
+{
+ // By API contract, QNetworkReply::metaDataChanged cannot really be trusted.
+ // Thus we need to call this upon receiving first data.
+ String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
+ String encoding = extractCharsetFromMediaType(contentType);
+ String mimeType = extractMIMETypeFromMediaType(contentType);
+
+ // Let's try to guess from the extension.
+ if (mimeType.isEmpty())
+ mimeType = MIMETypeRegistry::getMIMETypeForPath(m_reply->url().path());
+
+ ResourceResponse response(m_reply->url(), mimeType, m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding);
+ m_download.didReceiveResponse(response);
+}
+
+void QtFileDownloader::onReadyRead()
+{
+ if (m_destinationFile) {
+ QByteArray content = m_reply->readAll();
+ if (content.size() <= 0)
+ return;
+
+ qint64 bytesWritten = m_destinationFile->write(content);
+
+ if (bytesWritten == -1) {
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotWriteToFile);
+ return;
+ }
+
+ // There might a corner case to be fixed here if bytesWritten != content.size()
+ // does not actually represent an error.
+ ASSERT(bytesWritten == content.size());
+
+ m_download.didReceiveData(bytesWritten);
+ } else if (!m_headersRead) {
+ handleDownloadResponse();
+ m_headersRead = true;
+ }
+}
+
+void QtFileDownloader::onFinished()
+{
+ // If it's finished and we haven't even read the headers, it means we never got to onReadyRead and that we are
+ // probably dealing with the download of a local file or of a small file that was started with a handle.
+ if (!m_headersRead) {
+ handleDownloadResponse();
+ m_headersRead = true;
+ return;
+ }
+
+ if (!m_destinationFile)
+ return;
+
+ m_destinationFile = nullptr;
+
+ if (m_error == QNetworkReply::NoError)
+ m_download.didFinish();
+ else if (m_error == QNetworkReply::OperationCanceledError)
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCancelled);
+ else
+ abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorNetworkFailure);
+}
+
+void QtFileDownloader::onError(QNetworkReply::NetworkError code)
+{
+ m_error = code;
+}
+
+void QtFileDownloader::cancel()
+{
+ m_reply->abort();
+ // QtFileDownloader::onFinished() will be called and will raise a DownloadErrorCancelled.
+}
+
+} // namespace WebKit
+#include "moc_QtFileDownloader.cpp"
diff --git a/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h
new file mode 100644
index 000000000..58f2d5f1f
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This program 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 program 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 program; 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 QtFileDownloader_h
+#define QtFileDownloader_h
+
+#include <QNetworkReply>
+#include <QNetworkRequest>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QNetworkAccessManager;
+class QNetworkRequest;
+QT_END_NAMESPACE
+
+namespace WebCore {
+class ResourceError;
+}
+
+namespace WebKit {
+class Download;
+
+class QtFileDownloader : public QObject {
+ Q_OBJECT
+public:
+ QtFileDownloader(Download&, const QNetworkRequest&);
+ QtFileDownloader(Download&, QNetworkReply*);
+ virtual ~QtFileDownloader();
+
+ void cancel();
+ void startTransfer(const QString& destination);
+
+ enum DownloadError {
+ DownloadErrorAborted = 0,
+ DownloadErrorCannotWriteToFile,
+ DownloadErrorCannotOpenFile,
+ DownloadErrorDestinationAlreadyExists,
+ DownloadErrorCancelled,
+ DownloadErrorCannotDetermineFilename,
+ DownloadErrorNetworkFailure
+ };
+
+private Q_SLOTS:
+ void onReadyRead();
+ void onFinished();
+ void onError(QNetworkReply::NetworkError);
+
+private:
+ void makeConnections();
+ void abortDownloadWritingAndEmitError(QtFileDownloader::DownloadError);
+ void handleDownloadResponse();
+
+ Download& m_download;
+ std::unique_ptr<QNetworkReply> m_reply;
+ std::unique_ptr<QFile> m_destinationFile;
+ QNetworkReply::NetworkError m_error;
+ bool m_headersRead { false };
+};
+
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/Info.plist b/Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/Info.plist
deleted file mode 100644
index 45905e5a6..000000000
--- a/Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/Info.plist
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleGetInfoString</key>
- <string>${BUNDLE_VERSION}, Copyright 2003-2013 Apple Inc.</string>
- <key>CFBundleIdentifier</key>
- <string>com.apple.WebKit.${PRODUCT_NAME}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>${SHORT_VERSION_STRING}</string>
- <key>CFBundleVersion</key>
- <string>${BUNDLE_VERSION}</string>
- <key>LSFileQuarantineEnabled</key>
- <true/>
- <key>LSMinimumSystemVersion</key>
- <string>${MACOSX_DEPLOYMENT_TARGET}</string>
- <key>LSUIElement</key>
- <true/>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
- <key>CFBundleIconFile</key>
- <string>${APP_ICON}</string>
- <key>WebKitEntryPoint</key>
- <string>NetworkProcessMain</string>
-</dict>
-</plist>
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService.Development/Info.plist b/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService.Development/Info.plist
deleted file mode 100644
index c73c3d3bb..000000000
--- a/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService.Development/Info.plist
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleGetInfoString</key>
- <string>${BUNDLE_VERSION}, Copyright 2003-2013 Apple Inc.</string>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>com.apple.WebKit.Networking.Development</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>XPC!</string>
- <key>CFBundleShortVersionString</key>
- <string>${SHORT_VERSION_STRING}</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>${BUNDLE_VERSION}</string>
- <key>LSFileQuarantineEnabled</key>
- <true/>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
- <key>WebKitEntryPoint</key>
- <string>NetworkServiceInitializer</string>
- <key>LSUIElement</key>
- <true/>
- <key>XPCService</key>
- <dict>
- <key>ServiceType</key>
- <string>Application</string>
- <key>JoinExistingSession</key>
- <true/>
- <key>RunLoopType</key>
- <string>NSRunLoop</string>
- <key>_MultipleInstances</key>
- <true/>
- </dict>
-</dict>
-</plist>
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService/Info.plist b/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService/Info.plist
deleted file mode 100644
index ac5e4e522..000000000
--- a/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkService/Info.plist
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleGetInfoString</key>
- <string>${BUNDLE_VERSION}, Copyright 2003-2013 Apple Inc.</string>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>com.apple.WebKit.Networking</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>XPC!</string>
- <key>CFBundleShortVersionString</key>
- <string>${SHORT_VERSION_STRING}</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>${BUNDLE_VERSION}</string>
- <key>LSFileQuarantineEnabled</key>
- <true/>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
- <key>WebKitEntryPoint</key>
- <string>NetworkServiceInitializer</string>
- <key>LSUIElement</key>
- <true/>
- <key>XPCService</key>
- <dict>
- <key>ServiceType</key>
- <string>Application</string>
- <key>JoinExistingSession</key>
- <true/>
- <key>RunLoopType</key>
- <string>NSRunLoop</string>
- <key>_MultipleInstances</key>
- <true/>
- <key>EnvironmentVariables</key>
- <dict>
- <key>DYLD_INSERT_LIBRARIES</key>
- <string>$(WEBKIT2_FRAMEWORKS_DIR)/WebKit2.framework/NetworkProcess.app/Contents/MacOS/SecItemShim.dylib</string>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/qt/NetworkProcessMain.cpp b/Source/WebKit2/NetworkProcess/EntryPoint/qt/NetworkProcessMain.cpp
new file mode 100644
index 000000000..b102fc566
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/EntryPoint/qt/NetworkProcessMain.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 Konstantin Tokarev <annulen@yandex.ru>
+ *
+ * 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"
+
+namespace WebKit {
+Q_DECL_IMPORT int NetworkProcessMainQt(int argc, char** argv);
+}
+
+int main(int argc, char** argv)
+{
+ return WebKit::NetworkProcessMainQt(argc, argv);
+}
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/unix/NetworkProcessMain.cpp b/Source/WebKit2/NetworkProcess/EntryPoint/unix/NetworkProcessMain.cpp
new file mode 100644
index 000000000..b282e16a3
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/EntryPoint/unix/NetworkProcessMain.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include "NetworkProcessMainUnix.h"
+
+#include <cstdlib>
+
+using namespace WebKit;
+
+int main(int argc, char** argv)
+{
+ // Disable SSLv3 very early because it is practically impossible to safely
+ // use setenv() when multiple threads are running, as another thread calling
+ // getenv() could cause a crash, and many functions use getenv() internally.
+ // This workaround will stop working if glib-networking switches away from
+ // GnuTLS or simply stops parsing this variable. We intentionally do not
+ // overwrite this priority string if it's already set by the user.
+ // https://bugzilla.gnome.org/show_bug.cgi?id=738633
+ // WARNING: This needs to be KEPT IN SYNC with WebProcessMain.cpp.
+ setenv("G_TLS_GNUTLS_PRIORITY", "NORMAL:%COMPAT:%LATEST_RECORD_VERSION:!VERS-SSL3.0:!ARCFOUR-128", 0);
+
+ return NetworkProcessMainUnix(argc, argv);
+}
diff --git a/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp b/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
index 1e60d401b..025e2fc65 100644
--- a/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
+++ b/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
@@ -26,20 +26,21 @@
#include "config.h"
#include "NetworkBlobRegistry.h"
-#if ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)
-
+#include "BlobDataFileReferenceWithSandboxExtension.h"
#include "SandboxExtension.h"
+#include <WebCore/BlobPart.h>
#include <WebCore/BlobRegistryImpl.h>
-#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RunLoop.h>
using namespace WebCore;
namespace WebKit {
-NetworkBlobRegistry& NetworkBlobRegistry::shared()
+NetworkBlobRegistry& NetworkBlobRegistry::singleton()
{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(NetworkBlobRegistry, registry, ());
+ ASSERT(RunLoop::isMain());
+ static NeverDestroyed<NetworkBlobRegistry> registry;
return registry;
}
@@ -47,50 +48,73 @@ NetworkBlobRegistry::NetworkBlobRegistry()
{
}
-void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess* connection, const KURL& url, PassOwnPtr<BlobData> data, const Vector<RefPtr<SandboxExtension>>& newSandboxExtensions)
+void NetworkBlobRegistry::registerFileBlobURL(NetworkConnectionToWebProcess* connection, const URL& url, const String& path, RefPtr<SandboxExtension>&& sandboxExtension, const String& contentType)
{
- ASSERT(!m_sandboxExtensions.contains(url.string()));
-
- // Combine new extensions for File items and existing extensions for inner Blob items.
- Vector<RefPtr<SandboxExtension>> sandboxExtensions = newSandboxExtensions;
- const BlobDataItemList& items = data->items();
- for (size_t i = 0, count = items.size(); i < count; ++i) {
- if (items[i].type == BlobDataItem::Blob)
- sandboxExtensions.appendVector(m_sandboxExtensions.get(items[i].url.string()));
- }
+ blobRegistry().registerFileBlobURL(url, BlobDataFileReferenceWithSandboxExtension::create(path, sandboxExtension), contentType);
- blobRegistry().registerBlobURL(url, data);
+ ASSERT(!m_blobsForConnection.get(connection).contains(url));
+ BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(connection);
+ if (mapIterator == m_blobsForConnection.end())
+ mapIterator = m_blobsForConnection.add(connection, HashSet<URL>()).iterator;
+ mapIterator->value.add(url);
+}
- if (!sandboxExtensions.isEmpty())
- m_sandboxExtensions.add(url.string(), sandboxExtensions);
+void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess* connection, const URL& url, Vector<WebCore::BlobPart> blobParts, const String& contentType)
+{
+ blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
ASSERT(!m_blobsForConnection.get(connection).contains(url));
BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(connection);
if (mapIterator == m_blobsForConnection.end())
- mapIterator = m_blobsForConnection.add(connection, HashSet<KURL>()).iterator;
+ mapIterator = m_blobsForConnection.add(connection, HashSet<URL>()).iterator;
mapIterator->value.add(url);
}
-void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess* connection, const WebCore::KURL& url, const WebCore::KURL& srcURL)
+void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess* connection, const WebCore::URL& url, const WebCore::URL& srcURL)
{
+ // The connection may not be registered if NetworkProcess prevously crashed for any reason.
+ BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(connection);
+ if (mapIterator == m_blobsForConnection.end())
+ return;
+
blobRegistry().registerBlobURL(url, srcURL);
- SandboxExtensionMap::iterator iter = m_sandboxExtensions.find(srcURL.string());
- if (iter != m_sandboxExtensions.end())
- m_sandboxExtensions.add(url.string(), iter->value);
- ASSERT(m_blobsForConnection.contains(connection));
- ASSERT(m_blobsForConnection.find(connection)->value.contains(srcURL));
- m_blobsForConnection.find(connection)->value.add(url);
+ ASSERT(mapIterator->value.contains(srcURL));
+ mapIterator->value.add(url);
+}
+
+void NetworkBlobRegistry::registerBlobURLForSlice(NetworkConnectionToWebProcess* connection, const WebCore::URL& url, const WebCore::URL& srcURL, int64_t start, int64_t end)
+{
+ // The connection may not be registered if NetworkProcess prevously crashed for any reason.
+ BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(connection);
+ if (mapIterator == m_blobsForConnection.end())
+ return;
+
+ blobRegistry().registerBlobURLForSlice(url, srcURL, start, end);
+
+ ASSERT(mapIterator->value.contains(srcURL));
+ mapIterator->value.add(url);
}
-void NetworkBlobRegistry::unregisterBlobURL(NetworkConnectionToWebProcess* connection, const WebCore::KURL& url)
+void NetworkBlobRegistry::unregisterBlobURL(NetworkConnectionToWebProcess* connection, const WebCore::URL& url)
{
+ // The connection may not be registered if NetworkProcess prevously crashed for any reason.
+ BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(connection);
+ if (mapIterator == m_blobsForConnection.end())
+ return;
+
blobRegistry().unregisterBlobURL(url);
- m_sandboxExtensions.remove(url.string());
- ASSERT(m_blobsForConnection.contains(connection));
- ASSERT(m_blobsForConnection.find(connection)->value.contains(url));
- m_blobsForConnection.find(connection)->value.remove(url);
+ ASSERT(mapIterator->value.contains(url));
+ mapIterator->value.remove(url);
+}
+
+uint64_t NetworkBlobRegistry::blobSize(NetworkConnectionToWebProcess* connection, const WebCore::URL& url)
+{
+ if (!m_blobsForConnection.contains(connection) || !m_blobsForConnection.find(connection)->value.contains(url))
+ return 0;
+
+ return blobRegistry().blobSize(url);
}
void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
@@ -98,20 +122,30 @@ void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebP
if (!m_blobsForConnection.contains(connection))
return;
- HashSet<KURL>& blobsForConnection = m_blobsForConnection.find(connection)->value;
- for (HashSet<KURL>::iterator iter = blobsForConnection.begin(), end = blobsForConnection.end(); iter != end; ++iter) {
+ HashSet<URL>& blobsForConnection = m_blobsForConnection.find(connection)->value;
+ for (HashSet<URL>::iterator iter = blobsForConnection.begin(), end = blobsForConnection.end(); iter != end; ++iter)
blobRegistry().unregisterBlobURL(*iter);
- m_sandboxExtensions.remove(*iter);
- }
m_blobsForConnection.remove(connection);
}
-const Vector<RefPtr<SandboxExtension>> NetworkBlobRegistry::sandboxExtensions(const WebCore::KURL& url)
+Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(NetworkConnectionToWebProcess& connection, const WebCore::URL& url)
{
- return m_sandboxExtensions.get(url.string());
-}
+ if (!m_blobsForConnection.contains(&connection) || !m_blobsForConnection.find(&connection)->value.contains(url))
+ return Vector<RefPtr<BlobDataFileReference>>();
+
+ ASSERT(blobRegistry().isBlobRegistryImpl());
+ BlobData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
+ if (!blobData)
+ return Vector<RefPtr<BlobDataFileReference>>();
+
+ Vector<RefPtr<BlobDataFileReference>> result;
+ for (const BlobDataItem& item : blobData->items()) {
+ if (item.type() == BlobDataItem::Type::File)
+ result.append(item.file());
+ }
+ return result;
}
-#endif
+}
diff --git a/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h b/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h
index 6d71bbfc9..4adde415d 100644
--- a/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h
+++ b/Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h
@@ -26,14 +26,13 @@
#ifndef NetworkBlobRegistry_h
#define NetworkBlobRegistry_h
-#if ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)
-
-#include <WebCore/KURLHash.h>
+#include <WebCore/URLHash.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
namespace WebCore {
-class BlobData;
+class BlobDataFileReference;
+class BlobPart;
}
namespace WebKit {
@@ -45,28 +44,26 @@ class NetworkBlobRegistry {
WTF_MAKE_NONCOPYABLE(NetworkBlobRegistry);
public:
NetworkBlobRegistry();
- static NetworkBlobRegistry& shared();
+ static NetworkBlobRegistry& singleton();
- void registerBlobURL(NetworkConnectionToWebProcess*, const WebCore::KURL&, PassOwnPtr<WebCore::BlobData>, const Vector<RefPtr<SandboxExtension>>&);
- void registerBlobURL(NetworkConnectionToWebProcess*, const WebCore::KURL&, const WebCore::KURL& srcURL);
- void unregisterBlobURL(NetworkConnectionToWebProcess*, const WebCore::KURL&);
+ void registerFileBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&, const String& path, RefPtr<SandboxExtension>&&, const String& contentType);
+ void registerBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&, Vector<WebCore::BlobPart>, const String& contentType);
+ void registerBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&, const WebCore::URL& srcURL);
+ void registerBlobURLForSlice(NetworkConnectionToWebProcess*, const WebCore::URL&, const WebCore::URL& srcURL, int64_t start, int64_t end);
+ void unregisterBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&);
+ uint64_t blobSize(NetworkConnectionToWebProcess*, const WebCore::URL&);
void connectionToWebProcessDidClose(NetworkConnectionToWebProcess*);
- const Vector<RefPtr<SandboxExtension>> sandboxExtensions(const WebCore::KURL&);
+ Vector<RefPtr<WebCore::BlobDataFileReference>> filesInBlob(NetworkConnectionToWebProcess&, const WebCore::URL&);
private:
~NetworkBlobRegistry();
- typedef HashMap<String, Vector<RefPtr<SandboxExtension>>> SandboxExtensionMap;
- SandboxExtensionMap m_sandboxExtensions;
-
- typedef HashMap<NetworkConnectionToWebProcess*, HashSet<WebCore::KURL>> BlobForConnectionMap;
+ typedef HashMap<NetworkConnectionToWebProcess*, HashSet<WebCore::URL>> BlobForConnectionMap;
BlobForConnectionMap m_blobsForConnection;
};
}
-#endif // ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)
-
#endif // NetworkBlobRegistry_h
diff --git a/Source/WebKit2/NetworkProcess/HostRecord.cpp b/Source/WebKit2/NetworkProcess/HostRecord.cpp
deleted file mode 100644
index e7ce34b0b..000000000
--- a/Source/WebKit2/NetworkProcess/HostRecord.cpp
+++ /dev/null
@@ -1,231 +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 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 "HostRecord.h"
-
-#include "Logging.h"
-#include "NetworkConnectionToWebProcess.h"
-#include "NetworkProcess.h"
-#include "NetworkResourceLoadParameters.h"
-#include "NetworkResourceLoadScheduler.h"
-#include "NetworkResourceLoader.h"
-#include "SyncNetworkResourceLoader.h"
-#include <wtf/MainThread.h>
-
-#if ENABLE(NETWORK_PROCESS)
-
-using namespace WebCore;
-
-namespace WebKit {
-
-HostRecord::HostRecord(const String& name, int maxRequestsInFlight)
- : m_name(name)
- , m_maxRequestsInFlight(maxRequestsInFlight)
-{
-}
-
-HostRecord::~HostRecord()
-{
-#ifndef NDEBUG
- ASSERT(m_loadersInProgress.isEmpty());
- for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++)
- ASSERT(m_loadersPending[p].isEmpty());
-#endif
-}
-
-void HostRecord::scheduleResourceLoader(PassRefPtr<SchedulableLoader> loader)
-{
- ASSERT(isMainThread());
-
- loader->setHostRecord(this);
-
- if (loader->isSynchronous())
- m_syncLoadersPending.append(loader);
- else
- m_loadersPending[loader->priority()].append(loader);
-}
-
-void HostRecord::addLoaderInProgress(SchedulableLoader* loader)
-{
- ASSERT(isMainThread());
-
- m_loadersInProgress.add(loader);
- loader->setHostRecord(this);
-}
-
-inline bool removeLoaderFromQueue(SchedulableLoader* loader, LoaderQueue& queue)
-{
- LoaderQueue::iterator end = queue.end();
- for (LoaderQueue::iterator it = queue.begin(); it != end; ++it) {
- if (it->get() == loader) {
- loader->setHostRecord(0);
- queue.remove(it);
- return true;
- }
- }
- return false;
-}
-
-void HostRecord::removeLoader(SchedulableLoader* loader)
-{
- ASSERT(isMainThread());
-
- // FIXME (NetworkProcess): Due to IPC race conditions, it's possible this HostRecord will be asked to remove the same loader twice.
- // It would be nice to know the loader has already been removed and treat it as a no-op.
-
- SchedulableLoaderSet::iterator i = m_loadersInProgress.find(loader);
- if (i != m_loadersInProgress.end()) {
- i->get()->setHostRecord(0);
- m_loadersInProgress.remove(i);
- return;
- }
-
- if (removeLoaderFromQueue(loader, m_syncLoadersPending))
- return;
-
- for (int priority = ResourceLoadPriorityHighest; priority >= ResourceLoadPriorityLowest; --priority) {
- if (removeLoaderFromQueue(loader, m_loadersPending[priority]))
- return;
- }
-}
-
-bool HostRecord::hasRequests() const
-{
- if (!m_loadersInProgress.isEmpty())
- return true;
-
- for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++) {
- if (!m_loadersPending[p].isEmpty())
- return true;
- }
-
- return false;
-}
-
-uint64_t HostRecord::pendingRequestCount() const
-{
- uint64_t count = 0;
-
- for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++)
- count += m_loadersPending[p].size();
-
- return count;
-}
-
-uint64_t HostRecord::activeLoadCount() const
-{
- return m_loadersInProgress.size();
-}
-
-void HostRecord::servePendingRequestsForQueue(LoaderQueue& queue, ResourceLoadPriority priority)
-{
- // We only enforce the connection limit for http(s) hosts, which are the only ones with names.
- bool shouldLimitRequests = !name().isNull();
-
- // 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.
-
- // FIXME (NetworkProcess): The above comment about document parsing and stylesheets is a holdover
- // from the WebCore::ResourceLoadScheduler.
- // The behavior described was at one time important for WebCore's single threadedness.
- // It's possible that we don't care about it with the NetworkProcess.
- // We should either decide it's not important and change the above comment, or decide it is
- // still important and somehow account for it.
-
- // Very low priority loaders are only handled when no other loaders are in progress.
- if (shouldLimitRequests && priority == ResourceLoadPriorityVeryLow && !m_loadersInProgress.isEmpty())
- return;
-
- while (!queue.isEmpty()) {
- RefPtr<SchedulableLoader> loader = queue.first();
- ASSERT(loader->hostRecord() == this);
-
- // This request might be from WebProcess we've lost our connection to.
- // If so we should just skip it.
- if (!loader->connectionToWebProcess()) {
- removeLoader(loader.get());
- continue;
- }
-
- if (shouldLimitRequests && limitsRequests(priority, loader.get()))
- return;
-
- m_loadersInProgress.add(loader);
- queue.removeFirst();
-
- LOG(NetworkScheduling, "(NetworkProcess) HostRecord::servePendingRequestsForQueue - Starting load of %s\n", loader->request().url().string().utf8().data());
- loader->start();
- }
-}
-
-void HostRecord::servePendingRequests(ResourceLoadPriority minimumPriority)
-{
- LOG(NetworkScheduling, "(NetworkProcess) HostRecord::servePendingRequests Host name='%s'", name().utf8().data());
-
- // We serve synchronous requests before any other requests to improve responsiveness in any
- // WebProcess that is waiting on a synchronous load.
- servePendingRequestsForQueue(m_syncLoadersPending, ResourceLoadPriorityHighest);
-
- for (int priority = ResourceLoadPriorityHighest; priority >= minimumPriority; --priority)
- servePendingRequestsForQueue(m_loadersPending[priority], (ResourceLoadPriority)priority);
-}
-
-bool HostRecord::limitsRequests(ResourceLoadPriority priority, SchedulableLoader* loader) const
-{
- ASSERT(loader);
- ASSERT(loader->connectionToWebProcess());
-
- if (priority == ResourceLoadPriorityVeryLow && !m_loadersInProgress.isEmpty())
- return true;
-
- if (loader->connectionToWebProcess()->isSerialLoadingEnabled() && m_loadersInProgress.size() >= 1)
- return true;
-
- // If we're exactly at the limit for requests in flight, and this loader is asynchronous, then we're done serving new requests.
- // The synchronous loader exception handles the case where a sync XHR is made while 6 other requests are already in flight.
- if (m_loadersInProgress.size() == m_maxRequestsInFlight && !loader->isSynchronous())
- return true;
-
- // If we're already past the limit of the number of loaders in flight, we won't even serve new synchronous requests right now.
- if (m_loadersInProgress.size() > m_maxRequestsInFlight) {
-#ifndef NDEBUG
- // If we have more loaders in progress than we should, at least one of them had better be synchronous.
- SchedulableLoaderSet::iterator i = m_loadersInProgress.begin();
- SchedulableLoaderSet::iterator end = m_loadersInProgress.end();
- for (; i != end; ++i) {
- if (i->get()->isSynchronous())
- break;
- }
- ASSERT(i != end);
-#endif
- return true;
- }
- return false;
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/HostRecord.h b/Source/WebKit2/NetworkProcess/HostRecord.h
deleted file mode 100644
index 058208975..000000000
--- a/Source/WebKit2/NetworkProcess/HostRecord.h
+++ /dev/null
@@ -1,86 +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 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.
- */
-
-#ifndef HostRecord_h
-#define HostRecord_h
-
-#if ENABLE(NETWORK_PROCESS)
-
-#include <WebCore/ResourceLoadPriority.h>
-#include <wtf/Deque.h>
-#include <wtf/HashSet.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
-
-namespace WebKit {
-
-class NetworkResourceLoader;
-class SchedulableLoader;
-class SyncNetworkResourceLoader;
-
-typedef Deque<RefPtr<SchedulableLoader>> LoaderQueue;
-typedef uint64_t ResourceLoadIdentifier;
-
-class HostRecord : public RefCounted<HostRecord> {
-public:
- static PassRefPtr<HostRecord> create(const String& name, int maxRequestsInFlight)
- {
- return adoptRef(new HostRecord(name, maxRequestsInFlight));
- }
-
- ~HostRecord();
-
- const String& name() const { return m_name; }
-
- void scheduleResourceLoader(PassRefPtr<SchedulableLoader>);
- void addLoaderInProgress(SchedulableLoader*);
- void removeLoader(SchedulableLoader*);
- bool hasRequests() const;
- void servePendingRequests(WebCore::ResourceLoadPriority);
-
- uint64_t pendingRequestCount() const;
- uint64_t activeLoadCount() const;
-
-private:
- HostRecord(const String& name, int maxRequestsInFlight);
-
- void servePendingRequestsForQueue(LoaderQueue&, WebCore::ResourceLoadPriority);
- bool limitsRequests(WebCore::ResourceLoadPriority, SchedulableLoader*) const;
-
- LoaderQueue m_loadersPending[WebCore::ResourceLoadPriorityHighest + 1];
- LoaderQueue m_syncLoadersPending;
-
- typedef HashSet<RefPtr<SchedulableLoader>> SchedulableLoaderSet;
- SchedulableLoaderSet m_loadersInProgress;
-
- const String m_name;
- int m_maxRequestsInFlight;
-};
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
-
-#endif // #ifndef HostRecord_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp
index b21815418..812919890 100644
--- a/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp
+++ b/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp
@@ -26,46 +26,50 @@
#include "config.h"
#include "NetworkConnectionToWebProcess.h"
-#include "BlobRegistrationData.h"
-#include "ConnectionStack.h"
#include "NetworkBlobRegistry.h"
#include "NetworkConnectionToWebProcessMessages.h"
+#include "NetworkLoad.h"
#include "NetworkProcess.h"
#include "NetworkResourceLoadParameters.h"
#include "NetworkResourceLoader.h"
#include "NetworkResourceLoaderMessages.h"
#include "RemoteNetworkingContext.h"
-#include "SyncNetworkResourceLoader.h"
-#include <WebCore/BlobData.h>
+#include "SessionTracker.h"
+#include <WebCore/NotImplemented.h>
+#include <WebCore/PingHandle.h>
#include <WebCore/PlatformCookieJar.h>
#include <WebCore/ResourceLoaderOptions.h>
#include <WebCore/ResourceRequest.h>
-#include <WebCore/RunLoop.h>
-
-#if ENABLE(NETWORK_PROCESS)
+#include <WebCore/SessionID.h>
+#include <wtf/RunLoop.h>
using namespace WebCore;
namespace WebKit {
-PassRefPtr<NetworkConnectionToWebProcess> NetworkConnectionToWebProcess::create(CoreIPC::Connection::Identifier connectionIdentifier)
+Ref<NetworkConnectionToWebProcess> NetworkConnectionToWebProcess::create(IPC::Connection::Identifier connectionIdentifier)
{
- return adoptRef(new NetworkConnectionToWebProcess(connectionIdentifier));
+ return adoptRef(*new NetworkConnectionToWebProcess(connectionIdentifier));
}
-NetworkConnectionToWebProcess::NetworkConnectionToWebProcess(CoreIPC::Connection::Identifier connectionIdentifier)
- : m_serialLoadingEnabled(false)
+NetworkConnectionToWebProcess::NetworkConnectionToWebProcess(IPC::Connection::Identifier connectionIdentifier)
{
- m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
- m_connection->setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
+ m_connection = IPC::Connection::createServerConnection(connectionIdentifier, *this);
m_connection->open();
}
NetworkConnectionToWebProcess::~NetworkConnectionToWebProcess()
{
}
+
+void NetworkConnectionToWebProcess::didCleanupResourceLoader(NetworkResourceLoader& loader)
+{
+ ASSERT(m_networkResourceLoaders.get(loader.identifier()) == &loader);
+
+ m_networkResourceLoaders.remove(loader.identifier());
+}
-void NetworkConnectionToWebProcess::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder)
+void NetworkConnectionToWebProcess::didReceiveMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
{
if (decoder.messageReceiverName() == Messages::NetworkConnectionToWebProcess::messageReceiverName()) {
didReceiveNetworkConnectionToWebProcessMessage(connection, decoder);
@@ -82,7 +86,7 @@ void NetworkConnectionToWebProcess::didReceiveMessage(CoreIPC::Connection* conne
ASSERT_NOT_REACHED();
}
-void NetworkConnectionToWebProcess::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& reply)
+void NetworkConnectionToWebProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& reply)
{
if (decoder.messageReceiverName() == Messages::NetworkConnectionToWebProcess::messageReceiverName()) {
didReceiveSyncNetworkConnectionToWebProcessMessage(connection, decoder, reply);
@@ -91,49 +95,50 @@ void NetworkConnectionToWebProcess::didReceiveSyncMessage(CoreIPC::Connection* c
ASSERT_NOT_REACHED();
}
-void NetworkConnectionToWebProcess::didClose(CoreIPC::Connection*)
+void NetworkConnectionToWebProcess::didClose(IPC::Connection&)
{
// Protect ourself as we might be otherwise be deleted during this function.
- RefPtr<NetworkConnectionToWebProcess> protector(this);
-
- HashMap<ResourceLoadIdentifier, RefPtr<NetworkResourceLoader>>::iterator end = m_networkResourceLoaders.end();
- for (HashMap<ResourceLoadIdentifier, RefPtr<NetworkResourceLoader>>::iterator i = m_networkResourceLoaders.begin(); i != end; ++i)
- i->value->abort();
+ Ref<NetworkConnectionToWebProcess> protector(*this);
- HashMap<ResourceLoadIdentifier, RefPtr<SyncNetworkResourceLoader>>::iterator syncEnd = m_syncNetworkResourceLoaders.end();
- for (HashMap<ResourceLoadIdentifier, RefPtr<SyncNetworkResourceLoader>>::iterator i = m_syncNetworkResourceLoaders.begin(); i != syncEnd; ++i)
- i->value->abort();
+ Vector<RefPtr<NetworkResourceLoader>> loaders;
+ copyValuesToVector(m_networkResourceLoaders, loaders);
+ for (auto& loader : loaders)
+ loader->abort();
+ ASSERT(m_networkResourceLoaders.isEmpty());
- NetworkBlobRegistry::shared().connectionToWebProcessDidClose(this);
-
- m_networkResourceLoaders.clear();
-
- NetworkProcess::shared().removeNetworkConnectionToWebProcess(this);
+ NetworkBlobRegistry::singleton().connectionToWebProcessDidClose(this);
+ NetworkProcess::singleton().removeNetworkConnectionToWebProcess(this);
}
-void NetworkConnectionToWebProcess::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::StringReference, CoreIPC::StringReference)
+void NetworkConnectionToWebProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
{
}
void NetworkConnectionToWebProcess::scheduleResourceLoad(const NetworkResourceLoadParameters& loadParameters)
{
- RefPtr<NetworkResourceLoader> loader = NetworkResourceLoader::create(loadParameters, this);
- m_networkResourceLoaders.add(loadParameters.identifier, loader);
- NetworkProcess::shared().networkResourceLoadScheduler().scheduleLoader(loader.get());
+ auto loader = NetworkResourceLoader::create(loadParameters, *this);
+ m_networkResourceLoaders.add(loadParameters.identifier, loader.ptr());
+ loader->start();
}
-void NetworkConnectionToWebProcess::performSynchronousLoad(const NetworkResourceLoadParameters& loadParameters, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> reply)
+void NetworkConnectionToWebProcess::performSynchronousLoad(const NetworkResourceLoadParameters& loadParameters, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
{
- RefPtr<SyncNetworkResourceLoader> loader = SyncNetworkResourceLoader::create(loadParameters, this, reply);
- m_syncNetworkResourceLoaders.add(loadParameters.identifier, loader);
- NetworkProcess::shared().networkResourceLoadScheduler().scheduleLoader(loader.get());
+ auto loader = NetworkResourceLoader::create(loadParameters, *this, WTFMove(reply));
+ m_networkResourceLoaders.add(loadParameters.identifier, loader.ptr());
+ loader->start();
+}
+
+void NetworkConnectionToWebProcess::loadPing(const NetworkResourceLoadParameters& loadParameters)
+{
+ RefPtr<NetworkingContext> context = RemoteNetworkingContext::create(loadParameters.sessionID, loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
+
+ // PingHandle manages its own lifetime, deleting itself when its purpose has been fulfilled.
+ new PingHandle(context.get(), loadParameters.request, loadParameters.allowStoredCredentials == AllowStoredCredentials, PingHandle::UsesAsyncCallbacks::Yes);
}
void NetworkConnectionToWebProcess::removeLoadIdentifier(ResourceLoadIdentifier identifier)
{
- RefPtr<SchedulableLoader> loader = m_networkResourceLoaders.take(identifier);
- if (!loader)
- loader = m_syncNetworkResourceLoaders.take(identifier);
+ RefPtr<NetworkResourceLoader> loader = m_networkResourceLoaders.get(identifier);
// It's possible we have no loader for this identifier if the NetworkProcess crashed and this was a respawned NetworkProcess.
if (!loader)
@@ -142,24 +147,29 @@ void NetworkConnectionToWebProcess::removeLoadIdentifier(ResourceLoadIdentifier
// Abort the load now, as the WebProcess won't be able to respond to messages any more which might lead
// to leaked loader resources (connections, threads, etc).
loader->abort();
+ ASSERT(!m_networkResourceLoaders.contains(identifier));
}
-void NetworkConnectionToWebProcess::servePendingRequests(uint32_t resourceLoadPriority)
+void NetworkConnectionToWebProcess::setDefersLoading(ResourceLoadIdentifier identifier, bool defers)
{
- NetworkProcess::shared().networkResourceLoadScheduler().servePendingRequests(static_cast<ResourceLoadPriority>(resourceLoadPriority));
+ RefPtr<NetworkResourceLoader> loader = m_networkResourceLoaders.get(identifier);
+ if (!loader)
+ return;
+
+ loader->setDefersLoading(defers);
}
-void NetworkConnectionToWebProcess::setSerialLoadingEnabled(bool enabled)
+void NetworkConnectionToWebProcess::prefetchDNS(const String& hostname)
{
- m_serialLoadingEnabled = enabled;
+ NetworkProcess::singleton().prefetchDNS(hostname);
}
-static NetworkStorageSession& storageSession(bool privateBrowsingEnabled)
+static NetworkStorageSession& storageSession(SessionID sessionID)
{
- if (privateBrowsingEnabled) {
- NetworkStorageSession* privateSession = RemoteNetworkingContext::privateBrowsingSession();
- if (privateSession)
- return *privateSession;
+ if (sessionID.isEphemeral()) {
+ NetworkStorageSession* privateStorageSession = SessionTracker::storageSession(sessionID);
+ if (privateStorageSession)
+ return *privateStorageSession;
// Some requests with private browsing mode requested may still be coming shortly after NetworkProcess was told to destroy its session.
// FIXME: Find a way to track private browsing sessions more rigorously.
LOG_ERROR("Private browsing was requested, but there was no session for it. Please file a bug unless you just disabled private browsing, in which case it's an expected race.");
@@ -167,79 +177,97 @@ static NetworkStorageSession& storageSession(bool privateBrowsingEnabled)
return NetworkStorageSession::defaultStorageSession();
}
-void NetworkConnectionToWebProcess::startDownload(bool privateBrowsingEnabled, uint64_t downloadID, const ResourceRequest& request)
+void NetworkConnectionToWebProcess::startDownload(SessionID sessionID, DownloadID downloadID, const ResourceRequest& request)
{
- // FIXME: Do something with the private browsing flag.
- NetworkProcess::shared().downloadManager().startDownload(downloadID, request);
+ NetworkProcess::singleton().downloadManager().startDownload(sessionID, downloadID, request);
}
-void NetworkConnectionToWebProcess::convertMainResourceLoadToDownload(uint64_t mainResourceLoadIdentifier, uint64_t downloadID, const ResourceRequest& request, const ResourceResponse& response)
+void NetworkConnectionToWebProcess::convertMainResourceLoadToDownload(SessionID sessionID, uint64_t mainResourceLoadIdentifier, DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
{
+ auto& networkProcess = NetworkProcess::singleton();
if (!mainResourceLoadIdentifier) {
- NetworkProcess::shared().downloadManager().startDownload(downloadID, request);
+ networkProcess.downloadManager().startDownload(sessionID, downloadID, request);
return;
}
NetworkResourceLoader* loader = m_networkResourceLoaders.get(mainResourceLoadIdentifier);
- NetworkProcess::shared().downloadManager().convertHandleToDownload(downloadID, loader->handle(), request, response);
+ if (!loader) {
+ // If we're trying to download a blob here loader can be null.
+ return;
+ }
+
+#if USE(NETWORK_SESSION)
+ loader->networkLoad()->convertTaskToDownload(downloadID);
+#else
+ networkProcess.downloadManager().convertHandleToDownload(downloadID, loader->networkLoad()->handle(), request, response);
// Unblock the URL connection operation queue.
- loader->handle()->continueDidReceiveResponse();
+ loader->networkLoad()->handle()->continueDidReceiveResponse();
- loader->didConvertHandleToDownload();
+ loader->didConvertToDownload();
+#endif
}
-void NetworkConnectionToWebProcess::cookiesForDOM(bool privateBrowsingEnabled, const KURL& firstParty, const KURL& url, String& result)
+void NetworkConnectionToWebProcess::cookiesForDOM(SessionID sessionID, const URL& firstParty, const URL& url, String& result)
{
- result = WebCore::cookiesForDOM(storageSession(privateBrowsingEnabled), firstParty, url);
+ result = WebCore::cookiesForDOM(storageSession(sessionID), firstParty, url);
}
-void NetworkConnectionToWebProcess::setCookiesFromDOM(bool privateBrowsingEnabled, const KURL& firstParty, const KURL& url, const String& cookieString)
+void NetworkConnectionToWebProcess::setCookiesFromDOM(SessionID sessionID, const URL& firstParty, const URL& url, const String& cookieString)
{
- WebCore::setCookiesFromDOM(storageSession(privateBrowsingEnabled), firstParty, url, cookieString);
+ WebCore::setCookiesFromDOM(storageSession(sessionID), firstParty, url, cookieString);
}
-void NetworkConnectionToWebProcess::cookiesEnabled(bool privateBrowsingEnabled, const KURL& firstParty, const KURL& url, bool& result)
+void NetworkConnectionToWebProcess::cookiesEnabled(SessionID sessionID, const URL& firstParty, const URL& url, bool& result)
{
- result = WebCore::cookiesEnabled(storageSession(privateBrowsingEnabled), firstParty, url);
+ result = WebCore::cookiesEnabled(storageSession(sessionID), firstParty, url);
}
-void NetworkConnectionToWebProcess::cookieRequestHeaderFieldValue(bool privateBrowsingEnabled, const KURL& firstParty, const KURL& url, String& result)
+void NetworkConnectionToWebProcess::cookieRequestHeaderFieldValue(SessionID sessionID, const URL& firstParty, const URL& url, String& result)
{
- result = WebCore::cookieRequestHeaderFieldValue(storageSession(privateBrowsingEnabled), firstParty, url);
+ result = WebCore::cookieRequestHeaderFieldValue(storageSession(sessionID), firstParty, url);
}
-void NetworkConnectionToWebProcess::getRawCookies(bool privateBrowsingEnabled, const KURL& firstParty, const KURL& url, Vector<Cookie>& result)
+void NetworkConnectionToWebProcess::getRawCookies(SessionID sessionID, const URL& firstParty, const URL& url, Vector<Cookie>& result)
{
- WebCore::getRawCookies(storageSession(privateBrowsingEnabled), firstParty, url, result);
+ WebCore::getRawCookies(storageSession(sessionID), firstParty, url, result);
}
-void NetworkConnectionToWebProcess::deleteCookie(bool privateBrowsingEnabled, const KURL& url, const String& cookieName)
+void NetworkConnectionToWebProcess::deleteCookie(SessionID sessionID, const URL& url, const String& cookieName)
{
- WebCore::deleteCookie(storageSession(privateBrowsingEnabled), url, cookieName);
+ WebCore::deleteCookie(storageSession(sessionID), url, cookieName);
}
-void NetworkConnectionToWebProcess::registerBlobURL(const KURL& url, const BlobRegistrationData& data)
+void NetworkConnectionToWebProcess::registerFileBlobURL(const URL& url, const String& path, const SandboxExtension::Handle& extensionHandle, const String& contentType)
{
- Vector<RefPtr<SandboxExtension>> extensions;
- for (size_t i = 0, count = data.sandboxExtensions().size(); i < count; ++i) {
- if (RefPtr<SandboxExtension> extension = SandboxExtension::create(data.sandboxExtensions()[i]))
- extensions.append(extension);
- }
+ RefPtr<SandboxExtension> extension = SandboxExtension::create(extensionHandle);
- NetworkBlobRegistry::shared().registerBlobURL(this, url, data.releaseData(), extensions);
+ NetworkBlobRegistry::singleton().registerFileBlobURL(this, url, path, WTFMove(extension), contentType);
}
-void NetworkConnectionToWebProcess::registerBlobURLFromURL(const KURL& url, const KURL& srcURL)
+void NetworkConnectionToWebProcess::registerBlobURL(const URL& url, Vector<BlobPart> blobParts, const String& contentType)
{
- NetworkBlobRegistry::shared().registerBlobURL(this, url, srcURL);
+ NetworkBlobRegistry::singleton().registerBlobURL(this, url, WTFMove(blobParts), contentType);
}
-void NetworkConnectionToWebProcess::unregisterBlobURL(const KURL& url)
+void NetworkConnectionToWebProcess::registerBlobURLFromURL(const URL& url, const URL& srcURL)
{
- NetworkBlobRegistry::shared().unregisterBlobURL(this, url);
+ NetworkBlobRegistry::singleton().registerBlobURL(this, url, srcURL);
}
-} // namespace WebKit
+void NetworkConnectionToWebProcess::registerBlobURLForSlice(const URL& url, const URL& srcURL, int64_t start, int64_t end)
+{
+ NetworkBlobRegistry::singleton().registerBlobURLForSlice(this, url, srcURL, start, end);
+}
-#endif // ENABLE(NETWORK_PROCESS)
+void NetworkConnectionToWebProcess::unregisterBlobURL(const URL& url)
+{
+ NetworkBlobRegistry::singleton().unregisterBlobURL(this, url);
+}
+
+void NetworkConnectionToWebProcess::blobSize(const URL& url, uint64_t& resultSize)
+{
+ resultSize = NetworkBlobRegistry::singleton().blobSize(this, url);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.h
index e63215812..c80f08a58 100644
--- a/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.h
+++ b/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.h
@@ -26,10 +26,9 @@
#ifndef NetworkConnectionToWebProcess_h
#define NetworkConnectionToWebProcess_h
-#if ENABLE(NETWORK_PROCESS)
-
#include "BlockingResponseMap.h"
#include "Connection.h"
+#include "DownloadID.h"
#include "NetworkConnectionToWebProcessMessages.h"
#include <WebCore/ResourceLoadPriority.h>
#include <wtf/HashSet.h>
@@ -41,65 +40,65 @@ class ResourceRequest;
namespace WebKit {
-class BlobRegistrationData;
class NetworkConnectionToWebProcess;
class NetworkResourceLoader;
class SyncNetworkResourceLoader;
typedef uint64_t ResourceLoadIdentifier;
-class NetworkConnectionToWebProcess : public RefCounted<NetworkConnectionToWebProcess>, CoreIPC::Connection::Client {
+class NetworkConnectionToWebProcess : public RefCounted<NetworkConnectionToWebProcess>, IPC::Connection::Client {
public:
- static PassRefPtr<NetworkConnectionToWebProcess> create(CoreIPC::Connection::Identifier);
+ static Ref<NetworkConnectionToWebProcess> create(IPC::Connection::Identifier);
virtual ~NetworkConnectionToWebProcess();
- CoreIPC::Connection* connection() const { return m_connection.get(); }
+ IPC::Connection* connection() const { return m_connection.get(); }
- bool isSerialLoadingEnabled() const { return m_serialLoadingEnabled; }
+ void didCleanupResourceLoader(NetworkResourceLoader&);
private:
- NetworkConnectionToWebProcess(CoreIPC::Connection::Identifier);
+ NetworkConnectionToWebProcess(IPC::Connection::Identifier);
- // CoreIPC::Connection::Client
- virtual void didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&);
- virtual void didReceiveSyncMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&, OwnPtr<CoreIPC::MessageEncoder>&);
- virtual void didClose(CoreIPC::Connection*);
- virtual void didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::StringReference messageReceiverName, CoreIPC::StringReference messageName);
+ // IPC::Connection::Client
+ virtual void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
+ virtual void didReceiveSyncMessage(IPC::Connection&, IPC::MessageDecoder&, std::unique_ptr<IPC::MessageEncoder>&) override;
+ virtual void didClose(IPC::Connection&) override;
+ virtual void didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference messageReceiverName, IPC::StringReference messageName) override;
+ virtual IPC::ProcessType localProcessType() override { return IPC::ProcessType::Network; }
+ virtual IPC::ProcessType remoteProcessType() override { return IPC::ProcessType::Web; }
// Message handlers.
- void didReceiveNetworkConnectionToWebProcessMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&);
- void didReceiveSyncNetworkConnectionToWebProcessMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&, OwnPtr<CoreIPC::MessageEncoder>&);
+ void didReceiveNetworkConnectionToWebProcessMessage(IPC::Connection&, IPC::MessageDecoder&);
+ void didReceiveSyncNetworkConnectionToWebProcessMessage(IPC::Connection&, IPC::MessageDecoder&, std::unique_ptr<IPC::MessageEncoder>&);
void scheduleResourceLoad(const NetworkResourceLoadParameters&);
- void performSynchronousLoad(const NetworkResourceLoadParameters&, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>);
+ void performSynchronousLoad(const NetworkResourceLoadParameters&, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&&);
+ void loadPing(const NetworkResourceLoadParameters&);
+ void prefetchDNS(const String&);
void removeLoadIdentifier(ResourceLoadIdentifier);
- void crossOriginRedirectReceived(ResourceLoadIdentifier, const WebCore::KURL& redirectURL);
- void servePendingRequests(uint32_t resourceLoadPriority);
- void setSerialLoadingEnabled(bool);
- void startDownload(bool privateBrowsingEnabled, uint64_t downloadID, const WebCore::ResourceRequest&);
- void convertMainResourceLoadToDownload(uint64_t mainResourceLoadIdentifier, uint64_t downloadID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
-
- void cookiesForDOM(bool privateBrowsingEnabled, const WebCore::KURL& firstParty, const WebCore::KURL&, String& result);
- void setCookiesFromDOM(bool privateBrowsingEnabled, const WebCore::KURL& firstParty, const WebCore::KURL&, const String&);
- void cookiesEnabled(bool privateBrowsingEnabled, const WebCore::KURL& firstParty, const WebCore::KURL&, bool& result);
- void cookieRequestHeaderFieldValue(bool privateBrowsingEnabled, const WebCore::KURL& firstParty, const WebCore::KURL&, String& result);
- void getRawCookies(bool privateBrowsingEnabled, const WebCore::KURL& firstParty, const WebCore::KURL&, Vector<WebCore::Cookie>&);
- void deleteCookie(bool privateBrowsingEnabled, const WebCore::KURL&, const String& cookieName);
-
- void registerBlobURL(const WebCore::KURL&, const BlobRegistrationData&);
- void registerBlobURLFromURL(const WebCore::KURL&, const WebCore::KURL& srcURL);
- void unregisterBlobURL(const WebCore::KURL&);
-
- RefPtr<CoreIPC::Connection> m_connection;
+ void setDefersLoading(ResourceLoadIdentifier, bool);
+ void crossOriginRedirectReceived(ResourceLoadIdentifier, const WebCore::URL& redirectURL);
+ void startDownload(WebCore::SessionID, DownloadID, const WebCore::ResourceRequest&);
+ void convertMainResourceLoadToDownload(WebCore::SessionID, uint64_t mainResourceLoadIdentifier, DownloadID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
+
+ void cookiesForDOM(WebCore::SessionID, const WebCore::URL& firstParty, const WebCore::URL&, String& result);
+ void setCookiesFromDOM(WebCore::SessionID, const WebCore::URL& firstParty, const WebCore::URL&, const String&);
+ void cookiesEnabled(WebCore::SessionID, const WebCore::URL& firstParty, const WebCore::URL&, bool& result);
+ void cookieRequestHeaderFieldValue(WebCore::SessionID, const WebCore::URL& firstParty, const WebCore::URL&, String& result);
+ void getRawCookies(WebCore::SessionID, const WebCore::URL& firstParty, const WebCore::URL&, Vector<WebCore::Cookie>&);
+ void deleteCookie(WebCore::SessionID, const WebCore::URL&, const String& cookieName);
+
+ void registerFileBlobURL(const WebCore::URL&, const String& path, const SandboxExtension::Handle&, const String& contentType);
+ void registerBlobURL(const WebCore::URL&, Vector<WebCore::BlobPart>, const String& contentType);
+ void registerBlobURLFromURL(const WebCore::URL&, const WebCore::URL& srcURL);
+ void registerBlobURLForSlice(const WebCore::URL&, const WebCore::URL& srcURL, int64_t start, int64_t end);
+ void blobSize(const WebCore::URL&, uint64_t& resultSize);
+ void unregisterBlobURL(const WebCore::URL&);
+
+ RefPtr<IPC::Connection> m_connection;
HashMap<ResourceLoadIdentifier, RefPtr<NetworkResourceLoader>> m_networkResourceLoaders;
- HashMap<ResourceLoadIdentifier, RefPtr<SyncNetworkResourceLoader>> m_syncNetworkResourceLoaders;
-
- bool m_serialLoadingEnabled;
};
} // namespace WebKit
-#endif // ENABLE(NETWORK_PROCESS)
-
#endif // NetworkConnectionToWebProcess_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.messages.in
index afae1a230..03fdd92fd 100644
--- a/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.messages.in
+++ b/Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.messages.in
@@ -20,31 +20,29 @@
# 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.
-#if ENABLE(NETWORK_PROCESS)
-
messages -> NetworkConnectionToWebProcess LegacyReceiver {
ScheduleResourceLoad(WebKit::NetworkResourceLoadParameters resourceLoadParameters)
- PerformSynchronousLoad(WebKit::NetworkResourceLoadParameters resourceLoadParameters) -> (WebCore::ResourceError error, WebCore::ResourceResponse response, CoreIPC::DataReference data) Delayed
+ PerformSynchronousLoad(WebKit::NetworkResourceLoadParameters resourceLoadParameters) -> (WebCore::ResourceError error, WebCore::ResourceResponse response, Vector<char> data) Delayed
+ LoadPing(WebKit::NetworkResourceLoadParameters resourceLoadParameters)
RemoveLoadIdentifier(uint64_t resourceLoadIdentifier)
-
- ServePendingRequests(uint32_t resourceLoadPriority)
-
- SetSerialLoadingEnabled(bool enabled) -> ()
+ SetDefersLoading(uint64_t resourceLoadIdentifier, bool defers)
+ PrefetchDNS(String hostname)
- StartDownload(bool privateBrowsingEnabled, uint64_t downloadID, WebCore::ResourceRequest request)
- ConvertMainResourceLoadToDownload(uint64_t mainResourceLoadIdentifier, uint64_t downloadID, WebCore::ResourceRequest request, WebCore::ResourceResponse response)
+ StartDownload(WebCore::SessionID sessionID, WebKit::DownloadID downloadID, WebCore::ResourceRequest request)
+ ConvertMainResourceLoadToDownload(WebCore::SessionID sessionID, uint64_t mainResourceLoadIdentifier, WebKit::DownloadID downloadID, WebCore::ResourceRequest request, WebCore::ResourceResponse response)
- CookiesForDOM(bool privateBrowsingEnabled, WebCore::KURL firstParty, WebCore::KURL url) -> (WTF::String result)
- SetCookiesFromDOM(bool privateBrowsingEnabled, WebCore::KURL firstParty, WebCore::KURL url, WTF::String cookieString)
- CookiesEnabled(bool privateBrowsingEnabled, WebCore::KURL firstParty, WebCore::KURL url) -> (bool enabled)
- CookieRequestHeaderFieldValue(bool privateBrowsingEnabled, WebCore::KURL firstParty, WebCore::KURL url) -> (WTF::String result)
- GetRawCookies(bool privateBrowsingEnabled, WebCore::KURL firstParty, WebCore::KURL url) -> (WTF::Vector<WebCore::Cookie> cookies)
- DeleteCookie(bool privateBrowsingEnabled, WebCore::KURL url, WTF::String cookieName)
+ CookiesForDOM(WebCore::SessionID sessionID, WebCore::URL firstParty, WebCore::URL url) -> (String result)
+ SetCookiesFromDOM(WebCore::SessionID sessionID, WebCore::URL firstParty, WebCore::URL url, String cookieString)
+ CookiesEnabled(WebCore::SessionID sessionID, WebCore::URL firstParty, WebCore::URL url) -> (bool enabled)
+ CookieRequestHeaderFieldValue(WebCore::SessionID sessionID, WebCore::URL firstParty, WebCore::URL url) -> (String result)
+ GetRawCookies(WebCore::SessionID sessionID, WebCore::URL firstParty, WebCore::URL url) -> (Vector<WebCore::Cookie> cookies)
+ DeleteCookie(WebCore::SessionID sessionID, WebCore::URL url, String cookieName)
- RegisterBlobURL(WebCore::KURL url, WebKit::BlobRegistrationData data)
- RegisterBlobURLFromURL(WebCore::KURL url, WebCore::KURL srcURL)
- UnregisterBlobURL(WebCore::KURL url)
+ RegisterFileBlobURL(WebCore::URL url, String path, WebKit::SandboxExtension::Handle extensionHandle, String contentType)
+ RegisterBlobURL(WebCore::URL url, Vector<WebCore::BlobPart> blobParts, String contentType)
+ RegisterBlobURLFromURL(WebCore::URL url, WebCore::URL srcURL)
+ RegisterBlobURLForSlice(WebCore::URL url, WebCore::URL srcURL, int64_t start, int64_t end)
+ UnregisterBlobURL(WebCore::URL url)
+ BlobSize(WebCore::URL url) -> (uint64_t resultSize)
}
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/NetworkDataTask.h b/Source/WebKit2/NetworkProcess/NetworkDataTask.h
new file mode 100644
index 000000000..86482cb7a
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkDataTask.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkDataTask_h
+#define NetworkDataTask_h
+
+#include <WebCore/FrameLoaderTypes.h>
+#include <WebCore/ResourceHandleTypes.h>
+#include <WebCore/ResourceLoaderOptions.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/Timer.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/text/WTFString.h>
+
+#if PLATFORM(COCOA)
+OBJC_CLASS NSURLSessionDataTask;
+#endif
+
+namespace WebCore {
+class AuthenticationChallenge;
+class Credential;
+class ResourceError;
+class ResourceRequest;
+class ResourceResponse;
+class SharedBuffer;
+}
+
+namespace WebKit {
+
+class NetworkSession;
+class PendingDownload;
+
+enum class AuthenticationChallengeDisposition {
+ UseCredential,
+ PerformDefaultHandling,
+ Cancel,
+ RejectProtectionSpace
+};
+
+typedef std::function<void(const WebCore::ResourceRequest&)> RedirectCompletionHandler;
+typedef std::function<void(AuthenticationChallengeDisposition, const WebCore::Credential&)> ChallengeCompletionHandler;
+typedef std::function<void(WebCore::PolicyAction)> ResponseCompletionHandler;
+
+class NetworkDataTaskClient {
+public:
+ virtual void willPerformHTTPRedirection(const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, RedirectCompletionHandler) = 0;
+ virtual void didReceiveChallenge(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler) = 0;
+ virtual void didReceiveResponseNetworkSession(const WebCore::ResourceResponse&, ResponseCompletionHandler) = 0;
+ virtual void didReceiveData(RefPtr<WebCore::SharedBuffer>&&) = 0;
+ virtual void didCompleteWithError(const WebCore::ResourceError&) = 0;
+ virtual void didBecomeDownload() = 0;
+ virtual void didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend) = 0;
+ virtual void wasBlocked() = 0;
+ virtual void cannotShowURL() = 0;
+
+ virtual ~NetworkDataTaskClient() { }
+};
+
+class NetworkDataTask : public RefCounted<NetworkDataTask> {
+ friend class NetworkSession;
+public:
+ static Ref<NetworkDataTask> create(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& request, WebCore::StoredCredentials storedCredentials, WebCore::ContentSniffingPolicy shouldContentSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
+ {
+ return adoptRef(*new NetworkDataTask(session, client, request, storedCredentials, shouldContentSniff, shouldClearReferrerOnHTTPSToHTTPRedirect));
+ }
+
+ void suspend();
+ void cancel();
+ void resume();
+
+ typedef uint64_t TaskIdentifier;
+ TaskIdentifier taskIdentifier();
+
+ ~NetworkDataTask();
+
+ NetworkDataTaskClient& client() { return m_client; }
+
+ DownloadID pendingDownloadID() { return m_pendingDownloadID; }
+ PendingDownload* pendingDownload() { return m_pendingDownload; }
+ void setPendingDownloadID(DownloadID downloadID)
+ {
+ ASSERT(!m_pendingDownloadID.downloadID());
+ ASSERT(downloadID.downloadID());
+ m_pendingDownloadID = downloadID;
+ }
+ void setPendingDownload(PendingDownload& pendingDownload)
+ {
+ ASSERT(!m_pendingDownload);
+ m_pendingDownload = &pendingDownload;
+ }
+ bool tryPasswordBasedAuthentication(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler);
+ void willPerformHTTPRedirection(const WebCore::ResourceResponse&, WebCore::ResourceRequest&&, RedirectCompletionHandler);
+
+private:
+ NetworkDataTask(NetworkSession&, NetworkDataTaskClient&, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ContentSniffingPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect);
+
+ enum FailureType {
+ NoFailure,
+ BlockedFailure,
+ InvalidURLFailure
+ };
+ FailureType m_scheduledFailureType { NoFailure };
+ WebCore::Timer m_failureTimer;
+ void failureTimerFired();
+ void scheduleFailure(FailureType);
+
+ NetworkSession& m_session;
+ NetworkDataTaskClient& m_client;
+ PendingDownload* m_pendingDownload { nullptr };
+ DownloadID m_pendingDownloadID;
+ String m_user;
+ String m_password;
+ String m_lastHTTPMethod;
+ WebCore::ResourceRequest m_firstRequest;
+ bool m_shouldClearReferrerOnHTTPSToHTTPRedirect;
+#if PLATFORM(COCOA)
+ RetainPtr<NSURLSessionDataTask> m_task;
+#endif
+};
+
+#if PLATFORM(COCOA)
+WebCore::Credential serverTrustCredential(const WebCore::AuthenticationChallenge&);
+#endif
+
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/NetworkLoad.cpp b/Source/WebKit2/NetworkProcess/NetworkLoad.cpp
new file mode 100644
index 000000000..bf27fd306
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkLoad.cpp
@@ -0,0 +1,440 @@
+/*
+ * 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 "NetworkLoad.h"
+
+#include "AuthenticationManager.h"
+#include "NetworkProcess.h"
+#include "SessionTracker.h"
+#include "WebErrors.h"
+#include <WebCore/NotImplemented.h>
+#include <WebCore/ResourceHandle.h>
+#include <WebCore/SessionID.h>
+#include <wtf/MainThread.h>
+
+namespace WebKit {
+
+using namespace WebCore;
+
+NetworkLoad::NetworkLoad(NetworkLoadClient& client, const NetworkLoadParameters& parameters)
+ : m_client(client)
+ , m_parameters(parameters)
+#if !USE(NETWORK_SESSION)
+ , m_networkingContext(RemoteNetworkingContext::create(parameters.sessionID, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect))
+#endif
+ , m_currentRequest(parameters.request)
+{
+#if USE(NETWORK_SESSION)
+ if (parameters.request.url().protocolIsBlob()) {
+ m_handle = ResourceHandle::create(nullptr, parameters.request, this, parameters.defersLoading, parameters.contentSniffingPolicy == SniffContent);
+ return;
+ }
+ if (auto* networkSession = SessionTracker::networkSession(parameters.sessionID)) {
+ m_task = NetworkDataTask::create(*networkSession, *this, parameters.request, parameters.allowStoredCredentials, parameters.contentSniffingPolicy, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
+ if (!parameters.defersLoading)
+ m_task->resume();
+ } else
+ ASSERT_NOT_REACHED();
+#else
+ m_handle = ResourceHandle::create(m_networkingContext.get(), parameters.request, this, parameters.defersLoading, parameters.contentSniffingPolicy == SniffContent);
+#endif
+}
+
+NetworkLoad::~NetworkLoad()
+{
+ ASSERT(RunLoop::isMain());
+#if USE(NETWORK_SESSION)
+ if (m_responseCompletionHandler)
+ m_responseCompletionHandler(PolicyIgnore);
+#endif
+ if (m_handle)
+ m_handle->clearClient();
+}
+
+void NetworkLoad::setDefersLoading(bool defers)
+{
+#if USE(NETWORK_SESSION)
+ if (m_task) {
+ if (defers)
+ m_task->suspend();
+ else
+ m_task->resume();
+ }
+#endif
+ if (m_handle)
+ m_handle->setDefersLoading(defers);
+}
+
+void NetworkLoad::cancel()
+{
+#if USE(NETWORK_SESSION)
+ if (m_task)
+ m_task->cancel();
+#endif
+ if (m_handle)
+ m_handle->cancel();
+}
+
+void NetworkLoad::continueWillSendRequest(const WebCore::ResourceRequest& newRequest)
+{
+#if PLATFORM(COCOA)
+ m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(DoNotUpdateHTTPBody));
+#elif USE(SOUP)
+ // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127.
+ m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest);
+#endif
+
+ if (m_currentRequest.isNull()) {
+ if (m_handle)
+ m_handle->cancel();
+ didFail(m_handle.get(), cancelledError(m_currentRequest));
+ } else if (m_handle)
+ m_handle->continueWillSendRequest(m_currentRequest);
+
+#if USE(NETWORK_SESSION)
+ ASSERT(m_redirectCompletionHandler);
+ if (m_redirectCompletionHandler) {
+ m_redirectCompletionHandler(m_currentRequest);
+ m_redirectCompletionHandler = nullptr;
+ }
+#endif
+}
+
+void NetworkLoad::continueDidReceiveResponse()
+{
+#if USE(NETWORK_SESSION)
+ ASSERT(m_responseCompletionHandler);
+ if (m_responseCompletionHandler) {
+ m_responseCompletionHandler(PolicyUse);
+ m_responseCompletionHandler = nullptr;
+ }
+#endif
+ if (m_handle)
+ m_handle->continueDidReceiveResponse();
+}
+
+NetworkLoadClient::ShouldContinueDidReceiveResponse NetworkLoad::sharedDidReceiveResponse(const ResourceResponse& receivedResponse)
+{
+ ResourceResponse response = receivedResponse;
+ response.setSource(ResourceResponse::Source::Network);
+ if (m_parameters.needsCertificateInfo)
+ response.includeCertificateInfo();
+
+ return m_client.didReceiveResponse(response);
+}
+
+void NetworkLoad::sharedWillSendRedirectedRequest(const ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect.
+ ASSERT(!redirectResponse.isNull());
+ ASSERT(RunLoop::isMain());
+
+ auto oldRequest = m_currentRequest;
+ m_currentRequest = request;
+ m_client.willSendRedirectedRequest(oldRequest, request, redirectResponse);
+}
+
+#if USE(NETWORK_SESSION)
+
+void NetworkLoad::convertTaskToDownload(DownloadID downloadID)
+{
+ m_task->setPendingDownloadID(downloadID);
+
+ ASSERT(m_responseCompletionHandler);
+ if (m_responseCompletionHandler) {
+ m_responseCompletionHandler(PolicyDownload);
+ m_responseCompletionHandler = nullptr;
+ }
+}
+
+void NetworkLoad::setPendingDownloadID(DownloadID downloadID)
+{
+ m_task->setPendingDownloadID(downloadID);
+}
+
+void NetworkLoad::setPendingDownload(PendingDownload& pendingDownload)
+{
+ m_task->setPendingDownload(pendingDownload);
+}
+
+void NetworkLoad::willPerformHTTPRedirection(const ResourceResponse& response, const ResourceRequest& request, RedirectCompletionHandler completionHandler)
+{
+ ASSERT(!m_redirectCompletionHandler);
+ m_redirectCompletionHandler = completionHandler;
+ sharedWillSendRedirectedRequest(request, response);
+}
+
+void NetworkLoad::didReceiveChallenge(const AuthenticationChallenge& challenge, std::function<void(AuthenticationChallengeDisposition, const Credential&)> completionHandler)
+{
+ // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
+ ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
+
+ // Handle server trust evaluation at platform-level if requested, for performance reasons.
+ if (challenge.protectionSpace().authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
+ && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
+ completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpace, Credential());
+ return;
+ }
+
+ m_challengeCompletionHandler = completionHandler;
+ m_challenge = challenge;
+
+ if (m_client.isSynchronous()) {
+ // FIXME: We should ask the WebProcess like the asynchronous case below does.
+ // This is currently impossible as the WebProcess is blocked waiting on this synchronous load.
+ // It's possible that we can jump straight to the UI process to resolve this.
+ continueCanAuthenticateAgainstProtectionSpace(true);
+ return;
+ } else
+ m_client.canAuthenticateAgainstProtectionSpaceAsync(challenge.protectionSpace());
+}
+
+void NetworkLoad::didReceiveResponseNetworkSession(const ResourceResponse& response, ResponseCompletionHandler completionHandler)
+{
+ ASSERT(isMainThread());
+ if (m_task && m_task->pendingDownloadID().downloadID())
+ completionHandler(PolicyDownload);
+ else if (sharedDidReceiveResponse(response) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
+ completionHandler(PolicyUse);
+ else
+ m_responseCompletionHandler = completionHandler;
+}
+
+void NetworkLoad::didReceiveData(RefPtr<SharedBuffer>&& buffer)
+{
+ ASSERT(buffer);
+ auto size = buffer->size();
+ m_client.didReceiveBuffer(WTFMove(buffer), size);
+}
+
+void NetworkLoad::didCompleteWithError(const ResourceError& error)
+{
+ if (error.isNull())
+ m_client.didFinishLoading(WTF::monotonicallyIncreasingTime());
+ else
+ m_client.didFailLoading(error);
+}
+
+void NetworkLoad::didBecomeDownload()
+{
+ m_client.didConvertToDownload();
+}
+
+void NetworkLoad::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend)
+{
+ m_client.didSendData(totalBytesSent, totalBytesExpectedToSend);
+}
+
+void NetworkLoad::wasBlocked()
+{
+ m_client.didFailLoading(blockedError(m_currentRequest));
+}
+
+void NetworkLoad::cannotShowURL()
+{
+ m_client.didFailLoading(cannotShowURLError(m_currentRequest));
+}
+
+#endif
+
+void NetworkLoad::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse& receivedResponse)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+ if (sharedDidReceiveResponse(receivedResponse) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
+ m_handle->continueDidReceiveResponse();
+}
+
+void NetworkLoad::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int /* encodedDataLength */)
+{
+ // The NetworkProcess should never get a didReceiveData callback.
+ // We should always be using didReceiveBuffer.
+ ASSERT_NOT_REACHED();
+}
+
+void NetworkLoad::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<SharedBuffer> buffer, int reportedEncodedDataLength)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+ m_client.didReceiveBuffer(WTFMove(buffer), reportedEncodedDataLength);
+}
+
+void NetworkLoad::didFinishLoading(ResourceHandle* handle, double finishTime)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+ m_client.didFinishLoading(finishTime);
+}
+
+void NetworkLoad::didFail(ResourceHandle* handle, const ResourceError& error)
+{
+ ASSERT_UNUSED(handle, !handle || handle == m_handle);
+ ASSERT(!error.isNull());
+
+ m_client.didFailLoading(error);
+}
+
+void NetworkLoad::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+ sharedWillSendRedirectedRequest(request, redirectResponse);
+}
+
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+void NetworkLoad::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace)
+{
+ ASSERT(RunLoop::isMain());
+ ASSERT_UNUSED(handle, handle == m_handle);
+
+ // Handle server trust evaluation at platform-level if requested, for performance reasons.
+ if (protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
+ && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
+ continueCanAuthenticateAgainstProtectionSpace(false);
+ return;
+ }
+
+ if (m_client.isSynchronous()) {
+ // FIXME: We should ask the WebProcess like the asynchronous case below does.
+ // This is currently impossible as the WebProcess is blocked waiting on this synchronous load.
+ // It's possible that we can jump straight to the UI process to resolve this.
+ continueCanAuthenticateAgainstProtectionSpace(true);
+ return;
+ }
+
+ m_client.canAuthenticateAgainstProtectionSpaceAsync(protectionSpace);
+}
+#endif
+
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+void NetworkLoad::continueCanAuthenticateAgainstProtectionSpace(bool result)
+{
+#if USE(NETWORK_SESSION)
+ ASSERT_WITH_MESSAGE(!m_handle, "Blobs should never give authentication challenges");
+ ASSERT(m_challengeCompletionHandler);
+ auto completionHandler = WTFMove(m_challengeCompletionHandler);
+ if (!result) {
+ completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpace, Credential());
+ return;
+ }
+
+ if (!m_challenge.protectionSpace().isPasswordBased()) {
+ completionHandler(AuthenticationChallengeDisposition::UseCredential, serverTrustCredential(m_challenge));
+ return;
+ }
+
+ if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
+ completionHandler(AuthenticationChallengeDisposition::UseCredential, Credential());
+ return;
+ }
+
+ if (m_task) {
+ if (auto* pendingDownload = m_task->pendingDownload())
+ NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(*pendingDownload, m_challenge, completionHandler);
+ else
+ NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, m_challenge, completionHandler);
+ }
+#endif
+ if (m_handle)
+ m_handle->continueCanAuthenticateAgainstProtectionSpace(result);
+}
+#endif
+
+#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
+bool NetworkLoad::supportsDataArray()
+{
+ notImplemented();
+ return false;
+}
+
+void NetworkLoad::didReceiveDataArray(ResourceHandle*, CFArrayRef)
+{
+ ASSERT_NOT_REACHED();
+ notImplemented();
+}
+#endif
+
+void NetworkLoad::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+
+ m_client.didSendData(bytesSent, totalBytesToBeSent);
+}
+
+void NetworkLoad::wasBlocked(ResourceHandle* handle)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+
+ didFail(handle, WebKit::blockedError(m_currentRequest));
+}
+
+void NetworkLoad::cannotShowURL(ResourceHandle* handle)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+
+ didFail(handle, WebKit::cannotShowURLError(m_currentRequest));
+}
+
+bool NetworkLoad::shouldUseCredentialStorage(ResourceHandle* handle)
+{
+ ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start().
+
+ // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked.
+ // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer.
+
+ // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one.
+
+ return m_parameters.allowStoredCredentials == AllowStoredCredentials;
+}
+
+void NetworkLoad::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+ // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
+ ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
+
+ if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
+ challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
+ return;
+ }
+
+ NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, challenge);
+}
+
+void NetworkLoad::didCancelAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge&)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+
+ // This function is probably not needed (see <rdar://problem/8960124>).
+ notImplemented();
+}
+
+void NetworkLoad::receivedCancellation(ResourceHandle* handle, const AuthenticationChallenge&)
+{
+ ASSERT_UNUSED(handle, handle == m_handle);
+
+ m_handle->cancel();
+ didFail(m_handle.get(), cancelledError(m_currentRequest));
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/NetworkLoad.h b/Source/WebKit2/NetworkProcess/NetworkLoad.h
new file mode 100644
index 000000000..77164c2f2
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkLoad.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkLoad_h
+#define NetworkLoad_h
+
+#include "NetworkLoadClient.h"
+#include "NetworkLoadParameters.h"
+#include "RemoteNetworkingContext.h"
+#include <WebCore/ResourceHandleClient.h>
+
+#if USE(NETWORK_SESSION)
+#include "DownloadID.h"
+#include "NetworkSession.h"
+#include <WebCore/AuthenticationChallenge.h>
+#endif
+
+namespace WebKit {
+
+class NetworkLoad : public WebCore::ResourceHandleClient
+#if USE(NETWORK_SESSION)
+ , public NetworkDataTaskClient
+#endif
+{
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ NetworkLoad(NetworkLoadClient&, const NetworkLoadParameters&);
+ ~NetworkLoad();
+
+ void setDefersLoading(bool);
+ void cancel();
+
+ const WebCore::ResourceRequest& currentRequest() const { return m_currentRequest; }
+ void clearCurrentRequest() { m_currentRequest = WebCore::ResourceRequest(); }
+
+ void continueWillSendRequest(const WebCore::ResourceRequest&);
+ void continueDidReceiveResponse();
+
+#if USE(NETWORK_SESSION)
+ void convertTaskToDownload(DownloadID);
+ void setPendingDownloadID(DownloadID);
+ void setPendingDownload(PendingDownload&);
+ DownloadID pendingDownloadID() { return m_task->pendingDownloadID(); }
+
+ // NetworkDataTaskClient
+ virtual void willPerformHTTPRedirection(const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, RedirectCompletionHandler) final override;
+ virtual void didReceiveChallenge(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler) final override;
+ virtual void didReceiveResponseNetworkSession(const WebCore::ResourceResponse&, ResponseCompletionHandler) final override;
+ virtual void didReceiveData(RefPtr<WebCore::SharedBuffer>&&) final override;
+ virtual void didCompleteWithError(const WebCore::ResourceError&) final override;
+ virtual void didBecomeDownload() final override;
+ virtual void didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend) override;
+ virtual void wasBlocked() override;
+ virtual void cannotShowURL() override;
+#endif
+ // ResourceHandleClient
+ virtual void willSendRequestAsync(WebCore::ResourceHandle*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse) override;
+ virtual void didSendData(WebCore::ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ virtual void didReceiveResponseAsync(WebCore::ResourceHandle*, const WebCore::ResourceResponse&) override;
+ virtual void didReceiveData(WebCore::ResourceHandle*, const char*, unsigned, int encodedDataLength) override;
+ virtual void didReceiveBuffer(WebCore::ResourceHandle*, PassRefPtr<WebCore::SharedBuffer>, int encodedDataLength) override;
+ virtual void didFinishLoading(WebCore::ResourceHandle*, double finishTime) override;
+ virtual void didFail(WebCore::ResourceHandle*, const WebCore::ResourceError&) override;
+ virtual void wasBlocked(WebCore::ResourceHandle*) override;
+ virtual void cannotShowURL(WebCore::ResourceHandle*) override;
+ virtual bool shouldUseCredentialStorage(WebCore::ResourceHandle*) override;
+ virtual void didReceiveAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&) override;
+ virtual void didCancelAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&) override;
+ virtual void receivedCancellation(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&) override;
+ virtual bool usesAsyncCallbacks() override { return true; }
+ virtual bool loadingSynchronousXHR() override { return m_client.isSynchronous(); }
+
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ virtual void canAuthenticateAgainstProtectionSpaceAsync(WebCore::ResourceHandle*, const WebCore::ProtectionSpace&) override;
+#endif
+#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
+ virtual bool supportsDataArray() override;
+ virtual void didReceiveDataArray(WebCore::ResourceHandle*, CFArrayRef) override;
+#endif
+#if PLATFORM(COCOA)
+#if USE(CFNETWORK)
+ virtual void willCacheResponseAsync(WebCore::ResourceHandle*, CFCachedURLResponseRef) override;
+#else
+ virtual void willCacheResponseAsync(WebCore::ResourceHandle*, NSCachedURLResponse *) override;
+#endif
+#endif
+
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ void continueCanAuthenticateAgainstProtectionSpace(bool);
+#endif
+
+#if !USE(NETWORK_SESSION)
+ WebCore::ResourceHandle* handle() const { return m_handle.get(); }
+#endif
+
+private:
+ NetworkLoadClient::ShouldContinueDidReceiveResponse sharedDidReceiveResponse(const WebCore::ResourceResponse&);
+ void sharedWillSendRedirectedRequest(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
+
+ NetworkLoadClient& m_client;
+ const NetworkLoadParameters m_parameters;
+#if USE(NETWORK_SESSION)
+ RefPtr<NetworkDataTask> m_task;
+ WebCore::AuthenticationChallenge m_challenge;
+ ChallengeCompletionHandler m_challengeCompletionHandler;
+ ResponseCompletionHandler m_responseCompletionHandler;
+ RedirectCompletionHandler m_redirectCompletionHandler;
+#else
+ RefPtr<RemoteNetworkingContext> m_networkingContext;
+#endif
+ RefPtr<WebCore::ResourceHandle> m_handle;
+
+ WebCore::ResourceRequest m_currentRequest; // Updated on redirects.
+};
+
+} // namespace WebKit
+
+#endif // NetworkLoad_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkLoadClient.h b/Source/WebKit2/NetworkProcess/NetworkLoadClient.h
new file mode 100644
index 000000000..e454738a8
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkLoadClient.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkLoadClient_h
+#define NetworkLoadClient_h
+
+#include <WebCore/ResourceError.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/ResourceResponse.h>
+#include <WebCore/SharedBuffer.h>
+#include <wtf/Forward.h>
+
+#if PLATFORM(COCOA)
+typedef const struct _CFCachedURLResponse* CFCachedURLResponseRef;
+#endif
+
+namespace WebCore {
+class ProtectionSpace;
+}
+
+namespace WebKit {
+
+class NetworkLoadClient {
+public:
+ virtual ~NetworkLoadClient() { }
+
+ virtual bool isSynchronous() const = 0;
+
+ virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) = 0;
+ virtual void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) = 0;
+ virtual void willSendRedirectedRequest(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse) = 0;
+ enum class ShouldContinueDidReceiveResponse { No, Yes };
+ virtual ShouldContinueDidReceiveResponse didReceiveResponse(const WebCore::ResourceResponse&) = 0;
+ virtual void didReceiveBuffer(RefPtr<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) = 0;
+ virtual void didFinishLoading(double finishTime) = 0;
+ virtual void didFailLoading(const WebCore::ResourceError&) = 0;
+ virtual void didConvertToDownload() = 0;
+
+#if PLATFORM(COCOA)
+ virtual void willCacheResponseAsync(CFCachedURLResponseRef) = 0;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // NetworkLoadClient_h
+
diff --git a/Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.cpp b/Source/WebKit2/NetworkProcess/NetworkLoadParameters.cpp
index c82af840e..cc8487555 100644
--- a/Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.cpp
+++ b/Source/WebKit2/NetworkProcess/NetworkLoadParameters.cpp
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
- * Copyright (C) 2013 Company 100 Inc.
+ * 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
@@ -11,7 +10,7 @@
* 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 ``AS IS''
+ * 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
@@ -25,56 +24,24 @@
*/
#include "config.h"
-#include "NetworkProcessMainUnix.h"
+#include "NetworkLoadParameters.h"
-#if ENABLE(NETWORK_PROCESS)
-
-#include "WKBase.h"
-#include "WebKit2Initialize.h"
-#include <WebCore/RunLoop.h>
-#include <WebKit2/NetworkProcess.h>
-#include <error.h>
-#include <runtime/InitializeThreading.h>
-#include <stdlib.h>
-#include <wtf/MainThread.h>
-
-#if PLATFORM(EFL)
-#include <Ecore.h>
-#endif
-
-using namespace WebCore;
+#include "NetworkResourceLoadParameters.h"
namespace WebKit {
-WK_EXPORT int NetworkProcessMain(int argc, char* argv[])
+NetworkLoadParameters::NetworkLoadParameters(const NetworkResourceLoadParameters& parameters)
+ : webPageID(parameters.webPageID)
+ , webFrameID(parameters.webFrameID)
+ , sessionID(parameters.sessionID)
+ , request(parameters.request)
+ , contentSniffingPolicy(parameters.contentSniffingPolicy)
+ , allowStoredCredentials(parameters.allowStoredCredentials)
+ , clientCredentialPolicy(parameters.clientCredentialPolicy)
+ , shouldClearReferrerOnHTTPSToHTTPRedirect(parameters.shouldClearReferrerOnHTTPSToHTTPRedirect)
+ , defersLoading(parameters.defersLoading)
+ , needsCertificateInfo(parameters.needsCertificateInfo)
{
- if (argc != 2)
- return 1;
-
-#if PLATFORM(EFL)
- if (!ecore_init())
- return 1;
-
- if (!ecore_main_loop_glib_integrate())
- return 1;
-#endif
-
- InitializeWebKit2();
-
- // FIXME: handle proxy settings.
-
- int socket = atoi(argv[1]);
-
- WebKit::ChildProcessInitializationParameters parameters;
- parameters.connectionIdentifier = int(socket);
-
- NetworkProcess::shared().initialize(parameters);
-
- RunLoop::run();
-
- return 0;
}
} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/NetworkLoadParameters.h b/Source/WebKit2/NetworkProcess/NetworkLoadParameters.h
new file mode 100644
index 000000000..130aaa348
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkLoadParameters.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkLoadParameters_h
+#define NetworkLoadParameters_h
+
+#include <WebCore/ResourceLoaderOptions.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/SessionID.h>
+
+namespace WebKit {
+
+class NetworkResourceLoadParameters;
+
+class NetworkLoadParameters {
+public:
+ NetworkLoadParameters() = default;
+ NetworkLoadParameters(const NetworkResourceLoadParameters&);
+
+ uint64_t webPageID { 0 };
+ uint64_t webFrameID { 0 };
+ WebCore::SessionID sessionID { WebCore::SessionID::emptySessionID() };
+ WebCore::ResourceRequest request;
+ WebCore::ContentSniffingPolicy contentSniffingPolicy { WebCore::SniffContent };
+ WebCore::StoredCredentials allowStoredCredentials { WebCore::DoNotAllowStoredCredentials };
+ WebCore::ClientCredentialPolicy clientCredentialPolicy { WebCore::DoNotAskClientForAnyCredentials };
+ bool shouldClearReferrerOnHTTPSToHTTPRedirect { true };
+ bool defersLoading { false };
+ bool needsCertificateInfo { false };
+};
+
+} // namespace WebKit
+
+#endif // NetworkLoadParameters_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcess.cpp b/Source/WebKit2/NetworkProcess/NetworkProcess.cpp
index 917ddc5c1..75ce5d4a2 100644
--- a/Source/WebKit2/NetworkProcess/NetworkProcess.cpp
+++ b/Source/WebKit2/NetworkProcess/NetworkProcess.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,47 +26,64 @@
#include "config.h"
#include "NetworkProcess.h"
-#if ENABLE(NETWORK_PROCESS)
-
#include "ArgumentCoders.h"
#include "Attachment.h"
#include "AuthenticationManager.h"
+#include "ChildProcessMessages.h"
#include "CustomProtocolManager.h"
#include "Logging.h"
#include "NetworkConnectionToWebProcess.h"
#include "NetworkProcessCreationParameters.h"
#include "NetworkProcessPlatformStrategies.h"
#include "NetworkProcessProxyMessages.h"
+#include "NetworkResourceLoader.h"
#include "RemoteNetworkingContext.h"
-#include "SchedulableLoader.h"
+#include "SessionTracker.h"
#include "StatisticsData.h"
-#include "WebContextMessages.h"
#include "WebCookieManager.h"
-#include <WebCore/InitializeLogging.h>
+#include "WebProcessPoolMessages.h"
+#include "WebsiteData.h"
+#include <WebCore/DNS.h>
+#include <WebCore/DiagnosticLoggingClient.h>
+#include <WebCore/Logging.h>
+#include <WebCore/PlatformCookieJar.h>
#include <WebCore/ResourceRequest.h>
-#include <WebCore/RunLoop.h>
+#include <WebCore/SecurityOriginData.h>
+#include <WebCore/SecurityOriginHash.h>
+#include <WebCore/SessionID.h>
+#include <wtf/RunLoop.h>
#include <wtf/text/CString.h>
-#if USE(SECURITY_FRAMEWORK)
+#if ENABLE(SEC_ITEM_SHIM)
#include "SecItemShim.h"
#endif
+#if ENABLE(NETWORK_CACHE)
+#include "NetworkCache.h"
+#include "NetworkCacheCoders.h"
+#endif
+
using namespace WebCore;
namespace WebKit {
-NetworkProcess& NetworkProcess::shared()
+NetworkProcess& NetworkProcess::singleton()
{
- DEFINE_STATIC_LOCAL(NetworkProcess, networkProcess, ());
+ static NeverDestroyed<NetworkProcess> networkProcess;
return networkProcess;
}
NetworkProcess::NetworkProcess()
: m_hasSetCacheModel(false)
, m_cacheModel(CacheModelDocumentViewer)
-#if PLATFORM(MAC)
+ , m_diskCacheIsDisabledForTesting(false)
+ , m_canHandleHTTPSServerTrustEvaluation(true)
+#if PLATFORM(COCOA)
, m_clearCacheDispatchGroup(0)
#endif
+#if PLATFORM(IOS)
+ , m_webSQLiteDatabaseTracker(*this)
+#endif
{
NetworkProcessPlatformStrategies::initialize();
@@ -86,7 +103,7 @@ AuthenticationManager& NetworkProcess::authenticationManager()
DownloadManager& NetworkProcess::downloadManager()
{
- DEFINE_STATIC_LOCAL(DownloadManager, downloadManager, (this));
+ static NeverDestroyed<DownloadManager> downloadManager(*this);
return downloadManager;
}
@@ -104,28 +121,36 @@ bool NetworkProcess::shouldTerminate()
return false;
}
-void NetworkProcess::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder)
+void NetworkProcess::didReceiveMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
{
if (messageReceiverMap().dispatchMessage(connection, decoder))
return;
+ if (decoder.messageReceiverName() == Messages::ChildProcess::messageReceiverName()) {
+ ChildProcess::didReceiveMessage(connection, decoder);
+ return;
+ }
+
didReceiveNetworkProcessMessage(connection, decoder);
}
-void NetworkProcess::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder)
+void NetworkProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
{
- messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder);
+ if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder))
+ return;
+
+ didReceiveSyncNetworkProcessMessage(connection, decoder, replyEncoder);
}
-void NetworkProcess::didClose(CoreIPC::Connection*)
+void NetworkProcess::didClose(IPC::Connection&)
{
// The UIProcess just exited.
- RunLoop::current()->stop();
+ RunLoop::current().stop();
}
-void NetworkProcess::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::StringReference, CoreIPC::StringReference)
+void NetworkProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
{
- RunLoop::current()->stop();
+ RunLoop::current().stop();
}
void NetworkProcess::didCreateDownload()
@@ -138,7 +163,7 @@ void NetworkProcess::didDestroyDownload()
enableTermination();
}
-CoreIPC::Connection* NetworkProcess::downloadProxyConnection()
+IPC::Connection* NetworkProcess::downloadProxyConnection()
{
return parentProcessConnection();
}
@@ -148,18 +173,41 @@ AuthenticationManager& NetworkProcess::downloadsAuthenticationManager()
return authenticationManager();
}
+void NetworkProcess::lowMemoryHandler(Critical critical)
+{
+ platformLowMemoryHandler(critical);
+ WTF::releaseFastMallocFreeMemory();
+}
+
void NetworkProcess::initializeNetworkProcess(const NetworkProcessCreationParameters& parameters)
{
platformInitializeNetworkProcess(parameters);
+ WTF::setCurrentThreadIsUserInitiated();
+
+ auto& memoryPressureHandler = MemoryPressureHandler::singleton();
+ memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous) {
+ lowMemoryHandler(critical);
+ });
+ memoryPressureHandler.install();
+
+ m_diskCacheIsDisabledForTesting = parameters.shouldUseTestingNetworkSession;
+
+ m_diskCacheSizeOverride = parameters.diskCacheSizeOverride;
setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
-#if PLATFORM(MAC) || USE(CFNETWORK)
- RemoteNetworkingContext::setPrivateBrowsingStorageSessionIdentifierBase(parameters.uiProcessBundleIdentifier);
+ setCanHandleHTTPSServerTrustEvaluation(parameters.canHandleHTTPSServerTrustEvaluation);
+
+#if PLATFORM(COCOA) || USE(CFNETWORK)
+ SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
#endif
+ // FIXME: instead of handling this here, a message should be sent later (scales to multiple sessions)
if (parameters.privateBrowsingEnabled)
- RemoteNetworkingContext::ensurePrivateBrowsingSession();
+ RemoteNetworkingContext::ensurePrivateBrowsingSession(SessionID::legacyPrivateSessionID());
+
+ if (parameters.shouldUseTestingNetworkSession)
+ NetworkStorageSession::switchToNewTestingSession();
NetworkProcessSupplementMap::const_iterator it = m_supplements.begin();
NetworkProcessSupplementMap::const_iterator end = m_supplements.end();
@@ -167,12 +215,12 @@ void NetworkProcess::initializeNetworkProcess(const NetworkProcessCreationParame
it->value->initialize(parameters);
}
-void NetworkProcess::initializeConnection(CoreIPC::Connection* connection)
+void NetworkProcess::initializeConnection(IPC::Connection* connection)
{
ChildProcess::initializeConnection(connection);
-#if USE(SECURITY_FRAMEWORK)
- SecItemShim::shared().initializeConnection(connection);
+#if ENABLE(SEC_ITEM_SHIM)
+ SecItemShim::singleton().initializeConnection(connection);
#endif
NetworkProcessSupplementMap::const_iterator it = m_supplements.begin();
@@ -183,42 +231,246 @@ void NetworkProcess::initializeConnection(CoreIPC::Connection* connection)
void NetworkProcess::createNetworkConnectionToWebProcess()
{
-#if PLATFORM(MAC)
+#if USE(UNIX_DOMAIN_SOCKETS)
+ IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
+
+ RefPtr<NetworkConnectionToWebProcess> connection = NetworkConnectionToWebProcess::create(socketPair.server);
+ m_webProcessConnections.append(connection.release());
+
+ IPC::Attachment clientSocket(socketPair.client);
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientSocket), 0);
+#elif OS(DARWIN)
// Create the listening port.
mach_port_t listeningPort;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort);
// Create a listening connection.
- RefPtr<NetworkConnectionToWebProcess> connection = NetworkConnectionToWebProcess::create(CoreIPC::Connection::Identifier(listeningPort));
+ RefPtr<NetworkConnectionToWebProcess> connection = NetworkConnectionToWebProcess::create(IPC::Connection::Identifier(listeningPort));
m_webProcessConnections.append(connection.release());
- CoreIPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND);
+ IPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND);
parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientPort), 0);
#else
notImplemented();
#endif
}
-void NetworkProcess::ensurePrivateBrowsingSession()
+void NetworkProcess::clearCachedCredentials()
+{
+ NetworkStorageSession::defaultStorageSession().credentialStorage().clearCredentials();
+}
+
+void NetworkProcess::ensurePrivateBrowsingSession(SessionID sessionID)
+{
+ RemoteNetworkingContext::ensurePrivateBrowsingSession(sessionID);
+}
+
+void NetworkProcess::destroyPrivateBrowsingSession(SessionID sessionID)
+{
+ SessionTracker::destroySession(sessionID);
+}
+
+static void fetchDiskCacheEntries(SessionID sessionID, std::function<void (Vector<WebsiteData::Entry>)> completionHandler)
+{
+#if ENABLE(NETWORK_CACHE)
+ if (NetworkCache::singleton().isEnabled()) {
+ auto* origins = new HashSet<RefPtr<SecurityOrigin>>();
+
+ NetworkCache::singleton().traverse([completionHandler, origins](const NetworkCache::Cache::TraversalEntry *traversalEntry) {
+ if (!traversalEntry) {
+ Vector<WebsiteData::Entry> entries;
+
+ for (auto& origin : *origins)
+ entries.append(WebsiteData::Entry { origin, WebsiteDataTypeDiskCache });
+
+ delete origins;
+
+ RunLoop::main().dispatch([completionHandler, entries] {
+ completionHandler(entries);
+ });
+
+ return;
+ }
+
+ origins->add(SecurityOrigin::create(traversalEntry->entry.response().url()));
+ });
+
+ return;
+ }
+#endif
+
+ Vector<WebsiteData::Entry> entries;
+
+#if USE(CFURLCACHE)
+ for (auto& origin : NetworkProcess::cfURLCacheOrigins())
+ entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataTypeDiskCache });
+#endif
+
+ RunLoop::main().dispatch([completionHandler, entries] {
+ completionHandler(entries);
+ });
+}
+
+void NetworkProcess::fetchWebsiteData(SessionID sessionID, uint64_t websiteDataTypes, uint64_t callbackID)
+{
+ struct CallbackAggregator final : public RefCounted<CallbackAggregator> {
+ explicit CallbackAggregator(std::function<void (WebsiteData)> completionHandler)
+ : m_completionHandler(WTFMove(completionHandler))
+ {
+ }
+
+ ~CallbackAggregator()
+ {
+ ASSERT(RunLoop::isMain());
+
+ auto completionHandler = WTFMove(m_completionHandler);
+ auto websiteData = WTFMove(m_websiteData);
+
+ RunLoop::main().dispatch([completionHandler, websiteData] {
+ completionHandler(websiteData);
+ });
+ }
+
+ std::function<void (WebsiteData)> m_completionHandler;
+ WebsiteData m_websiteData;
+ };
+
+ RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator([this, callbackID](WebsiteData websiteData) {
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::DidFetchWebsiteData(callbackID, websiteData), 0);
+ }));
+
+ if (websiteDataTypes & WebsiteDataTypeCookies) {
+ if (auto* networkStorageSession = SessionTracker::storageSession(sessionID))
+ getHostnamesWithCookies(*networkStorageSession, callbackAggregator->m_websiteData.hostNamesWithCookies);
+ }
+
+ if (websiteDataTypes & WebsiteDataTypeDiskCache) {
+ fetchDiskCacheEntries(sessionID, [callbackAggregator](Vector<WebsiteData::Entry> entries) {
+ callbackAggregator->m_websiteData.entries.appendVector(entries);
+ });
+ }
+}
+
+void NetworkProcess::deleteWebsiteData(SessionID sessionID, uint64_t websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID)
+{
+#if PLATFORM(COCOA)
+ if (websiteDataTypes & WebsiteDataTypeHSTSCache) {
+ if (auto* networkStorageSession = SessionTracker::storageSession(sessionID))
+ clearHSTSCache(*networkStorageSession, modifiedSince);
+ }
+#endif
+
+ if (websiteDataTypes & WebsiteDataTypeCookies) {
+ if (auto* networkStorageSession = SessionTracker::storageSession(sessionID))
+ deleteAllCookiesModifiedSince(*networkStorageSession, modifiedSince);
+ }
+
+ auto completionHandler = [this, callbackID] {
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::DidDeleteWebsiteData(callbackID), 0);
+ };
+
+ if ((websiteDataTypes & WebsiteDataTypeDiskCache) && !sessionID.isEphemeral()) {
+ clearDiskCache(modifiedSince, WTFMove(completionHandler));
+ return;
+ }
+
+ completionHandler();
+}
+
+static void clearDiskCacheEntries(const Vector<SecurityOriginData>& origins, std::function<void ()> completionHandler)
+{
+#if ENABLE(NETWORK_CACHE)
+ if (NetworkCache::singleton().isEnabled()) {
+ auto* originsToDelete = new HashSet<RefPtr<SecurityOrigin>>();
+
+ for (auto& origin : origins)
+ originsToDelete->add(origin.securityOrigin());
+
+ auto* cacheKeysToDelete = new Vector<NetworkCache::Key>;
+
+ NetworkCache::singleton().traverse([completionHandler, originsToDelete, cacheKeysToDelete](const NetworkCache::Cache::TraversalEntry *traversalEntry) {
+
+ if (traversalEntry) {
+ if (originsToDelete->contains(SecurityOrigin::create(traversalEntry->entry.response().url())))
+ cacheKeysToDelete->append(traversalEntry->entry.key());
+ return;
+ }
+
+ delete originsToDelete;
+
+ for (auto& key : *cacheKeysToDelete)
+ NetworkCache::singleton().remove(key);
+
+ delete cacheKeysToDelete;
+
+ RunLoop::main().dispatch(completionHandler);
+ return;
+ });
+
+ return;
+ }
+#endif
+
+#if USE(CFURLCACHE)
+ NetworkProcess::clearCFURLCacheForOrigins(origins);
+#endif
+
+ RunLoop::main().dispatch(WTFMove(completionHandler));
+}
+
+void NetworkProcess::deleteWebsiteDataForOrigins(SessionID sessionID, uint64_t websiteDataTypes, const Vector<SecurityOriginData>& origins, const Vector<String>& cookieHostNames, uint64_t callbackID)
{
- RemoteNetworkingContext::ensurePrivateBrowsingSession();
+ if (websiteDataTypes & WebsiteDataTypeCookies) {
+ if (auto* networkStorageSession = SessionTracker::storageSession(sessionID))
+ deleteCookiesForHostnames(*networkStorageSession, cookieHostNames);
+ }
+
+ auto completionHandler = [this, callbackID] {
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::DidDeleteWebsiteDataForOrigins(callbackID), 0);
+ };
+
+ if ((websiteDataTypes & WebsiteDataTypeDiskCache) && !sessionID.isEphemeral()) {
+ clearDiskCacheEntries(origins, WTFMove(completionHandler));
+ return;
+ }
+
+ completionHandler();
}
-void NetworkProcess::destroyPrivateBrowsingSession()
+void NetworkProcess::downloadRequest(SessionID sessionID, DownloadID downloadID, const ResourceRequest& request)
{
- RemoteNetworkingContext::destroyPrivateBrowsingSession();
+ downloadManager().startDownload(sessionID, downloadID, request);
}
-void NetworkProcess::downloadRequest(uint64_t downloadID, const ResourceRequest& request)
+void NetworkProcess::resumeDownload(SessionID sessionID, DownloadID downloadID, const IPC::DataReference& resumeData, const String& path, const WebKit::SandboxExtension::Handle& sandboxExtensionHandle)
{
- downloadManager().startDownload(downloadID, request);
+ downloadManager().resumeDownload(sessionID, downloadID, resumeData, path, sandboxExtensionHandle);
}
-void NetworkProcess::cancelDownload(uint64_t downloadID)
+void NetworkProcess::cancelDownload(DownloadID downloadID)
{
downloadManager().cancelDownload(downloadID);
}
+#if PLATFORM(QT)
+void NetworkProcess::startTransfer(DownloadID downloadID, const String& destination)
+{
+ downloadManager().startTransfer(downloadID, destination);
+}
+#endif
+
+#if USE(NETWORK_SESSION)
+void NetworkProcess::continueCanAuthenticateAgainstProtectionSpace(DownloadID downloadID, bool canAuthenticate)
+{
+ downloadManager().continueCanAuthenticateAgainstProtectionSpace(downloadID, canAuthenticate);
+}
+
+void NetworkProcess::continueWillSendRequest(DownloadID downloadID, const WebCore::ResourceRequest& request)
+{
+ downloadManager().continueWillSendRequest(downloadID, request);
+}
+#endif
+
void NetworkProcess::setCacheModel(uint32_t cm)
{
CacheModel cacheModel = static_cast<CacheModel>(cm);
@@ -230,20 +482,44 @@ void NetworkProcess::setCacheModel(uint32_t cm)
}
}
-void NetworkProcess::getNetworkProcessStatistics(uint64_t callbackID)
+void NetworkProcess::setCanHandleHTTPSServerTrustEvaluation(bool value)
{
- NetworkResourceLoadScheduler& scheduler = NetworkProcess::shared().networkResourceLoadScheduler();
+ m_canHandleHTTPSServerTrustEvaluation = value;
+}
+void NetworkProcess::getNetworkProcessStatistics(uint64_t callbackID)
+{
StatisticsData data;
- data.statisticsNumbers.set("HostsPendingCount", scheduler.hostsPendingCount());
- data.statisticsNumbers.set("HostsActiveCount", scheduler.hostsActiveCount());
- data.statisticsNumbers.set("LoadsPendingCount", scheduler.loadsPendingCount());
- data.statisticsNumbers.set("LoadsActiveCount", scheduler.loadsActiveCount());
- data.statisticsNumbers.set("DownloadsActiveCount", shared().downloadManager().activeDownloadCount());
- data.statisticsNumbers.set("OutstandingAuthenticationChallengesCount", shared().authenticationManager().outstandingAuthenticationChallengeCount());
+ auto& networkProcess = NetworkProcess::singleton();
+ data.statisticsNumbers.set("DownloadsActiveCount", networkProcess.downloadManager().activeDownloadCount());
+ data.statisticsNumbers.set("OutstandingAuthenticationChallengesCount", networkProcess.authenticationManager().outstandingAuthenticationChallengeCount());
- parentProcessConnection()->send(Messages::WebContext::DidGetStatistics(data, callbackID), 0);
+ parentProcessConnection()->send(Messages::WebProcessPool::DidGetStatistics(data, callbackID), 0);
+}
+
+void NetworkProcess::logDiagnosticMessage(uint64_t webPageID, const String& message, const String& description, ShouldSample shouldSample)
+{
+ if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample))
+ return;
+
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::LogSampledDiagnosticMessage(webPageID, message, description), 0);
+}
+
+void NetworkProcess::logDiagnosticMessageWithResult(uint64_t webPageID, const String& message, const String& description, DiagnosticLoggingResultType result, ShouldSample shouldSample)
+{
+ if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample))
+ return;
+
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::LogSampledDiagnosticMessageWithResult(webPageID, message, description, result), 0);
+}
+
+void NetworkProcess::logDiagnosticMessageWithValue(uint64_t webPageID, const String& message, const String& description, const String& value, ShouldSample shouldSample)
+{
+ if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample))
+ return;
+
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::LogSampledDiagnosticMessageWithValue(webPageID, message, description, value), 0);
}
void NetworkProcess::terminate()
@@ -252,7 +528,36 @@ void NetworkProcess::terminate()
ChildProcess::terminate();
}
-#if !PLATFORM(MAC)
+void NetworkProcess::processWillSuspendImminently(bool& handled)
+{
+ lowMemoryHandler(Critical::Yes);
+ handled = true;
+}
+
+void NetworkProcess::prepareToSuspend()
+{
+ lowMemoryHandler(Critical::Yes);
+ parentProcessConnection()->send(Messages::NetworkProcessProxy::ProcessReadyToSuspend(), 0);
+}
+
+void NetworkProcess::cancelPrepareToSuspend()
+{
+ // Although it is tempting to send a NetworkProcessProxy::DidCancelProcessSuspension message from here
+ // we do not because prepareToSuspend() already replied with a NetworkProcessProxy::ProcessReadyToSuspend
+ // message. And NetworkProcessProxy expects to receive either a NetworkProcessProxy::ProcessReadyToSuspend-
+ // or NetworkProcessProxy::DidCancelProcessSuspension- message, but not both.
+}
+
+void NetworkProcess::processDidResume()
+{
+}
+
+void NetworkProcess::prefetchDNS(const String& hostname)
+{
+ WebCore::prefetchDNS(hostname);
+}
+
+#if !PLATFORM(COCOA)
void NetworkProcess::initializeProcess(const ChildProcessInitializationParameters&)
{
}
@@ -264,8 +569,10 @@ void NetworkProcess::initializeProcessName(const ChildProcessInitializationParam
void NetworkProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
{
}
+
+void NetworkProcess::platformLowMemoryHandler(Critical)
+{
+}
#endif
} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcess.h b/Source/WebKit2/NetworkProcess/NetworkProcess.h
index 00f4068cf..4b573b9b5 100644
--- a/Source/WebKit2/NetworkProcess/NetworkProcess.h
+++ b/Source/WebKit2/NetworkProcess/NetworkProcess.h
@@ -26,31 +26,45 @@
#ifndef NetworkProcess_h
#define NetworkProcess_h
-#if ENABLE(NETWORK_PROCESS)
-
#include "CacheModel.h"
#include "ChildProcess.h"
#include "DownloadManager.h"
#include "MessageReceiverMap.h"
-#include "NetworkResourceLoadScheduler.h"
+#include <WebCore/DiagnosticLoggingClient.h>
+#include <WebCore/MemoryPressureHandler.h>
+#include <WebCore/SessionID.h>
+#include <memory>
#include <wtf/Forward.h>
+#include <wtf/NeverDestroyed.h>
+
+#if PLATFORM(IOS)
+#include "WebSQLiteDatabaseTracker.h"
+#endif
+
+#if PLATFORM(QT)
+#include "QtNetworkAccessManager.h"
+#endif
namespace WebCore {
- class RunLoop;
+class CertificateInfo;
+class NetworkStorageSession;
+class SecurityOrigin;
+class SessionID;
+struct SecurityOriginData;
}
namespace WebKit {
-
class AuthenticationManager;
class NetworkConnectionToWebProcess;
class NetworkProcessSupplement;
-class PlatformCertificateInfo;
struct NetworkProcessCreationParameters;
class NetworkProcess : public ChildProcess, private DownloadManager::Client {
WTF_MAKE_NONCOPYABLE(NetworkProcess);
+ friend class NeverDestroyed<NetworkProcess>;
+ friend class NeverDestroyed<DownloadManager>;
public:
- static NetworkProcess& shared();
+ static NetworkProcess& singleton();
template <typename T>
T* supplement()
@@ -61,15 +75,39 @@ public:
template <typename T>
void addSupplement()
{
- m_supplements.add(T::supplementName(), adoptPtr<NetworkProcessSupplement>(new T(this)));
+ m_supplements.add(T::supplementName(), std::make_unique<T>(this));
}
void removeNetworkConnectionToWebProcess(NetworkConnectionToWebProcess*);
- NetworkResourceLoadScheduler& networkResourceLoadScheduler() { return m_networkResourceLoadScheduler; }
-
AuthenticationManager& authenticationManager();
DownloadManager& downloadManager();
+ bool canHandleHTTPSServerTrustEvaluation() const { return m_canHandleHTTPSServerTrustEvaluation; }
+
+ void processWillSuspendImminently(bool& handled);
+ void prepareToSuspend();
+ void cancelPrepareToSuspend();
+ void processDidResume();
+
+ // Diagnostic messages logging.
+ void logDiagnosticMessage(uint64_t webPageID, const String& message, const String& description, WebCore::ShouldSample);
+ void logDiagnosticMessageWithResult(uint64_t webPageID, const String& message, const String& description, WebCore::DiagnosticLoggingResultType, WebCore::ShouldSample);
+ void logDiagnosticMessageWithValue(uint64_t webPageID, const String& message, const String& description, const String& value, WebCore::ShouldSample);
+
+#if USE(CFURLCACHE)
+ static Vector<Ref<WebCore::SecurityOrigin>> cfURLCacheOrigins();
+ static void clearCFURLCacheForOrigins(const Vector<WebCore::SecurityOriginData>&);
+#endif
+
+#if PLATFORM(COCOA)
+ void clearHSTSCache(WebCore::NetworkStorageSession&, std::chrono::system_clock::time_point modifiedSince);
+#endif
+
+#if PLATFORM(QT)
+ QNetworkAccessManager& networkAccessManager() { return m_networkAccessManager; }
+#endif
+
+ void prefetchDNS(const String&);
private:
NetworkProcess();
@@ -77,66 +115,105 @@ private:
void platformInitializeNetworkProcess(const NetworkProcessCreationParameters&);
- virtual void terminate() OVERRIDE;
+ virtual void terminate() override;
void platformTerminate();
+ void lowMemoryHandler(WebCore::Critical);
+ void platformLowMemoryHandler(WebCore::Critical);
+
// ChildProcess
- virtual void initializeProcess(const ChildProcessInitializationParameters&) OVERRIDE;
- virtual void initializeProcessName(const ChildProcessInitializationParameters&) OVERRIDE;
- virtual void initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&) OVERRIDE;
- virtual void initializeConnection(CoreIPC::Connection*) OVERRIDE;
- virtual bool shouldTerminate() OVERRIDE;
-
- // CoreIPC::Connection::Client
- virtual void didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&) OVERRIDE;
- virtual void didReceiveSyncMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&, OwnPtr<CoreIPC::MessageEncoder>&);
- virtual void didClose(CoreIPC::Connection*) OVERRIDE;
- virtual void didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::StringReference messageReceiverName, CoreIPC::StringReference messageName) OVERRIDE;
+ virtual void initializeProcess(const ChildProcessInitializationParameters&) override;
+ virtual void initializeProcessName(const ChildProcessInitializationParameters&) override;
+ virtual void initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&) override;
+ virtual void initializeConnection(IPC::Connection*) override;
+ virtual bool shouldTerminate() override;
+
+ // IPC::Connection::Client
+ virtual void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
+ virtual void didReceiveSyncMessage(IPC::Connection&, IPC::MessageDecoder&, std::unique_ptr<IPC::MessageEncoder>&) override;
+ virtual void didClose(IPC::Connection&) override;
+ virtual void didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference messageReceiverName, IPC::StringReference messageName) override;
+ virtual IPC::ProcessType localProcessType() override { return IPC::ProcessType::Network; }
+ virtual IPC::ProcessType remoteProcessType() override { return IPC::ProcessType::UI; }
// DownloadManager::Client
- virtual void didCreateDownload() OVERRIDE;
- virtual void didDestroyDownload() OVERRIDE;
- virtual CoreIPC::Connection* downloadProxyConnection() OVERRIDE;
- virtual AuthenticationManager& downloadsAuthenticationManager() OVERRIDE;
+ virtual void didCreateDownload() override;
+ virtual void didDestroyDownload() override;
+ virtual IPC::Connection* downloadProxyConnection() override;
+ virtual AuthenticationManager& downloadsAuthenticationManager() override;
// Message Handlers
- void didReceiveNetworkProcessMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&);
+ void didReceiveNetworkProcessMessage(IPC::Connection&, IPC::MessageDecoder&);
+ void didReceiveSyncNetworkProcessMessage(IPC::Connection&, IPC::MessageDecoder&, std::unique_ptr<IPC::MessageEncoder>&);
void initializeNetworkProcess(const NetworkProcessCreationParameters&);
void createNetworkConnectionToWebProcess();
- void ensurePrivateBrowsingSession();
- void destroyPrivateBrowsingSession();
- void downloadRequest(uint64_t downloadID, const WebCore::ResourceRequest&);
- void cancelDownload(uint64_t downloadID);
+ void ensurePrivateBrowsingSession(WebCore::SessionID);
+ void destroyPrivateBrowsingSession(WebCore::SessionID);
+
+ void fetchWebsiteData(WebCore::SessionID, uint64_t websiteDataTypes, uint64_t callbackID);
+ void deleteWebsiteData(WebCore::SessionID, uint64_t websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID);
+ void deleteWebsiteDataForOrigins(WebCore::SessionID, uint64_t websiteDataTypes, const Vector<WebCore::SecurityOriginData>& origins, const Vector<String>& cookieHostNames, uint64_t callbackID);
+
+ void clearCachedCredentials();
+
+ // FIXME: This should take a session ID so we can identify which disk cache to delete.
+ void clearDiskCache(std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler);
+
+ void downloadRequest(WebCore::SessionID, DownloadID, const WebCore::ResourceRequest&);
+ void resumeDownload(WebCore::SessionID, DownloadID, const IPC::DataReference& resumeData, const String& path, const SandboxExtension::Handle&);
+ void cancelDownload(DownloadID);
+#if PLATFORM(QT)
+ void startTransfer(DownloadID, const String& destination);
+#endif
+#if USE(NETWORK_SESSION)
+ void continueCanAuthenticateAgainstProtectionSpace(DownloadID, bool canAuthenticate);
+ void continueWillSendRequest(DownloadID, const WebCore::ResourceRequest&);
+#endif
void setCacheModel(uint32_t);
- void allowSpecificHTTPSCertificateForHost(const PlatformCertificateInfo&, const String& host);
+ void allowSpecificHTTPSCertificateForHost(const WebCore::CertificateInfo&, const String& host);
+ void setCanHandleHTTPSServerTrustEvaluation(bool);
void getNetworkProcessStatistics(uint64_t callbackID);
void clearCacheForAllOrigins(uint32_t cachesToClear);
+#if USE(SOUP)
+ void setIgnoreTLSErrors(bool);
+ void userPreferredLanguagesChanged(const Vector<String>&);
+#endif
+
// Platform Helpers
void platformSetCacheModel(CacheModel);
// Connections to WebProcesses.
Vector<RefPtr<NetworkConnectionToWebProcess>> m_webProcessConnections;
- NetworkResourceLoadScheduler m_networkResourceLoadScheduler;
-
String m_diskCacheDirectory;
bool m_hasSetCacheModel;
CacheModel m_cacheModel;
+ int64_t m_diskCacheSizeOverride { -1 };
+ bool m_diskCacheIsDisabledForTesting;
+ bool m_canHandleHTTPSServerTrustEvaluation;
- typedef HashMap<const char*, OwnPtr<NetworkProcessSupplement>, PtrHash<const char*>> NetworkProcessSupplementMap;
+ typedef HashMap<const char*, std::unique_ptr<NetworkProcessSupplement>, PtrHash<const char*>> NetworkProcessSupplementMap;
NetworkProcessSupplementMap m_supplements;
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
+ void platformInitializeNetworkProcessCocoa(const NetworkProcessCreationParameters&);
+
// FIXME: We'd like to be able to do this without the #ifdef, but WorkQueue + BinarySemaphore isn't good enough since
// multiple requests to clear the cache can come in before previous requests complete, and we need to wait for all of them.
// In the future using WorkQueue and a counting semaphore would work, as would WorkQueue supporting the libdispatch concept of "work groups".
dispatch_group_t m_clearCacheDispatchGroup;
#endif
+
+#if PLATFORM(IOS)
+ WebSQLiteDatabaseTracker m_webSQLiteDatabaseTracker;
+#endif
+
+#if PLATFORM(QT)
+ QtNetworkAccessManager m_networkAccessManager;
+#endif
};
} // namespace WebKit
-#endif // ENABLE(NETWORK_PROCESS)
-
#endif // NetworkProcess_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit2/NetworkProcess/NetworkProcess.messages.in
index a5fcbc7be..3c6f89337 100644
--- a/Source/WebKit2/NetworkProcess/NetworkProcess.messages.in
+++ b/Source/WebKit2/NetworkProcess/NetworkProcess.messages.in
@@ -20,30 +20,53 @@
# 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.
-#if ENABLE(NETWORK_PROCESS)
-
messages -> NetworkProcess LegacyReceiver {
# Initializes the network process.
- InitializeNetworkProcess(WebKit::NetworkProcessCreationParameters processCreationParameters)
+ InitializeNetworkProcess(struct WebKit::NetworkProcessCreationParameters processCreationParameters)
# Creates a connection for communication with a WebProcess
CreateNetworkConnectionToWebProcess()
- EnsurePrivateBrowsingSession()
- DestroyPrivateBrowsingSession()
+#if USE(SOUP)
+ SetIgnoreTLSErrors(bool ignoreTLSErrors)
+ UserPreferredLanguagesChanged(Vector<String> languages)
+#endif
+
+ ClearCachedCredentials()
- DownloadRequest(uint64_t downloadID, WebCore::ResourceRequest request)
- CancelDownload(uint64_t downloadID)
+ EnsurePrivateBrowsingSession(WebCore::SessionID sessionID)
+ DestroyPrivateBrowsingSession(WebCore::SessionID sessionID)
+
+ FetchWebsiteData(WebCore::SessionID sessionID, uint64_t websiteDataTypes, uint64_t callbackID)
+ DeleteWebsiteData(WebCore::SessionID sessionID, uint64_t websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID)
+ DeleteWebsiteDataForOrigins(WebCore::SessionID sessionID, uint64_t websiteDataTypes, Vector<WebCore::SecurityOriginData> origins, Vector<String> cookieHostNames, uint64_t callbackID)
+
+ DownloadRequest(WebCore::SessionID sessionID, WebKit::DownloadID downloadID, WebCore::ResourceRequest request)
+ ResumeDownload(WebCore::SessionID sessionID, WebKit::DownloadID downloadID, IPC::DataReference resumeData, String path, WebKit::SandboxExtension::Handle sandboxExtensionHandle)
+ CancelDownload(WebKit::DownloadID downloadID)
+#if PLATFORM(QT)
+ StartTransfer(WebKit::DownloadID downloadID, String destination)
+#endif
+#if USE(NETWORK_SESSION)
+ ContinueCanAuthenticateAgainstProtectionSpace(WebKit::DownloadID downloadID, bool canAuthenticate)
+ ContinueWillSendRequest(WebKit::DownloadID downloadID, WebCore::ResourceRequest request)
+#endif
-#if PLATFORM(MAC)
SetProcessSuppressionEnabled(bool flag)
+#if PLATFORM(COCOA)
+ SetQOS(int latencyQOS, int throughputQOS)
#endif
- AllowSpecificHTTPSCertificateForHost(WebKit::PlatformCertificateInfo certificate, WTF::String host)
+ AllowSpecificHTTPSCertificateForHost(WebCore::CertificateInfo certificate, String host)
+ SetCanHandleHTTPSServerTrustEvaluation(bool value)
GetNetworkProcessStatistics(uint64_t callbackID)
ClearCacheForAllOrigins(uint32_t cachesToClear)
-}
+ SetCacheModel(uint32_t cacheModel);
-#endif // ENABLE(NETWORK_PROCESS)
+ ProcessWillSuspendImminently() -> (bool handled)
+ PrepareToSuspend()
+ CancelPrepareToSuspend()
+ ProcessDidResume()
+}
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.cpp b/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.cpp
new file mode 100644
index 000000000..da6fb1902
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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. 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 "NetworkProcessCreationParameters.h"
+
+#include "ArgumentCoders.h"
+
+#if PLATFORM(COCOA)
+#include "ArgumentCodersCF.h"
+#endif
+
+namespace WebKit {
+
+NetworkProcessCreationParameters::NetworkProcessCreationParameters()
+{
+}
+
+void NetworkProcessCreationParameters::encode(IPC::ArgumentEncoder& encoder) const
+{
+ encoder << privateBrowsingEnabled;
+ encoder.encodeEnum(cacheModel);
+ encoder << diskCacheSizeOverride;
+ encoder << canHandleHTTPSServerTrustEvaluation;
+ encoder << diskCacheDirectory;
+ encoder << diskCacheDirectoryExtensionHandle;
+#if ENABLE(NETWORK_CACHE)
+ encoder << shouldEnableNetworkCache;
+ encoder << shouldEnableNetworkCacheEfficacyLogging;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ encoder << shouldEnableNetworkCacheSpeculativeRevalidation;
+#endif
+#endif
+#if ENABLE(SECCOMP_FILTERS)
+ encoder << cookieStorageDirectory;
+#endif
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
+ encoder << uiProcessCookieStorageIdentifier;
+#endif
+#if PLATFORM(IOS)
+ encoder << cookieStorageDirectoryExtensionHandle;
+ encoder << containerCachesDirectoryExtensionHandle;
+ encoder << parentBundleDirectoryExtensionHandle;
+#endif
+ encoder << shouldUseTestingNetworkSession;
+ encoder << urlSchemesRegisteredForCustomProtocols;
+#if PLATFORM(COCOA)
+ encoder << parentProcessName;
+ encoder << uiProcessBundleIdentifier;
+ encoder << nsURLCacheMemoryCapacity;
+ encoder << nsURLCacheDiskCapacity;
+ encoder << httpProxy;
+ encoder << httpsProxy;
+#if TARGET_OS_IPHONE || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
+ IPC::encode(encoder, networkATSContext.get());
+#endif
+#endif
+#if USE(SOUP) || PLATFORM(QT)
+ encoder << cookiePersistentStoragePath;
+ encoder << cookiePersistentStorageType;
+ encoder.encodeEnum(cookieAcceptPolicy);
+ encoder << ignoreTLSErrors;
+ encoder << languages;
+#endif
+}
+
+bool NetworkProcessCreationParameters::decode(IPC::ArgumentDecoder& decoder, NetworkProcessCreationParameters& result)
+{
+ if (!decoder.decode(result.privateBrowsingEnabled))
+ return false;
+ if (!decoder.decodeEnum(result.cacheModel))
+ return false;
+ if (!decoder.decode(result.diskCacheSizeOverride))
+ return false;
+ if (!decoder.decode(result.canHandleHTTPSServerTrustEvaluation))
+ return false;
+ if (!decoder.decode(result.diskCacheDirectory))
+ return false;
+ if (!decoder.decode(result.diskCacheDirectoryExtensionHandle))
+ return false;
+#if ENABLE(NETWORK_CACHE)
+ if (!decoder.decode(result.shouldEnableNetworkCache))
+ return false;
+ if (!decoder.decode(result.shouldEnableNetworkCacheEfficacyLogging))
+ return false;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ if (!decoder.decode(result.shouldEnableNetworkCacheSpeculativeRevalidation))
+ return false;
+#endif
+#endif
+#if ENABLE(SECCOMP_FILTERS)
+ if (!decoder.decode(result.cookieStorageDirectory))
+ return false;
+#endif
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
+ if (!decoder.decode(result.uiProcessCookieStorageIdentifier))
+ return false;
+#endif
+#if PLATFORM(IOS)
+ if (!decoder.decode(result.cookieStorageDirectoryExtensionHandle))
+ return false;
+ if (!decoder.decode(result.containerCachesDirectoryExtensionHandle))
+ return false;
+ if (!decoder.decode(result.parentBundleDirectoryExtensionHandle))
+ return false;
+#endif
+ if (!decoder.decode(result.shouldUseTestingNetworkSession))
+ return false;
+ if (!decoder.decode(result.urlSchemesRegisteredForCustomProtocols))
+ return false;
+#if PLATFORM(COCOA)
+ if (!decoder.decode(result.parentProcessName))
+ return false;
+ if (!decoder.decode(result.uiProcessBundleIdentifier))
+ return false;
+ if (!decoder.decode(result.nsURLCacheMemoryCapacity))
+ return false;
+ if (!decoder.decode(result.nsURLCacheDiskCapacity))
+ return false;
+ if (!decoder.decode(result.httpProxy))
+ return false;
+ if (!decoder.decode(result.httpsProxy))
+ return false;
+#if TARGET_OS_IPHONE || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
+ if (!IPC::decode(decoder, result.networkATSContext))
+ return false;
+#endif
+#endif
+
+#if USE(SOUP) || PLATFORM(QT)
+ if (!decoder.decode(result.cookiePersistentStoragePath))
+ return false;
+ if (!decoder.decode(result.cookiePersistentStorageType))
+ return false;
+ if (!decoder.decodeEnum(result.cookieAcceptPolicy))
+ return false;
+ if (!decoder.decode(result.ignoreTLSErrors))
+ return false;
+ if (!decoder.decode(result.languages))
+ return false;
+#endif
+
+ return true;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.h b/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.h
new file mode 100644
index 000000000..dfd188a47
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.h
@@ -0,0 +1,104 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef NetworkProcessCreationParameters_h
+#define NetworkProcessCreationParameters_h
+
+#include "CacheModel.h"
+#include "SandboxExtension.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+#if USE(SOUP) || PLATFORM(QT)
+#include "HTTPCookieAcceptPolicy.h"
+#endif
+
+namespace IPC {
+class ArgumentDecoder;
+class ArgumentEncoder;
+}
+
+namespace WebKit {
+
+struct NetworkProcessCreationParameters {
+ NetworkProcessCreationParameters();
+
+ void encode(IPC::ArgumentEncoder&) const;
+ static bool decode(IPC::ArgumentDecoder&, NetworkProcessCreationParameters&);
+
+ bool privateBrowsingEnabled;
+ CacheModel cacheModel;
+ int64_t diskCacheSizeOverride { -1 };
+ bool canHandleHTTPSServerTrustEvaluation;
+
+ String diskCacheDirectory;
+ SandboxExtension::Handle diskCacheDirectoryExtensionHandle;
+#if ENABLE(NETWORK_CACHE)
+ bool shouldEnableNetworkCache;
+ bool shouldEnableNetworkCacheEfficacyLogging;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ bool shouldEnableNetworkCacheSpeculativeRevalidation;
+#endif
+#endif
+#if ENABLE(SECCOMP_FILTERS)
+ String cookieStorageDirectory;
+#endif
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
+ Vector<uint8_t> uiProcessCookieStorageIdentifier;
+#endif
+#if PLATFORM(IOS)
+ SandboxExtension::Handle cookieStorageDirectoryExtensionHandle;
+ SandboxExtension::Handle containerCachesDirectoryExtensionHandle;
+ SandboxExtension::Handle parentBundleDirectoryExtensionHandle;
+#endif
+ bool shouldUseTestingNetworkSession;
+
+ Vector<String> urlSchemesRegisteredForCustomProtocols;
+
+#if PLATFORM(COCOA)
+ String parentProcessName;
+ String uiProcessBundleIdentifier;
+ uint64_t nsURLCacheMemoryCapacity;
+ uint64_t nsURLCacheDiskCapacity;
+
+ String httpProxy;
+ String httpsProxy;
+#if TARGET_OS_IPHONE || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
+ RetainPtr<CFDataRef> networkATSContext;
+#endif
+#endif
+
+#if USE(SOUP) || PLATFORM(QT)
+ String cookiePersistentStoragePath;
+ uint32_t cookiePersistentStorageType;
+ HTTPCookieAcceptPolicy cookieAcceptPolicy;
+ bool ignoreTLSErrors;
+ Vector<String> languages;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // NetworkProcessCreationParameters_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.cpp b/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.cpp
index dcf758877..2f038ebc7 100644
--- a/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.cpp
+++ b/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.cpp
@@ -27,6 +27,7 @@
#include "NetworkProcessPlatformStrategies.h"
#include <WebCore/BlobRegistryImpl.h>
+#include <wtf/NeverDestroyed.h>
using namespace WebCore;
@@ -34,68 +35,33 @@ namespace WebKit {
void NetworkProcessPlatformStrategies::initialize()
{
- DEFINE_STATIC_LOCAL(NetworkProcessPlatformStrategies, platformStrategies, ());
- setPlatformStrategies(&platformStrategies);
+ static NeverDestroyed<NetworkProcessPlatformStrategies> platformStrategies;
+ setPlatformStrategies(&platformStrategies.get());
}
CookiesStrategy* NetworkProcessPlatformStrategies::createCookiesStrategy()
{
- return 0;
-}
-
-DatabaseStrategy* NetworkProcessPlatformStrategies::createDatabaseStrategy()
-{
- return 0;
+ return nullptr;
}
LoaderStrategy* NetworkProcessPlatformStrategies::createLoaderStrategy()
{
- return this;
+ return nullptr;
}
PasteboardStrategy* NetworkProcessPlatformStrategies::createPasteboardStrategy()
{
- return 0;
+ return nullptr;
}
PluginStrategy* NetworkProcessPlatformStrategies::createPluginStrategy()
{
- return 0;
-}
-
-SharedWorkerStrategy* NetworkProcessPlatformStrategies::createSharedWorkerStrategy()
-{
- return 0;
-}
-
-StorageStrategy* NetworkProcessPlatformStrategies::createStorageStrategy()
-{
- return 0;
-}
-
-VisitedLinkStrategy* NetworkProcessPlatformStrategies::createVisitedLinkStrategy()
-{
- return 0;
-}
-
-ResourceLoadScheduler* NetworkProcessPlatformStrategies::resourceLoadScheduler()
-{
- ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
-void NetworkProcessPlatformStrategies::loadResourceSynchronously(NetworkingContext*, unsigned long resourceLoadIdentifier, const ResourceRequest&, StoredCredentials, ClientCredentialPolicy, ResourceError&, ResourceResponse&, Vector<char>& data)
-{
- ASSERT_NOT_REACHED();
-}
-
-#if ENABLE(BLOB)
BlobRegistry* NetworkProcessPlatformStrategies::createBlobRegistry()
{
return new BlobRegistryImpl;
}
-#endif
-
-
}
diff --git a/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.h b/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.h
index 818ccebb1..b6c0b6102 100644
--- a/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.h
+++ b/Source/WebKit2/NetworkProcess/NetworkProcessPlatformStrategies.h
@@ -31,27 +31,17 @@
namespace WebKit {
-class NetworkProcessPlatformStrategies : public WebCore::PlatformStrategies, private WebCore::LoaderStrategy {
+class NetworkProcessPlatformStrategies : public WebCore::PlatformStrategies {
public:
static void initialize();
private:
// WebCore::PlatformStrategies
- virtual WebCore::CookiesStrategy* createCookiesStrategy() OVERRIDE;
- virtual WebCore::DatabaseStrategy* createDatabaseStrategy() OVERRIDE;
- virtual WebCore::LoaderStrategy* createLoaderStrategy() OVERRIDE;
- virtual WebCore::PasteboardStrategy* createPasteboardStrategy() OVERRIDE;
- virtual WebCore::PluginStrategy* createPluginStrategy() OVERRIDE;
- virtual WebCore::SharedWorkerStrategy* createSharedWorkerStrategy() OVERRIDE;
- virtual WebCore::StorageStrategy* createStorageStrategy() OVERRIDE;
- virtual WebCore::VisitedLinkStrategy* createVisitedLinkStrategy() OVERRIDE;
-
- // WebCore::LoaderStrategy
- virtual WebCore::ResourceLoadScheduler* resourceLoadScheduler() OVERRIDE;
- virtual void loadResourceSynchronously(WebCore::NetworkingContext*, unsigned long resourceLoadIdentifier, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ClientCredentialPolicy, WebCore::ResourceError&, WebCore::ResourceResponse&, Vector<char>& data) OVERRIDE;
-#if ENABLE(BLOB)
- virtual WebCore::BlobRegistry* createBlobRegistry() OVERRIDE;
-#endif
+ WebCore::CookiesStrategy* createCookiesStrategy() override;
+ WebCore::LoaderStrategy* createLoaderStrategy() override;
+ WebCore::PasteboardStrategy* createPasteboardStrategy() override;
+ WebCore::PluginStrategy* createPluginStrategy() override;
+ WebCore::BlobRegistry* createBlobRegistry() override;
};
} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/NetworkProcessMain.mm b/Source/WebKit2/NetworkProcess/NetworkProcessSupplement.h
index 87b9e4000..e2b46b391 100644
--- a/Source/WebKit2/NetworkProcess/EntryPoint/mac/LegacyProcess/NetworkProcessMain.mm
+++ b/Source/WebKit2/NetworkProcess/NetworkProcessSupplement.h
@@ -23,21 +23,22 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import "config.h"
+#ifndef NetworkProcessSupplement_h
+#define NetworkProcessSupplement_h
-#if ENABLE(NETWORK_PROCESS)
+#include "ChildProcessSupplement.h"
-#import "ChildProcessEntryPoint.h"
-#import "NetworkProcess.h"
-#import "WKBase.h"
+namespace WebKit {
-using namespace WebKit;
+struct NetworkProcessCreationParameters;
-extern "C" WK_EXPORT int NetworkProcessMain(int argc, char** argv);
+class NetworkProcessSupplement : public ChildProcessSupplement {
+public:
+ virtual void initialize(const NetworkProcessCreationParameters&)
+ {
+ }
+};
-int NetworkProcessMain(int argc, char** argv)
-{
- return ChildProcessMain<NetworkProcess, ChildProcessMainDelegate>(argc, argv);
-}
+} // namespace WebKit
-#endif // ENABLE(NETWORK_PROCESS)
+#endif // NetworkProcessSupplement_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.cpp b/Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.cpp
new file mode 100644
index 000000000..b56b2f7d8
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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. 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 "NetworkResourceLoadParameters.h"
+
+#include "ArgumentCoders.h"
+#include "DataReference.h"
+#include "WebCoreArgumentCoders.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+NetworkResourceLoadParameters::NetworkResourceLoadParameters()
+ : identifier(0)
+ , webPageID(0)
+ , webFrameID(0)
+ , sessionID(SessionID::emptySessionID())
+ , contentSniffingPolicy(SniffContent)
+ , allowStoredCredentials(DoNotAllowStoredCredentials)
+ , clientCredentialPolicy(DoNotAskClientForAnyCredentials)
+ , shouldClearReferrerOnHTTPSToHTTPRedirect(true)
+ , defersLoading(false)
+ , needsCertificateInfo(false)
+ , maximumBufferingTime(0_ms)
+{
+}
+
+void NetworkResourceLoadParameters::encode(IPC::ArgumentEncoder& encoder) const
+{
+ encoder << identifier;
+ encoder << webPageID;
+ encoder << webFrameID;
+ encoder << sessionID;
+ encoder << request;
+
+ encoder << static_cast<bool>(request.httpBody());
+ if (request.httpBody()) {
+ request.httpBody()->encode(encoder);
+
+ const Vector<FormDataElement>& elements = request.httpBody()->elements();
+ size_t fileCount = 0;
+ for (size_t i = 0, count = elements.size(); i < count; ++i) {
+ if (elements[i].m_type == FormDataElement::Type::EncodedFile)
+ ++fileCount;
+ }
+
+ SandboxExtension::HandleArray requestBodySandboxExtensions;
+ requestBodySandboxExtensions.allocate(fileCount);
+ size_t extensionIndex = 0;
+ for (size_t i = 0, count = elements.size(); i < count; ++i) {
+ const FormDataElement& element = elements[i];
+ if (element.m_type == FormDataElement::Type::EncodedFile) {
+ const String& path = element.m_shouldGenerateFile ? element.m_generatedFilename : element.m_filename;
+ SandboxExtension::createHandle(path, SandboxExtension::ReadOnly, requestBodySandboxExtensions[extensionIndex++]);
+ }
+ }
+ encoder << requestBodySandboxExtensions;
+ }
+
+ if (request.url().isLocalFile()) {
+ SandboxExtension::Handle requestSandboxExtension;
+ SandboxExtension::createHandle(request.url().fileSystemPath(), SandboxExtension::ReadOnly, requestSandboxExtension);
+ encoder << requestSandboxExtension;
+ }
+
+ encoder.encodeEnum(contentSniffingPolicy);
+ encoder.encodeEnum(allowStoredCredentials);
+ encoder.encodeEnum(clientCredentialPolicy);
+ encoder << shouldClearReferrerOnHTTPSToHTTPRedirect;
+ encoder << defersLoading;
+ encoder << needsCertificateInfo;
+ encoder << maximumBufferingTime;
+}
+
+bool NetworkResourceLoadParameters::decode(IPC::ArgumentDecoder& decoder, NetworkResourceLoadParameters& result)
+{
+ if (!decoder.decode(result.identifier))
+ return false;
+
+ if (!decoder.decode(result.webPageID))
+ return false;
+
+ if (!decoder.decode(result.webFrameID))
+ return false;
+
+ if (!decoder.decode(result.sessionID))
+ return false;
+
+ if (!decoder.decode(result.request))
+ return false;
+
+ bool hasHTTPBody;
+ if (!decoder.decode(hasHTTPBody))
+ return false;
+
+ if (hasHTTPBody) {
+ RefPtr<FormData> formData = FormData::decode(decoder);
+ if (!formData)
+ return false;
+ result.request.setHTTPBody(WTFMove(formData));
+
+ SandboxExtension::HandleArray requestBodySandboxExtensionHandles;
+ if (!decoder.decode(requestBodySandboxExtensionHandles))
+ return false;
+ for (size_t i = 0; i < requestBodySandboxExtensionHandles.size(); ++i) {
+ if (RefPtr<SandboxExtension> extension = SandboxExtension::create(requestBodySandboxExtensionHandles[i]))
+ result.requestBodySandboxExtensions.append(extension.release());
+ }
+ }
+
+ if (result.request.url().isLocalFile()) {
+ SandboxExtension::Handle resourceSandboxExtensionHandle;
+ if (!decoder.decode(resourceSandboxExtensionHandle))
+ return false;
+ result.resourceSandboxExtension = SandboxExtension::create(resourceSandboxExtensionHandle);
+ }
+
+ if (!decoder.decodeEnum(result.contentSniffingPolicy))
+ return false;
+ if (!decoder.decodeEnum(result.allowStoredCredentials))
+ return false;
+ if (!decoder.decodeEnum(result.clientCredentialPolicy))
+ return false;
+ if (!decoder.decode(result.shouldClearReferrerOnHTTPSToHTTPRedirect))
+ return false;
+ if (!decoder.decode(result.defersLoading))
+ return false;
+ if (!decoder.decode(result.needsCertificateInfo))
+ return false;
+ if (!decoder.decode(result.maximumBufferingTime))
+ return false;
+
+ return true;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.h b/Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.h
new file mode 100644
index 000000000..22e10c6af
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkResourceLoadParameters.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012, 2013 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.
+ */
+
+#ifndef NetworkResourceLoadParameters_h
+#define NetworkResourceLoadParameters_h
+
+#include "SandboxExtension.h"
+#include <WebCore/ResourceHandle.h>
+#include <WebCore/ResourceLoaderOptions.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/SessionID.h>
+
+namespace IPC {
+class ArgumentDecoder;
+class ArgumentEncoder;
+}
+
+namespace WebKit {
+
+typedef uint64_t ResourceLoadIdentifier;
+
+class NetworkResourceLoadParameters {
+public:
+ NetworkResourceLoadParameters();
+
+ void encode(IPC::ArgumentEncoder&) const;
+ static bool decode(IPC::ArgumentDecoder&, NetworkResourceLoadParameters&);
+
+ ResourceLoadIdentifier identifier;
+ uint64_t webPageID;
+ uint64_t webFrameID;
+ WebCore::SessionID sessionID;
+ WebCore::ResourceRequest request;
+ Vector<RefPtr<SandboxExtension>> requestBodySandboxExtensions; // Created automatically for the sender.
+ RefPtr<SandboxExtension> resourceSandboxExtension; // Created automatically for the sender.
+ WebCore::ContentSniffingPolicy contentSniffingPolicy;
+ WebCore::StoredCredentials allowStoredCredentials;
+ WebCore::ClientCredentialPolicy clientCredentialPolicy;
+ bool shouldClearReferrerOnHTTPSToHTTPRedirect;
+ bool defersLoading;
+ bool needsCertificateInfo;
+ std::chrono::milliseconds maximumBufferingTime;
+};
+
+} // namespace WebKit
+
+#endif // NetworkResourceLoadParameters_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.cpp b/Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.cpp
deleted file mode 100644
index 9aebcc699..000000000
--- a/Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-#include "config.h"
-#include "NetworkResourceLoadScheduler.h"
-
-#include "HostRecord.h"
-#include "Logging.h"
-#include "NetworkProcess.h"
-#include "NetworkResourceLoadParameters.h"
-#include "NetworkResourceLoader.h"
-#include "SyncNetworkResourceLoader.h"
-#include <wtf/MainThread.h>
-#include <wtf/text/CString.h>
-
-#if ENABLE(NETWORK_PROCESS)
-
-using namespace WebCore;
-
-namespace WebKit {
-
-static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
-
-NetworkResourceLoadScheduler::NetworkResourceLoadScheduler()
- : m_nonHTTPProtocolHost(HostRecord::create(String(), maxRequestsInFlightForNonHTTPProtocols))
- , m_requestTimer(this, &NetworkResourceLoadScheduler::requestTimerFired)
-
-{
- platformInitializeMaximumHTTPConnectionCountPerHost();
-}
-
-void NetworkResourceLoadScheduler::scheduleServePendingRequests()
-{
- if (!m_requestTimer.isActive())
- m_requestTimer.startOneShot(0);
-}
-
-void NetworkResourceLoadScheduler::requestTimerFired(WebCore::Timer<NetworkResourceLoadScheduler>*)
-{
- servePendingRequests();
-}
-
-void NetworkResourceLoadScheduler::scheduleLoader(PassRefPtr<SchedulableLoader> loader)
-{
- ResourceLoadPriority priority = loader->priority();
- const ResourceRequest& resourceRequest = loader->request();
-
- LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::scheduleLoader resource '%s'", resourceRequest.url().string().utf8().data());
-
- HostRecord* host = hostForURL(resourceRequest.url(), CreateIfNotFound);
- bool hadRequests = host->hasRequests();
- host->scheduleResourceLoader(loader);
-
- if (priority > ResourceLoadPriorityLow || !resourceRequest.url().protocolIsInHTTPFamily() || (priority == ResourceLoadPriorityLow && !hadRequests)) {
- // Try to request important resources immediately.
- host->servePendingRequests(priority);
- return;
- }
-
- // Handle asynchronously so early low priority requests don't get scheduled before later high priority ones.
- scheduleServePendingRequests();
-}
-
-HostRecord* NetworkResourceLoadScheduler::hostForURL(const WebCore::KURL& url, CreateHostPolicy createHostPolicy)
-{
- if (!url.protocolIsInHTTPFamily())
- return m_nonHTTPProtocolHost.get();
-
- m_hosts.checkConsistency();
- String hostName = url.host();
- HostRecord* host = m_hosts.get(hostName);
- if (!host && createHostPolicy == CreateIfNotFound) {
- RefPtr<HostRecord> newHost = HostRecord::create(hostName, m_maxRequestsInFlightPerHost);
- host = newHost.get();
- m_hosts.add(hostName, newHost.release());
- }
-
- return host;
-}
-
-void NetworkResourceLoadScheduler::removeLoader(SchedulableLoader* loader)
-{
- ASSERT(isMainThread());
- ASSERT(loader);
-
- LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::removeLoadIdentifier removing loader %s", loader->request().url().string().utf8().data());
-
- HostRecord* host = loader->hostRecord();
-
- // Due to a race condition the WebProcess might have messaged the NetworkProcess to remove this identifier
- // after the NetworkProcess has already removed it internally.
- // In this situation we might not have a HostRecord to clean up.
- if (host)
- host->removeLoader(loader);
-
- scheduleServePendingRequests();
-}
-
-void NetworkResourceLoadScheduler::receivedRedirect(SchedulableLoader* loader, const WebCore::KURL& redirectURL)
-{
- ASSERT(isMainThread());
- LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::receivedRedirect loader originally for '%s' redirected to '%s'", loader->request().url().string().utf8().data(), redirectURL.string().utf8().data());
-
- HostRecord* oldHost = loader->hostRecord();
-
- // The load may have been cancelled while the message was in flight from network thread to main thread.
- if (!oldHost)
- return;
-
- HostRecord* newHost = hostForURL(redirectURL, CreateIfNotFound);
-
- if (oldHost->name() == newHost->name())
- return;
-
- oldHost->removeLoader(loader);
- newHost->addLoaderInProgress(loader);
-}
-
-void NetworkResourceLoadScheduler::servePendingRequests(ResourceLoadPriority minimumPriority)
-{
- LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::servePendingRequests Serving requests for up to %i hosts with minimum priority %i", m_hosts.size(), minimumPriority);
-
- m_requestTimer.stop();
-
- m_nonHTTPProtocolHost->servePendingRequests(minimumPriority);
-
- m_hosts.checkConsistency();
- Vector<RefPtr<HostRecord>> hostsToServe;
- copyValuesToVector(m_hosts, hostsToServe);
-
- size_t size = hostsToServe.size();
- for (size_t i = 0; i < size; ++i) {
- HostRecord* host = hostsToServe[i].get();
- if (host->hasRequests())
- host->servePendingRequests(minimumPriority);
- else
- m_hosts.remove(host->name());
- }
-}
-
-static bool removeScheduledLoadersCalled = false;
-
-void NetworkResourceLoadScheduler::removeScheduledLoaders(void* context)
-{
- ASSERT(isMainThread());
- ASSERT(removeScheduledLoadersCalled);
-
- NetworkResourceLoadScheduler* scheduler = static_cast<NetworkResourceLoadScheduler*>(context);
- scheduler->removeScheduledLoaders();
-}
-
-void NetworkResourceLoadScheduler::removeScheduledLoaders()
-{
- Vector<RefPtr<SchedulableLoader>> loadersToRemove;
- {
- MutexLocker locker(m_loadersToRemoveMutex);
- loadersToRemove = m_loadersToRemove;
- m_loadersToRemove.clear();
- removeScheduledLoadersCalled = false;
- }
-
- for (size_t i = 0; i < loadersToRemove.size(); ++i)
- removeLoader(loadersToRemove[i].get());
-}
-
-void NetworkResourceLoadScheduler::scheduleRemoveLoader(SchedulableLoader* loader)
-{
- MutexLocker locker(m_loadersToRemoveMutex);
-
- m_loadersToRemove.append(loader);
-
- if (!removeScheduledLoadersCalled) {
- removeScheduledLoadersCalled = true;
- callOnMainThread(NetworkResourceLoadScheduler::removeScheduledLoaders, this);
- }
-}
-
-uint64_t NetworkResourceLoadScheduler::hostsPendingCount() const
-{
- uint64_t count = m_nonHTTPProtocolHost->pendingRequestCount() ? 1 : 0;
-
- HostMap::const_iterator end = m_hosts.end();
- for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i) {
- if (i->value->pendingRequestCount())
- ++count;
- }
-
- return count;
-}
-
-uint64_t NetworkResourceLoadScheduler::loadsPendingCount() const
-{
- uint64_t count = m_nonHTTPProtocolHost->pendingRequestCount();
-
- HostMap::const_iterator end = m_hosts.end();
- for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i)
- count += i->value->pendingRequestCount();
-
- return count;
-}
-
-uint64_t NetworkResourceLoadScheduler::hostsActiveCount() const
-{
- uint64_t count = 0;
-
- if (m_nonHTTPProtocolHost->activeLoadCount())
- count = 1;
-
- HostMap::const_iterator end = m_hosts.end();
- for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i) {
- if (i->value->activeLoadCount())
- ++count;
- }
-
- return count;
-}
-
-uint64_t NetworkResourceLoadScheduler::loadsActiveCount() const
-{
- uint64_t count = m_nonHTTPProtocolHost->activeLoadCount();
-
- HostMap::const_iterator end = m_hosts.end();
- for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i)
- count += i->value->activeLoadCount();
-
- return count;
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.h b/Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.h
deleted file mode 100644
index dfe710268..000000000
--- a/Source/WebKit2/NetworkProcess/NetworkResourceLoadScheduler.h
+++ /dev/null
@@ -1,108 +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 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.
- */
-
-#ifndef NetworkResourceLoadScheduler_h
-#define NetworkResourceLoadScheduler_h
-
-#include <WebCore/ResourceLoadPriority.h>
-#include <WebCore/Timer.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/text/StringHash.h>
-
-#if ENABLE(NETWORK_PROCESS)
-
-namespace WebCore {
-class KURL;
-}
-
-namespace WebKit {
-
-class HostRecord;
-class SchedulableLoader;
-
-class NetworkResourceLoadScheduler {
- WTF_MAKE_NONCOPYABLE(NetworkResourceLoadScheduler); WTF_MAKE_FAST_ALLOCATED;
-
-public:
- NetworkResourceLoadScheduler();
-
- // Adds the request to the queue for its host.
- void scheduleLoader(PassRefPtr<SchedulableLoader>);
-
- // Called by the WebProcess when a ResourceLoader is being cleaned up.
- void removeLoader(SchedulableLoader*);
-
- // Called within the NetworkProcess on a background thread when a resource load has finished.
- void scheduleRemoveLoader(SchedulableLoader*);
-
- void receivedRedirect(SchedulableLoader*, const WebCore::KURL& redirectURL);
- void servePendingRequests(WebCore::ResourceLoadPriority = WebCore::ResourceLoadPriorityVeryLow);
-
- // For NetworkProcess statistics reporting.
- uint64_t hostsPendingCount() const;
- uint64_t loadsPendingCount() const;
- uint64_t hostsActiveCount() const;
- uint64_t loadsActiveCount() const;
-
-private:
- enum CreateHostPolicy {
- CreateIfNotFound,
- FindOnly
- };
-
- HostRecord* hostForURL(const WebCore::KURL&, CreateHostPolicy = FindOnly);
-
- void scheduleServePendingRequests();
- void requestTimerFired(WebCore::Timer<NetworkResourceLoadScheduler>*);
-
- void platformInitializeMaximumHTTPConnectionCountPerHost();
-
- static void removeScheduledLoaders(void* context);
- void removeScheduledLoaders();
-
- typedef HashMap<String, RefPtr<HostRecord>, StringHash> HostMap;
- HostMap m_hosts;
-
- typedef HashSet<RefPtr<SchedulableLoader>> SchedulableLoaderSet;
- SchedulableLoaderSet m_loaders;
-
- RefPtr<HostRecord> m_nonHTTPProtocolHost;
-
- bool m_isSerialLoadingEnabled;
-
- WebCore::Timer<NetworkResourceLoadScheduler> m_requestTimer;
-
- Mutex m_loadersToRemoveMutex;
- Vector<RefPtr<SchedulableLoader>> m_loadersToRemove;
-
- unsigned m_maxRequestsInFlightPerHost;
-};
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
-
-#endif // NetworkResourceLoadScheduler_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp b/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp
index 5ad12d324..cef04f346 100644
--- a/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp
+++ b/Source/WebKit2/NetworkProcess/NetworkResourceLoader.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,325 +26,605 @@
#include "config.h"
#include "NetworkResourceLoader.h"
-#if ENABLE(NETWORK_PROCESS)
-
-#include "AuthenticationManager.h"
#include "DataReference.h"
#include "Logging.h"
+#include "NetworkBlobRegistry.h"
+#include "NetworkCache.h"
#include "NetworkConnectionToWebProcess.h"
-#include "NetworkProcess.h"
+#include "NetworkLoad.h"
#include "NetworkProcessConnectionMessages.h"
-#include "NetworkResourceLoadParameters.h"
-#include "PlatformCertificateInfo.h"
-#include "RemoteNetworkingContext.h"
-#include "ShareableResource.h"
-#include "SharedMemory.h"
#include "WebCoreArgumentCoders.h"
-#include "WebErrors.h"
#include "WebResourceLoaderMessages.h"
-#include <WebCore/NotImplemented.h>
-#include <WebCore/ResourceBuffer.h>
-#include <WebCore/ResourceHandle.h>
+#include <WebCore/BlobDataFileReference.h>
+#include <WebCore/CertificateInfo.h>
+#include <WebCore/HTTPHeaderNames.h>
+#include <WebCore/ProtectionSpace.h>
+#include <WebCore/SharedBuffer.h>
+#include <WebCore/SynchronousLoaderClient.h>
#include <wtf/CurrentTime.h>
-#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
using namespace WebCore;
namespace WebKit {
-NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& loadParameters, NetworkConnectionToWebProcess* connection)
- : SchedulableLoader(loadParameters, connection)
- , m_bytesReceived(0)
- , m_handleConvertedToDownload(false)
-{
- ASSERT(isMainThread());
-}
+struct NetworkResourceLoader::SynchronousLoadData {
+ SynchronousLoadData(RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
+ : delayedReply(WTFMove(reply))
+ {
+ ASSERT(delayedReply);
+ }
+ ResourceRequest currentRequest;
+ RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
+ ResourceResponse response;
+ ResourceError error;
+};
-NetworkResourceLoader::~NetworkResourceLoader()
+static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
{
- ASSERT(isMainThread());
- ASSERT(!m_handle);
+ ASSERT(data.delayedReply);
+ ASSERT(!data.response.isNull() || !data.error.isNull());
+
+ Vector<char> responseBuffer;
+ if (buffer && buffer->size())
+ responseBuffer.append(buffer->data(), buffer->size());
+
+ data.delayedReply->send(data.error, data.response, responseBuffer);
+ data.delayedReply = nullptr;
}
-void NetworkResourceLoader::start()
+NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& synchronousReply)
+ : m_parameters(parameters)
+ , m_connection(connection)
+ , m_defersLoading(parameters.defersLoading)
+ , m_bufferingTimer(*this, &NetworkResourceLoader::bufferingTimerFired)
{
- ASSERT(isMainThread());
+ ASSERT(RunLoop::isMain());
+ // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
+ // Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
+ ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials);
+
+ if (originalRequest().httpBody()) {
+ for (const auto& element : originalRequest().httpBody()->elements()) {
+ if (element.m_type == FormDataElement::Type::EncodedBlob)
+ m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
+ }
+ }
- // Explicit ref() balanced by a deref() in NetworkResourceLoader::resourceHandleStopped()
- ref();
-
- // FIXME (NetworkProcess): Create RemoteNetworkingContext with actual settings.
- m_networkingContext = RemoteNetworkingContext::create(false, false, inPrivateBrowsingMode(), shouldClearReferrerOnHTTPSToHTTPRedirect());
+ if (originalRequest().url().protocolIsBlob()) {
+ ASSERT(!m_parameters.resourceSandboxExtension);
+ m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
+ }
- consumeSandboxExtensions();
+ if (synchronousReply)
+ m_synchronousLoadData = std::make_unique<SynchronousLoadData>(WTFMove(synchronousReply));
+}
- // FIXME (NetworkProcess): Pass an actual value for defersLoading
- m_handle = ResourceHandle::create(m_networkingContext.get(), request(), this, false /* defersLoading */, contentSniffingPolicy() == SniffContent);
+NetworkResourceLoader::~NetworkResourceLoader()
+{
+ ASSERT(RunLoop::isMain());
+ ASSERT(!m_networkLoad);
+ ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
}
-void NetworkResourceLoader::cleanup()
+#if ENABLE(NETWORK_CACHE)
+bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
{
- ASSERT(isMainThread());
+ if (!NetworkCache::singleton().isEnabled())
+ return false;
+ if (sessionID().isEphemeral())
+ return false;
+ if (!request.url().protocolIsInHTTPFamily())
+ return false;
+
+ return true;
+}
- invalidateSandboxExtensions();
+bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
+{
+ if (!canUseCache(request))
+ return false;
+ // Limit cached redirects to avoid cycles and other trouble.
+ // Networking layer follows over 30 redirects but caching that many seems unnecessary.
+ static const unsigned maximumCachedRedirectCount { 5 };
+ if (m_redirectCount > maximumCachedRedirectCount)
+ return false;
+
+ return true;
+}
+#endif
- if (FormData* formData = request().httpBody())
- formData->removeGeneratedFilesIfNeeded();
+bool NetworkResourceLoader::isSynchronous() const
+{
+ return !!m_synchronousLoadData;
+}
- // Tell the scheduler about this finished loader soon so it can start more network requests.
- NetworkProcess::shared().networkResourceLoadScheduler().scheduleRemoveLoader(this);
+void NetworkResourceLoader::start()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (m_defersLoading)
+ return;
- if (m_handle) {
- // Explicit deref() balanced by a ref() in NetworkResourceLoader::start()
- // This might cause the NetworkResourceLoader to be destroyed and therefore we do it last.
- m_handle = 0;
- deref();
+#if ENABLE(NETWORK_CACHE)
+ if (canUseCache(originalRequest())) {
+ retrieveCacheEntry(originalRequest());
+ return;
}
+#endif
+
+ startNetworkLoad(originalRequest());
}
-template<typename U> bool NetworkResourceLoader::sendAbortingOnFailure(const U& message, unsigned messageSendFlags)
+#if ENABLE(NETWORK_CACHE)
+void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
{
- bool result = messageSenderConnection()->send(message, messageSenderDestinationID(), messageSendFlags);
- if (!result)
- abort();
- return result;
+ ASSERT(canUseCache(request));
+
+ RefPtr<NetworkResourceLoader> loader(this);
+ NetworkCache::singleton().retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [loader, request](std::unique_ptr<NetworkCache::Entry> entry) {
+ if (loader->hasOneRef()) {
+ // The loader has been aborted and is only held alive by this lambda.
+ return;
+ }
+ if (!entry) {
+ loader->startNetworkLoad(request);
+ return;
+ }
+ if (entry->redirectRequest()) {
+ loader->dispatchWillSendRequestForCacheEntry(WTFMove(entry));
+ return;
+ }
+ if (loader->m_parameters.needsCertificateInfo && !entry->response().containsCertificateInfo()) {
+ loader->startNetworkLoad(request);
+ return;
+ }
+ if (entry->needsValidation()) {
+ loader->validateCacheEntry(WTFMove(entry));
+ return;
+ }
+ loader->didRetrieveCacheEntry(WTFMove(entry));
+ });
}
+#endif
-void NetworkResourceLoader::didConvertHandleToDownload()
+void NetworkResourceLoader::startNetworkLoad(const ResourceRequest& request)
{
- ASSERT(m_handle);
- m_handleConvertedToDownload = true;
+ consumeSandboxExtensions();
+
+ if (isSynchronous() || m_parameters.maximumBufferingTime > 0_ms)
+ m_bufferedData = SharedBuffer::create();
+
+#if ENABLE(NETWORK_CACHE)
+ if (canUseCache(request))
+ m_bufferedDataForCache = SharedBuffer::create();
+#endif
+
+ NetworkLoadParameters parameters = m_parameters;
+ parameters.defersLoading = m_defersLoading;
+ parameters.request = request;
+ m_networkLoad = std::make_unique<NetworkLoad>(*this, parameters);
}
-void NetworkResourceLoader::abort()
+void NetworkResourceLoader::setDefersLoading(bool defers)
{
- ASSERT(isMainThread());
+ if (m_defersLoading == defers)
+ return;
+ m_defersLoading = defers;
- if (m_handle && !m_handleConvertedToDownload)
- m_handle->cancel();
+ if (m_networkLoad) {
+ m_networkLoad->setDefersLoading(defers);
+ return;
+ }
- cleanup();
+ if (!m_defersLoading)
+ start();
}
-void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse& response)
+void NetworkResourceLoader::cleanup()
{
- ASSERT_UNUSED(handle, handle == m_handle);
+ ASSERT(RunLoop::isMain());
- // FIXME (NetworkProcess): Cache the response.
- if (FormData* formData = request().httpBody())
- formData->removeGeneratedFilesIfNeeded();
+ m_bufferingTimer.stop();
- sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponseWithCertificateInfo(response, PlatformCertificateInfo(response), isLoadingMainResource()));
+ invalidateSandboxExtensions();
- // m_handle will be 0 if the request got aborted above.
- if (!m_handle)
- return;
+ m_networkLoad = nullptr;
+
+ // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
+ m_connection->didCleanupResourceLoader(*this);
+}
+
+void NetworkResourceLoader::didConvertToDownload()
+{
+ ASSERT(m_networkLoad);
+ m_didConvertToDownload = true;
+#if USE(NETWORK_SESSION)
+ m_networkLoad = nullptr;
+#endif
+}
- if (!isLoadingMainResource()) {
- // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
- m_handle->continueDidReceiveResponse();
+void NetworkResourceLoader::abort()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (m_networkLoad && !m_didConvertToDownload) {
+#if ENABLE(NETWORK_CACHE)
+ if (canUseCache(m_networkLoad->currentRequest())) {
+ // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
+ if (!m_response.isNull())
+ NetworkCache::singleton().remove(m_networkLoad->currentRequest());
+ }
+#endif
+ m_networkLoad->cancel();
}
+
+ cleanup();
}
-void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int encodedDataLength)
+auto NetworkResourceLoader::didReceiveResponse(const ResourceResponse& receivedResponse) -> ShouldContinueDidReceiveResponse
{
- // The NetworkProcess should never get a didReceiveData callback.
- // We should always be using didReceiveBuffer.
- ASSERT_NOT_REACHED();
+ m_response = receivedResponse;
+
+ // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
+ if (!isSynchronous() && m_response.isMultipart())
+ m_bufferedData = nullptr;
+
+ bool shouldSendDidReceiveResponse = true;
+#if ENABLE(NETWORK_CACHE)
+ if (m_response.isMultipart())
+ m_bufferedDataForCache = nullptr;
+
+ if (m_cacheEntryForValidation) {
+ bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
+ if (validationSucceeded) {
+ NetworkCache::singleton().update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
+ // If the request was conditional then this revalidation was not triggered by the network cache and we pass the
+ // 304 response to WebCore.
+ if (originalRequest().isConditional())
+ m_cacheEntryForValidation = nullptr;
+ } else
+ m_cacheEntryForValidation = nullptr;
+ }
+ shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
+#endif
+
+ bool shouldWaitContinueDidReceiveResponse = originalRequest().requester() == ResourceRequest::Requester::Main;
+ if (shouldSendDidReceiveResponse) {
+ if (isSynchronous())
+ m_synchronousLoadData->response = m_response;
+ else {
+ if (!sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(m_response, shouldWaitContinueDidReceiveResponse)))
+ return ShouldContinueDidReceiveResponse::No;
+ }
+ }
+
+ // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
+ bool shouldContinueDidReceiveResponse = !shouldWaitContinueDidReceiveResponse;
+#if ENABLE(NETWORK_CACHE)
+ shouldContinueDidReceiveResponse = shouldContinueDidReceiveResponse || m_cacheEntryForValidation;
+#endif
+
+ return shouldContinueDidReceiveResponse ? ShouldContinueDidReceiveResponse::Yes : ShouldContinueDidReceiveResponse::No;
}
-void NetworkResourceLoader::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<SharedBuffer> buffer, int encodedDataLength)
+void NetworkResourceLoader::didReceiveBuffer(RefPtr<SharedBuffer>&& buffer, int reportedEncodedDataLength)
{
- ASSERT_UNUSED(handle, handle == m_handle);
+#if ENABLE(NETWORK_CACHE)
+ ASSERT(!m_cacheEntryForValidation);
+
+ if (m_bufferedDataForCache) {
+ // Prevent memory growth in case of streaming data.
+ const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
+ if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
+ m_bufferedDataForCache->append(buffer.get());
+ else
+ m_bufferedDataForCache = nullptr;
+ }
+#endif
+ // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
+ unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
- // FIXME (NetworkProcess): For the memory cache we'll also need to cache the response data here.
- // Such buffering will need to be thread safe, as this callback is happening on a background thread.
-
m_bytesReceived += buffer->size();
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
- ShareableResource::Handle shareableResourceHandle;
- tryGetShareableHandleFromSharedBuffer(shareableResourceHandle, buffer.get());
- if (!shareableResourceHandle.isNull()) {
- // Since we're delivering this resource by ourselves all at once, we'll abort the resource handle since we don't need anymore callbacks from ResourceHandle.
- abort();
- send(Messages::WebResourceLoader::DidReceiveResource(shareableResourceHandle, currentTime()));
+ if (m_bufferedData) {
+ m_bufferedData->append(buffer.get());
+ m_bufferedDataEncodedDataLength += encodedDataLength;
+ startBufferingTimerIfNeeded();
return;
}
-#endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-
- CoreIPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size());
- sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
+ sendBufferMaybeAborting(*buffer, encodedDataLength);
}
-void NetworkResourceLoader::didFinishLoading(ResourceHandle* handle, double finishTime)
+void NetworkResourceLoader::didFinishLoading(double finishTime)
{
- ASSERT_UNUSED(handle, handle == m_handle);
+#if ENABLE(NETWORK_CACHE)
+ if (m_cacheEntryForValidation) {
+ // 304 Not Modified
+ ASSERT(m_response.httpStatusCode() == 304);
+ LOG(NetworkCache, "(NetworkProcess) revalidated");
+ didRetrieveCacheEntry(WTFMove(m_cacheEntryForValidation));
+ return;
+ }
+#endif
+
+ if (isSynchronous())
+ sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
+ else {
+ if (m_bufferedData && !m_bufferedData->isEmpty()) {
+ // FIXME: Pass a real value or remove the encoded data size feature.
+ bool shouldContinue = sendBufferMaybeAborting(*m_bufferedData, -1);
+ if (!shouldContinue)
+ return;
+ }
+ send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
+ }
+
+#if ENABLE(NETWORK_CACHE)
+ tryStoreAsCacheEntry();
+#endif
- // FIXME (NetworkProcess): For the memory cache we'll need to update the finished status of the cached resource here.
- // Such bookkeeping will need to be thread safe, as this callback is happening on a background thread.
- send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
-
cleanup();
}
-void NetworkResourceLoader::didFail(ResourceHandle* handle, const ResourceError& error)
+void NetworkResourceLoader::didFailLoading(const ResourceError& error)
{
- ASSERT_UNUSED(handle, handle == m_handle);
+ ASSERT(!error.isNull());
+
+#if ENABLE(NETWORK_CACHE)
+ m_cacheEntryForValidation = nullptr;
+#endif
+
+ if (isSynchronous()) {
+ m_synchronousLoadData->error = error;
+ sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
+ } else if (auto* connection = messageSenderConnection())
+ connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID(), 0);
- // FIXME (NetworkProcess): For the memory cache we'll need to update the finished status of the cached resource here.
- // Such bookkeeping will need to be thread safe, as this callback is happening on a background thread.
- send(Messages::WebResourceLoader::DidFailResourceLoad(error));
cleanup();
}
-void NetworkResourceLoader::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& redirectResponse)
+void NetworkResourceLoader::willSendRedirectedRequest(const ResourceRequest& request, const WebCore::ResourceRequest& redirectRequest, const ResourceResponse& redirectResponse)
{
- ASSERT_UNUSED(handle, handle == m_handle);
-
- // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect.
- ASSERT(!redirectResponse.isNull());
- ASSERT(isMainThread());
-
- m_suggestedRequestForWillSendRequest = request;
+ ++m_redirectCount;
+
+ if (isSynchronous()) {
+ ResourceRequest overridenRequest = redirectRequest;
+ // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
+ // This includes at least updating host records, and comparing the current request instead of the original request here.
+ if (!protocolHostAndPortAreEqual(originalRequest().url(), redirectRequest.url())) {
+ ASSERT(m_synchronousLoadData->error.isNull());
+ m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
+ m_networkLoad->clearCurrentRequest();
+ overridenRequest = ResourceRequest();
+ }
+ continueWillSendRequest(overridenRequest);
+ return;
+ }
+ sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
- // This message is DispatchMessageEvenWhenWaitingForSyncReply to avoid a situation where the NetworkProcess is deadlocked waiting for 6 connections
- // to complete while the WebProcess is waiting for a 7th to complete.
- sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(request, redirectResponse), CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
+#if ENABLE(NETWORK_CACHE)
+ if (canUseCachedRedirect(request))
+ NetworkCache::singleton().storeRedirect(request, redirectResponse, redirectRequest);
+#else
+ UNUSED_PARAM(request);
+#endif
}
void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest& newRequest)
{
- m_suggestedRequestForWillSendRequest.updateFromDelegatePreservingOldHTTPBody(newRequest.nsURLRequest(DoNotUpdateHTTPBody));
+#if ENABLE(NETWORK_CACHE)
+ if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
+ LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
- RunLoop::main()->dispatch(bind(&NetworkResourceLoadScheduler::receivedRedirect, &NetworkProcess::shared().networkResourceLoadScheduler(), this, m_suggestedRequestForWillSendRequest.url()));
- m_handle->continueWillSendRequest(m_suggestedRequestForWillSendRequest);
+ if (canUseCachedRedirect(newRequest))
+ retrieveCacheEntry(newRequest);
+ else
+ startNetworkLoad(newRequest);
- m_suggestedRequestForWillSendRequest = ResourceRequest();
+ m_isWaitingContinueWillSendRequestForCachedRedirect = false;
+ return;
+ }
+#endif
+ m_networkLoad->continueWillSendRequest(newRequest);
}
void NetworkResourceLoader::continueDidReceiveResponse()
{
// FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
// Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
- if (!m_handle)
- return;
-
- m_handle->continueDidReceiveResponse();
+ if (m_networkLoad)
+ m_networkLoad->continueDidReceiveResponse();
}
-void NetworkResourceLoader::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
- ASSERT_UNUSED(handle, handle == m_handle);
-
- send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
+ if (!isSynchronous())
+ send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
}
-void NetworkResourceLoader::wasBlocked(ResourceHandle* handle)
+void NetworkResourceLoader::startBufferingTimerIfNeeded()
{
- ASSERT_UNUSED(handle, handle == m_handle);
-
- didFail(handle, WebKit::blockedError(request()));
+ if (isSynchronous())
+ return;
+ if (m_bufferingTimer.isActive())
+ return;
+ m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
}
-void NetworkResourceLoader::cannotShowURL(ResourceHandle* handle)
+void NetworkResourceLoader::bufferingTimerFired()
{
- ASSERT_UNUSED(handle, handle == m_handle);
+ ASSERT(m_bufferedData);
+ ASSERT(m_networkLoad);
- didFail(handle, WebKit::cannotShowURLError(request()));
+ if (m_bufferedData->isEmpty())
+ return;
+
+ IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
+ size_t encodedLength = m_bufferedDataEncodedDataLength;
+
+ m_bufferedData = SharedBuffer::create();
+ m_bufferedDataEncodedDataLength = 0;
+
+ sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
}
-bool NetworkResourceLoader::shouldUseCredentialStorage(ResourceHandle* handle)
+bool NetworkResourceLoader::sendBufferMaybeAborting(SharedBuffer& buffer, size_t encodedDataLength)
{
- ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start().
+ ASSERT(!isSynchronous());
- // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked.
- // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer.
-
- // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one.
+#if PLATFORM(COCOA)
+ ShareableResource::Handle shareableResourceHandle;
+ NetworkResourceLoader::tryGetShareableHandleFromSharedBuffer(shareableResourceHandle, buffer);
+ if (!shareableResourceHandle.isNull()) {
+ send(Messages::WebResourceLoader::DidReceiveResource(shareableResourceHandle, currentTime()));
+ abort();
+ return false;
+ }
+#endif
- return allowStoredCredentials() == AllowStoredCredentials;
+ IPC::SharedBufferDataReference dataReference(&buffer);
+ return sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
}
-void NetworkResourceLoader::shouldUseCredentialStorageAsync(ResourceHandle* handle)
+#if ENABLE(NETWORK_CACHE)
+void NetworkResourceLoader::tryStoreAsCacheEntry()
{
- ASSERT_UNUSED(handle, handle == m_handle);
+ if (!canUseCache(m_networkLoad->currentRequest()))
+ return;
+ if (!m_bufferedDataForCache)
+ return;
- handle->continueShouldUseCredentialStorage(shouldUseCredentialStorage(handle));
+ // Keep the connection alive.
+ RefPtr<NetworkConnectionToWebProcess> connection(&connectionToWebProcess());
+ RefPtr<NetworkResourceLoader> loader(this);
+ NetworkCache::singleton().store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader, connection](NetworkCache::MappedBody& mappedBody) {
+#if ENABLE(SHAREABLE_RESOURCE)
+ if (mappedBody.shareableResourceHandle.isNull())
+ return;
+ LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
+ loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
+#endif
+ });
}
-void NetworkResourceLoader::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
+void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
{
- ASSERT_UNUSED(handle, handle == m_handle);
-
- // FIXME (http://webkit.org/b/115291): Since we go straight to the UI process for authentication we don't get WebCore's
- // cross-origin check before asking the client for credentials.
- // Therefore we are too permissive in the case where the ClientCredentialPolicy is DoNotAskClientForCrossOriginCredentials.
- if (clientCredentialPolicy() == DoNotAskClientForAnyCredentials) {
- challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
- return;
+ if (isSynchronous()) {
+ m_synchronousLoadData->response = entry->response();
+ sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
+ } else {
+ bool needsContinueDidReceiveResponseMessage = originalRequest().requester() == ResourceRequest::Requester::Main;
+ sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
+
+#if ENABLE(SHAREABLE_RESOURCE)
+ if (!entry->shareableResourceHandle().isNull())
+ send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle(), currentTime()));
+ else {
+#endif
+ bool shouldContinue = sendBufferMaybeAborting(*entry->buffer(), entry->buffer()->size());
+ if (!shouldContinue)
+ return;
+ send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
+#if ENABLE(SHAREABLE_RESOURCE)
+ }
+#endif
}
- NetworkProcess::shared().authenticationManager().didReceiveAuthenticationChallenge(webPageID(), webFrameID(), challenge);
+ cleanup();
}
-void NetworkResourceLoader::didCancelAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
+void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
{
- ASSERT_UNUSED(handle, handle == m_handle);
+ ASSERT(!m_networkLoad);
+
+ // If the request is already conditional then the revalidation was not triggered by the disk cache
+ // and we should not overwrite the existing conditional headers.
+ ResourceRequest revalidationRequest = originalRequest();
+ if (!revalidationRequest.isConditional()) {
+ String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
+ String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
+ if (!eTag.isEmpty())
+ revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
+ if (!lastModified.isEmpty())
+ revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
+ }
+
+ m_cacheEntryForValidation = WTFMove(entry);
- // This function is probably not needed (see <rdar://problem/8960124>).
- notImplemented();
+ startNetworkLoad(revalidationRequest);
}
-CoreIPC::Connection* NetworkResourceLoader::messageSenderConnection()
+void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
{
- return connectionToWebProcess()->connection();
+ ASSERT(entry->redirectRequest());
+ LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
+
+ ++m_redirectCount;
+ sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(*entry->redirectRequest(), entry->response()));
+ m_isWaitingContinueWillSendRequestForCachedRedirect = true;
}
+#endif
-uint64_t NetworkResourceLoader::messageSenderDestinationID()
+IPC::Connection* NetworkResourceLoader::messageSenderConnection()
{
- return identifier();
+ return connectionToWebProcess().connection();
}
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
-void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace)
+void NetworkResourceLoader::consumeSandboxExtensions()
{
- ASSERT(isMainThread());
- ASSERT_UNUSED(handle, handle == m_handle);
+ ASSERT(!m_didConsumeSandboxExtensions);
+
+ for (auto& extension : m_parameters.requestBodySandboxExtensions)
+ extension->consume();
- // This message is DispatchMessageEvenWhenWaitingForSyncReply to avoid a situation where the NetworkProcess is deadlocked
- // waiting for 6 connections to complete while the WebProcess is waiting for a 7th to complete.
- sendAbortingOnFailure(Messages::WebResourceLoader::CanAuthenticateAgainstProtectionSpace(protectionSpace), CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
+ if (auto& extension = m_parameters.resourceSandboxExtension)
+ extension->consume();
+
+ for (auto& fileReference : m_fileReferences)
+ fileReference->prepareForFileAccess();
+
+ m_didConsumeSandboxExtensions = true;
}
-void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
+void NetworkResourceLoader::invalidateSandboxExtensions()
{
- m_handle->continueCanAuthenticateAgainstProtectionSpace(result);
-}
+ if (m_didConsumeSandboxExtensions) {
+ for (auto& extension : m_parameters.requestBodySandboxExtensions)
+ extension->revoke();
+ if (auto& extension = m_parameters.resourceSandboxExtension)
+ extension->revoke();
+ for (auto& fileReference : m_fileReferences)
+ fileReference->revokeFileAccess();
+
+ m_didConsumeSandboxExtensions = false;
+ }
-#endif
+ m_fileReferences.clear();
+}
-#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
-bool NetworkResourceLoader::supportsDataArray()
+template<typename T>
+bool NetworkResourceLoader::sendAbortingOnFailure(T&& message, unsigned messageSendFlags)
{
- notImplemented();
- return false;
+ bool result = messageSenderConnection()->send(std::forward<T>(message), messageSenderDestinationID(), messageSendFlags);
+ if (!result)
+ abort();
+ return result;
}
-void NetworkResourceLoader::didReceiveDataArray(ResourceHandle*, CFArrayRef)
+void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(const ProtectionSpace& protectionSpace)
{
- ASSERT_NOT_REACHED();
- notImplemented();
-}
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ sendAbortingOnFailure(Messages::WebResourceLoader::CanAuthenticateAgainstProtectionSpace(protectionSpace));
+#else
+ UNUSED_PARAM(protectionSpace);
#endif
+}
-#if PLATFORM(MAC)
-void NetworkResourceLoader::willStopBufferingData(ResourceHandle*, const char*, int)
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
{
- notImplemented();
+ m_networkLoad->continueCanAuthenticateAgainstProtectionSpace(result);
}
-#endif // PLATFORM(MAC)
+#endif
} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h b/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h
index 798cccf20..d9810dcb4 100644
--- a/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h
+++ b/Source/WebKit2/NetworkProcess/NetworkResourceLoader.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
@@ -26,116 +26,146 @@
#ifndef NetworkResourceLoader_h
#define NetworkResourceLoader_h
-#if ENABLE(NETWORK_PROCESS)
-
#include "MessageSender.h"
-#include "SchedulableLoader.h"
+#include "NetworkConnectionToWebProcessMessages.h"
+#include "NetworkLoadClient.h"
+#include "NetworkResourceLoadParameters.h"
#include "ShareableResource.h"
-#include <WebCore/ResourceHandleClient.h>
-#include <WebCore/RunLoop.h>
-
-typedef const struct _CFCachedURLResponse* CFCachedURLResponseRef;
+#include <WebCore/Timer.h>
+#include <wtf/Optional.h>
namespace WebCore {
-class ResourceBuffer;
-class ResourceHandle;
+class BlobDataFileReference;
class ResourceRequest;
}
namespace WebKit {
class NetworkConnectionToWebProcess;
-class RemoteNetworkingContext;
+class NetworkLoad;
+class SandboxExtension;
-class NetworkResourceLoader : public SchedulableLoader, public WebCore::ResourceHandleClient, public CoreIPC::MessageSender {
+namespace NetworkCache {
+class Entry;
+}
+
+class NetworkResourceLoader final : public RefCounted<NetworkResourceLoader>, public NetworkLoadClient, public IPC::MessageSender {
public:
- static RefPtr<NetworkResourceLoader> create(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection)
+ static Ref<NetworkResourceLoader> create(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply = nullptr)
{
- return adoptRef(new NetworkResourceLoader(parameters, connection));
+ return adoptRef(*new NetworkResourceLoader(parameters, connection, WTFMove(reply)));
}
-
- ~NetworkResourceLoader();
-
- WebCore::ResourceHandle* handle() const { return m_handle.get(); }
- void didConvertHandleToDownload();
-
- virtual void start() OVERRIDE;
- virtual void abort() OVERRIDE;
-
- // ResourceHandleClient methods
- virtual void willSendRequestAsync(WebCore::ResourceHandle*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse) OVERRIDE;
- virtual void didSendData(WebCore::ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) OVERRIDE;
- virtual void didReceiveResponseAsync(WebCore::ResourceHandle*, const WebCore::ResourceResponse&) OVERRIDE;
- virtual void didReceiveData(WebCore::ResourceHandle*, const char*, int, int encodedDataLength) OVERRIDE;
- virtual void didReceiveBuffer(WebCore::ResourceHandle*, PassRefPtr<WebCore::SharedBuffer>, int encodedDataLength) OVERRIDE;
- virtual void didFinishLoading(WebCore::ResourceHandle*, double finishTime) OVERRIDE;
- virtual void didFail(WebCore::ResourceHandle*, const WebCore::ResourceError&) OVERRIDE;
- virtual void wasBlocked(WebCore::ResourceHandle*) OVERRIDE;
- virtual void cannotShowURL(WebCore::ResourceHandle*) OVERRIDE;
- virtual bool shouldUseCredentialStorage(WebCore::ResourceHandle*) OVERRIDE;
- virtual void shouldUseCredentialStorageAsync(WebCore::ResourceHandle*) OVERRIDE;
- virtual void didReceiveAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&) OVERRIDE;
- virtual void didCancelAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&) OVERRIDE;
- virtual bool usesAsyncCallbacks() OVERRIDE { return true; }
+ virtual ~NetworkResourceLoader();
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
- virtual void canAuthenticateAgainstProtectionSpaceAsync(WebCore::ResourceHandle*, const WebCore::ProtectionSpace&) OVERRIDE;
-#endif
+ const WebCore::ResourceRequest& originalRequest() const { return m_parameters.request; }
-#if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
- virtual bool supportsDataArray() OVERRIDE;
- virtual void didReceiveDataArray(WebCore::ResourceHandle*, CFArrayRef) OVERRIDE;
-#endif
+ NetworkLoad* networkLoad() const { return m_networkLoad.get(); }
+
+ void start();
+ void abort();
-#if PLATFORM(MAC)
+ void setDefersLoading(bool);
+
+#if PLATFORM(COCOA)
static size_t fileBackedResourceMinimumSize();
- virtual void willCacheResponseAsync(WebCore::ResourceHandle*, NSCachedURLResponse *) OVERRIDE;
- virtual void willStopBufferingData(WebCore::ResourceHandle*, const char*, int) OVERRIDE;
-#endif // PLATFORM(MAC)
+ virtual void willCacheResponseAsync(CFCachedURLResponseRef) override;
+#endif
// Message handlers.
- void didReceiveNetworkResourceLoaderMessage(CoreIPC::Connection*, CoreIPC::MessageDecoder&);
+ void didReceiveNetworkResourceLoaderMessage(IPC::Connection&, IPC::MessageDecoder&);
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+#if PLATFORM(COCOA)
static void tryGetShareableHandleFromCFURLCachedResponse(ShareableResource::Handle&, CFCachedURLResponseRef);
+ static void tryGetShareableHandleFromSharedBuffer(ShareableResource::Handle&, WebCore::SharedBuffer&);
+#endif
+
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ void continueCanAuthenticateAgainstProtectionSpace(bool);
#endif
+ void continueWillSendRequest(const WebCore::ResourceRequest& newRequest);
+
+ WebCore::SharedBuffer* bufferedData() { return m_bufferedData.get(); }
+ const WebCore::ResourceResponse& response() const { return m_response; }
+
+ NetworkConnectionToWebProcess& connectionToWebProcess() { return m_connection; }
+ WebCore::SessionID sessionID() const { return m_parameters.sessionID; }
+ ResourceLoadIdentifier identifier() const { return m_parameters.identifier; }
+
+ struct SynchronousLoadData;
+
+ // NetworkLoadClient.
+ virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
+ virtual void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) override;
+ virtual bool isSynchronous() const override;
+ virtual void willSendRedirectedRequest(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse) override;
+ virtual ShouldContinueDidReceiveResponse didReceiveResponse(const WebCore::ResourceResponse&) override;
+ virtual void didReceiveBuffer(RefPtr<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) override;
+ virtual void didFinishLoading(double finishTime) override;
+ virtual void didFailLoading(const WebCore::ResourceError&) override;
+ virtual void didConvertToDownload() override;
private:
- NetworkResourceLoader(const NetworkResourceLoadParameters&, NetworkConnectionToWebProcess*);
+ NetworkResourceLoader(const NetworkResourceLoadParameters&, NetworkConnectionToWebProcess&, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&&);
- // CoreIPC::MessageSender
- virtual CoreIPC::Connection* messageSenderConnection() OVERRIDE;
- virtual uint64_t messageSenderDestinationID() OVERRIDE;
+ // IPC::MessageSender
+ virtual IPC::Connection* messageSenderConnection() override;
+ virtual uint64_t messageSenderDestinationID() override { return m_parameters.identifier; }
- void continueWillSendRequest(const WebCore::ResourceRequest& newRequest);
- void continueDidReceiveResponse();
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
- void continueCanAuthenticateAgainstProtectionSpace(bool);
+#if ENABLE(NETWORK_CACHE)
+ bool canUseCache(const WebCore::ResourceRequest&) const;
+ bool canUseCachedRedirect(const WebCore::ResourceRequest&) const;
+
+ void tryStoreAsCacheEntry();
+ void retrieveCacheEntry(const WebCore::ResourceRequest&);
+ void didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry>);
+ void validateCacheEntry(std::unique_ptr<NetworkCache::Entry>);
+ void dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry>);
#endif
+ void startNetworkLoad(const WebCore::ResourceRequest&);
+ void continueDidReceiveResponse();
+
void cleanup();
void platformDidReceiveResponse(const WebCore::ResourceResponse&);
- template<typename U> bool sendAbortingOnFailure(const U& message, unsigned messageSendFlags = 0);
+ void startBufferingTimerIfNeeded();
+ void bufferingTimerFired();
+ bool sendBufferMaybeAborting(WebCore::SharedBuffer&, size_t encodedDataLength);
+
+ void consumeSandboxExtensions();
+ void invalidateSandboxExtensions();
+
+ template<typename T> bool sendAbortingOnFailure(T&& message, unsigned messageSendFlags = 0);
- RefPtr<RemoteNetworkingContext> m_networkingContext;
- RefPtr<WebCore::ResourceHandle> m_handle;
+ const NetworkResourceLoadParameters m_parameters;
- // Keep the suggested request around while asynchronously asking to update it, because some parts of the request don't survive IPC.
- WebCore::ResourceRequest m_suggestedRequestForWillSendRequest;
+ Ref<NetworkConnectionToWebProcess> m_connection;
- uint64_t m_bytesReceived;
+ std::unique_ptr<NetworkLoad> m_networkLoad;
- bool m_handleConvertedToDownload;
+ WebCore::ResourceResponse m_response;
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
- static void tryGetShareableHandleFromSharedBuffer(ShareableResource::Handle&, WebCore::SharedBuffer*);
+ size_t m_bytesReceived { 0 };
+ size_t m_bufferedDataEncodedDataLength { 0 };
+ RefPtr<WebCore::SharedBuffer> m_bufferedData;
+ unsigned m_redirectCount { 0 };
+
+ std::unique_ptr<SynchronousLoadData> m_synchronousLoadData;
+ Vector<RefPtr<WebCore::BlobDataFileReference>> m_fileReferences;
+
+ bool m_didConvertToDownload { false };
+ bool m_didConsumeSandboxExtensions { false };
+ bool m_defersLoading { false };
+
+ WebCore::Timer m_bufferingTimer;
+#if ENABLE(NETWORK_CACHE)
+ RefPtr<WebCore::SharedBuffer> m_bufferedDataForCache;
+ std::unique_ptr<NetworkCache::Entry> m_cacheEntryForValidation;
+ bool m_isWaitingContinueWillSendRequestForCachedRedirect { false };
#endif
};
} // namespace WebKit
-#endif // ENABLE(NETWORK_PROCESS)
-
#endif // NetworkResourceLoader_h
diff --git a/Source/WebKit2/NetworkProcess/NetworkResourceLoader.messages.in b/Source/WebKit2/NetworkProcess/NetworkResourceLoader.messages.in
index 00706af43..ebb8d7cd3 100644
--- a/Source/WebKit2/NetworkProcess/NetworkResourceLoader.messages.in
+++ b/Source/WebKit2/NetworkProcess/NetworkResourceLoader.messages.in
@@ -24,5 +24,7 @@ messages -> NetworkResourceLoader LegacyReceiver {
ContinueWillSendRequest(WebCore::ResourceRequest request)
ContinueDidReceiveResponse()
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
ContinueCanAuthenticateAgainstProtectionSpace(bool canAuthenticate)
+#endif
}
diff --git a/Source/WebKit2/NetworkProcess/NetworkSession.h b/Source/WebKit2/NetworkProcess/NetworkSession.h
new file mode 100644
index 000000000..083ed96fe
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/NetworkSession.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkSession_h
+#define NetworkSession_h
+
+#if PLATFORM(COCOA)
+OBJC_CLASS NSURLSession;
+OBJC_CLASS NSOperationQueue;
+OBJC_CLASS WKNetworkSessionDelegate;
+#endif
+
+#include "DownloadID.h"
+#include "NetworkDataTask.h"
+#include <WebCore/SessionID.h>
+#include <wtf/HashMap.h>
+#include <wtf/Ref.h>
+#include <wtf/RefCounted.h>
+
+namespace WebKit {
+
+class CustomProtocolManager;
+
+class NetworkSession {
+ friend class NetworkDataTask;
+public:
+ enum class Type {
+ Normal,
+ Ephemeral
+ };
+ NetworkSession(Type, WebCore::SessionID, CustomProtocolManager*);
+ ~NetworkSession();
+
+ static NetworkSession& defaultSession();
+
+ NetworkDataTask* dataTaskForIdentifier(NetworkDataTask::TaskIdentifier);
+
+ void addDownloadID(NetworkDataTask::TaskIdentifier, DownloadID);
+ DownloadID downloadID(NetworkDataTask::TaskIdentifier);
+ DownloadID takeDownloadID(NetworkDataTask::TaskIdentifier);
+
+private:
+ HashMap<NetworkDataTask::TaskIdentifier, NetworkDataTask*> m_dataTaskMap;
+ HashMap<NetworkDataTask::TaskIdentifier, DownloadID> m_downloadMap;
+#if PLATFORM(COCOA)
+ RetainPtr<NSURLSession> m_sessionWithCredentialStorage;
+ RetainPtr<NSURLSession> m_sessionWithoutCredentialStorage;
+ RetainPtr<WKNetworkSessionDelegate> m_sessionDelegate;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // NetworkSession_h
diff --git a/Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.h b/Source/WebKit2/NetworkProcess/RemoteNetworkingContext.h
index d0402246b..e44a5d078 100644
--- a/Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.h
+++ b/Source/WebKit2/NetworkProcess/RemoteNetworkingContext.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 University of Szeged. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,40 +28,54 @@
#define RemoteNetworkingContext_h
#include <WebCore/NetworkingContext.h>
+#include <WebCore/SessionID.h>
namespace WebKit {
-class RemoteNetworkingContext : public WebCore::NetworkingContext {
+class RemoteNetworkingContext final : public WebCore::NetworkingContext {
public:
- static PassRefPtr<RemoteNetworkingContext> create(bool needsSiteSpecificQuirks, bool localFileContentSniffingEnabled, bool privateBrowsingEnabled, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
+ static Ref<RemoteNetworkingContext> create(WebCore::SessionID sessionID, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
{
- return adoptRef(new RemoteNetworkingContext(needsSiteSpecificQuirks, localFileContentSniffingEnabled, privateBrowsingEnabled, shouldClearReferrerOnHTTPSToHTTPRedirect));
+ return adoptRef(*new RemoteNetworkingContext(sessionID, shouldClearReferrerOnHTTPSToHTTPRedirect));
}
virtual ~RemoteNetworkingContext();
- static void setPrivateBrowsingStorageSessionIdentifierBase(const String&);
- static void ensurePrivateBrowsingSession();
- static void destroyPrivateBrowsingSession();
+ // FIXME: Remove platform-specific code and use SessionTracker.
+ static void ensurePrivateBrowsingSession(WebCore::SessionID);
- static WebCore::NetworkStorageSession* privateBrowsingSession();
-
- virtual bool shouldClearReferrerOnHTTPSToHTTPRedirect() const OVERRIDE;
+ virtual bool shouldClearReferrerOnHTTPSToHTTPRedirect() const override { return m_shouldClearReferrerOnHTTPSToHTTPRedirect; }
private:
- RemoteNetworkingContext(bool needsSiteSpecificQuirks, bool localFileContentSniffingEnabled, bool privateBrowsingEnabled, bool m_shouldClearReferrerOnHTTPSToHTTPRedirect);
+ RemoteNetworkingContext(WebCore::SessionID sessionID, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
+ : m_sessionID(sessionID)
+ , m_shouldClearReferrerOnHTTPSToHTTPRedirect(shouldClearReferrerOnHTTPSToHTTPRedirect)
+ {
+ }
- virtual bool isValid() const OVERRIDE;
+ virtual bool isValid() const override;
+ virtual WebCore::NetworkStorageSession& storageSession() const override;
- virtual bool needsSiteSpecificQuirks() const OVERRIDE;
- virtual bool localFileContentSniffingEnabled() const OVERRIDE;
- virtual WebCore::NetworkStorageSession& storageSession() const OVERRIDE;
- virtual RetainPtr<CFDataRef> sourceApplicationAuditData() const OVERRIDE;
- virtual WebCore::ResourceError blockedError(const WebCore::ResourceRequest&) const OVERRIDE;
+#if PLATFORM(COCOA)
+ void setLocalFileContentSniffingEnabled(bool value) { m_localFileContentSniffingEnabled = value; }
+ virtual bool localFileContentSniffingEnabled() const override;
+ virtual RetainPtr<CFDataRef> sourceApplicationAuditData() const override;
+ virtual String sourceApplicationIdentifier() const override;
+ virtual WebCore::ResourceError blockedError(const WebCore::ResourceRequest&) const override;
+#endif
- bool m_needsSiteSpecificQuirks;
- bool m_localFileContentSniffingEnabled;
- bool m_privateBrowsingEnabled;
+ WebCore::SessionID m_sessionID;
bool m_shouldClearReferrerOnHTTPSToHTTPRedirect;
+
+#if PLATFORM(COCOA)
+ bool m_localFileContentSniffingEnabled = false;
+#endif
+
+#if PLATFORM(QT)
+ QObject* originatingObject() const override { return nullptr; }
+ QNetworkAccessManager* networkAccessManager() const override;
+ bool mimeSniffingEnabled() const override { return true; }
+ bool thirdPartyCookiePolicyPermission(const QUrl&) const override { return true; }
+#endif
};
}
diff --git a/Source/WebKit2/NetworkProcess/SchedulableLoader.cpp b/Source/WebKit2/NetworkProcess/SchedulableLoader.cpp
deleted file mode 100644
index ae7b20397..000000000
--- a/Source/WebKit2/NetworkProcess/SchedulableLoader.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2013 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 "SchedulableLoader.h"
-
-#if ENABLE(NETWORK_PROCESS)
-
-#include "NetworkBlobRegistry.h"
-#include "NetworkConnectionToWebProcess.h"
-#include "NetworkResourceLoadParameters.h"
-#include <WebCore/FormData.h>
-
-using namespace WebCore;
-
-namespace WebKit {
-
-SchedulableLoader::SchedulableLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection)
- : m_identifier(parameters.identifier)
- , m_webPageID(parameters.webPageID)
- , m_webFrameID(parameters.webFrameID)
- , m_request(parameters.request)
- , m_priority(parameters.priority)
- , m_contentSniffingPolicy(parameters.contentSniffingPolicy)
- , m_allowStoredCredentials(parameters.allowStoredCredentials)
- , m_clientCredentialPolicy(parameters.clientCredentialPolicy)
- , m_inPrivateBrowsingMode(parameters.inPrivateBrowsingMode)
- , m_shouldClearReferrerOnHTTPSToHTTPRedirect(parameters.shouldClearReferrerOnHTTPSToHTTPRedirect)
- , m_isLoadingMainResource(parameters.isMainResource)
- , m_sandboxExtensionsAreConsumed(false)
- , m_connection(connection)
-{
- // Either this loader has both a webPageID and webFrameID, or it is not allowed to ask the client for authentication credentials.
- // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
- // Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
- ASSERT((m_webPageID && m_webFrameID) || m_clientCredentialPolicy == DoNotAskClientForAnyCredentials);
-
- for (size_t i = 0, count = parameters.requestBodySandboxExtensions.size(); i < count; ++i) {
- if (RefPtr<SandboxExtension> extension = SandboxExtension::create(parameters.requestBodySandboxExtensions[i]))
- m_requestBodySandboxExtensions.append(extension);
- }
-
-#if ENABLE(BLOB)
- if (m_request.httpBody()) {
- const Vector<FormDataElement>& elements = m_request.httpBody()->elements();
- for (size_t i = 0, count = elements.size(); i < count; ++i) {
- if (elements[i].m_type == FormDataElement::encodedBlob) {
- Vector<RefPtr<SandboxExtension>> blobElementExtensions = NetworkBlobRegistry::shared().sandboxExtensions(elements[i].m_url);
- m_requestBodySandboxExtensions.appendVector(blobElementExtensions);
- }
- }
- }
-
- if (m_request.url().protocolIs("blob")) {
- ASSERT(!SandboxExtension::create(parameters.resourceSandboxExtension));
- m_resourceSandboxExtensions = NetworkBlobRegistry::shared().sandboxExtensions(m_request.url());
- } else
-#endif
- if (RefPtr<SandboxExtension> resourceSandboxExtension = SandboxExtension::create(parameters.resourceSandboxExtension))
- m_resourceSandboxExtensions.append(resourceSandboxExtension);
-}
-
-SchedulableLoader::~SchedulableLoader()
-{
- ASSERT(!m_hostRecord);
-}
-
-void SchedulableLoader::consumeSandboxExtensions()
-{
- for (size_t i = 0, count = m_requestBodySandboxExtensions.size(); i < count; ++i)
- m_requestBodySandboxExtensions[i]->consume();
-
- for (size_t i = 0, count = m_resourceSandboxExtensions.size(); i < count; ++i)
- m_resourceSandboxExtensions[i]->consume();
-
- m_sandboxExtensionsAreConsumed = true;
-}
-
-void SchedulableLoader::invalidateSandboxExtensions()
-{
- if (m_sandboxExtensionsAreConsumed) {
- for (size_t i = 0, count = m_requestBodySandboxExtensions.size(); i < count; ++i)
- m_requestBodySandboxExtensions[i]->revoke();
- for (size_t i = 0, count = m_resourceSandboxExtensions.size(); i < count; ++i)
- m_resourceSandboxExtensions[i]->revoke();
- }
-
- m_requestBodySandboxExtensions.clear();
- m_resourceSandboxExtensions.clear();
-
- m_sandboxExtensionsAreConsumed = false;
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/SchedulableLoader.h b/Source/WebKit2/NetworkProcess/SchedulableLoader.h
deleted file mode 100644
index 81ff5e5ce..000000000
--- a/Source/WebKit2/NetworkProcess/SchedulableLoader.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef SchedulableLoader_h
-#define SchedulableLoader_h
-
-#include "HostRecord.h"
-#include <WebCore/ResourceLoaderOptions.h>
-#include <WebCore/ResourceRequest.h>
-#include <wtf/MainThread.h>
-#include <wtf/RefCounted.h>
-
-#if ENABLE(NETWORK_PROCESS)
-
-namespace WebKit {
-
-class NetworkConnectionToWebProcess;
-class NetworkResourceLoadParameters;
-class SandboxExtension;
-
-class SchedulableLoader : public RefCounted<SchedulableLoader> {
-public:
- virtual ~SchedulableLoader();
-
- ResourceLoadIdentifier identifier() const { return m_identifier; }
- uint64_t webPageID() const { return m_webPageID; }
- uint64_t webFrameID() const { return m_webFrameID; }
- const WebCore::ResourceRequest& request() const { return m_request; }
- WebCore::ResourceLoadPriority priority() const { return m_priority; }
- WebCore::ContentSniffingPolicy contentSniffingPolicy() const { return m_contentSniffingPolicy; }
- WebCore::StoredCredentials allowStoredCredentials() const { return m_allowStoredCredentials; }
- WebCore::ClientCredentialPolicy clientCredentialPolicy() const { return m_clientCredentialPolicy; }
- bool inPrivateBrowsingMode() const { return m_inPrivateBrowsingMode; }
- bool isLoadingMainResource() const { return m_isLoadingMainResource; }
-
- NetworkConnectionToWebProcess* connectionToWebProcess() const { return m_connection.get(); }
-
- virtual void start() = 0;
- virtual void abort() = 0;
-
- virtual bool isSynchronous() { return false; }
-
- void setHostRecord(HostRecord* hostRecord) { ASSERT(isMainThread()); m_hostRecord = hostRecord; }
- HostRecord* hostRecord() const { ASSERT(isMainThread()); return m_hostRecord.get(); }
-
-protected:
- SchedulableLoader(const NetworkResourceLoadParameters&, NetworkConnectionToWebProcess*);
-
- void consumeSandboxExtensions();
- void invalidateSandboxExtensions();
-
- bool shouldClearReferrerOnHTTPSToHTTPRedirect() const { return m_shouldClearReferrerOnHTTPSToHTTPRedirect; }
-
-private:
- ResourceLoadIdentifier m_identifier;
- uint64_t m_webPageID;
- uint64_t m_webFrameID;
- WebCore::ResourceRequest m_request;
- WebCore::ResourceLoadPriority m_priority;
- WebCore::ContentSniffingPolicy m_contentSniffingPolicy;
- WebCore::StoredCredentials m_allowStoredCredentials;
- WebCore::ClientCredentialPolicy m_clientCredentialPolicy;
- bool m_inPrivateBrowsingMode;
- bool m_shouldClearReferrerOnHTTPSToHTTPRedirect;
- bool m_isLoadingMainResource;
-
- Vector<RefPtr<SandboxExtension>> m_requestBodySandboxExtensions;
- Vector<RefPtr<SandboxExtension>> m_resourceSandboxExtensions;
- bool m_sandboxExtensionsAreConsumed;
-
- RefPtr<NetworkConnectionToWebProcess> m_connection;
-
- RefPtr<HostRecord> m_hostRecord;
-};
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
-
-#endif // SchedulableLoader_h
diff --git a/Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.cpp b/Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.cpp
deleted file mode 100644
index 02b05ed7d..000000000
--- a/Source/WebKit2/NetworkProcess/SyncNetworkResourceLoader.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2013 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 "SyncNetworkResourceLoader.h"
-
-#if ENABLE(NETWORK_PROCESS)
-
-#include "DataReference.h"
-#include "NetworkProcess.h"
-#include "RemoteNetworkingContext.h"
-#include <WebCore/ResourceError.h>
-#include <WebCore/ResourceHandle.h>
-#include <WebCore/ResourceResponse.h>
-#include <wtf/MainThread.h>
-
-using namespace WebCore;
-
-namespace WebKit {
-
-SyncNetworkResourceLoader::SyncNetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> reply)
- : SchedulableLoader(parameters, connection)
- , m_delayedReply(reply)
-{
-}
-
-void SyncNetworkResourceLoader::start()
-{
- // FIXME (NetworkProcess): This is called on the NetworkProcess main thread, blocking any other requests from being scheduled.
- // This should move to a background thread, but we'd either need to be sure that:
- // A - ResourceHandle::loadResourceSynchronously is safe to run on a background thread.
- // B - Write custom loading logic that is known to be safe on a background thread.
-
- ASSERT(isMainThread());
-
- ResourceError error;
- ResourceResponse response;
- Vector<char> data;
-
- // FIXME (NetworkProcess): Create RemoteNetworkingContext with actual settings.
- RefPtr<RemoteNetworkingContext> networkingContext = RemoteNetworkingContext::create(false, false, inPrivateBrowsingMode(), shouldClearReferrerOnHTTPSToHTTPRedirect());
-
- consumeSandboxExtensions();
-
- ResourceHandle::loadResourceSynchronously(networkingContext.get(), request(), allowStoredCredentials(), error, response, data);
-
- cleanup();
-
- m_delayedReply->send(error, response, CoreIPC::DataReference((uint8_t*)data.data(), data.size()));
-}
-
-void SyncNetworkResourceLoader::abort()
-{
- cleanup();
-}
-
-void SyncNetworkResourceLoader::cleanup()
-{
- invalidateSandboxExtensions();
- NetworkProcess::shared().networkResourceLoadScheduler().scheduleRemoveLoader(this);
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
new file mode 100644
index 000000000..9ea0d3f41
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2014-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 "NetworkCache.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "Logging.h"
+#include "NetworkCacheSpeculativeLoadManager.h"
+#include "NetworkCacheStatistics.h"
+#include "NetworkCacheStorage.h"
+#include <WebCore/CacheValidation.h>
+#include <WebCore/FileSystem.h>
+#include <WebCore/HTTPHeaderNames.h>
+#include <WebCore/NetworkStorageSession.h>
+#include <WebCore/PlatformCookieJar.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/ResourceResponse.h>
+#include <WebCore/SharedBuffer.h>
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/StringBuilder.h>
+
+#if PLATFORM(COCOA)
+#include <notify.h>
+#endif
+
+namespace WebKit {
+namespace NetworkCache {
+
+static const AtomicString& resourceType()
+{
+ ASSERT(WTF::isMainThread());
+ static NeverDestroyed<const AtomicString> resource("resource", AtomicString::ConstructFromLiteral);
+ return resource;
+}
+
+Cache& singleton()
+{
+ static NeverDestroyed<Cache> instance;
+ return instance;
+}
+
+#if PLATFORM(GTK)
+static void dumpFileChanged(Cache* cache)
+{
+ cache->dumpContentsToFile();
+}
+#endif
+
+bool Cache::initialize(const String& cachePath, const Parameters& parameters)
+{
+ m_storage = Storage::open(cachePath);
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ if (parameters.enableNetworkCacheSpeculativeRevalidation)
+ m_speculativeLoadManager = std::make_unique<SpeculativeLoadManager>(*m_storage);
+#endif
+
+ if (parameters.enableEfficacyLogging)
+ m_statistics = Statistics::open(cachePath);
+
+#if PLATFORM(COCOA)
+ // Triggers with "notifyutil -p com.apple.WebKit.Cache.dump".
+ if (m_storage) {
+ int token;
+ notify_register_dispatch("com.apple.WebKit.Cache.dump", &token, dispatch_get_main_queue(), ^(int) {
+ dumpContentsToFile();
+ });
+ }
+#endif
+#if PLATFORM(GTK)
+ // Triggers with "touch $cachePath/dump".
+ if (m_storage) {
+ CString dumpFilePath = WebCore::fileSystemRepresentation(WebCore::pathByAppendingComponent(m_storage->basePath(), "dump"));
+ GRefPtr<GFile> dumpFile = adoptGRef(g_file_new_for_path(dumpFilePath.data()));
+ GFileMonitor* monitor = g_file_monitor_file(dumpFile.get(), G_FILE_MONITOR_NONE, nullptr, nullptr);
+ g_signal_connect_swapped(monitor, "changed", G_CALLBACK(dumpFileChanged), this);
+ }
+#endif
+
+ LOG(NetworkCache, "(NetworkProcess) opened cache storage, success %d", !!m_storage);
+ return !!m_storage;
+}
+
+void Cache::setCapacity(size_t maximumSize)
+{
+ if (!m_storage)
+ return;
+ m_storage->setCapacity(maximumSize);
+}
+
+static Key makeCacheKey(const WebCore::ResourceRequest& request)
+{
+#if ENABLE(CACHE_PARTITIONING)
+ String partition = request.cachePartition();
+#else
+ String partition;
+#endif
+ if (partition.isEmpty())
+ partition = ASCIILiteral("No partition");
+
+ // FIXME: This implements minimal Range header disk cache support. We don't parse
+ // ranges so only the same exact range request will be served from the cache.
+ String range = request.httpHeaderField(WebCore::HTTPHeaderName::Range);
+ return { partition, resourceType(), range, request.url().string() };
+}
+
+static String headerValueForVary(const WebCore::ResourceRequest& request, const String& headerName)
+{
+ // Explicit handling for cookies is needed because they are added magically by the networking layer.
+ // FIXME: The value might have changed between making the request and retrieving the cookie here.
+ // We could fetch the cookie when making the request but that seems overkill as the case is very rare and it
+ // is a blocking operation. This should be sufficient to cover reasonable cases.
+ if (headerName == httpHeaderNameString(WebCore::HTTPHeaderName::Cookie))
+ return WebCore::cookieRequestHeaderFieldValue(WebCore::NetworkStorageSession::defaultStorageSession(), request.firstPartyForCookies(), request.url());
+ return request.httpHeaderField(headerName);
+}
+
+static Vector<std::pair<String, String>> collectVaryingRequestHeaders(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response)
+{
+ String varyValue = response.httpHeaderField(WebCore::HTTPHeaderName::Vary);
+ if (varyValue.isEmpty())
+ return { };
+ Vector<String> varyingHeaderNames;
+ varyValue.split(',', /*allowEmptyEntries*/ false, varyingHeaderNames);
+ Vector<std::pair<String, String>> varyingRequestHeaders;
+ varyingRequestHeaders.reserveCapacity(varyingHeaderNames.size());
+ for (auto& varyHeaderName : varyingHeaderNames) {
+ String headerName = varyHeaderName.stripWhiteSpace();
+ String headerValue = headerValueForVary(request, headerName);
+ varyingRequestHeaders.append(std::make_pair(headerName, headerValue));
+ }
+ return varyingRequestHeaders;
+}
+
+static bool verifyVaryingRequestHeaders(const Vector<std::pair<String, String>>& varyingRequestHeaders, const WebCore::ResourceRequest& request)
+{
+ for (auto& varyingRequestHeader : varyingRequestHeaders) {
+ // FIXME: Vary: * in response would ideally trigger a cache delete instead of a store.
+ if (varyingRequestHeader.first == "*")
+ return false;
+ String headerValue = headerValueForVary(request, varyingRequestHeader.first);
+ if (headerValue != varyingRequestHeader.second)
+ return false;
+ }
+ return true;
+}
+
+static bool cachePolicyAllowsExpired(WebCore::ResourceRequestCachePolicy policy)
+{
+ switch (policy) {
+ case WebCore::ReturnCacheDataElseLoad:
+ case WebCore::ReturnCacheDataDontLoad:
+ return true;
+ case WebCore::UseProtocolCachePolicy:
+ case WebCore::ReloadIgnoringCacheData:
+ return false;
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+static bool responseHasExpired(const WebCore::ResourceResponse& response, std::chrono::system_clock::time_point timestamp, Optional<std::chrono::microseconds> maxStale)
+{
+ if (response.cacheControlContainsNoCache())
+ return true;
+
+ auto age = WebCore::computeCurrentAge(response, timestamp);
+ auto lifetime = WebCore::computeFreshnessLifetimeForHTTPFamily(response, timestamp);
+
+ auto maximumStaleness = maxStale ? maxStale.value() : 0_ms;
+ bool hasExpired = age - lifetime > maximumStaleness;
+
+#ifndef LOG_DISABLED
+ if (hasExpired)
+ LOG(NetworkCache, "(NetworkProcess) needsRevalidation hasExpired age=%f lifetime=%f max-stale=%g", age, lifetime, maxStale);
+#endif
+
+ return hasExpired;
+}
+
+static bool responseNeedsRevalidation(const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, std::chrono::system_clock::time_point timestamp)
+{
+ auto requestDirectives = WebCore::parseCacheControlDirectives(request.httpHeaderFields());
+ if (requestDirectives.noCache)
+ return true;
+ // For requests we ignore max-age values other than zero.
+ if (requestDirectives.maxAge && requestDirectives.maxAge.value() == 0_ms)
+ return true;
+
+ return responseHasExpired(response, timestamp, requestDirectives.maxStale);
+}
+
+static UseDecision makeUseDecision(const Entry& entry, const WebCore::ResourceRequest& request)
+{
+ // The request is conditional so we force revalidation from the network. We merely check the disk cache
+ // so we can update the cache entry.
+ if (request.isConditional() && !entry.redirectRequest())
+ return UseDecision::Validate;
+
+ if (!verifyVaryingRequestHeaders(entry.varyingRequestHeaders(), request))
+ return UseDecision::NoDueToVaryingHeaderMismatch;
+
+ // We never revalidate in the case of a history navigation.
+ if (cachePolicyAllowsExpired(request.cachePolicy()))
+ return UseDecision::Use;
+
+ if (!responseNeedsRevalidation(entry.response(), request, entry.timeStamp()))
+ return UseDecision::Use;
+
+ if (!entry.response().hasCacheValidatorFields())
+ return UseDecision::NoDueToMissingValidatorFields;
+
+ return entry.redirectRequest() ? UseDecision::NoDueToExpiredRedirect : UseDecision::Validate;
+}
+
+static RetrieveDecision makeRetrieveDecision(const WebCore::ResourceRequest& request)
+{
+ // FIXME: Support HEAD requests.
+ if (request.httpMethod() != "GET")
+ return RetrieveDecision::NoDueToHTTPMethod;
+ if (request.cachePolicy() == WebCore::ReloadIgnoringCacheData && !request.isConditional())
+ return RetrieveDecision::NoDueToReloadIgnoringCache;
+
+ return RetrieveDecision::Yes;
+}
+
+// http://tools.ietf.org/html/rfc7231#page-48
+static bool isStatusCodeCacheableByDefault(int statusCode)
+{
+ switch (statusCode) {
+ case 200: // OK
+ case 203: // Non-Authoritative Information
+ case 204: // No Content
+ case 206: // Partial Content
+ case 300: // Multiple Choices
+ case 301: // Moved Permanently
+ case 404: // Not Found
+ case 405: // Method Not Allowed
+ case 410: // Gone
+ case 414: // URI Too Long
+ case 501: // Not Implemented
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isStatusCodePotentiallyCacheable(int statusCode)
+{
+ switch (statusCode) {
+ case 201: // Created
+ case 202: // Accepted
+ case 205: // Reset Content
+ case 302: // Found
+ case 303: // See Other
+ case 307: // Temporary redirect
+ case 403: // Forbidden
+ case 406: // Not Acceptable
+ case 415: // Unsupported Media Type
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isMediaMIMEType(const String& mimeType)
+{
+ if (mimeType.startsWith("video/", /*caseSensitive*/ false))
+ return true;
+ if (mimeType.startsWith("audio/", /*caseSensitive*/ false))
+ return true;
+ return false;
+}
+
+static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response)
+{
+ if (!originalRequest.url().protocolIsInHTTPFamily() || !response.isHTTP())
+ return StoreDecision::NoDueToProtocol;
+
+ if (originalRequest.httpMethod() != "GET")
+ return StoreDecision::NoDueToHTTPMethod;
+
+ auto requestDirectives = WebCore::parseCacheControlDirectives(originalRequest.httpHeaderFields());
+ if (requestDirectives.noStore)
+ return StoreDecision::NoDueToNoStoreRequest;
+
+ if (response.cacheControlContainsNoStore())
+ return StoreDecision::NoDueToNoStoreResponse;
+
+ if (!isStatusCodeCacheableByDefault(response.httpStatusCode())) {
+ // http://tools.ietf.org/html/rfc7234#section-4.3.2
+ bool hasExpirationHeaders = response.expires() || response.cacheControlMaxAge();
+ bool expirationHeadersAllowCaching = isStatusCodePotentiallyCacheable(response.httpStatusCode()) && hasExpirationHeaders;
+ if (!expirationHeadersAllowCaching)
+ return StoreDecision::NoDueToHTTPStatusCode;
+ }
+
+ bool isMainResource = originalRequest.requester() == WebCore::ResourceRequest::Requester::Main;
+ bool storeUnconditionallyForHistoryNavigation = isMainResource || originalRequest.priority() == WebCore::ResourceLoadPriority::VeryHigh;
+ if (!storeUnconditionallyForHistoryNavigation) {
+ auto now = std::chrono::system_clock::now();
+ bool hasNonZeroLifetime = !response.cacheControlContainsNoCache() && WebCore::computeFreshnessLifetimeForHTTPFamily(response, now) > 0_ms;
+
+ bool possiblyReusable = response.hasCacheValidatorFields() || hasNonZeroLifetime;
+ if (!possiblyReusable)
+ return StoreDecision::NoDueToUnlikelyToReuse;
+ }
+
+ // Media loaded via XHR is likely being used for MSE streaming (YouTube and Netflix for example).
+ // Streaming media fills the cache quickly and is unlikely to be reused.
+ // FIXME: We should introduce a separate media cache partition that doesn't affect other resources.
+ // FIXME: We should also make sure make the MSE paths are copy-free so we can use mapped buffers from disk effectively.
+ bool isLikelyStreamingMedia = originalRequest.requester() == WebCore::ResourceRequest::Requester::XHR && isMediaMIMEType(response.mimeType());
+ if (isLikelyStreamingMedia)
+ return StoreDecision::NoDueToStreamingMedia;
+
+ return StoreDecision::Yes;
+}
+
+void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameID& frameID, std::function<void (std::unique_ptr<Entry>)> completionHandler)
+{
+ ASSERT(isEnabled());
+ ASSERT(request.url().protocolIsInHTTPFamily());
+
+ LOG(NetworkCache, "(NetworkProcess) retrieving %s priority %d", request.url().string().ascii().data(), static_cast<int>(request.priority()));
+
+ if (m_statistics)
+ m_statistics->recordRetrievalRequest(frameID.first);
+
+ Key storageKey = makeCacheKey(request);
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ if (m_speculativeLoadManager)
+ m_speculativeLoadManager->registerLoad(frameID, request, storageKey);
+#endif
+
+ auto retrieveDecision = makeRetrieveDecision(request);
+ if (retrieveDecision != RetrieveDecision::Yes) {
+ if (m_statistics)
+ m_statistics->recordNotUsingCacheForRequest(frameID.first, storageKey, request, retrieveDecision);
+
+ completionHandler(nullptr);
+ return;
+ }
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ if (m_speculativeLoadManager && m_speculativeLoadManager->retrieve(frameID, storageKey, [request, completionHandler](std::unique_ptr<Entry> entry) {
+ if (entry && verifyVaryingRequestHeaders(entry->varyingRequestHeaders(), request))
+ completionHandler(WTFMove(entry));
+ else
+ completionHandler(nullptr);
+ }))
+ return;
+#endif
+
+ auto startTime = std::chrono::system_clock::now();
+ auto priority = static_cast<unsigned>(request.priority());
+
+ m_storage->retrieve(storageKey, priority, [this, request, completionHandler, startTime, storageKey, frameID](std::unique_ptr<Storage::Record> record) {
+ if (!record) {
+ LOG(NetworkCache, "(NetworkProcess) not found in storage");
+
+ if (m_statistics)
+ m_statistics->recordRetrievalFailure(frameID.first, storageKey, request);
+
+ completionHandler(nullptr);
+ return false;
+ }
+
+ ASSERT(record->key == storageKey);
+
+ auto entry = Entry::decodeStorageRecord(*record);
+
+ auto useDecision = entry ? makeUseDecision(*entry, request) : UseDecision::NoDueToDecodeFailure;
+ switch (useDecision) {
+ case UseDecision::Use:
+ break;
+ case UseDecision::Validate:
+ entry->setNeedsValidation();
+ break;
+ default:
+ entry = nullptr;
+ };
+
+#if !LOG_DISABLED
+ auto elapsedMS = static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime).count());
+ LOG(NetworkCache, "(NetworkProcess) retrieve complete useDecision=%d priority=%d time=%" PRIi64 "ms", static_cast<int>(useDecision), static_cast<int>(request.priority()), elapsedMS);
+#endif
+ completionHandler(WTFMove(entry));
+
+ if (m_statistics)
+ m_statistics->recordRetrievedCachedEntry(frameID.first, storageKey, request, useDecision);
+ return useDecision != UseDecision::NoDueToDecodeFailure;
+ });
+}
+
+std::unique_ptr<Entry> Cache::store(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& responseData, std::function<void (MappedBody&)> completionHandler)
+{
+ ASSERT(isEnabled());
+ ASSERT(responseData);
+
+ LOG(NetworkCache, "(NetworkProcess) storing %s, partition %s", request.url().string().latin1().data(), makeCacheKey(request).partition().latin1().data());
+
+ StoreDecision storeDecision = makeStoreDecision(request, response);
+ if (storeDecision != StoreDecision::Yes) {
+ LOG(NetworkCache, "(NetworkProcess) didn't store, storeDecision=%d", static_cast<int>(storeDecision));
+ auto key = makeCacheKey(request);
+
+ auto isSuccessfulRevalidation = response.httpStatusCode() == 304;
+ if (!isSuccessfulRevalidation) {
+ // Make sure we don't keep a stale entry in the cache.
+ remove(key);
+ }
+
+ if (m_statistics)
+ m_statistics->recordNotCachingResponse(key, storeDecision);
+
+ return nullptr;
+ }
+
+ std::unique_ptr<Entry> cacheEntry = std::make_unique<Entry>(makeCacheKey(request), response, WTFMove(responseData), collectVaryingRequestHeaders(request, response));
+
+ auto record = cacheEntry->encodeAsStorageRecord();
+
+ m_storage->store(record, [completionHandler](const Data& bodyData) {
+ MappedBody mappedBody;
+#if ENABLE(SHAREABLE_RESOURCE)
+ if (RefPtr<SharedMemory> sharedMemory = bodyData.tryCreateSharedMemory()) {
+ mappedBody.shareableResource = ShareableResource::create(WTFMove(sharedMemory), 0, bodyData.size());
+ ASSERT(mappedBody.shareableResource);
+ mappedBody.shareableResource->createHandle(mappedBody.shareableResourceHandle);
+ }
+#endif
+ completionHandler(mappedBody);
+ LOG(NetworkCache, "(NetworkProcess) stored");
+ });
+
+ return cacheEntry;
+}
+
+std::unique_ptr<Entry> Cache::storeRedirect(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& redirectRequest)
+{
+ ASSERT(isEnabled());
+
+ LOG(NetworkCache, "(NetworkProcess) storing redirect %s -> %s", request.url().string().latin1().data(), redirectRequest.url().string().latin1().data());
+
+ StoreDecision storeDecision = makeStoreDecision(request, response);
+ if (storeDecision != StoreDecision::Yes) {
+ LOG(NetworkCache, "(NetworkProcess) didn't store redirect, storeDecision=%d", static_cast<int>(storeDecision));
+ auto key = makeCacheKey(request);
+ if (m_statistics)
+ m_statistics->recordNotCachingResponse(key, storeDecision);
+
+ return nullptr;
+ }
+
+ std::unique_ptr<Entry> cacheEntry = std::make_unique<Entry>(makeCacheKey(request), response, redirectRequest, collectVaryingRequestHeaders(request, response));
+
+ auto record = cacheEntry->encodeAsStorageRecord();
+
+ m_storage->store(record, nullptr);
+
+ return cacheEntry;
+}
+
+std::unique_ptr<Entry> Cache::update(const WebCore::ResourceRequest& originalRequest, const GlobalFrameID& frameID, const Entry& existingEntry, const WebCore::ResourceResponse& validatingResponse)
+{
+ LOG(NetworkCache, "(NetworkProcess) updating %s", originalRequest.url().string().latin1().data());
+
+ WebCore::ResourceResponse response = existingEntry.response();
+ WebCore::updateResponseHeadersAfterRevalidation(response, validatingResponse);
+ response.setSource(WebCore::ResourceResponse::Source::DiskCache);
+
+ auto updateEntry = std::make_unique<Entry>(existingEntry.key(), response, existingEntry.buffer(), collectVaryingRequestHeaders(originalRequest, response));
+ auto updateRecord = updateEntry->encodeAsStorageRecord();
+
+ m_storage->store(updateRecord, { });
+
+ if (m_statistics)
+ m_statistics->recordRevalidationSuccess(frameID.first, existingEntry.key(), originalRequest);
+
+ return updateEntry;
+}
+
+void Cache::remove(const Key& key)
+{
+ ASSERT(isEnabled());
+
+ m_storage->remove(key);
+}
+
+void Cache::remove(const WebCore::ResourceRequest& request)
+{
+ remove(makeCacheKey(request));
+}
+
+void Cache::traverse(const std::function<void (const TraversalEntry*)>& traverseHandler)
+{
+ ASSERT(isEnabled());
+
+ // Protect against clients making excessive traversal requests.
+ const unsigned maximumTraverseCount = 3;
+ if (m_traverseCount >= maximumTraverseCount) {
+ WTFLogAlways("Maximum parallel cache traverse count exceeded. Ignoring traversal request.");
+
+ RunLoop::main().dispatch([traverseHandler] {
+ traverseHandler(nullptr);
+ });
+ return;
+ }
+
+ ++m_traverseCount;
+
+ m_storage->traverse(resourceType(), 0, [this, traverseHandler](const Storage::Record* record, const Storage::RecordInfo& recordInfo) {
+ if (!record) {
+ --m_traverseCount;
+ traverseHandler(nullptr);
+ return;
+ }
+
+ auto entry = Entry::decodeStorageRecord(*record);
+ if (!entry)
+ return;
+
+ TraversalEntry traversalEntry { *entry, recordInfo };
+ traverseHandler(&traversalEntry);
+ });
+}
+
+String Cache::dumpFilePath() const
+{
+ return WebCore::pathByAppendingComponent(m_storage->versionPath(), "dump.json");
+}
+
+void Cache::dumpContentsToFile()
+{
+ if (!m_storage)
+ return;
+ auto fd = WebCore::openFile(dumpFilePath(), WebCore::OpenForWrite);
+ if (!WebCore::isHandleValid(fd))
+ return;
+ auto prologue = String("{\n\"entries\": [\n").utf8();
+ WebCore::writeToFile(fd, prologue.data(), prologue.length());
+
+ struct Totals {
+ unsigned count { 0 };
+ double worth { 0 };
+ size_t bodySize { 0 };
+ };
+ Totals totals;
+ auto flags = Storage::TraverseFlag::ComputeWorth | Storage::TraverseFlag::ShareCount;
+ size_t capacity = m_storage->capacity();
+ m_storage->traverse(resourceType(), flags, [fd, totals, capacity](const Storage::Record* record, const Storage::RecordInfo& info) mutable {
+ if (!record) {
+ StringBuilder epilogue;
+ epilogue.appendLiteral("{}\n],\n");
+ epilogue.appendLiteral("\"totals\": {\n");
+ epilogue.appendLiteral("\"capacity\": ");
+ epilogue.appendNumber(capacity);
+ epilogue.appendLiteral(",\n");
+ epilogue.appendLiteral("\"count\": ");
+ epilogue.appendNumber(totals.count);
+ epilogue.appendLiteral(",\n");
+ epilogue.appendLiteral("\"bodySize\": ");
+ epilogue.appendNumber(totals.bodySize);
+ epilogue.appendLiteral(",\n");
+ epilogue.appendLiteral("\"averageWorth\": ");
+ epilogue.appendNumber(totals.count ? totals.worth / totals.count : 0);
+ epilogue.appendLiteral("\n");
+ epilogue.appendLiteral("}\n}\n");
+ auto writeData = epilogue.toString().utf8();
+ WebCore::writeToFile(fd, writeData.data(), writeData.length());
+ WebCore::closeFile(fd);
+ return;
+ }
+ auto entry = Entry::decodeStorageRecord(*record);
+ if (!entry)
+ return;
+ ++totals.count;
+ totals.worth += info.worth;
+ totals.bodySize += info.bodySize;
+
+ StringBuilder json;
+ entry->asJSON(json, info);
+ json.appendLiteral(",\n");
+ auto writeData = json.toString().utf8();
+ WebCore::writeToFile(fd, writeData.data(), writeData.length());
+ });
+}
+
+void Cache::deleteDumpFile()
+{
+ auto queue = WorkQueue::create("com.apple.WebKit.Cache.delete");
+ StringCapture dumpFilePathCapture(dumpFilePath());
+ queue->dispatch([dumpFilePathCapture] {
+ WebCore::deleteFile(dumpFilePathCapture.string());
+ });
+}
+
+void Cache::clear(std::chrono::system_clock::time_point modifiedSince, std::function<void ()>&& completionHandler)
+{
+ LOG(NetworkCache, "(NetworkProcess) clearing cache");
+
+ if (m_statistics)
+ m_statistics->clear();
+
+ if (!m_storage) {
+ RunLoop::main().dispatch(completionHandler);
+ return;
+ }
+ String anyType;
+ m_storage->clear(anyType, modifiedSince, WTFMove(completionHandler));
+
+ deleteDumpFile();
+}
+
+void Cache::clear()
+{
+ clear(std::chrono::system_clock::time_point::min(), nullptr);
+}
+
+String Cache::recordsPath() const
+{
+ return m_storage ? m_storage->recordsPath() : String();
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCache.h b/Source/WebKit2/NetworkProcess/cache/NetworkCache.h
new file mode 100644
index 000000000..38db1fab8
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCache.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2014-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.
+ */
+
+#ifndef NetworkCache_h
+#define NetworkCache_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheEntry.h"
+#include "NetworkCacheStorage.h"
+#include "ShareableResource.h"
+#include <WebCore/ResourceResponse.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class ResourceRequest;
+class SharedBuffer;
+class URL;
+}
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Cache;
+class SpeculativeLoadManager;
+class Statistics;
+
+Cache& singleton();
+
+struct MappedBody {
+#if ENABLE(SHAREABLE_RESOURCE)
+ RefPtr<ShareableResource> shareableResource;
+ ShareableResource::Handle shareableResourceHandle;
+#endif
+};
+
+enum class RetrieveDecision {
+ Yes,
+ NoDueToHTTPMethod,
+ NoDueToConditionalRequest,
+ NoDueToReloadIgnoringCache
+};
+
+// FIXME: This enum is used in the Statistics code in a way that prevents removing or reordering anything.
+enum class StoreDecision {
+ Yes,
+ NoDueToProtocol,
+ NoDueToHTTPMethod,
+ NoDueToAttachmentResponse, // Unused.
+ NoDueToNoStoreResponse,
+ NoDueToHTTPStatusCode,
+ NoDueToNoStoreRequest,
+ NoDueToUnlikelyToReuse,
+ NoDueToStreamingMedia
+};
+
+enum class UseDecision {
+ Use,
+ Validate,
+ NoDueToVaryingHeaderMismatch,
+ NoDueToMissingValidatorFields,
+ NoDueToDecodeFailure,
+ NoDueToExpiredRedirect,
+};
+
+using GlobalFrameID = std::pair<uint64_t /*webPageID*/, uint64_t /*webFrameID*/>;
+
+class Cache {
+ WTF_MAKE_NONCOPYABLE(Cache);
+ friend class WTF::NeverDestroyed<Cache>;
+public:
+ struct Parameters {
+ bool enableEfficacyLogging;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ bool enableNetworkCacheSpeculativeRevalidation;
+#endif
+ };
+ bool initialize(const String& cachePath, const Parameters&);
+ void setCapacity(size_t);
+
+ bool isEnabled() const { return !!m_storage; }
+
+ // Completion handler may get called back synchronously on failure.
+ void retrieve(const WebCore::ResourceRequest&, const GlobalFrameID&, std::function<void (std::unique_ptr<Entry>)>);
+ std::unique_ptr<Entry> store(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&, std::function<void (MappedBody&)>);
+ std::unique_ptr<Entry> storeRedirect(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, const WebCore::ResourceRequest& redirectRequest);
+ std::unique_ptr<Entry> update(const WebCore::ResourceRequest&, const GlobalFrameID&, const Entry&, const WebCore::ResourceResponse& validatingResponse);
+
+ struct TraversalEntry {
+ const Entry& entry;
+ const Storage::RecordInfo& recordInfo;
+ };
+ void traverse(const std::function<void (const TraversalEntry*)>&);
+ void remove(const Key&);
+ void remove(const WebCore::ResourceRequest&);
+
+ void clear();
+ void clear(std::chrono::system_clock::time_point modifiedSince, std::function<void ()>&& completionHandler);
+
+ void dumpContentsToFile();
+
+ String recordsPath() const;
+
+private:
+ Cache() = default;
+ ~Cache() = delete;
+
+ String dumpFilePath() const;
+ void deleteDumpFile();
+
+ std::unique_ptr<Storage> m_storage;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+ std::unique_ptr<SpeculativeLoadManager> m_speculativeLoadManager;
+#endif
+ std::unique_ptr<Statistics> m_statistics;
+
+ unsigned m_traverseCount { 0 };
+};
+
+}
+}
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.cpp
new file mode 100644
index 000000000..32c0a1ec5
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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 "NetworkCacheBlobStorage.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "Logging.h"
+#include "NetworkCacheFileSystem.h"
+#include <WebCore/FileSystem.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <wtf/RunLoop.h>
+#include <wtf/SHA1.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+BlobStorage::BlobStorage(const String& blobDirectoryPath)
+ : m_blobDirectoryPath(blobDirectoryPath)
+{
+}
+
+String BlobStorage::blobDirectoryPath() const
+{
+ return m_blobDirectoryPath.isolatedCopy();
+}
+
+void BlobStorage::synchronize()
+{
+ ASSERT(!RunLoop::isMain());
+
+ WebCore::makeAllDirectories(blobDirectoryPath());
+
+ m_approximateSize = 0;
+ auto blobDirectory = blobDirectoryPath();
+ traverseDirectory(blobDirectory, [this, &blobDirectory](const String& name, DirectoryEntryType type) {
+ if (type != DirectoryEntryType::File)
+ return;
+ auto path = WebCore::pathByAppendingComponent(blobDirectory, name);
+ auto filePath = WebCore::fileSystemRepresentation(path);
+ struct stat stat;
+ ::stat(filePath.data(), &stat);
+ // No clients left for this blob.
+ if (stat.st_nlink == 1)
+ unlink(filePath.data());
+ else
+ m_approximateSize += stat.st_size;
+ });
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) blob synchronization completed approximateSize=%zu", approximateSize());
+}
+
+String BlobStorage::blobPathForHash(const SHA1::Digest& hash) const
+{
+ auto hashAsString = SHA1::hexDigest(hash);
+ return WebCore::pathByAppendingComponent(blobDirectoryPath(), String::fromUTF8(hashAsString));
+}
+
+BlobStorage::Blob BlobStorage::add(const String& path, const Data& data)
+{
+ ASSERT(!RunLoop::isMain());
+
+ auto hash = computeSHA1(data);
+ if (data.isEmpty())
+ return { data, hash };
+
+ auto blobPath = WebCore::fileSystemRepresentation(blobPathForHash(hash));
+ auto linkPath = WebCore::fileSystemRepresentation(path);
+ unlink(linkPath.data());
+
+ bool blobExists = access(blobPath.data(), F_OK) != -1;
+ if (blobExists) {
+ auto existingData = mapFile(blobPath.data());
+ if (bytesEqual(existingData, data)) {
+ link(blobPath.data(), linkPath.data());
+ return { existingData, hash };
+ }
+ unlink(blobPath.data());
+ }
+
+ auto mappedData = data.mapToFile(blobPath.data());
+ if (mappedData.isNull())
+ return { };
+
+ link(blobPath.data(), linkPath.data());
+
+ m_approximateSize += mappedData.size();
+
+ return { mappedData, hash };
+}
+
+BlobStorage::Blob BlobStorage::get(const String& path)
+{
+ ASSERT(!RunLoop::isMain());
+
+ auto linkPath = WebCore::fileSystemRepresentation(path);
+ auto data = mapFile(linkPath.data());
+
+ return { data, computeSHA1(data) };
+}
+
+void BlobStorage::remove(const String& path)
+{
+ ASSERT(!RunLoop::isMain());
+
+ auto linkPath = WebCore::fileSystemRepresentation(path);
+ unlink(linkPath.data());
+}
+
+unsigned BlobStorage::shareCount(const String& path)
+{
+ ASSERT(!RunLoop::isMain());
+
+ auto linkPath = WebCore::fileSystemRepresentation(path);
+ struct stat stat;
+ if (::stat(linkPath.data(), &stat) < 0)
+ return 0;
+ // Link count is 2 in the single client case (the blob file and a link).
+ return stat.st_nlink - 1;
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.h
new file mode 100644
index 000000000..e4b494cf9
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheBlobStorage_h
+#define NetworkCacheBlobStorage_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheData.h"
+#include "NetworkCacheKey.h"
+#include <wtf/SHA1.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+// BlobStorage deduplicates the data using SHA1 hash computed over the blob bytes.
+class BlobStorage {
+ WTF_MAKE_NONCOPYABLE(BlobStorage);
+public:
+ BlobStorage(const String& blobDirectoryPath);
+
+ struct Blob {
+ Data data;
+ SHA1::Digest hash;
+ };
+ // These are all synchronous and should not be used from the main thread.
+ Blob add(const String& path, const Data&);
+ Blob get(const String& path);
+
+ // Blob won't be removed until synchronization.
+ void remove(const String& path);
+
+ unsigned shareCount(const String& path);
+
+ size_t approximateSize() const { return m_approximateSize; }
+
+ void synchronize();
+
+private:
+ String blobDirectoryPath() const;
+ String blobPathForHash(const SHA1::Digest&) const;
+
+ const String m_blobDirectoryPath;
+
+ std::atomic<size_t> m_approximateSize { 0 };
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoder.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoder.h
new file mode 100644
index 000000000..4b4be369d
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoder.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010, 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
+ * 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.
+ */
+
+#ifndef NetworkCacheCoder_h
+#define NetworkCacheCoder_h
+
+#if ENABLE(NETWORK_CACHE)
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Decoder;
+class Encoder;
+
+template<typename T> struct Coder {
+ static void encode(Encoder& encoder, const T& t)
+ {
+ t.encode(encoder);
+ }
+
+ static bool decode(Decoder& decoder, T& t)
+ {
+ return T::decode(decoder, t);
+ }
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.cpp
new file mode 100644
index 000000000..868d7c3ed
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2011, 2014-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 "NetworkCacheCoders.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "WebCoreArgumentCoders.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+void Coder<AtomicString>::encode(Encoder& encoder, const AtomicString& atomicString)
+{
+ encoder << atomicString.string();
+}
+
+bool Coder<AtomicString>::decode(Decoder& decoder, AtomicString& atomicString)
+{
+ String string;
+ if (!decoder.decode(string))
+ return false;
+
+ atomicString = string;
+ return true;
+}
+
+void Coder<CString>::encode(Encoder& encoder, const CString& string)
+{
+ // Special case the null string.
+ if (string.isNull()) {
+ encoder << std::numeric_limits<uint32_t>::max();
+ return;
+ }
+
+ uint32_t length = string.length();
+ encoder << length;
+ encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(string.data()), length);
+}
+
+bool Coder<CString>::decode(Decoder& decoder, CString& result)
+{
+ uint32_t length;
+ if (!decoder.decode(length))
+ return false;
+
+ if (length == std::numeric_limits<uint32_t>::max()) {
+ // This is the null string.
+ result = CString();
+ return true;
+ }
+
+ // Before allocating the string, make sure that the decoder buffer is big enough.
+ if (!decoder.bufferIsLargeEnoughToContain<char>(length))
+ return false;
+
+ char* buffer;
+ CString string = CString::newUninitialized(length, buffer);
+ if (!decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(buffer), length))
+ return false;
+
+ result = string;
+ return true;
+}
+
+
+void Coder<String>::encode(Encoder& encoder, const String& string)
+{
+ // Special case the null string.
+ if (string.isNull()) {
+ encoder << std::numeric_limits<uint32_t>::max();
+ return;
+ }
+
+ uint32_t length = string.length();
+ bool is8Bit = string.is8Bit();
+
+ encoder << length << is8Bit;
+
+ if (is8Bit)
+ encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(string.characters8()), length * sizeof(LChar));
+ else
+ encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(string.characters16()), length * sizeof(UChar));
+}
+
+template <typename CharacterType>
+static inline bool decodeStringText(Decoder& decoder, uint32_t length, String& result)
+{
+ // Before allocating the string, make sure that the decoder buffer is big enough.
+ if (!decoder.bufferIsLargeEnoughToContain<CharacterType>(length))
+ return false;
+
+ CharacterType* buffer;
+ String string = String::createUninitialized(length, buffer);
+ if (!decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(buffer), length * sizeof(CharacterType)))
+ return false;
+
+ result = string;
+ return true;
+}
+
+bool Coder<String>::decode(Decoder& decoder, String& result)
+{
+ uint32_t length;
+ if (!decoder.decode(length))
+ return false;
+
+ if (length == std::numeric_limits<uint32_t>::max()) {
+ // This is the null string.
+ result = String();
+ return true;
+ }
+
+ bool is8Bit;
+ if (!decoder.decode(is8Bit))
+ return false;
+
+ if (is8Bit)
+ return decodeStringText<LChar>(decoder, length, result);
+ return decodeStringText<UChar>(decoder, length, result);
+}
+
+void Coder<WebCore::CertificateInfo>::encode(Encoder& encoder, const WebCore::CertificateInfo& certificateInfo)
+{
+ // FIXME: Cocoa CertificateInfo is a CF object tree. Generalize CF type coding so we don't need to use ArgumentCoder here.
+ IPC::ArgumentEncoder argumentEncoder;
+ argumentEncoder << certificateInfo;
+ encoder << static_cast<uint64_t>(argumentEncoder.bufferSize());
+ encoder.encodeFixedLengthData(argumentEncoder.buffer(), argumentEncoder.bufferSize());
+}
+
+bool Coder<WebCore::CertificateInfo>::decode(Decoder& decoder, WebCore::CertificateInfo& certificateInfo)
+{
+ uint64_t certificateSize;
+ if (!decoder.decode(certificateSize))
+ return false;
+ Vector<uint8_t> data(certificateSize);
+ if (!decoder.decodeFixedLengthData(data.data(), data.size()))
+ return false;
+ IPC::ArgumentDecoder argumentDecoder(data.data(), data.size());
+ return argumentDecoder.decode(certificateInfo);
+}
+
+void Coder<SHA1::Digest>::encode(Encoder& encoder, const SHA1::Digest& digest)
+{
+ encoder.encodeFixedLengthData(digest.data(), sizeof(digest));
+}
+
+bool Coder<SHA1::Digest>::decode(Decoder& decoder, SHA1::Digest& digest)
+{
+ return decoder.decodeFixedLengthData(digest.data(), sizeof(digest));
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.h
new file mode 100644
index 000000000..13aefbf4f
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheCoders.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2010, 2014-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.
+ */
+
+#ifndef NetworkCacheCoders_h
+#define NetworkCacheCoders_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheDecoder.h"
+#include "NetworkCacheEncoder.h"
+#include <WebCore/CertificateInfo.h>
+#include <utility>
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/SHA1.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+template<typename T, typename U> struct Coder<std::pair<T, U>> {
+ static void encode(Encoder& encoder, const std::pair<T, U>& pair)
+ {
+ encoder << pair.first << pair.second;
+ }
+
+ static bool decode(Decoder& decoder, std::pair<T, U>& pair)
+ {
+ T first;
+ if (!decoder.decode(first))
+ return false;
+
+ U second;
+ if (!decoder.decode(second))
+ return false;
+
+ pair.first = first;
+ pair.second = second;
+ return true;
+ }
+};
+
+template<typename Rep, typename Period> struct Coder<std::chrono::duration<Rep, Period>> {
+ static void encode(Encoder& encoder, const std::chrono::duration<Rep, Period>& duration)
+ {
+ static_assert(std::is_integral<Rep>::value && std::is_signed<Rep>::value && sizeof(Rep) <= sizeof(int64_t), "Serialization of this Rep type is not supported yet. Only signed integer type which can be fit in an int64_t is currently supported.");
+ encoder << static_cast<int64_t>(duration.count());
+ }
+
+ static bool decode(Decoder& decoder, std::chrono::duration<Rep, Period>& result)
+ {
+ int64_t count;
+ if (!decoder.decode(count))
+ return false;
+ result = std::chrono::duration<Rep, Period>(static_cast<Rep>(count));
+ return true;
+ }
+};
+
+template<typename KeyType, typename ValueType> struct Coder<WTF::KeyValuePair<KeyType, ValueType>> {
+ static void encode(Encoder& encoder, const WTF::KeyValuePair<KeyType, ValueType>& pair)
+ {
+ encoder << pair.key << pair.value;
+ }
+
+ static bool decode(Decoder& decoder, WTF::KeyValuePair<KeyType, ValueType>& pair)
+ {
+ KeyType key;
+ if (!decoder.decode(key))
+ return false;
+
+ ValueType value;
+ if (!decoder.decode(value))
+ return false;
+
+ pair.key = key;
+ pair.value = value;
+ return true;
+ }
+};
+
+template<bool fixedSizeElements, typename T, size_t inlineCapacity> struct VectorCoder;
+
+template<typename T, size_t inlineCapacity> struct VectorCoder<false, T, inlineCapacity> {
+ static void encode(Encoder& encoder, const Vector<T, inlineCapacity>& vector)
+ {
+ encoder << static_cast<uint64_t>(vector.size());
+ for (size_t i = 0; i < vector.size(); ++i)
+ encoder << vector[i];
+ }
+
+ static bool decode(Decoder& decoder, Vector<T, inlineCapacity>& vector)
+ {
+ uint64_t size;
+ if (!decoder.decode(size))
+ return false;
+
+ Vector<T, inlineCapacity> tmp;
+ for (size_t i = 0; i < size; ++i) {
+ T element;
+ if (!decoder.decode(element))
+ return false;
+
+ tmp.append(WTFMove(element));
+ }
+
+ tmp.shrinkToFit();
+ vector.swap(tmp);
+ return true;
+ }
+};
+
+template<typename T, size_t inlineCapacity> struct VectorCoder<true, T, inlineCapacity> {
+ static void encode(Encoder& encoder, const Vector<T, inlineCapacity>& vector)
+ {
+ encoder << static_cast<uint64_t>(vector.size());
+ encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(vector.data()), vector.size() * sizeof(T), alignof(T));
+ }
+
+ static bool decode(Decoder& decoder, Vector<T, inlineCapacity>& vector)
+ {
+ uint64_t size;
+ if (!decoder.decode(size))
+ return false;
+
+ // Since we know the total size of the elements, we can allocate the vector in
+ // one fell swoop. Before allocating we must however make sure that the decoder buffer
+ // is big enough.
+ if (!decoder.bufferIsLargeEnoughToContain<T>(size))
+ return false;
+
+ Vector<T, inlineCapacity> temp;
+ temp.resize(size);
+
+ decoder.decodeFixedLengthData(reinterpret_cast<uint8_t*>(temp.data()), size * sizeof(T));
+
+ vector.swap(temp);
+ return true;
+ }
+};
+
+template<typename T, size_t inlineCapacity> struct Coder<Vector<T, inlineCapacity>> : VectorCoder<std::is_arithmetic<T>::value, T, inlineCapacity> { };
+
+template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> struct Coder<HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> {
+ typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMapType;
+
+ static void encode(Encoder& encoder, const HashMapType& hashMap)
+ {
+ encoder << static_cast<uint64_t>(hashMap.size());
+ for (typename HashMapType::const_iterator it = hashMap.begin(), end = hashMap.end(); it != end; ++it)
+ encoder << *it;
+ }
+
+ static bool decode(Decoder& decoder, HashMapType& hashMap)
+ {
+ uint64_t hashMapSize;
+ if (!decoder.decode(hashMapSize))
+ return false;
+
+ HashMapType tempHashMap;
+ for (uint64_t i = 0; i < hashMapSize; ++i) {
+ KeyArg key;
+ MappedArg value;
+ if (!decoder.decode(key))
+ return false;
+ if (!decoder.decode(value))
+ return false;
+
+ if (!tempHashMap.add(key, value).isNewEntry) {
+ // The hash map already has the specified key, bail.
+ return false;
+ }
+ }
+
+ hashMap.swap(tempHashMap);
+ return true;
+ }
+};
+
+template<typename KeyArg, typename HashArg, typename KeyTraitsArg> struct Coder<HashSet<KeyArg, HashArg, KeyTraitsArg>> {
+ typedef HashSet<KeyArg, HashArg, KeyTraitsArg> HashSetType;
+
+ static void encode(Encoder& encoder, const HashSetType& hashSet)
+ {
+ encoder << static_cast<uint64_t>(hashSet.size());
+ for (typename HashSetType::const_iterator it = hashSet.begin(), end = hashSet.end(); it != end; ++it)
+ encoder << *it;
+ }
+
+ static bool decode(Decoder& decoder, HashSetType& hashSet)
+ {
+ uint64_t hashSetSize;
+ if (!decoder.decode(hashSetSize))
+ return false;
+
+ HashSetType tempHashSet;
+ for (uint64_t i = 0; i < hashSetSize; ++i) {
+ KeyArg key;
+ if (!decoder.decode(key))
+ return false;
+
+ if (!tempHashSet.add(key).isNewEntry) {
+ // The hash map already has the specified key, bail.
+ return false;
+ }
+ }
+
+ hashSet.swap(tempHashSet);
+ return true;
+ }
+};
+
+template<> struct Coder<AtomicString> {
+ static void encode(Encoder&, const AtomicString&);
+ static bool decode(Decoder&, AtomicString&);
+};
+
+template<> struct Coder<CString> {
+ static void encode(Encoder&, const CString&);
+ static bool decode(Decoder&, CString&);
+};
+
+template<> struct Coder<String> {
+ static void encode(Encoder&, const String&);
+ static bool decode(Decoder&, String&);
+};
+
+template<> struct Coder<WebCore::CertificateInfo> {
+ static void encode(Encoder&, const WebCore::CertificateInfo&);
+ static bool decode(Decoder&, WebCore::CertificateInfo&);
+};
+
+template<> struct Coder<SHA1::Digest> {
+ static void encode(Encoder&, const SHA1::Digest&);
+ static bool decode(Decoder&, SHA1::Digest&);
+};
+
+}
+}
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheData.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheData.cpp
new file mode 100644
index 000000000..f950d69ed
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheData.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "NetworkCacheData.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+Data Data::mapToFile(const char* path) const
+{
+ int fd = open(path, O_CREAT | O_EXCL | O_RDWR , S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ return { };
+
+ if (ftruncate(fd, m_size) < 0) {
+ close(fd);
+ return { };
+ }
+
+ void* map = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) {
+ close(fd);
+ return { };
+ }
+
+ uint8_t* mapData = static_cast<uint8_t*>(map);
+ apply([&mapData](const uint8_t* bytes, size_t bytesSize) {
+ memcpy(mapData, bytes, bytesSize);
+ mapData += bytesSize;
+ return true;
+ });
+
+ // Drop the write permission.
+ mprotect(map, m_size, PROT_READ);
+
+ // Flush (asynchronously) to file, turning this into clean memory.
+ msync(map, m_size, MS_ASYNC);
+
+ return Data::adoptMap(map, m_size, fd);
+}
+
+Data mapFile(const char* path)
+{
+ int fd = open(path, O_RDONLY, 0);
+ if (fd < 0)
+ return { };
+ struct stat stat;
+ if (fstat(fd, &stat) < 0) {
+ close(fd);
+ return { };
+ }
+ size_t size = stat.st_size;
+ if (!size) {
+ close(fd);
+ return Data::empty();
+ }
+
+ return adoptAndMapFile(fd, 0, size);
+}
+
+Data adoptAndMapFile(int fd, size_t offset, size_t size)
+{
+ if (!size) {
+ close(fd);
+ return Data::empty();
+ }
+
+ void* map = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, offset);
+ if (map == MAP_FAILED) {
+ close(fd);
+ return { };
+ }
+
+ return Data::adoptMap(map, size, fd);
+}
+
+SHA1::Digest computeSHA1(const Data& data)
+{
+ SHA1 sha1;
+ data.apply([&sha1](const uint8_t* data, size_t size) {
+ sha1.addBytes(data, size);
+ return true;
+ });
+ SHA1::Digest digest;
+ sha1.computeHash(digest);
+ return digest;
+}
+
+bool bytesEqual(const Data& a, const Data& b)
+{
+ if (a.isNull() || b.isNull())
+ return false;
+ if (a.size() != b.size())
+ return false;
+ return !memcmp(a.data(), b.data(), a.size());
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif // #if ENABLE(NETWORK_CACHE)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheData.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheData.h
new file mode 100644
index 000000000..225589854
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheData.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheData_h
+#define NetworkCacheData_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include <functional>
+#include <wtf/FunctionDispatcher.h>
+#include <wtf/SHA1.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/text/WTFString.h>
+
+#if USE(SOUP)
+#include <WebCore/GRefPtrSoup.h>
+#endif
+
+namespace WebKit {
+
+class SharedMemory;
+
+namespace NetworkCache {
+
+#if PLATFORM(COCOA)
+template <typename T> class DispatchPtr;
+template <typename T> DispatchPtr<T> adoptDispatch(T dispatchObject);
+
+// FIXME: Use OSObjectPtr instead when it works with dispatch_data_t on all platforms.
+template<typename T> class DispatchPtr {
+public:
+ DispatchPtr()
+ : m_ptr(nullptr)
+ {
+ }
+ explicit DispatchPtr(T ptr)
+ : m_ptr(ptr)
+ {
+ if (m_ptr)
+ dispatch_retain(m_ptr);
+ }
+ DispatchPtr(const DispatchPtr& other)
+ : m_ptr(other.m_ptr)
+ {
+ if (m_ptr)
+ dispatch_retain(m_ptr);
+ }
+ ~DispatchPtr()
+ {
+ if (m_ptr)
+ dispatch_release(m_ptr);
+ }
+
+ DispatchPtr& operator=(const DispatchPtr& other)
+ {
+ auto copy = other;
+ std::swap(m_ptr, copy.m_ptr);
+ return *this;
+ }
+
+ T get() const { return m_ptr; }
+ explicit operator bool() const { return m_ptr; }
+
+ friend DispatchPtr adoptDispatch<T>(T);
+
+private:
+ struct Adopt { };
+ DispatchPtr(Adopt, T data)
+ : m_ptr(data)
+ {
+ }
+
+ T m_ptr;
+};
+
+template <typename T> DispatchPtr<T> adoptDispatch(T dispatchObject)
+{
+ return DispatchPtr<T>(typename DispatchPtr<T>::Adopt { }, dispatchObject);
+}
+#endif
+
+class Data {
+public:
+ Data() { }
+ Data(const uint8_t*, size_t);
+
+ static Data empty();
+ static Data adoptMap(void* map, size_t, int fd);
+
+#if PLATFORM(COCOA)
+ enum class Backing { Buffer, Map };
+ Data(DispatchPtr<dispatch_data_t>, Backing = Backing::Buffer);
+#endif
+#if USE(SOUP)
+ Data(GRefPtr<SoupBuffer>&&, int fd = -1);
+#endif
+ bool isNull() const;
+ bool isEmpty() const { return !m_size; }
+
+ const uint8_t* data() const;
+ size_t size() const { return m_size; }
+ bool isMap() const { return m_isMap; }
+ RefPtr<SharedMemory> tryCreateSharedMemory() const;
+
+ Data subrange(size_t offset, size_t) const;
+
+ bool apply(const std::function<bool (const uint8_t*, size_t)>&&) const;
+
+ Data mapToFile(const char* path) const;
+
+#if PLATFORM(COCOA)
+ dispatch_data_t dispatchData() const { return m_dispatchData.get(); }
+#endif
+
+#if USE(SOUP)
+ SoupBuffer* soupBuffer() const { return m_buffer.get(); }
+#endif
+private:
+#if PLATFORM(COCOA)
+ mutable DispatchPtr<dispatch_data_t> m_dispatchData;
+#endif
+#if USE(SOUP)
+ mutable GRefPtr<SoupBuffer> m_buffer;
+ int m_fileDescriptor { -1 };
+#endif
+ mutable const uint8_t* m_data { nullptr };
+ size_t m_size { 0 };
+ bool m_isMap { false };
+};
+
+Data concatenate(const Data&, const Data&);
+bool bytesEqual(const Data&, const Data&);
+Data adoptAndMapFile(int fd, size_t offset, size_t);
+Data mapFile(const char* path);
+SHA1::Digest computeSHA1(const Data&);
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp
new file mode 100644
index 000000000..644c38e30
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "config.h"
+#include "NetworkCacheData.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "SharedMemory.h"
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+Data::Data(const uint8_t* data, size_t size)
+ : m_size(size)
+{
+ uint8_t* copiedData = static_cast<uint8_t*>(fastMalloc(size));
+ memcpy(copiedData, data, size);
+ m_buffer = adoptGRef(soup_buffer_new_with_owner(copiedData, size, copiedData, fastFree));
+}
+
+Data::Data(GRefPtr<SoupBuffer>&& buffer, int fd)
+ : m_buffer(buffer)
+ , m_fileDescriptor(fd)
+ , m_size(buffer ? buffer->length : 0)
+ , m_isMap(m_size && fd != -1)
+{
+}
+
+Data Data::empty()
+{
+ GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new(SOUP_MEMORY_TAKE, nullptr, 0));
+ return { WTFMove(buffer) };
+}
+
+const uint8_t* Data::data() const
+{
+ return m_buffer ? reinterpret_cast<const uint8_t*>(m_buffer->data) : nullptr;
+}
+
+bool Data::isNull() const
+{
+ return !m_buffer;
+}
+
+bool Data::apply(const std::function<bool (const uint8_t*, size_t)>&& applier) const
+{
+ if (!m_size)
+ return false;
+
+ return applier(reinterpret_cast<const uint8_t*>(m_buffer->data), m_buffer->length);
+}
+
+Data Data::subrange(size_t offset, size_t size) const
+{
+ if (!m_buffer)
+ return { };
+
+ GRefPtr<SoupBuffer> subBuffer = adoptGRef(soup_buffer_new_subbuffer(m_buffer.get(), offset, size));
+ return { WTFMove(subBuffer) };
+}
+
+Data concatenate(const Data& a, const Data& b)
+{
+ if (a.isNull())
+ return b;
+ if (b.isNull())
+ return a;
+
+ size_t size = a.size() + b.size();
+ uint8_t* data = static_cast<uint8_t*>(fastMalloc(size));
+ memcpy(data, a.soupBuffer()->data, a.soupBuffer()->length);
+ memcpy(data + a.soupBuffer()->length, b.soupBuffer()->data, b.soupBuffer()->length);
+ GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new_with_owner(data, size, data, fastFree));
+ return { WTFMove(buffer) };
+}
+
+struct MapWrapper {
+ ~MapWrapper()
+ {
+ munmap(map, size);
+ close(fileDescriptor);
+ }
+
+ void* map;
+ size_t size;
+ int fileDescriptor;
+};
+
+static void deleteMapWrapper(MapWrapper* wrapper)
+{
+ delete wrapper;
+}
+
+Data Data::adoptMap(void* map, size_t size, int fd)
+{
+ ASSERT(map);
+ ASSERT(map != MAP_FAILED);
+ MapWrapper* wrapper = new MapWrapper { map, size, fd };
+ GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new_with_owner(map, size, wrapper, reinterpret_cast<GDestroyNotify>(deleteMapWrapper)));
+ return { WTFMove(buffer), fd };
+}
+
+RefPtr<SharedMemory> Data::tryCreateSharedMemory() const
+{
+ if (isNull() || !isMap())
+ return nullptr;
+
+ return SharedMemory::wrapMap(const_cast<char*>(m_buffer->data), m_buffer->length, m_fileDescriptor);
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.cpp
new file mode 100644
index 000000000..80e657578
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2010, 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
+ * 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 "NetworkCacheDecoder.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheEncoder.h"
+
+namespace WebKit {
+namespace NetworkCache {
+
+Decoder::Decoder(const uint8_t* buffer, size_t bufferSize)
+ : m_buffer(buffer)
+ , m_bufferPosition(buffer)
+ , m_bufferEnd(buffer + bufferSize)
+{
+}
+
+Decoder::~Decoder()
+{
+}
+
+bool Decoder::bufferIsLargeEnoughToContain(size_t size) const
+{
+ return size <= static_cast<size_t>(m_bufferEnd - m_bufferPosition);
+}
+
+bool Decoder::decodeFixedLengthData(uint8_t* data, size_t size)
+{
+ if (!bufferIsLargeEnoughToContain(size))
+ return false;
+
+ memcpy(data, m_bufferPosition, size);
+ m_bufferPosition += size;
+
+ Encoder::updateChecksumForData(m_sha1, data, size);
+ return true;
+}
+
+template<typename Type>
+bool Decoder::decodeNumber(Type& value)
+{
+ if (!bufferIsLargeEnoughToContain(sizeof(value)))
+ return false;
+
+ memcpy(&value, m_bufferPosition, sizeof(value));
+ m_bufferPosition += sizeof(Type);
+
+ Encoder::updateChecksumForNumber(m_sha1, value);
+ return true;
+}
+
+bool Decoder::decode(bool& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(uint8_t& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(uint16_t& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(uint32_t& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(uint64_t& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(int32_t& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(int64_t& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(float& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::decode(double& result)
+{
+ return decodeNumber(result);
+}
+
+bool Decoder::verifyChecksum()
+{
+ SHA1::Digest computedHash;
+ m_sha1.computeHash(computedHash);
+
+ SHA1::Digest savedHash;
+ if (!decodeFixedLengthData(savedHash.data(), sizeof(savedHash)))
+ return false;
+
+ return computedHash == savedHash;
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.h
new file mode 100644
index 000000000..12e3d03dc
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDecoder.h
@@ -0,0 +1,103 @@
+/*
+ * 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
+ * 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.
+ */
+
+#ifndef NetworkCacheDecoder_h
+#define NetworkCacheDecoder_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheCoder.h"
+#include <wtf/SHA1.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Decoder {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ Decoder(const uint8_t* buffer, size_t bufferSize);
+ virtual ~Decoder();
+
+ size_t length() const { return m_bufferEnd - m_buffer; }
+ size_t currentOffset() const { return m_bufferPosition - m_buffer; }
+
+ bool verifyChecksum();
+
+ bool decodeFixedLengthData(uint8_t*, size_t);
+
+ bool decode(bool&);
+ bool decode(uint8_t&);
+ bool decode(uint16_t&);
+ bool decode(uint32_t&);
+ bool decode(uint64_t&);
+ bool decode(int32_t&);
+ bool decode(int64_t&);
+ bool decode(float&);
+ bool decode(double&);
+
+ template<typename T> bool decodeEnum(T& result)
+ {
+ static_assert(sizeof(T) <= 8, "Enum type T must not be larger than 64 bits!");
+
+ uint64_t value;
+ if (!decode(value))
+ return false;
+
+ result = static_cast<T>(value);
+ return true;
+ }
+
+ template<typename T> bool decode(T& t)
+ {
+ return Coder<T>::decode(*this, t);
+ }
+
+ template<typename T>
+ bool bufferIsLargeEnoughToContain(size_t numElements) const
+ {
+ static_assert(std::is_arithmetic<T>::value, "Type T must have a fixed, known encoded size!");
+
+ if (numElements > std::numeric_limits<size_t>::max() / sizeof(T))
+ return false;
+
+ return bufferIsLargeEnoughToContain(numElements * sizeof(T));
+ }
+
+private:
+ bool bufferIsLargeEnoughToContain(size_t) const;
+ template<typename Type> bool decodeNumber(Type&);
+
+ const uint8_t* m_buffer;
+ const uint8_t* m_bufferPosition;
+ const uint8_t* m_bufferEnd;
+
+ SHA1 m_sha1;
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp
new file mode 100644
index 000000000..0c2d7191d
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010, 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
+ * 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 "NetworkCacheEncoder.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+namespace WebKit {
+namespace NetworkCache {
+
+Encoder::Encoder()
+{
+}
+
+Encoder::~Encoder()
+{
+}
+
+uint8_t* Encoder::grow(size_t size)
+{
+ size_t newPosition = m_buffer.size();
+ m_buffer.grow(m_buffer.size() + size);
+ return m_buffer.data() + newPosition;
+}
+
+void Encoder::updateChecksumForData(SHA1& sha1, const uint8_t* data, size_t size)
+{
+ auto typeSalt = Salt<uint8_t*>::value;
+ sha1.addBytes(reinterpret_cast<uint8_t*>(&typeSalt), sizeof(typeSalt));
+ sha1.addBytes(data, size);
+}
+
+void Encoder::encodeFixedLengthData(const uint8_t* data, size_t size)
+{
+ updateChecksumForData(m_sha1, data, size);
+
+ uint8_t* buffer = grow(size);
+ memcpy(buffer, data, size);
+}
+
+template<typename Type>
+void Encoder::encodeNumber(Type value)
+{
+ Encoder::updateChecksumForNumber(m_sha1, value);
+
+ uint8_t* buffer = grow(sizeof(Type));
+ memcpy(buffer, &value, sizeof(Type));
+}
+
+void Encoder::encode(bool value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(uint8_t value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(uint16_t value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(uint32_t value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(uint64_t value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(int32_t value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(int64_t value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(float value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encode(double value)
+{
+ encodeNumber(value);
+}
+
+void Encoder::encodeChecksum()
+{
+ SHA1::Digest hash;
+ m_sha1.computeHash(hash);
+ encodeFixedLengthData(hash.data(), hash.size());
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.h
new file mode 100644
index 000000000..469c06c59
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef NetworkCacheEncoder_h
+#define NetworkCacheEncoder_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheCoder.h"
+#include <wtf/SHA1.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Encoder;
+class DataReference;
+
+class Encoder {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ Encoder();
+ virtual ~Encoder();
+
+ void encodeChecksum();
+ void encodeFixedLengthData(const uint8_t*, size_t);
+
+ template<typename T> void encodeEnum(T t)
+ {
+ COMPILE_ASSERT(sizeof(T) <= sizeof(uint64_t), enum_type_must_not_be_larger_than_64_bits);
+
+ encode(static_cast<uint64_t>(t));
+ }
+
+ template<typename T> void encode(const T& t)
+ {
+ Coder<T>::encode(*this, t);
+ }
+
+ template<typename T> Encoder& operator<<(const T& t)
+ {
+ encode(t);
+ return *this;
+ }
+
+ const uint8_t* buffer() const { return m_buffer.data(); }
+ size_t bufferSize() const { return m_buffer.size(); }
+
+ static void updateChecksumForData(SHA1&, const uint8_t*, size_t);
+ template <typename Type> static void updateChecksumForNumber(SHA1&, Type);
+
+private:
+ void encode(bool);
+ void encode(uint8_t);
+ void encode(uint16_t);
+ void encode(uint32_t);
+ void encode(uint64_t);
+ void encode(int32_t);
+ void encode(int64_t);
+ void encode(float);
+ void encode(double);
+
+ template<typename Type> void encodeNumber(Type);
+
+ uint8_t* grow(size_t);
+
+ template <typename Type> struct Salt;
+
+ Vector<uint8_t, 4096> m_buffer;
+ SHA1 m_sha1;
+};
+
+template <> struct Encoder::Salt<bool> { static const unsigned value = 3; };
+template <> struct Encoder::Salt<uint8_t> { static const unsigned value = 5; };
+template <> struct Encoder::Salt<uint16_t> { static const unsigned value = 7; };
+template <> struct Encoder::Salt<uint32_t> { static const unsigned value = 11; };
+template <> struct Encoder::Salt<uint64_t> { static const unsigned value = 13; };
+template <> struct Encoder::Salt<int32_t> { static const unsigned value = 17; };
+template <> struct Encoder::Salt<int64_t> { static const unsigned value = 19; };
+template <> struct Encoder::Salt<float> { static const unsigned value = 23; };
+template <> struct Encoder::Salt<double> { static const unsigned value = 29; };
+template <> struct Encoder::Salt<uint8_t*> { static const unsigned value = 101; };
+
+template <typename Type>
+void Encoder::updateChecksumForNumber(SHA1& sha1, Type value)
+{
+ auto typeSalt = Salt<Type>::value;
+ sha1.addBytes(reinterpret_cast<uint8_t*>(&typeSalt), sizeof(typeSalt));
+ sha1.addBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+}
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp
new file mode 100644
index 000000000..faa4f04d1
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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 "NetworkCache.h"
+
+#include "Logging.h"
+#include "NetworkCacheCoders.h"
+#include "NetworkCacheDecoder.h"
+#include "NetworkCacheEncoder.h"
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/SharedBuffer.h>
+#include <wtf/text/StringBuilder.h>
+
+#if ENABLE(NETWORK_CACHE)
+
+namespace WebKit {
+namespace NetworkCache {
+
+Entry::Entry(const Key& key, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& buffer, const Vector<std::pair<String, String>>& varyingRequestHeaders)
+ : m_key(key)
+ , m_timeStamp(std::chrono::system_clock::now())
+ , m_response(response)
+ , m_varyingRequestHeaders(varyingRequestHeaders)
+ , m_buffer(WTFMove(buffer))
+{
+ ASSERT(m_key.type() == "resource");
+}
+
+Entry::Entry(const Key& key, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& redirectRequest, const Vector<std::pair<String, String>>& varyingRequestHeaders)
+ : m_key(key)
+ , m_timeStamp(std::chrono::system_clock::now())
+ , m_response(response)
+ , m_varyingRequestHeaders(varyingRequestHeaders)
+ , m_redirectRequest(WebCore::ResourceRequest::adopt(redirectRequest.copyData())) // Don't include the underlying platform request object.
+{
+ ASSERT(m_key.type() == "resource");
+ // Redirect body is not needed even if exists.
+ m_redirectRequest->setHTTPBody(nullptr);
+}
+
+Entry::Entry(const Entry& other)
+ : m_key(other.m_key)
+ , m_timeStamp(other.m_timeStamp)
+ , m_response(other.m_response)
+ , m_varyingRequestHeaders(other.m_varyingRequestHeaders)
+ , m_buffer(other.m_buffer)
+ , m_sourceStorageRecord(other.m_sourceStorageRecord)
+{
+}
+
+Entry::Entry(const Storage::Record& storageEntry)
+ : m_key(storageEntry.key)
+ , m_timeStamp(storageEntry.timeStamp)
+ , m_sourceStorageRecord(storageEntry)
+{
+ ASSERT(m_key.type() == "resource");
+}
+
+Storage::Record Entry::encodeAsStorageRecord() const
+{
+ Encoder encoder;
+ encoder << m_response;
+
+ bool hasVaryingRequestHeaders = !m_varyingRequestHeaders.isEmpty();
+ encoder << hasVaryingRequestHeaders;
+ if (hasVaryingRequestHeaders)
+ encoder << m_varyingRequestHeaders;
+
+ bool isRedirect = !!m_redirectRequest;
+ encoder << isRedirect;
+ if (isRedirect)
+ m_redirectRequest->encodeWithoutPlatformData(encoder);
+
+ encoder.encodeChecksum();
+
+ Data header(encoder.buffer(), encoder.bufferSize());
+ Data body;
+ if (m_buffer)
+ body = { reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size() };
+
+ return { m_key, m_timeStamp, header, body };
+}
+
+std::unique_ptr<Entry> Entry::decodeStorageRecord(const Storage::Record& storageEntry)
+{
+ auto entry = std::make_unique<Entry>(storageEntry);
+
+ Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
+ if (!decoder.decode(entry->m_response))
+ return nullptr;
+ entry->m_response.setSource(WebCore::ResourceResponse::Source::DiskCache);
+
+ bool hasVaryingRequestHeaders;
+ if (!decoder.decode(hasVaryingRequestHeaders))
+ return nullptr;
+
+ if (hasVaryingRequestHeaders) {
+ if (!decoder.decode(entry->m_varyingRequestHeaders))
+ return nullptr;
+ }
+
+ bool isRedirect;
+ if (!decoder.decode(isRedirect))
+ return nullptr;
+
+ if (isRedirect) {
+ entry->m_redirectRequest = std::make_unique<WebCore::ResourceRequest>();
+ if (!entry->m_redirectRequest->decodeWithoutPlatformData(decoder))
+ return nullptr;
+ }
+
+ if (!decoder.verifyChecksum()) {
+ LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
+ return nullptr;
+ }
+
+ return entry;
+}
+
+#if ENABLE(SHAREABLE_RESOURCE)
+void Entry::initializeShareableResourceHandleFromStorageRecord() const
+{
+ RefPtr<SharedMemory> sharedMemory = m_sourceStorageRecord.body.tryCreateSharedMemory();
+ if (!sharedMemory)
+ return;
+
+ RefPtr<ShareableResource> shareableResource = ShareableResource::create(sharedMemory.release(), 0, m_sourceStorageRecord.body.size());
+ ASSERT(shareableResource);
+ shareableResource->createHandle(m_shareableResourceHandle);
+}
+#endif
+
+void Entry::initializeBufferFromStorageRecord() const
+{
+#if ENABLE(SHAREABLE_RESOURCE)
+ if (!shareableResourceHandle().isNull()) {
+ m_buffer = m_shareableResourceHandle.tryWrapInSharedBuffer();
+ if (m_buffer)
+ return;
+ }
+#endif
+ m_buffer = WebCore::SharedBuffer::create(m_sourceStorageRecord.body.data(), m_sourceStorageRecord.body.size());
+}
+
+WebCore::SharedBuffer* Entry::buffer() const
+{
+ if (!m_buffer)
+ initializeBufferFromStorageRecord();
+
+ return m_buffer.get();
+}
+
+#if ENABLE(SHAREABLE_RESOURCE)
+ShareableResource::Handle& Entry::shareableResourceHandle() const
+{
+ if (m_shareableResourceHandle.isNull())
+ initializeShareableResourceHandleFromStorageRecord();
+
+ return m_shareableResourceHandle;
+}
+#endif
+
+bool Entry::needsValidation() const
+{
+ return m_response.source() == WebCore::ResourceResponse::Source::DiskCacheAfterValidation;
+}
+
+void Entry::setNeedsValidation()
+{
+ ASSERT(m_response.source() == WebCore::ResourceResponse::Source::DiskCache);
+ m_response.setSource(WebCore::ResourceResponse::Source::DiskCacheAfterValidation);
+}
+
+void Entry::asJSON(StringBuilder& json, const Storage::RecordInfo& info) const
+{
+ json.appendLiteral("{\n");
+ json.appendLiteral("\"hash\": ");
+ json.appendQuotedJSONString(m_key.hashAsString());
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"bodySize\": ");
+ json.appendNumber(info.bodySize);
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"worth\": ");
+ json.appendNumber(info.worth);
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"partition\": ");
+ json.appendQuotedJSONString(m_key.partition());
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"timestamp\": ");
+ json.appendNumber(std::chrono::duration_cast<std::chrono::milliseconds>(m_timeStamp.time_since_epoch()).count());
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"URL\": ");
+ json.appendQuotedJSONString(m_response.url().string());
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"bodyHash\": ");
+ json.appendQuotedJSONString(info.bodyHash);
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"bodyShareCount\": ");
+ json.appendNumber(info.bodyShareCount);
+ json.appendLiteral(",\n");
+ json.appendLiteral("\"headers\": {\n");
+ bool firstHeader = true;
+ for (auto& header : m_response.httpHeaderFields()) {
+ if (!firstHeader)
+ json.appendLiteral(",\n");
+ firstHeader = false;
+ json.appendLiteral(" ");
+ json.appendQuotedJSONString(header.key);
+ json.appendLiteral(": ");
+ json.appendQuotedJSONString(header.value);
+ }
+ json.appendLiteral("\n}\n");
+ json.appendLiteral("}");
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h
new file mode 100644
index 000000000..0855a4efe
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheEntry_h
+#define NetworkCacheEntry_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheStorage.h"
+#include "ShareableResource.h"
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/ResourceResponse.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class SharedBuffer;
+}
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Entry {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ Entry(const Key&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&, const Vector<std::pair<String, String>>& varyingRequestHeaders);
+ Entry(const Key&, const WebCore::ResourceResponse&, const WebCore::ResourceRequest& redirectRequest, const Vector<std::pair<String, String>>& varyingRequestHeaders);
+ explicit Entry(const Storage::Record&);
+ Entry(const Entry&);
+
+ Storage::Record encodeAsStorageRecord() const;
+ static std::unique_ptr<Entry> decodeStorageRecord(const Storage::Record&);
+
+ const Key& key() const { return m_key; }
+ std::chrono::system_clock::time_point timeStamp() const { return m_timeStamp; }
+ const WebCore::ResourceResponse& response() const { return m_response; }
+ const Vector<std::pair<String, String>>& varyingRequestHeaders() const { return m_varyingRequestHeaders; }
+
+ WebCore::SharedBuffer* buffer() const;
+ const WebCore::ResourceRequest* redirectRequest() const { return m_redirectRequest.get(); }
+
+#if ENABLE(SHAREABLE_RESOURCE)
+ ShareableResource::Handle& shareableResourceHandle() const;
+#endif
+
+ bool needsValidation() const;
+ void setNeedsValidation();
+
+ const Storage::Record& sourceStorageRecord() const { return m_sourceStorageRecord; }
+
+ void asJSON(StringBuilder&, const Storage::RecordInfo&) const;
+
+private:
+ void initializeBufferFromStorageRecord() const;
+#if ENABLE(SHAREABLE_RESOURCE)
+ void initializeShareableResourceHandleFromStorageRecord() const;
+#endif
+
+ Key m_key;
+ std::chrono::system_clock::time_point m_timeStamp;
+ WebCore::ResourceResponse m_response;
+ Vector<std::pair<String, String>> m_varyingRequestHeaders;
+
+ std::unique_ptr<WebCore::ResourceRequest> m_redirectRequest;
+ mutable RefPtr<WebCore::SharedBuffer> m_buffer;
+#if ENABLE(SHAREABLE_RESOURCE)
+ mutable ShareableResource::Handle m_shareableResourceHandle;
+#endif
+
+ Storage::Record m_sourceStorageRecord { };
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.cpp
new file mode 100644
index 000000000..93d6a58d6
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "NetworkCacheFileSystem.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include <WebCore/FileSystem.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <wtf/text/CString.h>
+
+#if USE(SOUP)
+#include <gio/gio.h>
+#include <wtf/glib/GRefPtr.h>
+#endif
+
+namespace WebKit {
+namespace NetworkCache {
+
+static DirectoryEntryType directoryEntryType(uint8_t dtype)
+{
+ switch (dtype) {
+ case DT_DIR:
+ return DirectoryEntryType::Directory;
+ case DT_REG:
+ return DirectoryEntryType::File;
+ default:
+ ASSERT_NOT_REACHED();
+ return DirectoryEntryType::File;
+ }
+}
+
+void traverseDirectory(const String& path, const std::function<void (const String&, DirectoryEntryType)>& function)
+{
+ DIR* dir = opendir(WebCore::fileSystemRepresentation(path).data());
+ if (!dir)
+ return;
+ dirent* dp;
+ while ((dp = readdir(dir))) {
+ if (dp->d_type != DT_DIR && dp->d_type != DT_REG)
+ continue;
+ const char* name = dp->d_name;
+ if (!strcmp(name, ".") || !strcmp(name, ".."))
+ continue;
+ auto nameString = String::fromUTF8(name);
+ if (nameString.isNull())
+ continue;
+ function(nameString, directoryEntryType(dp->d_type));
+ }
+ closedir(dir);
+}
+
+void deleteDirectoryRecursively(const String& path)
+{
+ traverseDirectory(path, [&path](const String& name, DirectoryEntryType type) {
+ String entryPath = WebCore::pathByAppendingComponent(path, name);
+ switch (type) {
+ case DirectoryEntryType::File:
+ WebCore::deleteFile(entryPath);
+ break;
+ case DirectoryEntryType::Directory:
+ deleteDirectoryRecursively(entryPath);
+ break;
+ // This doesn't follow symlinks.
+ }
+ });
+ WebCore::deleteEmptyDirectory(path);
+}
+
+FileTimes fileTimes(const String& path)
+{
+#if HAVE(STAT_BIRTHTIME)
+ struct stat fileInfo;
+ if (stat(WebCore::fileSystemRepresentation(path).data(), &fileInfo))
+ return { };
+ return { std::chrono::system_clock::from_time_t(fileInfo.st_birthtime), std::chrono::system_clock::from_time_t(fileInfo.st_mtime) };
+#elif USE(SOUP)
+ // There's no st_birthtime in some operating systems like Linux, so we use xattrs to set/get the creation time.
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(WebCore::fileSystemRepresentation(path).data()));
+ GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(file.get(), "xattr::birthtime,time::modified", G_FILE_QUERY_INFO_NONE, nullptr, nullptr));
+ if (!fileInfo)
+ return { };
+ const char* birthtimeString = g_file_info_get_attribute_string(fileInfo.get(), "xattr::birthtime");
+ if (!birthtimeString)
+ return { };
+ return { std::chrono::system_clock::from_time_t(g_ascii_strtoull(birthtimeString, nullptr, 10)),
+ std::chrono::system_clock::from_time_t(g_file_info_get_attribute_uint64(fileInfo.get(), "time::modified")) };
+#endif
+}
+
+void updateFileModificationTimeIfNeeded(const String& path)
+{
+ auto times = fileTimes(path);
+ if (times.creation != times.modification) {
+ // Don't update more than once per hour.
+ if (std::chrono::system_clock::now() - times.modification < std::chrono::hours(1))
+ return;
+ }
+ // This really updates both the access time and the modification time.
+ utimes(WebCore::fileSystemRepresentation(path).data(), nullptr);
+}
+
+}
+}
+
+#endif // ENABLE(NETWORK_CACHE)
diff --git a/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm b/Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.h
index 1c6ab641a..17407e8ab 100644
--- a/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheFileSystem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -23,26 +23,33 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import "config.h"
+#ifndef NetworkCacheFileSystem_h
+#define NetworkCacheFileSystem_h
-#if HAVE(XPC)
+#if ENABLE(NETWORK_CACHE)
-#import "EnvironmentUtilities.h"
-#import "NetworkProcess.h"
-#import "WKBase.h"
-#import "XPCServiceEntryPoint.h"
+#include <WebCore/FileSystem.h>
+#include <functional>
-using namespace WebKit;
+namespace WebKit {
+namespace NetworkCache {
-extern "C" WK_EXPORT void NetworkServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage);
+enum class DirectoryEntryType { Directory, File };
+void traverseDirectory(const String& path, const std::function<void (const String& fileName, DirectoryEntryType)>&);
-void NetworkServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage)
-{
- // Remove the SecItemShim from the DYLD_INSERT_LIBRARIES environment variable so any processes spawned by
- // the this process don't try to insert the shim and crash.
- EnvironmentUtilities::stripValuesEndingWithString("DYLD_INSERT_LIBRARIES", "/SecItemShim.dylib");
+void deleteDirectoryRecursively(const String& path);
- XPCServiceInitializer<NetworkProcess, XPCServiceInitializerDelegate>(connection, initializerMessage);
+struct FileTimes {
+ std::chrono::system_clock::time_point creation;
+ std::chrono::system_clock::time_point modification;
+};
+FileTimes fileTimes(const String& path);
+void updateFileModificationTimeIfNeeded(const String& path);
+
+}
}
-#endif // HAVE(XPC)
+#endif
+
+#endif
+
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannel.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannel.h
new file mode 100644
index 000000000..c5edaa8f2
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannel.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheIOChannel_h
+#define NetworkCacheIOChannel_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheData.h"
+#include <functional>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/text/WTFString.h>
+
+#if USE(SOUP)
+#include <wtf/glib/GRefPtr.h>
+#endif
+
+namespace WebKit {
+namespace NetworkCache {
+
+class IOChannel : public ThreadSafeRefCounted<IOChannel> {
+public:
+ enum class Type { Read, Write, Create };
+ static Ref<IOChannel> open(const String& file, Type);
+
+ // Using nullptr as queue submits the result to the main queue.
+ // FIXME: We should add WorkQueue::main() instead.
+ void read(size_t offset, size_t, WorkQueue*, std::function<void (Data&, int error)>);
+ void write(size_t offset, const Data&, WorkQueue*, std::function<void (int error)>);
+
+ const String& path() const { return m_path; }
+ Type type() const { return m_type; }
+
+ int fileDescriptor() const { return m_fileDescriptor; }
+
+private:
+ IOChannel(const String& filePath, IOChannel::Type);
+
+#if USE(SOUP)
+ void readSyncInThread(size_t offset, size_t, WorkQueue*, std::function<void (Data&, int error)>);
+#endif
+
+ String m_path;
+ Type m_type;
+
+ int m_fileDescriptor { 0 };
+#if PLATFORM(COCOA)
+ DispatchPtr<dispatch_io_t> m_dispatchIO;
+#endif
+#if USE(SOUP)
+ GRefPtr<GInputStream> m_inputStream;
+ GRefPtr<GOutputStream> m_outputStream;
+ GRefPtr<GFileIOStream> m_ioStream;
+#endif
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp
new file mode 100644
index 000000000..080ce256d
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "config.h"
+#include "NetworkCacheIOChannel.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheFileSystem.h"
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+#include <wtf/glib/GUniquePtr.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+static const size_t gDefaultReadBufferSize = 4096;
+
+IOChannel::IOChannel(const String& filePath, Type type)
+ : m_path(filePath)
+ , m_type(type)
+{
+ auto path = WebCore::fileSystemRepresentation(filePath);
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(path.data()));
+ switch (m_type) {
+ case Type::Create: {
+ g_file_delete(file.get(), nullptr, nullptr);
+ m_outputStream = adoptGRef(G_OUTPUT_STREAM(g_file_create(file.get(), static_cast<GFileCreateFlags>(G_FILE_CREATE_PRIVATE), nullptr, nullptr)));
+#if !HAVE(STAT_BIRTHTIME)
+ GUniquePtr<char> birthtimeString(g_strdup_printf("%" G_GUINT64_FORMAT, std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())));
+ g_file_set_attribute_string(file.get(), "xattr::birthtime", birthtimeString.get(), G_FILE_QUERY_INFO_NONE, nullptr, nullptr);
+#endif
+ break;
+ }
+ case Type::Write: {
+ m_ioStream = adoptGRef(g_file_open_readwrite(file.get(), nullptr, nullptr));
+ break;
+ }
+ case Type::Read:
+ m_inputStream = adoptGRef(G_INPUT_STREAM(g_file_read(file.get(), nullptr, nullptr)));
+ break;
+ }
+}
+
+Ref<IOChannel> IOChannel::open(const String& filePath, IOChannel::Type type)
+{
+ return adoptRef(*new IOChannel(filePath, type));
+}
+
+static inline void runTaskInQueue(std::function<void ()> task, WorkQueue* queue)
+{
+ if (queue) {
+ queue->dispatch(task);
+ return;
+ }
+
+ // Using nullptr as queue submits the result to the main context.
+ RunLoop::main().dispatch(WTFMove(task));
+}
+
+static void fillDataFromReadBuffer(SoupBuffer* readBuffer, size_t size, Data& data)
+{
+ GRefPtr<SoupBuffer> buffer;
+ if (size != readBuffer->length) {
+ // The subbuffer does not copy the data.
+ buffer = adoptGRef(soup_buffer_new_subbuffer(readBuffer, 0, size));
+ } else
+ buffer = readBuffer;
+
+ if (data.isNull()) {
+ // First chunk, we need to force the data to be copied.
+ data = { reinterpret_cast<const uint8_t*>(buffer->data), size };
+ } else {
+ Data dataRead(WTFMove(buffer));
+ // Concatenate will copy the data.
+ data = concatenate(data, dataRead);
+ }
+}
+
+struct ReadAsyncData {
+ RefPtr<IOChannel> channel;
+ GRefPtr<SoupBuffer> buffer;
+ RefPtr<WorkQueue> queue;
+ size_t bytesToRead;
+ std::function<void (Data&, int error)> completionHandler;
+ Data data;
+};
+
+static void inputStreamReadReadyCallback(GInputStream* stream, GAsyncResult* result, gpointer userData)
+{
+ std::unique_ptr<ReadAsyncData> asyncData(static_cast<ReadAsyncData*>(userData));
+ gssize bytesRead = g_input_stream_read_finish(stream, result, nullptr);
+ if (bytesRead == -1) {
+ WorkQueue* queue = asyncData->queue.get();
+ auto* asyncDataPtr = asyncData.release();
+ runTaskInQueue([asyncDataPtr] {
+ std::unique_ptr<ReadAsyncData> asyncData(asyncDataPtr);
+ asyncData->completionHandler(asyncData->data, -1);
+ }, queue);
+ return;
+ }
+
+ if (!bytesRead) {
+ WorkQueue* queue = asyncData->queue.get();
+ auto* asyncDataPtr = asyncData.release();
+ runTaskInQueue([asyncDataPtr] {
+ std::unique_ptr<ReadAsyncData> asyncData(asyncDataPtr);
+ asyncData->completionHandler(asyncData->data, 0);
+ }, queue);
+ return;
+ }
+
+ ASSERT(bytesRead > 0);
+ fillDataFromReadBuffer(asyncData->buffer.get(), static_cast<size_t>(bytesRead), asyncData->data);
+
+ size_t pendingBytesToRead = asyncData->bytesToRead - asyncData->data.size();
+ if (!pendingBytesToRead) {
+ WorkQueue* queue = asyncData->queue.get();
+ auto* asyncDataPtr = asyncData.release();
+ runTaskInQueue([asyncDataPtr] {
+ std::unique_ptr<ReadAsyncData> asyncData(asyncDataPtr);
+ asyncData->completionHandler(asyncData->data, 0);
+ }, queue);
+ return;
+ }
+
+ size_t bytesToRead = std::min(pendingBytesToRead, asyncData->buffer->length);
+ // Use a local variable for the data buffer to pass it to g_input_stream_read_async(), because ReadAsyncData is released.
+ auto data = const_cast<char*>(asyncData->buffer->data);
+ g_input_stream_read_async(stream, data, bytesToRead, G_PRIORITY_DEFAULT, nullptr,
+ reinterpret_cast<GAsyncReadyCallback>(inputStreamReadReadyCallback), asyncData.release());
+}
+
+void IOChannel::read(size_t offset, size_t size, WorkQueue* queue, std::function<void (Data&, int error)> completionHandler)
+{
+ RefPtr<IOChannel> channel(this);
+ if (!m_inputStream) {
+ runTaskInQueue([channel, completionHandler] {
+ Data data;
+ completionHandler(data, -1);
+ }, queue);
+ return;
+ }
+
+ if (!isMainThread()) {
+ readSyncInThread(offset, size, queue, completionHandler);
+ return;
+ }
+
+ size_t bufferSize = std::min(size, gDefaultReadBufferSize);
+ uint8_t* bufferData = static_cast<uint8_t*>(fastMalloc(bufferSize));
+ GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new_with_owner(bufferData, bufferSize, bufferData, fastFree));
+ ReadAsyncData* asyncData = new ReadAsyncData { this, buffer.get(), queue, size, completionHandler, { } };
+
+ // FIXME: implement offset.
+ g_input_stream_read_async(m_inputStream.get(), const_cast<char*>(buffer->data), bufferSize, G_PRIORITY_DEFAULT, nullptr,
+ reinterpret_cast<GAsyncReadyCallback>(inputStreamReadReadyCallback), asyncData);
+}
+
+void IOChannel::readSyncInThread(size_t offset, size_t size, WorkQueue* queue, std::function<void (Data&, int error)> completionHandler)
+{
+ ASSERT(!isMainThread());
+
+ RefPtr<IOChannel> channel(this);
+ detachThread(createThread("IOChannel::readSync", [channel, size, queue, completionHandler] {
+ size_t bufferSize = std::min(size, gDefaultReadBufferSize);
+ uint8_t* bufferData = static_cast<uint8_t*>(fastMalloc(bufferSize));
+ GRefPtr<SoupBuffer> readBuffer = adoptGRef(soup_buffer_new_with_owner(bufferData, bufferSize, bufferData, fastFree));
+ Data data;
+ size_t pendingBytesToRead = size;
+ size_t bytesToRead = bufferSize;
+ do {
+ // FIXME: implement offset.
+ gssize bytesRead = g_input_stream_read(channel->m_inputStream.get(), const_cast<char*>(readBuffer->data), bytesToRead, nullptr, nullptr);
+ if (bytesRead == -1) {
+ runTaskInQueue([channel, completionHandler] {
+ Data data;
+ completionHandler(data, -1);
+ }, queue);
+ return;
+ }
+
+ if (!bytesRead)
+ break;
+
+ ASSERT(bytesRead > 0);
+ fillDataFromReadBuffer(readBuffer.get(), static_cast<size_t>(bytesRead), data);
+
+ pendingBytesToRead = size - data.size();
+ bytesToRead = std::min(pendingBytesToRead, readBuffer->length);
+ } while (pendingBytesToRead);
+
+ GRefPtr<SoupBuffer> bufferCapture = data.soupBuffer();
+ runTaskInQueue([channel, bufferCapture, completionHandler] {
+ GRefPtr<SoupBuffer> buffer = bufferCapture;
+ Data data = { WTFMove(buffer) };
+ completionHandler(data, 0);
+ }, queue);
+ }));
+}
+
+struct WriteAsyncData {
+ RefPtr<IOChannel> channel;
+ GRefPtr<SoupBuffer> buffer;
+ RefPtr<WorkQueue> queue;
+ std::function<void (int error)> completionHandler;
+};
+
+static void outputStreamWriteReadyCallback(GOutputStream* stream, GAsyncResult* result, gpointer userData)
+{
+ std::unique_ptr<WriteAsyncData> asyncData(static_cast<WriteAsyncData*>(userData));
+ gssize bytesWritten = g_output_stream_write_finish(stream, result, nullptr);
+ if (bytesWritten == -1) {
+ WorkQueue* queue = asyncData->queue.get();
+ auto* asyncDataPtr = asyncData.release();
+ runTaskInQueue([asyncDataPtr] {
+ std::unique_ptr<WriteAsyncData> asyncData(asyncDataPtr);
+ asyncData->completionHandler(-1);
+ }, queue);
+ return;
+ }
+
+ gssize pendingBytesToWrite = asyncData->buffer->length - bytesWritten;
+ if (!pendingBytesToWrite) {
+ WorkQueue* queue = asyncData->queue.get();
+ auto* asyncDataPtr = asyncData.release();
+ runTaskInQueue([asyncDataPtr] {
+ std::unique_ptr<WriteAsyncData> asyncData(asyncDataPtr);
+ asyncData->completionHandler(0);
+ }, queue);
+ return;
+ }
+
+ asyncData->buffer = adoptGRef(soup_buffer_new_subbuffer(asyncData->buffer.get(), bytesWritten, pendingBytesToWrite));
+ // Use a local variable for the data buffer to pass it to g_output_stream_write_async(), because WriteAsyncData is released.
+ auto data = asyncData->buffer->data;
+ g_output_stream_write_async(stream, data, pendingBytesToWrite, G_PRIORITY_DEFAULT_IDLE, nullptr,
+ reinterpret_cast<GAsyncReadyCallback>(outputStreamWriteReadyCallback), asyncData.release());
+}
+
+void IOChannel::write(size_t offset, const Data& data, WorkQueue* queue, std::function<void (int error)> completionHandler)
+{
+ RefPtr<IOChannel> channel(this);
+ if (!m_outputStream && !m_ioStream) {
+ runTaskInQueue([channel, completionHandler] {
+ completionHandler(-1);
+ }, queue);
+ return;
+ }
+
+ GOutputStream* stream = m_outputStream ? m_outputStream.get() : g_io_stream_get_output_stream(G_IO_STREAM(m_ioStream.get()));
+ if (!stream) {
+ runTaskInQueue([channel, completionHandler] {
+ completionHandler(-1);
+ }, queue);
+ return;
+ }
+
+ WriteAsyncData* asyncData = new WriteAsyncData { this, data.soupBuffer(), queue, completionHandler };
+ // FIXME: implement offset.
+ g_output_stream_write_async(stream, asyncData->buffer->data, data.size(), G_PRIORITY_DEFAULT_IDLE, nullptr,
+ reinterpret_cast<GAsyncReadyCallback>(outputStreamWriteReadyCallback), asyncData);
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp
new file mode 100644
index 000000000..1f06a65bb
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2014-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 "NetworkCacheKey.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheCoders.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+Key::Key(const Key& o)
+ : m_partition(o.m_partition.isolatedCopy())
+ , m_type(o.m_type.isolatedCopy())
+ , m_identifier(o.m_identifier.isolatedCopy())
+ , m_range(o.m_range.isolatedCopy())
+ , m_hash(o.m_hash)
+{
+}
+
+Key::Key(const String& partition, const String& type, const String& range, const String& identifier)
+ : m_partition(partition.isolatedCopy())
+ , m_type(type.isolatedCopy())
+ , m_identifier(identifier.isolatedCopy())
+ , m_range(range.isolatedCopy())
+ , m_hash(computeHash())
+{
+}
+
+Key::Key(WTF::HashTableDeletedValueType)
+ : m_identifier(WTF::HashTableDeletedValue)
+{
+}
+
+Key& Key::operator=(const Key& other)
+{
+ m_partition = other.m_partition.isolatedCopy();
+ m_type = other.m_type.isolatedCopy();
+ m_identifier = other.m_identifier.isolatedCopy();
+ m_range = other.m_range.isolatedCopy();
+ m_hash = other.m_hash;
+ return *this;
+}
+
+static void hashString(SHA1& sha1, const String& string)
+{
+ if (string.isNull())
+ return;
+
+ if (string.is8Bit() && string.containsOnlyASCII()) {
+ const uint8_t nullByte = 0;
+ sha1.addBytes(string.characters8(), string.length());
+ sha1.addBytes(&nullByte, 1);
+ return;
+ }
+ auto cString = string.utf8();
+ // Include terminating null byte.
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length() + 1);
+}
+
+Key::HashType Key::computeHash() const
+{
+ // We don't really need a cryptographic hash. The key is always verified against the entry header.
+ // SHA1 just happens to be suitably sized, fast and available.
+ SHA1 sha1;
+ hashString(sha1, m_partition);
+ hashString(sha1, m_type);
+ hashString(sha1, m_identifier);
+ hashString(sha1, m_range);
+ SHA1::Digest hash;
+ sha1.computeHash(hash);
+ return hash;
+}
+
+String Key::hashAsString() const
+{
+ StringBuilder builder;
+ builder.reserveCapacity(hashStringLength());
+ for (auto byte : m_hash) {
+ builder.append(upperNibbleToASCIIHexDigit(byte));
+ builder.append(lowerNibbleToASCIIHexDigit(byte));
+ }
+ return builder.toString();
+}
+
+template <typename CharType> bool hexDigitsToHash(CharType* characters, Key::HashType& hash)
+{
+ for (unsigned i = 0; i < sizeof(hash); ++i) {
+ auto high = characters[2 * i];
+ auto low = characters[2 * i + 1];
+ if (!isASCIIHexDigit(high) || !isASCIIHexDigit(low))
+ return false;
+ hash[i] = toASCIIHexValue(high, low);
+ }
+ return true;
+}
+
+bool Key::stringToHash(const String& string, HashType& hash)
+{
+ if (string.length() != hashStringLength())
+ return false;
+ if (string.is8Bit())
+ return hexDigitsToHash(string.characters8(), hash);
+ return hexDigitsToHash(string.characters16(), hash);
+}
+
+bool Key::operator==(const Key& other) const
+{
+ return m_hash == other.m_hash && m_partition == other.m_partition && m_type == other.m_type && m_identifier == other.m_identifier && m_range == other.m_range;
+}
+
+void Key::encode(Encoder& encoder) const
+{
+ encoder << m_partition;
+ encoder << m_type;
+ encoder << m_identifier;
+ encoder << m_range;
+ encoder << m_hash;
+}
+
+bool Key::decode(Decoder& decoder, Key& key)
+{
+ return decoder.decode(key.m_partition) && decoder.decode(key.m_type) && decoder.decode(key.m_identifier) && decoder.decode(key.m_range) && decoder.decode(key.m_hash);
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h
new file mode 100644
index 000000000..12a7007fd
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2014-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.
+ */
+
+#ifndef NetworkCacheKey_h
+#define NetworkCacheKey_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include <wtf/SHA1.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Encoder;
+class Decoder;
+
+class Key {
+public:
+ typedef SHA1::Digest HashType;
+
+ Key() { }
+ Key(const Key&);
+ Key(Key&&) = default;
+ Key(const String& partition, const String& type, const String& range, const String& identifier);
+
+ Key& operator=(const Key&);
+ Key& operator=(Key&&) = default;
+
+ Key(WTF::HashTableDeletedValueType);
+ bool isHashTableDeletedValue() const { return m_identifier.isHashTableDeletedValue(); }
+
+ bool isNull() const { return m_identifier.isNull(); }
+
+ const String& partition() const { return m_partition; }
+ const String& identifier() const { return m_identifier; }
+ const String& type() const { return m_type; }
+ const String& range() const { return m_range; }
+
+ HashType hash() const { return m_hash; }
+
+ static bool stringToHash(const String&, HashType&);
+
+ static size_t hashStringLength() { return 2 * sizeof(m_hash); }
+ String hashAsString() const;
+
+ void encode(Encoder&) const;
+ static bool decode(Decoder&, Key&);
+
+ bool operator==(const Key&) const;
+ bool operator!=(const Key& other) const { return !(*this == other); }
+
+private:
+ HashType computeHash() const;
+
+ String m_partition;
+ String m_type;
+ String m_identifier;
+ String m_range;
+ HashType m_hash;
+};
+
+}
+}
+
+namespace WTF {
+
+struct NetworkCacheKeyHash {
+ static unsigned hash(const WebKit::NetworkCache::Key& key)
+ {
+ static_assert(SHA1::hashSize >= sizeof(unsigned), "Hash size must be greater than sizeof(unsigned)");
+ return *reinterpret_cast<const unsigned*>(key.hash().data());
+ }
+
+ static bool equal(const WebKit::NetworkCache::Key& a, const WebKit::NetworkCache::Key& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<WebKit::NetworkCache::Key> {
+ typedef NetworkCacheKeyHash Hash;
+};
+
+template<> struct HashTraits<WebKit::NetworkCache::Key> : SimpleClassHashTraits<WebKit::NetworkCache::Key> {
+ static const bool emptyValueIsZero = false;
+
+ static const bool hasIsEmptyValueFunction = true;
+ static bool isEmptyValue(const WebKit::NetworkCache::Key& key) { return key.isNull(); }
+};
+
+} // namespace WTF
+
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp
new file mode 100644
index 000000000..f6f594030
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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"
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#include "NetworkCacheSpeculativeLoad.h"
+
+#include "Logging.h"
+#include "NetworkCache.h"
+#include "NetworkLoad.h"
+#include <WebCore/SessionID.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+using namespace WebCore;
+
+SpeculativeLoad::SpeculativeLoad(const GlobalFrameID& frameID, const ResourceRequest& request, std::unique_ptr<NetworkCache::Entry> cacheEntryForValidation, RevalidationCompletionHandler&& completionHandler)
+ : m_frameID(frameID)
+ , m_completionHandler(WTFMove(completionHandler))
+ , m_originalRequest(request)
+ , m_bufferedDataForCache(SharedBuffer::create())
+ , m_cacheEntryForValidation(WTFMove(cacheEntryForValidation))
+{
+ ASSERT(m_cacheEntryForValidation);
+ ASSERT(m_cacheEntryForValidation->needsValidation());
+
+ NetworkLoadParameters parameters;
+ parameters.sessionID = SessionID::defaultSessionID();
+ parameters.allowStoredCredentials = AllowStoredCredentials;
+ parameters.contentSniffingPolicy = DoNotSniffContent;
+ parameters.request = m_originalRequest;
+ m_networkLoad = std::make_unique<NetworkLoad>(*this, parameters);
+}
+
+SpeculativeLoad::~SpeculativeLoad()
+{
+ ASSERT(!m_networkLoad);
+}
+
+void SpeculativeLoad::willSendRedirectedRequest(const ResourceRequest& request, const ResourceRequest& redirectRequest, const ResourceResponse& redirectResponse)
+{
+ updateRedirectChainStatus(m_redirectChainCacheStatus, redirectResponse);
+}
+
+auto SpeculativeLoad::didReceiveResponse(const ResourceResponse& receivedResponse) -> ShouldContinueDidReceiveResponse
+{
+ m_response = receivedResponse;
+
+ if (m_response.isMultipart())
+ m_bufferedDataForCache = nullptr;
+
+ ASSERT(m_cacheEntryForValidation);
+
+ bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
+ if (validationSucceeded) {
+ m_cacheEntryForValidation = NetworkCache::singleton().update(m_originalRequest, m_frameID, *m_cacheEntryForValidation, m_response);
+ didComplete();
+ return ShouldContinueDidReceiveResponse::No;
+ }
+
+ m_cacheEntryForValidation = nullptr;
+
+ return ShouldContinueDidReceiveResponse::Yes;
+}
+
+void SpeculativeLoad::didReceiveBuffer(RefPtr<SharedBuffer>&& buffer, int reportedEncodedDataLength)
+{
+ ASSERT(!m_cacheEntryForValidation);
+
+ if (m_bufferedDataForCache) {
+ // Prevent memory growth in case of streaming data.
+ const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
+ if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
+ m_bufferedDataForCache->append(buffer.get());
+ else
+ m_bufferedDataForCache = nullptr;
+ }
+}
+
+void SpeculativeLoad::didFinishLoading(double finishTime)
+{
+ ASSERT(!m_cacheEntryForValidation);
+
+ bool allowStale = m_originalRequest.cachePolicy() >= ReturnCacheDataElseLoad;
+ bool hasCacheableRedirect = m_response.isHTTP() && redirectChainAllowsReuse(m_redirectChainCacheStatus, allowStale ? ReuseExpiredRedirection : DoNotReuseExpiredRedirection);
+ if (hasCacheableRedirect && m_redirectChainCacheStatus.status == RedirectChainCacheStatus::CachedRedirection) {
+ // Maybe we should cache the actual redirects instead of the end result?
+ auto now = std::chrono::system_clock::now();
+ auto responseEndOfValidity = now + computeFreshnessLifetimeForHTTPFamily(m_response, now) - computeCurrentAge(m_response, now);
+ hasCacheableRedirect = responseEndOfValidity <= m_redirectChainCacheStatus.endOfValidity;
+ }
+
+ if (m_bufferedDataForCache && hasCacheableRedirect)
+ m_cacheEntryForValidation = NetworkCache::singleton().store(m_originalRequest, m_response, WTFMove(m_bufferedDataForCache), [](NetworkCache::MappedBody& mappedBody) { });
+ else if (!hasCacheableRedirect) {
+ // Make sure we don't keep a stale entry in the cache.
+ NetworkCache::singleton().remove(m_originalRequest);
+ }
+
+ didComplete();
+}
+
+void SpeculativeLoad::didFailLoading(const ResourceError&)
+{
+ m_cacheEntryForValidation = nullptr;
+
+ didComplete();
+}
+
+void SpeculativeLoad::didComplete()
+{
+ RELEASE_ASSERT(RunLoop::isMain());
+
+ m_networkLoad = nullptr;
+
+ m_completionHandler(WTFMove(m_cacheEntryForValidation));
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h
new file mode 100644
index 000000000..3ce3b63bf
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheSpeculativeLoad_h
+#define NetworkCacheSpeculativeLoad_h
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#include "NetworkCache.h"
+#include "NetworkCacheEntry.h"
+#include "NetworkLoadClient.h"
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/ResourceResponse.h>
+#include <WebCore/SharedBuffer.h>
+
+namespace WebKit {
+
+class NetworkLoad;
+
+namespace NetworkCache {
+
+class SpeculativeLoad final : public NetworkLoadClient {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef std::function<void (std::unique_ptr<NetworkCache::Entry>)> RevalidationCompletionHandler;
+ SpeculativeLoad(const GlobalFrameID&, const WebCore::ResourceRequest&, std::unique_ptr<NetworkCache::Entry>, RevalidationCompletionHandler&&);
+
+ virtual ~SpeculativeLoad();
+
+private:
+ // NetworkLoadClient.
+ virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override { }
+ virtual void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) override { }
+ virtual bool isSynchronous() const override { return false; }
+ virtual void willSendRedirectedRequest(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse) override;
+ virtual ShouldContinueDidReceiveResponse didReceiveResponse(const WebCore::ResourceResponse&) override;
+ virtual void didReceiveBuffer(RefPtr<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) override;
+ virtual void didFinishLoading(double finishTime) override;
+ virtual void didFailLoading(const WebCore::ResourceError&) override;
+ virtual void didConvertToDownload() override { ASSERT_NOT_REACHED(); }
+#if PLATFORM(COCOA)
+ virtual void willCacheResponseAsync(CFCachedURLResponseRef) override { }
+#endif
+
+ void didComplete();
+
+ GlobalFrameID m_frameID;
+ RevalidationCompletionHandler m_completionHandler;
+ WebCore::ResourceRequest m_originalRequest;
+
+ std::unique_ptr<NetworkLoad> m_networkLoad;
+
+ WebCore::ResourceResponse m_response;
+
+ RefPtr<WebCore::SharedBuffer> m_bufferedDataForCache;
+ std::unique_ptr<NetworkCache::Entry> m_cacheEntryForValidation;
+
+ WebCore::RedirectChainCacheStatus m_redirectChainCacheStatus;
+};
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#endif // NetworkCacheSpeculativeLoad_h
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp
new file mode 100644
index 000000000..027591100
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp
@@ -0,0 +1,453 @@
+/*
+ * 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"
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#include "NetworkCacheSpeculativeLoadManager.h"
+
+#include "Logging.h"
+#include "NetworkCacheEntry.h"
+#include "NetworkCacheSpeculativeLoad.h"
+#include "NetworkCacheSubresourcesEntry.h"
+#include "NetworkProcess.h"
+#include <WebCore/DiagnosticLoggingKeys.h>
+#include <WebCore/HysteresisActivity.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+
+namespace NetworkCache {
+
+using namespace WebCore;
+
+static const auto preloadedEntryLifetime = 10_s;
+
+#if !LOG_DISABLED
+static HashCountedSet<String>& allSpeculativeLoadingDiagnosticMessages()
+{
+ static NeverDestroyed<HashCountedSet<String>> messages;
+ return messages;
+}
+
+static void printSpeculativeLoadingDiagnosticMessageCounts()
+{
+ LOG(NetworkCacheSpeculativePreloading, "-- Speculative loading statistics --");
+ for (auto& pair : allSpeculativeLoadingDiagnosticMessages())
+ LOG(NetworkCacheSpeculativePreloading, "%s: %u", pair.key.utf8().data(), pair.value);
+}
+#endif
+
+static void logSpeculativeLoadingDiagnosticMessage(const GlobalFrameID& frameID, const String& message)
+{
+#if !LOG_DISABLED
+ if (WebKit2LogNetworkCacheSpeculativePreloading.state == WTFLogChannelOn)
+ allSpeculativeLoadingDiagnosticMessages().add(message);
+#endif
+ NetworkProcess::singleton().logDiagnosticMessage(frameID.first, WebCore::DiagnosticLoggingKeys::networkCacheKey(), message, WebCore::ShouldSample::Yes);
+}
+
+static const AtomicString& subresourcesType()
+{
+ ASSERT(RunLoop::isMain());
+ static NeverDestroyed<const AtomicString> resource("subresources", AtomicString::ConstructFromLiteral);
+ return resource;
+}
+
+static inline Key makeSubresourcesKey(const Key& resourceKey)
+{
+ return Key(resourceKey.partition(), subresourcesType(), resourceKey.range(), resourceKey.identifier());
+}
+
+static inline ResourceRequest constructRevalidationRequest(const Entry& entry)
+{
+ ResourceRequest revalidationRequest(entry.key().identifier());
+
+ String eTag = entry.response().httpHeaderField(HTTPHeaderName::ETag);
+ if (!eTag.isEmpty())
+ revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
+
+ String lastModified = entry.response().httpHeaderField(HTTPHeaderName::LastModified);
+ if (!lastModified.isEmpty())
+ revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
+
+ return revalidationRequest;
+}
+
+static bool responseNeedsRevalidation(const ResourceResponse& response, std::chrono::system_clock::time_point timestamp)
+{
+ if (response.cacheControlContainsNoCache())
+ return true;
+
+ auto age = computeCurrentAge(response, timestamp);
+ auto lifetime = computeFreshnessLifetimeForHTTPFamily(response, timestamp);
+ return age - lifetime > 0_ms;
+}
+
+class SpeculativeLoadManager::ExpiringEntry {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit ExpiringEntry(std::function<void()>&& expirationHandler)
+ : m_lifetimeTimer(WTFMove(expirationHandler))
+ {
+ m_lifetimeTimer.startOneShot(preloadedEntryLifetime);
+ }
+
+private:
+ Timer m_lifetimeTimer;
+};
+
+class SpeculativeLoadManager::PreloadedEntry : private ExpiringEntry {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ PreloadedEntry(std::unique_ptr<Entry> entry, WasRevalidated wasRevalidated, std::function<void()>&& lifetimeReachedHandler)
+ : ExpiringEntry(WTFMove(lifetimeReachedHandler))
+ , m_entry(WTFMove(entry))
+ , m_wasRevalidated(wasRevalidated == WasRevalidated::Yes)
+ { }
+
+ std::unique_ptr<Entry> takeCacheEntry()
+ {
+ ASSERT(m_entry);
+ return WTFMove(m_entry);
+ }
+
+ bool wasRevalidated() const { return m_wasRevalidated; }
+
+private:
+ std::unique_ptr<Entry> m_entry;
+ bool m_wasRevalidated;
+};
+
+class SpeculativeLoadManager::PendingFrameLoad : public RefCounted<PendingFrameLoad> {
+public:
+ static Ref<PendingFrameLoad> create(Storage& storage, const Key& mainResourceKey, std::function<void()>&& loadCompletionHandler)
+ {
+ return adoptRef(*new PendingFrameLoad(storage, mainResourceKey, WTFMove(loadCompletionHandler)));
+ }
+
+ ~PendingFrameLoad()
+ {
+ ASSERT(m_didFinishLoad);
+ ASSERT(m_didRetrieveExistingEntry);
+ }
+
+ void registerSubresource(const Key& subresourceKey)
+ {
+ ASSERT(RunLoop::isMain());
+ m_subresourceKeys.append(subresourceKey);
+ m_loadHysteresisActivity.impulse();
+ }
+
+ void markLoadAsCompleted()
+ {
+ ASSERT(RunLoop::isMain());
+ if (m_didFinishLoad)
+ return;
+
+#if !LOG_DISABLED
+ printSpeculativeLoadingDiagnosticMessageCounts();
+#endif
+
+ m_didFinishLoad = true;
+ saveToDiskIfReady();
+ m_loadCompletionHandler();
+ }
+
+ void setExistingSubresourcesEntry(std::unique_ptr<SubresourcesEntry> entry)
+ {
+ ASSERT(!m_existingEntry);
+ ASSERT(!m_didRetrieveExistingEntry);
+
+ m_existingEntry = WTFMove(entry);
+ m_didRetrieveExistingEntry = true;
+ saveToDiskIfReady();
+ }
+
+private:
+ PendingFrameLoad(Storage& storage, const Key& mainResourceKey, std::function<void()>&& loadCompletionHandler)
+ : m_storage(storage)
+ , m_mainResourceKey(mainResourceKey)
+ , m_loadCompletionHandler(WTFMove(loadCompletionHandler))
+ , m_loadHysteresisActivity([this](HysteresisState state) { if (state == HysteresisState::Stopped) markLoadAsCompleted(); })
+ { }
+
+ void saveToDiskIfReady()
+ {
+ if (!m_didFinishLoad || !m_didRetrieveExistingEntry)
+ return;
+
+ if (m_subresourceKeys.isEmpty())
+ return;
+
+#if !LOG_DISABLED
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Saving to disk list of subresources for '%s':", m_mainResourceKey.identifier().utf8().data());
+ for (auto& subresourceKey : m_subresourceKeys)
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) * Subresource: '%s'.", subresourceKey.identifier().utf8().data());
+#endif
+
+ if (m_existingEntry) {
+ m_existingEntry->updateSubresourceKeys(m_subresourceKeys);
+ m_storage.store(m_existingEntry->encodeAsStorageRecord(), [](const Data&) { });
+ } else {
+ SubresourcesEntry entry(makeSubresourcesKey(m_mainResourceKey), m_subresourceKeys);
+ m_storage.store(entry.encodeAsStorageRecord(), [](const Data&) { });
+ }
+ }
+
+ Storage& m_storage;
+ Key m_mainResourceKey;
+ Vector<Key> m_subresourceKeys;
+ std::function<void()> m_loadCompletionHandler;
+ HysteresisActivity m_loadHysteresisActivity;
+ std::unique_ptr<SubresourcesEntry> m_existingEntry;
+ bool m_didFinishLoad { false };
+ bool m_didRetrieveExistingEntry { false };
+};
+
+SpeculativeLoadManager::SpeculativeLoadManager(Storage& storage)
+ : m_storage(storage)
+{
+}
+
+SpeculativeLoadManager::~SpeculativeLoadManager()
+{
+}
+
+bool SpeculativeLoadManager::retrieve(const GlobalFrameID& frameID, const Key& storageKey, const RetrieveCompletionHandler& completionHandler)
+{
+ // Check already preloaded entries.
+ if (auto preloadedEntry = m_preloadedEntries.take(storageKey)) {
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Retrieval: Using preloaded entry to satisfy request for '%s':", storageKey.identifier().utf8().data());
+ if (preloadedEntry->wasRevalidated())
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::successfulSpeculativeWarmupWithRevalidationKey());
+ else
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::successfulSpeculativeWarmupWithoutRevalidationKey());
+
+ completionHandler(preloadedEntry->takeCacheEntry());
+ return true;
+ }
+
+ // Check pending speculative revalidations.
+ if (!m_pendingPreloads.contains(storageKey)) {
+ if (m_notPreloadedEntries.remove(storageKey))
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::entryWronglyNotWarmedUpKey());
+ else
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::unknownEntryRequestKey());
+
+ return false;
+ }
+
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Retrieval: revalidation already in progress for '%s':", storageKey.identifier().utf8().data());
+
+ // FIXME: This breaks incremental loading when the revalidation is not successful.
+ auto addResult = m_pendingRetrieveRequests.add(storageKey, nullptr);
+ if (addResult.isNewEntry)
+ addResult.iterator->value = std::make_unique<Vector<RetrieveCompletionHandler>>();
+ addResult.iterator->value->append(completionHandler);
+ return true;
+}
+
+void SpeculativeLoadManager::registerLoad(const GlobalFrameID& frameID, const ResourceRequest& request, const Key& resourceKey)
+{
+ ASSERT(RunLoop::isMain());
+
+ if (!request.url().protocolIsInHTTPFamily() || request.httpMethod() != "GET")
+ return;
+
+ auto isMainResource = request.requester() == ResourceRequest::Requester::Main;
+ if (isMainResource) {
+ // Mark previous load in this frame as completed if necessary.
+ if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameID))
+ pendingFrameLoad->markLoadAsCompleted();
+
+ ASSERT(!m_pendingFrameLoads.contains(frameID));
+
+ // Start tracking loads in this frame.
+ RefPtr<PendingFrameLoad> pendingFrameLoad = PendingFrameLoad::create(m_storage, resourceKey, [this, frameID] {
+ bool wasRemoved = m_pendingFrameLoads.remove(frameID);
+ ASSERT_UNUSED(wasRemoved, wasRemoved);
+ });
+ m_pendingFrameLoads.add(frameID, pendingFrameLoad);
+
+ // Retrieve the subresources entry if it exists to start speculative revalidation and to update it.
+ retrieveSubresourcesEntry(resourceKey, [this, frameID, pendingFrameLoad](std::unique_ptr<SubresourcesEntry> entry) {
+ if (entry)
+ startSpeculativeRevalidation(frameID, *entry);
+
+ pendingFrameLoad->setExistingSubresourcesEntry(WTFMove(entry));
+ });
+ return;
+ }
+
+ if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameID))
+ pendingFrameLoad->registerSubresource(resourceKey);
+}
+
+void SpeculativeLoadManager::addPreloadedEntry(std::unique_ptr<Entry> entry, const GlobalFrameID& frameID, WasRevalidated wasRevalidated)
+{
+ ASSERT(entry);
+ ASSERT(!entry->needsValidation());
+ auto key = entry->key();
+ m_preloadedEntries.add(key, std::make_unique<PreloadedEntry>(WTFMove(entry), wasRevalidated, [this, key, frameID] {
+ auto preloadedEntry = m_preloadedEntries.take(key);
+ ASSERT(preloadedEntry);
+ if (preloadedEntry->wasRevalidated())
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::wastedSpeculativeWarmupWithRevalidationKey());
+ else
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::wastedSpeculativeWarmupWithoutRevalidationKey());
+ }));
+}
+
+void SpeculativeLoadManager::retrieveEntryFromStorage(const Key& key, const RetrieveCompletionHandler& completionHandler)
+{
+ m_storage.retrieve(key, static_cast<unsigned>(ResourceLoadPriority::Medium), [completionHandler](std::unique_ptr<Storage::Record> record) {
+ if (!record) {
+ completionHandler(nullptr);
+ return false;
+ }
+ auto entry = Entry::decodeStorageRecord(*record);
+ if (!entry) {
+ completionHandler(nullptr);
+ return false;
+ }
+
+ auto& response = entry->response();
+ if (!response.hasCacheValidatorFields()) {
+ completionHandler(nullptr);
+ return true;
+ }
+
+ if (responseNeedsRevalidation(response, entry->timeStamp()))
+ entry->setNeedsValidation();
+
+ completionHandler(WTFMove(entry));
+ return true;
+ });
+}
+
+bool SpeculativeLoadManager::satisfyPendingRequests(const Key& key, Entry* entry)
+{
+ auto completionHandlers = m_pendingRetrieveRequests.take(key);
+ if (!completionHandlers)
+ return false;
+
+ for (auto& completionHandler : *completionHandlers)
+ completionHandler(entry ? std::make_unique<Entry>(*entry) : nullptr);
+
+ return true;
+}
+
+void SpeculativeLoadManager::revalidateEntry(std::unique_ptr<Entry> entry, const GlobalFrameID& frameID)
+{
+ ASSERT(entry);
+ ASSERT(entry->needsValidation());
+
+ auto key = entry->key();
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Speculatively revalidating '%s':", key.identifier().utf8().data());
+ auto revalidator = std::make_unique<SpeculativeLoad>(frameID, constructRevalidationRequest(*entry), WTFMove(entry), [this, key, frameID](std::unique_ptr<Entry> revalidatedEntry) {
+ ASSERT(!revalidatedEntry || !revalidatedEntry->needsValidation());
+ auto protectRevalidator = m_pendingPreloads.take(key);
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Speculative revalidation completed for '%s':", key.identifier().utf8().data());
+
+ if (satisfyPendingRequests(key, revalidatedEntry.get())) {
+ if (revalidatedEntry)
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::successfulSpeculativeWarmupWithRevalidationKey());
+ return;
+ }
+
+ if (revalidatedEntry)
+ addPreloadedEntry(WTFMove(revalidatedEntry), frameID, WasRevalidated::Yes);
+ });
+ m_pendingPreloads.add(key, WTFMove(revalidator));
+}
+
+void SpeculativeLoadManager::preloadEntry(const Key& key, const GlobalFrameID& frameID)
+{
+ m_pendingPreloads.add(key, nullptr);
+ retrieveEntryFromStorage(key, [this, key, frameID](std::unique_ptr<Entry> entry) {
+ m_pendingPreloads.remove(key);
+
+ if (satisfyPendingRequests(key, entry.get())) {
+ if (entry)
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::successfulSpeculativeWarmupWithoutRevalidationKey());
+ return;
+ }
+
+ if (!entry)
+ return;
+
+ if (entry->needsValidation())
+ revalidateEntry(WTFMove(entry), frameID);
+ else
+ addPreloadedEntry(WTFMove(entry), frameID, WasRevalidated::No);
+ });
+}
+
+void SpeculativeLoadManager::startSpeculativeRevalidation(const GlobalFrameID& frameID, SubresourcesEntry& entry)
+{
+ for (auto& subresource : entry.subresources()) {
+ auto key = subresource.key;
+ if (!subresource.value.isTransient)
+ preloadEntry(key, frameID);
+ else {
+ LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Not preloading '%s' because it is marked as transient", subresource.key.identifier().utf8().data());
+ m_notPreloadedEntries.add(key, std::make_unique<ExpiringEntry>([this, key, frameID] {
+ logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::entryRightlyNotWarmedUpKey());
+ m_notPreloadedEntries.remove(key);
+ }));
+ }
+ }
+}
+
+void SpeculativeLoadManager::retrieveSubresourcesEntry(const Key& storageKey, std::function<void (std::unique_ptr<SubresourcesEntry>)> completionHandler)
+{
+ ASSERT(storageKey.type() == "resource");
+ auto subresourcesStorageKey = makeSubresourcesKey(storageKey);
+ m_storage.retrieve(subresourcesStorageKey, static_cast<unsigned>(ResourceLoadPriority::Medium), [completionHandler](std::unique_ptr<Storage::Record> record) {
+ if (!record) {
+ completionHandler(nullptr);
+ return false;
+ }
+
+ auto subresourcesEntry = SubresourcesEntry::decodeStorageRecord(*record);
+ if (!subresourcesEntry) {
+ completionHandler(nullptr);
+ return false;
+ }
+
+ completionHandler(WTFMove(subresourcesEntry));
+ return true;
+ });
+}
+
+} // namespace NetworkCache
+
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h
new file mode 100644
index 000000000..4c1de7200
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheSpeculativeLoadManager_h
+#define NetworkCacheSpeculativeLoadManager_h
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#include "NetworkCache.h"
+#include "NetworkCacheStorage.h"
+#include <WebCore/ResourceRequest.h>
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+
+namespace NetworkCache {
+
+class Entry;
+class SpeculativeLoad;
+class SubresourcesEntry;
+
+class SpeculativeLoadManager {
+public:
+ explicit SpeculativeLoadManager(Storage&);
+ ~SpeculativeLoadManager();
+
+ void registerLoad(const GlobalFrameID&, const WebCore::ResourceRequest&, const Key& resourceKey);
+
+ typedef std::function<void (std::unique_ptr<Entry>)> RetrieveCompletionHandler;
+ bool retrieve(const GlobalFrameID&, const Key& storageKey, const RetrieveCompletionHandler&);
+
+private:
+ enum class WasRevalidated { No, Yes };
+ void addPreloadedEntry(std::unique_ptr<Entry>, const GlobalFrameID&, WasRevalidated);
+ void preloadEntry(const Key&, const GlobalFrameID&);
+ void retrieveEntryFromStorage(const Key&, const RetrieveCompletionHandler&);
+ void revalidateEntry(std::unique_ptr<Entry>, const GlobalFrameID&);
+ bool satisfyPendingRequests(const Key&, Entry*);
+ void retrieveSubresourcesEntry(const Key& storageKey, std::function<void (std::unique_ptr<SubresourcesEntry>)>);
+ void startSpeculativeRevalidation(const GlobalFrameID&, SubresourcesEntry&);
+
+ Storage& m_storage;
+
+ class PendingFrameLoad;
+ HashMap<GlobalFrameID, RefPtr<PendingFrameLoad>> m_pendingFrameLoads;
+
+ HashMap<Key, std::unique_ptr<SpeculativeLoad>> m_pendingPreloads;
+ HashMap<Key, std::unique_ptr<Vector<RetrieveCompletionHandler>>> m_pendingRetrieveRequests;
+
+ class PreloadedEntry;
+ HashMap<Key, std::unique_ptr<PreloadedEntry>> m_preloadedEntries;
+
+ class ExpiringEntry;
+ HashMap<Key, std::unique_ptr<ExpiringEntry>> m_notPreloadedEntries; // For logging.
+};
+
+} // namespace NetworkCache
+
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#endif // NetworkCacheSpeculativeLoadManager_h
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp
new file mode 100644
index 000000000..263393db7
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp
@@ -0,0 +1,462 @@
+/*
+ * 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"
+
+#if ENABLE(NETWORK_CACHE)
+#include "NetworkCacheStatistics.h"
+
+#include "Logging.h"
+#include "NetworkCache.h"
+#include "NetworkCacheFileSystem.h"
+#include "NetworkProcess.h"
+#include <WebCore/DiagnosticLoggingKeys.h>
+#include <WebCore/DiagnosticLoggingResultType.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/SQLiteDatabaseTracker.h>
+#include <WebCore/SQLiteStatement.h>
+#include <WebCore/SQLiteTransaction.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+static const char* StatisticsDatabaseName = "WebKitCacheStatistics.db";
+static const std::chrono::milliseconds mininumWriteInterval = std::chrono::milliseconds(10000);
+
+static bool executeSQLCommand(WebCore::SQLiteDatabase& database, const String& sql)
+{
+ ASSERT(!RunLoop::isMain());
+ ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+ ASSERT(database.isOpen());
+
+ bool result = database.executeCommand(sql);
+ if (!result)
+ LOG_ERROR("Network cache statistics: failed to execute statement \"%s\" error \"%s\"", sql.utf8().data(), database.lastErrorMsg());
+
+ return result;
+}
+
+static bool executeSQLStatement(WebCore::SQLiteStatement& statement)
+{
+ ASSERT(!RunLoop::isMain());
+ ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+ ASSERT(statement.database().isOpen());
+
+ if (statement.step() != SQLITE_DONE) {
+ LOG_ERROR("Network cache statistics: failed to execute statement \"%s\" error \"%s\"", statement.query().utf8().data(), statement.database().lastErrorMsg());
+ return false;
+ }
+
+ return true;
+}
+
+std::unique_ptr<Statistics> Statistics::open(const String& cachePath)
+{
+ ASSERT(RunLoop::isMain());
+
+ String databasePath = WebCore::pathByAppendingComponent(cachePath, StatisticsDatabaseName);
+ return std::unique_ptr<Statistics>(new Statistics(databasePath));
+}
+
+Statistics::Statistics(const String& databasePath)
+ : m_serialBackgroundIOQueue(WorkQueue::create("com.apple.WebKit.Cache.Statistics.Background", WorkQueue::Type::Serial, WorkQueue::QOS::Background))
+ , m_writeTimer(*this, &Statistics::writeTimerFired)
+{
+ initialize(databasePath);
+}
+
+void Statistics::initialize(const String& databasePath)
+{
+ ASSERT(RunLoop::isMain());
+
+ auto startTime = std::chrono::system_clock::now();
+
+ StringCapture databasePathCapture(databasePath);
+ StringCapture networkCachePathCapture(singleton().recordsPath());
+ serialBackgroundIOQueue().dispatch([this, databasePathCapture, networkCachePathCapture, startTime] {
+ WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+
+ String databasePath = databasePathCapture.string();
+ if (!WebCore::makeAllDirectories(WebCore::directoryName(databasePath)))
+ return;
+
+ LOG(NetworkCache, "(NetworkProcess) Opening network cache statistics database at %s...", databasePath.utf8().data());
+ m_database.open(databasePath);
+ m_database.disableThreadingChecks();
+ if (!m_database.isOpen()) {
+ LOG_ERROR("Network cache statistics: Failed to open / create the network cache statistics database");
+ return;
+ }
+
+ executeSQLCommand(m_database, ASCIILiteral("CREATE TABLE IF NOT EXISTS AlreadyRequested (hash TEXT PRIMARY KEY)"));
+ executeSQLCommand(m_database, ASCIILiteral("CREATE TABLE IF NOT EXISTS UncachedReason (hash TEXT PRIMARY KEY, reason INTEGER)"));
+
+ WebCore::SQLiteStatement statement(m_database, ASCIILiteral("SELECT count(*) FROM AlreadyRequested"));
+ if (statement.prepareAndStep() != SQLITE_ROW) {
+ LOG_ERROR("Network cache statistics: Failed to count the number of rows in AlreadyRequested table");
+ return;
+ }
+
+ m_approximateEntryCount = statement.getColumnInt(0);
+
+#if !LOG_DISABLED
+ auto elapsedMS = static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime).count());
+#endif
+ LOG(NetworkCache, "(NetworkProcess) Network cache statistics database load complete, entries=%lu time=%" PRIi64 "ms", static_cast<size_t>(m_approximateEntryCount), elapsedMS);
+
+ if (!m_approximateEntryCount) {
+ bootstrapFromNetworkCache(networkCachePathCapture.string());
+#if !LOG_DISABLED
+ elapsedMS = static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime).count());
+#endif
+ LOG(NetworkCache, "(NetworkProcess) Network cache statistics database bootstrapping complete, entries=%lu time=%" PRIi64 "ms", static_cast<size_t>(m_approximateEntryCount), elapsedMS);
+ }
+ });
+}
+
+void Statistics::bootstrapFromNetworkCache(const String& networkCachePath)
+{
+ ASSERT(!RunLoop::isMain());
+
+ LOG(NetworkCache, "(NetworkProcess) Bootstrapping the network cache statistics database from the network cache...");
+
+ Vector<StringCapture> hashes;
+ traverseRecordsFiles(networkCachePath, ASCIILiteral("resource"), [&hashes](const String& fileName, const String& hashString, const String& type, bool isBodyBlob, const String& recordDirectoryPath) {
+ if (isBodyBlob)
+ return;
+
+ Key::HashType hash;
+ if (!Key::stringToHash(hashString, hash))
+ return;
+
+ hashes.append(hashString);
+ });
+
+ WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+ WebCore::SQLiteTransaction writeTransaction(m_database);
+ writeTransaction.begin();
+
+ addHashesToDatabase(hashes);
+
+ writeTransaction.commit();
+}
+
+void Statistics::shrinkIfNeeded()
+{
+ ASSERT(RunLoop::isMain());
+ const size_t maxEntries = 100000;
+
+ if (m_approximateEntryCount < maxEntries)
+ return;
+
+ LOG(NetworkCache, "(NetworkProcess) shrinking statistics cache m_approximateEntryCount=%lu, maxEntries=%lu", static_cast<size_t>(m_approximateEntryCount), maxEntries);
+
+ clear();
+
+ StringCapture networkCachePathCapture(singleton().recordsPath());
+ serialBackgroundIOQueue().dispatch([this, networkCachePathCapture] {
+ bootstrapFromNetworkCache(networkCachePathCapture.string());
+ LOG(NetworkCache, "(NetworkProcess) statistics cache shrink completed m_approximateEntryCount=%lu", static_cast<size_t>(m_approximateEntryCount));
+ });
+}
+
+void Statistics::recordRetrievalRequest(uint64_t webPageID)
+{
+ NetworkProcess::singleton().logDiagnosticMessage(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalRequestKey(), WebCore::ShouldSample::Yes);
+}
+
+void Statistics::recordNotCachingResponse(const Key& key, StoreDecision storeDecision)
+{
+ ASSERT(storeDecision != StoreDecision::Yes);
+
+ m_storeDecisionsToAdd.set(key.hashAsString(), storeDecision);
+ if (!m_writeTimer.isActive())
+ m_writeTimer.startOneShot(mininumWriteInterval);
+}
+
+static String retrieveDecisionToDiagnosticKey(RetrieveDecision retrieveDecision)
+{
+ switch (retrieveDecision) {
+ case RetrieveDecision::NoDueToHTTPMethod:
+ return WebCore::DiagnosticLoggingKeys::unsupportedHTTPMethodKey();
+ case RetrieveDecision::NoDueToConditionalRequest:
+ return WebCore::DiagnosticLoggingKeys::isConditionalRequestKey();
+ case RetrieveDecision::NoDueToReloadIgnoringCache:
+ return WebCore::DiagnosticLoggingKeys::isReloadIgnoringCacheDataKey();
+ case RetrieveDecision::Yes:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ return emptyString();
+}
+
+void Statistics::recordNotUsingCacheForRequest(uint64_t webPageID, const Key& key, const WebCore::ResourceRequest& request, RetrieveDecision retrieveDecision)
+{
+ ASSERT(retrieveDecision != RetrieveDecision::Yes);
+
+ String hash = key.hashAsString();
+ WebCore::URL requestURL = request.url();
+ queryWasEverRequested(hash, NeedUncachedReason::No, [this, hash, requestURL, webPageID, retrieveDecision](bool wasEverRequested, const Optional<StoreDecision>&) {
+ if (wasEverRequested) {
+ String diagnosticKey = retrieveDecisionToDiagnosticKey(retrieveDecision);
+ LOG(NetworkCache, "(NetworkProcess) webPageID %" PRIu64 ": %s was previously requested but we are not using the cache, reason: %s", webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
+ NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::unusedKey(), diagnosticKey, WebCore::ShouldSample::Yes);
+ } else {
+ NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::requestKey(), WebCore::DiagnosticLoggingKeys::neverSeenBeforeKey(), WebCore::ShouldSample::Yes);
+ markAsRequested(hash);
+ }
+ });
+}
+
+static String storeDecisionToDiagnosticKey(StoreDecision storeDecision)
+{
+ switch (storeDecision) {
+ case StoreDecision::NoDueToProtocol:
+ return WebCore::DiagnosticLoggingKeys::notHTTPFamilyKey();
+ case StoreDecision::NoDueToHTTPMethod:
+ return WebCore::DiagnosticLoggingKeys::unsupportedHTTPMethodKey();
+ case StoreDecision::NoDueToAttachmentResponse:
+ return WebCore::DiagnosticLoggingKeys::isAttachmentKey();
+ case StoreDecision::NoDueToNoStoreResponse:
+ case StoreDecision::NoDueToNoStoreRequest:
+ return WebCore::DiagnosticLoggingKeys::cacheControlNoStoreKey();
+ case StoreDecision::NoDueToHTTPStatusCode:
+ return WebCore::DiagnosticLoggingKeys::uncacheableStatusCodeKey();
+ case StoreDecision::NoDueToUnlikelyToReuse:
+ return WebCore::DiagnosticLoggingKeys::unlikelyToReuseKey();
+ case StoreDecision::NoDueToStreamingMedia:
+ return WebCore::DiagnosticLoggingKeys::streamingMedia();
+ case StoreDecision::Yes:
+ // It was stored but could not be retrieved so it must have been pruned from the cache.
+ return WebCore::DiagnosticLoggingKeys::noLongerInCacheKey();
+ }
+ return String();
+}
+
+void Statistics::recordRetrievalFailure(uint64_t webPageID, const Key& key, const WebCore::ResourceRequest& request)
+{
+ String hash = key.hashAsString();
+ WebCore::URL requestURL = request.url();
+ queryWasEverRequested(hash, NeedUncachedReason::Yes, [this, hash, requestURL, webPageID](bool wasPreviouslyRequested, const Optional<StoreDecision>& storeDecision) {
+ if (wasPreviouslyRequested) {
+ String diagnosticKey = storeDecisionToDiagnosticKey(storeDecision.value());
+ LOG(NetworkCache, "(NetworkProcess) webPageID %" PRIu64 ": %s was previously request but is not in the cache, reason: %s", webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
+ NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::notInCacheKey(), diagnosticKey, WebCore::ShouldSample::Yes);
+ } else {
+ NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::requestKey(), WebCore::DiagnosticLoggingKeys::neverSeenBeforeKey(), WebCore::ShouldSample::Yes);
+ markAsRequested(hash);
+ }
+ });
+}
+
+static String cachedEntryReuseFailureToDiagnosticKey(UseDecision decision)
+{
+ switch (decision) {
+ case UseDecision::NoDueToVaryingHeaderMismatch:
+ return WebCore::DiagnosticLoggingKeys::varyingHeaderMismatchKey();
+ case UseDecision::NoDueToMissingValidatorFields:
+ return WebCore::DiagnosticLoggingKeys::missingValidatorFieldsKey();
+ case UseDecision::NoDueToDecodeFailure:
+ case UseDecision::NoDueToExpiredRedirect:
+ return WebCore::DiagnosticLoggingKeys::otherKey();
+ case UseDecision::Use:
+ case UseDecision::Validate:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ return emptyString();
+}
+
+void Statistics::recordRetrievedCachedEntry(uint64_t webPageID, const Key& key, const WebCore::ResourceRequest& request, UseDecision decision)
+{
+ WebCore::URL requestURL = request.url();
+ if (decision == UseDecision::Use) {
+ LOG(NetworkCache, "(NetworkProcess) webPageID %" PRIu64 ": %s is in the cache and is used", webPageID, requestURL.string().ascii().data());
+ NetworkProcess::singleton().logDiagnosticMessageWithResult(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalKey(), WebCore::DiagnosticLoggingResultPass, WebCore::ShouldSample::Yes);
+ return;
+ }
+
+ if (decision == UseDecision::Validate) {
+ LOG(NetworkCache, "(NetworkProcess) webPageID %" PRIu64 ": %s is in the cache but needs revalidation", webPageID, requestURL.string().ascii().data());
+ NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalKey(), WebCore::DiagnosticLoggingKeys::needsRevalidationKey(), WebCore::ShouldSample::Yes);
+ return;
+ }
+
+ String diagnosticKey = cachedEntryReuseFailureToDiagnosticKey(decision);
+ LOG(NetworkCache, "(NetworkProcess) webPageID %" PRIu64 ": %s is in the cache but wasn't used, reason: %s", webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
+ NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::unusableCachedEntryKey(), diagnosticKey, WebCore::ShouldSample::Yes);
+}
+
+void Statistics::recordRevalidationSuccess(uint64_t webPageID, const Key& key, const WebCore::ResourceRequest& request)
+{
+ WebCore::URL requestURL = request.url();
+ LOG(NetworkCache, "(NetworkProcess) webPageID %" PRIu64 ": %s was successfully revalidated", webPageID, requestURL.string().ascii().data());
+
+ NetworkProcess::singleton().logDiagnosticMessageWithResult(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::revalidatingKey(), WebCore::DiagnosticLoggingResultPass, WebCore::ShouldSample::Yes);
+}
+
+void Statistics::markAsRequested(const String& hash)
+{
+ ASSERT(RunLoop::isMain());
+
+ m_hashesToAdd.add(hash);
+ if (!m_writeTimer.isActive())
+ m_writeTimer.startOneShot(mininumWriteInterval);
+}
+
+void Statistics::writeTimerFired()
+{
+ ASSERT(RunLoop::isMain());
+
+ Vector<StringCapture> hashesToAdd;
+ copyToVector(m_hashesToAdd, hashesToAdd);
+ m_hashesToAdd.clear();
+
+ Vector<std::pair<StringCapture, StoreDecision>> storeDecisionsToAdd;
+ copyToVector(m_storeDecisionsToAdd, storeDecisionsToAdd);
+ m_storeDecisionsToAdd.clear();
+
+ shrinkIfNeeded();
+
+ serialBackgroundIOQueue().dispatch([this, hashesToAdd, storeDecisionsToAdd] {
+ if (!m_database.isOpen())
+ return;
+
+ WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+ WebCore::SQLiteTransaction writeTransaction(m_database);
+ writeTransaction.begin();
+
+ addHashesToDatabase(hashesToAdd);
+ addStoreDecisionsToDatabase(storeDecisionsToAdd);
+
+ writeTransaction.commit();
+ });
+}
+
+void Statistics::queryWasEverRequested(const String& hash, NeedUncachedReason needUncachedReason, const RequestedCompletionHandler& completionHandler)
+{
+ ASSERT(RunLoop::isMain());
+
+ // Query pending writes first.
+ bool wasAlreadyRequested = m_hashesToAdd.contains(hash);
+ if (wasAlreadyRequested && needUncachedReason == NeedUncachedReason::No) {
+ completionHandler(true, Nullopt);
+ return;
+ }
+ if (needUncachedReason == NeedUncachedReason::Yes && m_storeDecisionsToAdd.contains(hash)) {
+ completionHandler(true, m_storeDecisionsToAdd.get(hash));
+ return;
+ }
+
+ // Query the database.
+ auto everRequestedQuery = std::make_unique<EverRequestedQuery>(EverRequestedQuery { hash, needUncachedReason == NeedUncachedReason::Yes, completionHandler });
+ auto& query = *everRequestedQuery;
+ m_activeQueries.add(WTFMove(everRequestedQuery));
+ serialBackgroundIOQueue().dispatch([this, wasAlreadyRequested, &query] () mutable {
+ WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+ Optional<StoreDecision> storeDecision;
+ if (m_database.isOpen()) {
+ if (!wasAlreadyRequested) {
+ WebCore::SQLiteStatement statement(m_database, ASCIILiteral("SELECT hash FROM AlreadyRequested WHERE hash=?"));
+ if (statement.prepare() == SQLITE_OK) {
+ statement.bindText(1, query.hash);
+ wasAlreadyRequested = (statement.step() == SQLITE_ROW);
+ }
+ }
+ if (wasAlreadyRequested && query.needUncachedReason) {
+ WebCore::SQLiteStatement statement(m_database, ASCIILiteral("SELECT reason FROM UncachedReason WHERE hash=?"));
+ storeDecision = StoreDecision::Yes;
+ if (statement.prepare() == SQLITE_OK) {
+ statement.bindText(1, query.hash);
+ if (statement.step() == SQLITE_ROW)
+ storeDecision = static_cast<StoreDecision>(statement.getColumnInt(0));
+ }
+ }
+ }
+ RunLoop::main().dispatch([this, &query, wasAlreadyRequested, storeDecision] {
+ query.completionHandler(wasAlreadyRequested, storeDecision);
+ m_activeQueries.remove(&query);
+ });
+ });
+}
+
+void Statistics::clear()
+{
+ ASSERT(RunLoop::isMain());
+
+ serialBackgroundIOQueue().dispatch([this] {
+ if (m_database.isOpen()) {
+ WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+ WebCore::SQLiteTransaction deleteTransaction(m_database);
+ deleteTransaction.begin();
+ executeSQLCommand(m_database, ASCIILiteral("DELETE FROM AlreadyRequested"));
+ executeSQLCommand(m_database, ASCIILiteral("DELETE FROM UncachedReason"));
+ deleteTransaction.commit();
+ m_approximateEntryCount = 0;
+ }
+ });
+}
+
+void Statistics::addHashesToDatabase(const Vector<StringCapture>& hashes)
+{
+ ASSERT(!RunLoop::isMain());
+ ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+ ASSERT(m_database.isOpen());
+
+ WebCore::SQLiteStatement statement(m_database, ASCIILiteral("INSERT OR IGNORE INTO AlreadyRequested (hash) VALUES (?)"));
+ if (statement.prepare() != SQLITE_OK)
+ return;
+
+ for (auto& hash : hashes) {
+ statement.bindText(1, hash.string());
+ if (executeSQLStatement(statement))
+ ++m_approximateEntryCount;
+ statement.reset();
+ }
+}
+
+void Statistics::addStoreDecisionsToDatabase(const Vector<std::pair<StringCapture, StoreDecision>>& storeDecisions)
+{
+ ASSERT(!RunLoop::isMain());
+ ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+ ASSERT(m_database.isOpen());
+
+ WebCore::SQLiteStatement statement(m_database, ASCIILiteral("INSERT OR REPLACE INTO UncachedReason (hash, reason) VALUES (?, ?)"));
+ if (statement.prepare() != SQLITE_OK)
+ return;
+
+ for (auto& pair : storeDecisions) {
+ statement.bindText(1, pair.first.string());
+ statement.bindInt(2, static_cast<int>(pair.second));
+ executeSQLStatement(statement);
+ statement.reset();
+ }
+}
+
+}
+}
+
+#endif // ENABLE(NETWORK_CACHE)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h
new file mode 100644
index 000000000..9f048e722
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheStatistics_h
+#define NetworkCacheStatistics_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCache.h"
+#include "NetworkCacheKey.h"
+#include <WebCore/SQLiteDatabase.h>
+#include <WebCore/Timer.h>
+#include <wtf/WorkQueue.h>
+
+namespace WebCore {
+class ResourceRequest;
+}
+
+namespace WebKit {
+namespace NetworkCache {
+
+class Statistics {
+public:
+ static std::unique_ptr<Statistics> open(const String& cachePath);
+
+ void clear();
+
+ void recordRetrievalRequest(uint64_t webPageID);
+ void recordNotCachingResponse(const Key&, StoreDecision);
+ void recordNotUsingCacheForRequest(uint64_t webPageID, const Key&, const WebCore::ResourceRequest&, RetrieveDecision);
+ void recordRetrievalFailure(uint64_t webPageID, const Key&, const WebCore::ResourceRequest&);
+ void recordRetrievedCachedEntry(uint64_t webPageID, const Key&, const WebCore::ResourceRequest&, UseDecision);
+ void recordRevalidationSuccess(uint64_t webPageID, const Key&, const WebCore::ResourceRequest&);
+
+private:
+ explicit Statistics(const String& databasePath);
+
+ WorkQueue& serialBackgroundIOQueue() { return m_serialBackgroundIOQueue.get(); }
+
+ void initialize(const String& databasePath);
+ void bootstrapFromNetworkCache(const String& networkCachePath);
+ void shrinkIfNeeded();
+
+ void addHashesToDatabase(const Vector<StringCapture>& hashes);
+ void addStoreDecisionsToDatabase(const Vector<std::pair<StringCapture, NetworkCache::StoreDecision>>&);
+ void writeTimerFired();
+
+ typedef std::function<void (bool wasEverRequested, const Optional<StoreDecision>&)> RequestedCompletionHandler;
+ enum class NeedUncachedReason { No, Yes };
+ void queryWasEverRequested(const String&, NeedUncachedReason, const RequestedCompletionHandler&);
+ void markAsRequested(const String& hash);
+
+ struct EverRequestedQuery {
+ String hash;
+ bool needUncachedReason;
+ RequestedCompletionHandler completionHandler;
+ };
+
+ std::atomic<size_t> m_approximateEntryCount { 0 };
+
+ mutable Ref<WorkQueue> m_serialBackgroundIOQueue;
+ mutable HashSet<std::unique_ptr<const EverRequestedQuery>> m_activeQueries;
+ WebCore::SQLiteDatabase m_database;
+ HashSet<String> m_hashesToAdd;
+ HashMap<String, NetworkCache::StoreDecision> m_storeDecisionsToAdd;
+ WebCore::Timer m_writeTimer;
+};
+
+}
+}
+
+#endif // ENABLE(NETWORK_CACHE)
+
+#endif // NetworkCacheStatistics_h
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp
new file mode 100644
index 000000000..1f650bfd1
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (C) 2014-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 "NetworkCacheStorage.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "Logging.h"
+#include "NetworkCacheCoders.h"
+#include "NetworkCacheFileSystem.h"
+#include "NetworkCacheIOChannel.h"
+#include <mutex>
+#include <wtf/Condition.h>
+#include <wtf/Lock.h>
+#include <wtf/RandomNumber.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+static const char versionDirectoryPrefix[] = "Version ";
+static const char recordsDirectoryName[] = "Records";
+static const char blobsDirectoryName[] = "Blobs";
+static const char blobSuffix[] = "-blob";
+
+static double computeRecordWorth(FileTimes);
+
+struct Storage::ReadOperation {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ReadOperation(const Key& key, const RetrieveCompletionHandler& completionHandler)
+ : key(key)
+ , completionHandler(completionHandler)
+ { }
+
+ void cancel();
+ bool finish();
+
+ const Key key;
+ const RetrieveCompletionHandler completionHandler;
+
+ std::unique_ptr<Record> resultRecord;
+ SHA1::Digest expectedBodyHash;
+ BlobStorage::Blob resultBodyBlob;
+ std::atomic<unsigned> activeCount { 0 };
+ bool isCanceled { false };
+};
+
+void Storage::ReadOperation::cancel()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (isCanceled)
+ return;
+ isCanceled = true;
+ completionHandler(nullptr);
+}
+
+bool Storage::ReadOperation::finish()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (isCanceled)
+ return false;
+ if (resultRecord && resultRecord->body.isNull()) {
+ if (resultBodyBlob.hash == expectedBodyHash)
+ resultRecord->body = resultBodyBlob.data;
+ else
+ resultRecord = nullptr;
+ }
+ return completionHandler(WTFMove(resultRecord));
+}
+
+struct Storage::WriteOperation {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ WriteOperation(const Record& record, const MappedBodyHandler& mappedBodyHandler)
+ : record(record)
+ , mappedBodyHandler(mappedBodyHandler)
+ { }
+
+ const Record record;
+ const MappedBodyHandler mappedBodyHandler;
+
+ std::atomic<unsigned> activeCount { 0 };
+};
+
+struct Storage::TraverseOperation {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ TraverseOperation(const String& type, TraverseFlags flags, const TraverseHandler& handler)
+ : type(type)
+ , flags(flags)
+ , handler(handler)
+ { }
+
+ const String type;
+ const TraverseFlags flags;
+ const TraverseHandler handler;
+
+ Lock activeMutex;
+ Condition activeCondition;
+ unsigned activeCount { 0 };
+};
+
+std::unique_ptr<Storage> Storage::open(const String& cachePath)
+{
+ ASSERT(RunLoop::isMain());
+
+ if (!WebCore::makeAllDirectories(cachePath))
+ return nullptr;
+ return std::unique_ptr<Storage>(new Storage(cachePath));
+}
+
+static String makeVersionedDirectoryPath(const String& baseDirectoryPath)
+{
+ String versionSubdirectory = versionDirectoryPrefix + String::number(Storage::version);
+ return WebCore::pathByAppendingComponent(baseDirectoryPath, versionSubdirectory);
+}
+
+static String makeRecordsDirectoryPath(const String& baseDirectoryPath)
+{
+ return WebCore::pathByAppendingComponent(makeVersionedDirectoryPath(baseDirectoryPath), recordsDirectoryName);
+}
+
+static String makeBlobDirectoryPath(const String& baseDirectoryPath)
+{
+ return WebCore::pathByAppendingComponent(makeVersionedDirectoryPath(baseDirectoryPath), blobsDirectoryName);
+}
+
+void traverseRecordsFiles(const String& recordsPath, const String& expectedType, const std::function<void (const String& fileName, const String& hashString, const String& type, bool isBlob, const String& recordDirectoryPath)>& function)
+{
+ traverseDirectory(recordsPath, [&recordsPath, &function, &expectedType](const String& partitionName, DirectoryEntryType entryType) {
+ if (entryType != DirectoryEntryType::Directory)
+ return;
+ String partitionPath = WebCore::pathByAppendingComponent(recordsPath, partitionName);
+ traverseDirectory(partitionPath, [&function, &partitionPath, &expectedType](const String& actualType, DirectoryEntryType entryType) {
+ if (entryType != DirectoryEntryType::Directory)
+ return;
+ if (!expectedType.isEmpty() && expectedType != actualType)
+ return;
+ String recordDirectoryPath = WebCore::pathByAppendingComponent(partitionPath, actualType);
+ traverseDirectory(recordDirectoryPath, [&function, &recordDirectoryPath, &actualType](const String& fileName, DirectoryEntryType entryType) {
+ if (entryType != DirectoryEntryType::File || fileName.length() < Key::hashStringLength())
+ return;
+
+ String hashString = fileName.substring(0, Key::hashStringLength());
+ auto isBlob = fileName.length() > Key::hashStringLength() && fileName.endsWith(blobSuffix);
+ function(fileName, hashString, actualType, isBlob, recordDirectoryPath);
+ });
+ });
+ });
+}
+
+static void deleteEmptyRecordsDirectories(const String& recordsPath)
+{
+ traverseDirectory(recordsPath, [&recordsPath](const String& partitionName, DirectoryEntryType type) {
+ if (type != DirectoryEntryType::Directory)
+ return;
+
+ // Delete [type] sub-folders.
+ String partitionPath = WebCore::pathByAppendingComponent(recordsPath, partitionName);
+ traverseDirectory(partitionPath, [&partitionPath](const String& subdirName, DirectoryEntryType entryType) {
+ if (entryType != DirectoryEntryType::Directory)
+ return;
+
+ // Let system figure out if it is really empty.
+ WebCore::deleteEmptyDirectory(WebCore::pathByAppendingComponent(partitionPath, subdirName));
+ });
+
+ // Delete [Partition] folders.
+ // Let system figure out if it is really empty.
+ WebCore::deleteEmptyDirectory(WebCore::pathByAppendingComponent(recordsPath, partitionName));
+ });
+}
+
+Storage::Storage(const String& baseDirectoryPath)
+ : m_basePath(baseDirectoryPath)
+ , m_recordsPath(makeRecordsDirectoryPath(baseDirectoryPath))
+ , m_readOperationTimeoutTimer(*this, &Storage::cancelAllReadOperations)
+ , m_writeOperationDispatchTimer(*this, &Storage::dispatchPendingWriteOperations)
+ , m_ioQueue(WorkQueue::create("com.apple.WebKit.Cache.Storage", WorkQueue::Type::Concurrent))
+ , m_backgroundIOQueue(WorkQueue::create("com.apple.WebKit.Cache.Storage.background", WorkQueue::Type::Concurrent, WorkQueue::QOS::Background))
+ , m_serialBackgroundIOQueue(WorkQueue::create("com.apple.WebKit.Cache.Storage.serialBackground", WorkQueue::Type::Serial, WorkQueue::QOS::Background))
+ , m_blobStorage(makeBlobDirectoryPath(baseDirectoryPath))
+{
+ deleteOldVersions();
+ synchronize();
+}
+
+Storage::~Storage()
+{
+}
+
+String Storage::basePath() const
+{
+ return m_basePath.isolatedCopy();
+}
+
+String Storage::versionPath() const
+{
+ return makeVersionedDirectoryPath(basePath());
+}
+
+String Storage::recordsPath() const
+{
+ return m_recordsPath.isolatedCopy();
+}
+
+size_t Storage::approximateSize() const
+{
+ return m_approximateRecordsSize + m_blobStorage.approximateSize();
+}
+
+void Storage::synchronize()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (m_synchronizationInProgress || m_shrinkInProgress)
+ return;
+ m_synchronizationInProgress = true;
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) synchronizing cache");
+
+ backgroundIOQueue().dispatch([this] {
+ auto recordFilter = std::make_unique<ContentsFilter>();
+ auto blobFilter = std::make_unique<ContentsFilter>();
+ size_t recordsSize = 0;
+ unsigned count = 0;
+ String anyType;
+ traverseRecordsFiles(recordsPath(), anyType, [&recordFilter, &blobFilter, &recordsSize, &count](const String& fileName, const String& hashString, const String& type, bool isBlob, const String& recordDirectoryPath) {
+ auto filePath = WebCore::pathByAppendingComponent(recordDirectoryPath, fileName);
+
+ Key::HashType hash;
+ if (!Key::stringToHash(hashString, hash)) {
+ WebCore::deleteFile(filePath);
+ return;
+ }
+ long long fileSize = 0;
+ WebCore::getFileSize(filePath, fileSize);
+ if (!fileSize) {
+ WebCore::deleteFile(filePath);
+ return;
+ }
+
+ if (isBlob) {
+ blobFilter->add(hash);
+ return;
+ }
+
+ recordFilter->add(hash);
+ recordsSize += fileSize;
+ ++count;
+ });
+
+ auto* recordFilterPtr = recordFilter.release();
+ auto* blobFilterPtr = blobFilter.release();
+ RunLoop::main().dispatch([this, recordFilterPtr, blobFilterPtr, recordsSize] {
+ auto recordFilter = std::unique_ptr<ContentsFilter>(recordFilterPtr);
+ auto blobFilter = std::unique_ptr<ContentsFilter>(blobFilterPtr);
+
+ for (auto& recordFilterKey : m_recordFilterHashesAddedDuringSynchronization)
+ recordFilter->add(recordFilterKey);
+ m_recordFilterHashesAddedDuringSynchronization.clear();
+
+ for (auto& hash : m_blobFilterHashesAddedDuringSynchronization)
+ blobFilter->add(hash);
+ m_blobFilterHashesAddedDuringSynchronization.clear();
+
+ m_recordFilter = WTFMove(recordFilter);
+ m_blobFilter = WTFMove(blobFilter);
+ m_approximateRecordsSize = recordsSize;
+ m_synchronizationInProgress = false;
+ });
+
+ m_blobStorage.synchronize();
+
+ deleteEmptyRecordsDirectories(recordsPath());
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) cache synchronization completed size=%zu count=%u", recordsSize, count);
+ });
+}
+
+void Storage::addToRecordFilter(const Key& key)
+{
+ ASSERT(RunLoop::isMain());
+
+ if (m_recordFilter)
+ m_recordFilter->add(key.hash());
+
+ // If we get new entries during filter synchronization take care to add them to the new filter as well.
+ if (m_synchronizationInProgress)
+ m_recordFilterHashesAddedDuringSynchronization.append(key.hash());
+}
+
+bool Storage::mayContain(const Key& key) const
+{
+ ASSERT(RunLoop::isMain());
+ return !m_recordFilter || m_recordFilter->mayContain(key.hash());
+}
+
+bool Storage::mayContainBlob(const Key& key) const
+{
+ ASSERT(RunLoop::isMain());
+ return !m_blobFilter || m_blobFilter->mayContain(key.hash());
+}
+
+String Storage::recordDirectoryPathForKey(const Key& key) const
+{
+ ASSERT(!key.partition().isEmpty());
+ ASSERT(!key.type().isEmpty());
+ return WebCore::pathByAppendingComponent(WebCore::pathByAppendingComponent(recordsPath(), key.partition()), key.type());
+}
+
+String Storage::recordPathForKey(const Key& key) const
+{
+ return WebCore::pathByAppendingComponent(recordDirectoryPathForKey(key), key.hashAsString());
+}
+
+static String blobPathForRecordPath(const String& recordPath)
+{
+ return recordPath + blobSuffix;
+}
+
+String Storage::blobPathForKey(const Key& key) const
+{
+ return blobPathForRecordPath(recordPathForKey(key));
+}
+
+struct RecordMetaData {
+ RecordMetaData() { }
+ explicit RecordMetaData(const Key& key)
+ : cacheStorageVersion(Storage::version)
+ , key(key)
+ { }
+
+ unsigned cacheStorageVersion;
+ Key key;
+ // FIXME: Add encoder/decoder for time_point.
+ std::chrono::milliseconds epochRelativeTimeStamp;
+ SHA1::Digest headerHash;
+ uint64_t headerSize;
+ SHA1::Digest bodyHash;
+ uint64_t bodySize;
+ bool isBodyInline;
+
+ // Not encoded as a field. Header starts immediately after meta data.
+ uint64_t headerOffset;
+};
+
+static bool decodeRecordMetaData(RecordMetaData& metaData, const Data& fileData)
+{
+ bool success = false;
+ fileData.apply([&metaData, &success](const uint8_t* data, size_t size) {
+ Decoder decoder(data, size);
+ if (!decoder.decode(metaData.cacheStorageVersion))
+ return false;
+ if (!decoder.decode(metaData.key))
+ return false;
+ if (!decoder.decode(metaData.epochRelativeTimeStamp))
+ return false;
+ if (!decoder.decode(metaData.headerHash))
+ return false;
+ if (!decoder.decode(metaData.headerSize))
+ return false;
+ if (!decoder.decode(metaData.bodyHash))
+ return false;
+ if (!decoder.decode(metaData.bodySize))
+ return false;
+ if (!decoder.decode(metaData.isBodyInline))
+ return false;
+ if (!decoder.verifyChecksum())
+ return false;
+ metaData.headerOffset = decoder.currentOffset();
+ success = true;
+ return false;
+ });
+ return success;
+}
+
+static bool decodeRecordHeader(const Data& fileData, RecordMetaData& metaData, Data& headerData)
+{
+ if (!decodeRecordMetaData(metaData, fileData)) {
+ LOG(NetworkCacheStorage, "(NetworkProcess) meta data decode failure");
+ return false;
+ }
+
+ if (metaData.cacheStorageVersion != Storage::version) {
+ LOG(NetworkCacheStorage, "(NetworkProcess) version mismatch");
+ return false;
+ }
+
+ headerData = fileData.subrange(metaData.headerOffset, metaData.headerSize);
+ if (metaData.headerHash != computeSHA1(headerData)) {
+ LOG(NetworkCacheStorage, "(NetworkProcess) header checksum mismatch");
+ return false;
+ }
+ return true;
+}
+
+void Storage::readRecord(ReadOperation& readOperation, const Data& recordData)
+{
+ ASSERT(!RunLoop::isMain());
+
+ RecordMetaData metaData;
+ Data headerData;
+ if (!decodeRecordHeader(recordData, metaData, headerData))
+ return;
+
+ if (metaData.key != readOperation.key)
+ return;
+
+ // Sanity check against time stamps in future.
+ auto timeStamp = std::chrono::system_clock::time_point(metaData.epochRelativeTimeStamp);
+ if (timeStamp > std::chrono::system_clock::now())
+ return;
+
+ Data bodyData;
+ if (metaData.isBodyInline) {
+ size_t bodyOffset = metaData.headerOffset + headerData.size();
+ if (bodyOffset + metaData.bodySize != recordData.size())
+ return;
+ bodyData = recordData.subrange(bodyOffset, metaData.bodySize);
+ if (metaData.bodyHash != computeSHA1(bodyData))
+ return;
+ }
+
+ readOperation.expectedBodyHash = metaData.bodyHash;
+ readOperation.resultRecord = std::make_unique<Storage::Record>(Storage::Record {
+ metaData.key,
+ timeStamp,
+ headerData,
+ bodyData
+ });
+}
+
+static Data encodeRecordMetaData(const RecordMetaData& metaData)
+{
+ Encoder encoder;
+
+ encoder << metaData.cacheStorageVersion;
+ encoder << metaData.key;
+ encoder << metaData.epochRelativeTimeStamp;
+ encoder << metaData.headerHash;
+ encoder << metaData.headerSize;
+ encoder << metaData.bodyHash;
+ encoder << metaData.bodySize;
+ encoder << metaData.isBodyInline;
+
+ encoder.encodeChecksum();
+
+ return Data(encoder.buffer(), encoder.bufferSize());
+}
+
+Optional<BlobStorage::Blob> Storage::storeBodyAsBlob(WriteOperation& writeOperation)
+{
+ auto blobPath = blobPathForKey(writeOperation.record.key);
+
+ // Store the body.
+ auto blob = m_blobStorage.add(blobPath, writeOperation.record.body);
+ if (blob.data.isNull())
+ return { };
+
+ ++writeOperation.activeCount;
+
+ RunLoop::main().dispatch([this, blob, &writeOperation] {
+ if (m_blobFilter)
+ m_blobFilter->add(writeOperation.record.key.hash());
+ if (m_synchronizationInProgress)
+ m_blobFilterHashesAddedDuringSynchronization.append(writeOperation.record.key.hash());
+
+ if (writeOperation.mappedBodyHandler)
+ writeOperation.mappedBodyHandler(blob.data);
+
+ finishWriteOperation(writeOperation);
+ });
+ return blob;
+}
+
+Data Storage::encodeRecord(const Record& record, Optional<BlobStorage::Blob> blob)
+{
+ ASSERT(!blob || bytesEqual(blob.value().data, record.body));
+
+ RecordMetaData metaData(record.key);
+ metaData.epochRelativeTimeStamp = std::chrono::duration_cast<std::chrono::milliseconds>(record.timeStamp.time_since_epoch());
+ metaData.headerHash = computeSHA1(record.header);
+ metaData.headerSize = record.header.size();
+ metaData.bodyHash = blob ? blob.value().hash : computeSHA1(record.body);
+ metaData.bodySize = record.body.size();
+ metaData.isBodyInline = !blob;
+
+ auto encodedMetaData = encodeRecordMetaData(metaData);
+ auto headerData = concatenate(encodedMetaData, record.header);
+
+ if (metaData.isBodyInline)
+ return concatenate(headerData, record.body);
+
+ return { headerData };
+}
+
+void Storage::removeFromPendingWriteOperations(const Key& key)
+{
+ while (true) {
+ auto found = m_pendingWriteOperations.findIf([&key](const std::unique_ptr<WriteOperation>& operation) {
+ return operation->record.key == key;
+ });
+
+ if (found == m_pendingWriteOperations.end())
+ break;
+
+ m_pendingWriteOperations.remove(found);
+ }
+}
+
+void Storage::remove(const Key& key)
+{
+ ASSERT(RunLoop::isMain());
+
+ if (!mayContain(key))
+ return;
+
+ // We can't remove the key from the Bloom filter (but some false positives are expected anyway).
+ // For simplicity we also don't reduce m_approximateSize on removals.
+ // The next synchronization will update everything.
+
+ removeFromPendingWriteOperations(key);
+
+ serialBackgroundIOQueue().dispatch([this, key] {
+ WebCore::deleteFile(recordPathForKey(key));
+ m_blobStorage.remove(blobPathForKey(key));
+ });
+}
+
+void Storage::updateFileModificationTime(const String& path)
+{
+ StringCapture filePathCapture(path);
+ serialBackgroundIOQueue().dispatch([filePathCapture] {
+ updateFileModificationTimeIfNeeded(filePathCapture.string());
+ });
+}
+
+void Storage::dispatchReadOperation(std::unique_ptr<ReadOperation> readOperationPtr)
+{
+ ASSERT(RunLoop::isMain());
+
+ auto& readOperation = *readOperationPtr;
+ m_activeReadOperations.add(WTFMove(readOperationPtr));
+
+ // I/O pressure may make disk operations slow. If they start taking very long time we rather go to network.
+ const auto readTimeout = 1500_ms;
+ m_readOperationTimeoutTimer.startOneShot(readTimeout);
+
+ bool shouldGetBodyBlob = mayContainBlob(readOperation.key);
+
+ ioQueue().dispatch([this, &readOperation, shouldGetBodyBlob] {
+ auto recordPath = recordPathForKey(readOperation.key);
+
+ ++readOperation.activeCount;
+ if (shouldGetBodyBlob)
+ ++readOperation.activeCount;
+
+ auto channel = IOChannel::open(recordPath, IOChannel::Type::Read);
+ channel->read(0, std::numeric_limits<size_t>::max(), &ioQueue(), [this, &readOperation](const Data& fileData, int error) {
+ if (!error)
+ readRecord(readOperation, fileData);
+ finishReadOperation(readOperation);
+ });
+
+ if (shouldGetBodyBlob) {
+ // Read the blob in parallel with the record read.
+ auto blobPath = blobPathForKey(readOperation.key);
+ readOperation.resultBodyBlob = m_blobStorage.get(blobPath);
+ finishReadOperation(readOperation);
+ }
+ });
+}
+
+void Storage::finishReadOperation(ReadOperation& readOperation)
+{
+ ASSERT(readOperation.activeCount);
+ // Record and blob reads must finish.
+ if (--readOperation.activeCount)
+ return;
+
+ RunLoop::main().dispatch([this, &readOperation] {
+ bool success = readOperation.finish();
+ if (success)
+ updateFileModificationTime(recordPathForKey(readOperation.key));
+ else if (!readOperation.isCanceled)
+ remove(readOperation.key);
+
+ ASSERT(m_activeReadOperations.contains(&readOperation));
+ m_activeReadOperations.remove(&readOperation);
+
+ if (m_activeReadOperations.isEmpty())
+ m_readOperationTimeoutTimer.stop();
+
+ dispatchPendingReadOperations();
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) read complete success=%d", success);
+ });
+}
+
+void Storage::cancelAllReadOperations()
+{
+ ASSERT(RunLoop::isMain());
+
+ for (auto& readOperation : m_activeReadOperations)
+ readOperation->cancel();
+
+ size_t pendingCount = 0;
+ for (int priority = maximumRetrievePriority; priority >= 0; --priority) {
+ auto& pendingRetrieveQueue = m_pendingReadOperationsByPriority[priority];
+ pendingCount += pendingRetrieveQueue.size();
+ for (auto it = pendingRetrieveQueue.rbegin(), end = pendingRetrieveQueue.rend(); it != end; ++it)
+ (*it)->cancel();
+ pendingRetrieveQueue.clear();
+ }
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) retrieve timeout, canceled %u active and %zu pending", m_activeReadOperations.size(), pendingCount);
+}
+
+void Storage::dispatchPendingReadOperations()
+{
+ ASSERT(RunLoop::isMain());
+
+ const int maximumActiveReadOperationCount = 5;
+
+ for (int priority = maximumRetrievePriority; priority >= 0; --priority) {
+ if (m_activeReadOperations.size() > maximumActiveReadOperationCount) {
+ LOG(NetworkCacheStorage, "(NetworkProcess) limiting parallel retrieves");
+ return;
+ }
+ auto& pendingRetrieveQueue = m_pendingReadOperationsByPriority[priority];
+ if (pendingRetrieveQueue.isEmpty())
+ continue;
+ dispatchReadOperation(pendingRetrieveQueue.takeLast());
+ }
+}
+
+template <class T> bool retrieveFromMemory(const T& operations, const Key& key, Storage::RetrieveCompletionHandler& completionHandler)
+{
+ for (auto& operation : operations) {
+ if (operation->record.key == key) {
+ LOG(NetworkCacheStorage, "(NetworkProcess) found write operation in progress");
+ auto record = operation->record;
+ RunLoop::main().dispatch([record, completionHandler] {
+ completionHandler(std::make_unique<Storage::Record>(record));
+ });
+ return true;
+ }
+ }
+ return false;
+}
+
+void Storage::dispatchPendingWriteOperations()
+{
+ ASSERT(RunLoop::isMain());
+
+ const int maximumActiveWriteOperationCount { 1 };
+
+ while (!m_pendingWriteOperations.isEmpty()) {
+ if (m_activeWriteOperations.size() >= maximumActiveWriteOperationCount) {
+ LOG(NetworkCacheStorage, "(NetworkProcess) limiting parallel writes");
+ return;
+ }
+ dispatchWriteOperation(m_pendingWriteOperations.takeLast());
+ }
+}
+
+static bool shouldStoreBodyAsBlob(const Data& bodyData)
+{
+ const size_t maximumInlineBodySize { 16 * 1024 };
+ return bodyData.size() > maximumInlineBodySize;
+}
+
+void Storage::dispatchWriteOperation(std::unique_ptr<WriteOperation> writeOperationPtr)
+{
+ ASSERT(RunLoop::isMain());
+
+ auto& writeOperation = *writeOperationPtr;
+ m_activeWriteOperations.add(WTFMove(writeOperationPtr));
+
+ // This was added already when starting the store but filter might have been wiped.
+ addToRecordFilter(writeOperation.record.key);
+
+ backgroundIOQueue().dispatch([this, &writeOperation] {
+ auto recordDirectorPath = recordDirectoryPathForKey(writeOperation.record.key);
+ auto recordPath = recordPathForKey(writeOperation.record.key);
+
+ WebCore::makeAllDirectories(recordDirectorPath);
+
+ ++writeOperation.activeCount;
+
+ bool shouldStoreAsBlob = shouldStoreBodyAsBlob(writeOperation.record.body);
+ auto blob = shouldStoreAsBlob ? storeBodyAsBlob(writeOperation) : Nullopt;
+
+ auto recordData = encodeRecord(writeOperation.record, blob);
+
+ auto channel = IOChannel::open(recordPath, IOChannel::Type::Create);
+ size_t recordSize = recordData.size();
+ channel->write(0, recordData, nullptr, [this, &writeOperation, recordSize](int error) {
+ // On error the entry still stays in the contents filter until next synchronization.
+ m_approximateRecordsSize += recordSize;
+ finishWriteOperation(writeOperation);
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) write complete error=%d", error);
+ });
+ });
+}
+
+void Storage::finishWriteOperation(WriteOperation& writeOperation)
+{
+ ASSERT(RunLoop::isMain());
+ ASSERT(writeOperation.activeCount);
+ ASSERT(m_activeWriteOperations.contains(&writeOperation));
+
+ if (--writeOperation.activeCount)
+ return;
+
+ m_activeWriteOperations.remove(&writeOperation);
+ dispatchPendingWriteOperations();
+
+ shrinkIfNeeded();
+}
+
+void Storage::retrieve(const Key& key, unsigned priority, RetrieveCompletionHandler&& completionHandler)
+{
+ ASSERT(RunLoop::isMain());
+ ASSERT(priority <= maximumRetrievePriority);
+ ASSERT(!key.isNull());
+
+ if (!m_capacity) {
+ completionHandler(nullptr);
+ return;
+ }
+
+ if (!mayContain(key)) {
+ completionHandler(nullptr);
+ return;
+ }
+
+ if (retrieveFromMemory(m_pendingWriteOperations, key, completionHandler))
+ return;
+ if (retrieveFromMemory(m_activeWriteOperations, key, completionHandler))
+ return;
+
+ auto readOperation = std::make_unique<ReadOperation>(key, WTFMove(completionHandler));
+ m_pendingReadOperationsByPriority[priority].prepend(WTFMove(readOperation));
+ dispatchPendingReadOperations();
+}
+
+void Storage::store(const Record& record, MappedBodyHandler&& mappedBodyHandler)
+{
+ ASSERT(RunLoop::isMain());
+ ASSERT(!record.key.isNull());
+
+ if (!m_capacity)
+ return;
+
+ auto writeOperation = std::make_unique<WriteOperation>(record, WTFMove(mappedBodyHandler));
+ m_pendingWriteOperations.prepend(WTFMove(writeOperation));
+
+ // Add key to the filter already here as we do lookups from the pending operations too.
+ addToRecordFilter(record.key);
+
+ bool isInitialWrite = m_pendingWriteOperations.size() == 1;
+ if (!isInitialWrite)
+ return;
+
+ // Delay the start of writes a bit to avoid affecting early page load.
+ // Completing writes will dispatch more writes without delay.
+ static const auto initialWriteDelay = 1_s;
+ m_writeOperationDispatchTimer.startOneShot(initialWriteDelay);
+}
+
+void Storage::traverse(const String& type, TraverseFlags flags, TraverseHandler&& traverseHandler)
+{
+ ASSERT(RunLoop::isMain());
+ ASSERT(traverseHandler);
+ // Avoid non-thread safe std::function copies.
+
+ auto traverseOperationPtr = std::make_unique<TraverseOperation>(type, flags, WTFMove(traverseHandler));
+ auto& traverseOperation = *traverseOperationPtr;
+ m_activeTraverseOperations.add(WTFMove(traverseOperationPtr));
+
+ ioQueue().dispatch([this, &traverseOperation] {
+ traverseRecordsFiles(recordsPath(), traverseOperation.type, [this, &traverseOperation](const String& fileName, const String& hashString, const String& type, bool isBlob, const String& recordDirectoryPath) {
+ ASSERT(type == traverseOperation.type);
+ if (isBlob)
+ return;
+
+ auto recordPath = WebCore::pathByAppendingComponent(recordDirectoryPath, fileName);
+
+ double worth = -1;
+ if (traverseOperation.flags & TraverseFlag::ComputeWorth)
+ worth = computeRecordWorth(fileTimes(recordPath));
+ unsigned bodyShareCount = 0;
+ if (traverseOperation.flags & TraverseFlag::ShareCount)
+ bodyShareCount = m_blobStorage.shareCount(blobPathForRecordPath(recordPath));
+
+ std::unique_lock<Lock> lock(traverseOperation.activeMutex);
+ ++traverseOperation.activeCount;
+
+ auto channel = IOChannel::open(recordPath, IOChannel::Type::Read);
+ channel->read(0, std::numeric_limits<size_t>::max(), nullptr, [this, &traverseOperation, worth, bodyShareCount](Data& fileData, int) {
+ RecordMetaData metaData;
+ Data headerData;
+ if (decodeRecordHeader(fileData, metaData, headerData)) {
+ Record record {
+ metaData.key,
+ std::chrono::system_clock::time_point(metaData.epochRelativeTimeStamp),
+ headerData,
+ { }
+ };
+ RecordInfo info {
+ static_cast<size_t>(metaData.bodySize),
+ worth,
+ bodyShareCount,
+ String::fromUTF8(SHA1::hexDigest(metaData.bodyHash))
+ };
+ traverseOperation.handler(&record, info);
+ }
+
+ std::lock_guard<Lock> lock(traverseOperation.activeMutex);
+ --traverseOperation.activeCount;
+ traverseOperation.activeCondition.notifyOne();
+ });
+
+ const unsigned maximumParallelReadCount = 5;
+ traverseOperation.activeCondition.wait(lock, [&traverseOperation] {
+ return traverseOperation.activeCount <= maximumParallelReadCount;
+ });
+ });
+ // Wait for all reads to finish.
+ std::unique_lock<Lock> lock(traverseOperation.activeMutex);
+ traverseOperation.activeCondition.wait(lock, [&traverseOperation] {
+ return !traverseOperation.activeCount;
+ });
+ RunLoop::main().dispatch([this, &traverseOperation] {
+ traverseOperation.handler(nullptr, { });
+ m_activeTraverseOperations.remove(&traverseOperation);
+ });
+ });
+}
+
+void Storage::setCapacity(size_t capacity)
+{
+ ASSERT(RunLoop::isMain());
+
+#if !ASSERT_DISABLED
+ const size_t assumedAverageRecordSize = 50 << 10;
+ size_t maximumRecordCount = capacity / assumedAverageRecordSize;
+ // ~10 bits per element are required for <1% false positive rate.
+ size_t effectiveBloomFilterCapacity = ContentsFilter::tableSize / 10;
+ // If this gets hit it might be time to increase the filter size.
+ ASSERT(maximumRecordCount < effectiveBloomFilterCapacity);
+#endif
+
+ m_capacity = capacity;
+
+ shrinkIfNeeded();
+}
+
+void Storage::clear(const String& type, std::chrono::system_clock::time_point modifiedSinceTime, std::function<void ()>&& completionHandler)
+{
+ ASSERT(RunLoop::isMain());
+ LOG(NetworkCacheStorage, "(NetworkProcess) clearing cache");
+
+ if (m_recordFilter)
+ m_recordFilter->clear();
+ if (m_blobFilter)
+ m_blobFilter->clear();
+ m_approximateRecordsSize = 0;
+
+ // Avoid non-thread safe std::function copies.
+ auto* completionHandlerPtr = completionHandler ? new std::function<void ()>(WTFMove(completionHandler)) : nullptr;
+ StringCapture typeCapture(type);
+ ioQueue().dispatch([this, modifiedSinceTime, completionHandlerPtr, typeCapture] {
+ auto recordsPath = this->recordsPath();
+ traverseRecordsFiles(recordsPath, typeCapture.string(), [modifiedSinceTime](const String& fileName, const String& hashString, const String& type, bool isBlob, const String& recordDirectoryPath) {
+ auto filePath = WebCore::pathByAppendingComponent(recordDirectoryPath, fileName);
+ if (modifiedSinceTime > std::chrono::system_clock::time_point::min()) {
+ auto times = fileTimes(filePath);
+ if (times.modification < modifiedSinceTime)
+ return;
+ }
+ WebCore::deleteFile(filePath);
+ });
+
+ deleteEmptyRecordsDirectories(recordsPath);
+
+ // This cleans unreferenced blobs.
+ m_blobStorage.synchronize();
+
+ if (completionHandlerPtr) {
+ RunLoop::main().dispatch([completionHandlerPtr] {
+ (*completionHandlerPtr)();
+ delete completionHandlerPtr;
+ });
+ }
+ });
+}
+
+static double computeRecordWorth(FileTimes times)
+{
+ using namespace std::chrono;
+ auto age = system_clock::now() - times.creation;
+ // File modification time is updated manually on cache read. We don't use access time since OS may update it automatically.
+ auto accessAge = times.modification - times.creation;
+
+ // For sanity.
+ if (age <= 0_s || accessAge < 0_s || accessAge > age)
+ return 0;
+
+ // We like old entries that have been accessed recently.
+ return duration<double>(accessAge) / age;
+}
+
+static double deletionProbability(FileTimes times, unsigned bodyShareCount)
+{
+ static const double maximumProbability { 0.33 };
+ static const unsigned maximumEffectiveShareCount { 5 };
+
+ auto worth = computeRecordWorth(times);
+
+ // Adjust a bit so the most valuable entries don't get deleted at all.
+ auto effectiveWorth = std::min(1.1 * worth, 1.);
+
+ auto probability = (1 - effectiveWorth) * maximumProbability;
+
+ // It is less useful to remove an entry that shares its body data.
+ if (bodyShareCount)
+ probability /= std::min(bodyShareCount, maximumEffectiveShareCount);
+
+ return probability;
+}
+
+void Storage::shrinkIfNeeded()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (approximateSize() > m_capacity)
+ shrink();
+}
+
+void Storage::shrink()
+{
+ ASSERT(RunLoop::isMain());
+
+ if (m_shrinkInProgress || m_synchronizationInProgress)
+ return;
+ m_shrinkInProgress = true;
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) shrinking cache approximateSize=%zu capacity=%zu", approximateSize(), m_capacity);
+
+ backgroundIOQueue().dispatch([this] {
+ auto recordsPath = this->recordsPath();
+ String anyType;
+ traverseRecordsFiles(recordsPath, anyType, [this](const String& fileName, const String& hashString, const String& type, bool isBlob, const String& recordDirectoryPath) {
+ if (isBlob)
+ return;
+
+ auto recordPath = WebCore::pathByAppendingComponent(recordDirectoryPath, fileName);
+ auto blobPath = blobPathForRecordPath(recordPath);
+
+ auto times = fileTimes(recordPath);
+ unsigned bodyShareCount = m_blobStorage.shareCount(blobPath);
+ auto probability = deletionProbability(times, bodyShareCount);
+
+ bool shouldDelete = randomNumber() < probability;
+
+ LOG(NetworkCacheStorage, "Deletion probability=%f bodyLinkCount=%d shouldDelete=%d", probability, bodyShareCount, shouldDelete);
+
+ if (shouldDelete) {
+ WebCore::deleteFile(recordPath);
+ m_blobStorage.remove(blobPath);
+ }
+ });
+
+ RunLoop::main().dispatch([this] {
+ m_shrinkInProgress = false;
+ // We could synchronize during the shrink traversal. However this is fast and it is better to have just one code path.
+ synchronize();
+ });
+
+ LOG(NetworkCacheStorage, "(NetworkProcess) cache shrink completed");
+ });
+}
+
+void Storage::deleteOldVersions()
+{
+ backgroundIOQueue().dispatch([this] {
+ auto cachePath = basePath();
+ traverseDirectory(cachePath, [&cachePath](const String& subdirName, DirectoryEntryType type) {
+ if (type != DirectoryEntryType::Directory)
+ return;
+ if (!subdirName.startsWith(versionDirectoryPrefix))
+ return;
+ auto versionString = subdirName.substring(strlen(versionDirectoryPrefix));
+ bool success;
+ unsigned directoryVersion = versionString.toUIntStrict(&success);
+ if (!success)
+ return;
+ if (directoryVersion >= version)
+ return;
+
+#if PLATFORM(MAC)
+ // Allow the last stable version of the cache to co-exist with the latest development one on Mac.
+ const unsigned lastStableVersion = 4;
+ if (directoryVersion == lastStableVersion)
+ return;
+#endif
+
+ auto oldVersionPath = WebCore::pathByAppendingComponent(cachePath, subdirName);
+ LOG(NetworkCacheStorage, "(NetworkProcess) deleting old cache version, path %s", oldVersionPath.utf8().data());
+
+ deleteDirectoryRecursively(oldVersionPath);
+ });
+ });
+}
+
+}
+}
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h
new file mode 100644
index 000000000..4762a9cbf
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014-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.
+ */
+
+#ifndef NetworkCacheStorage_h
+#define NetworkCacheStorage_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheBlobStorage.h"
+#include "NetworkCacheData.h"
+#include "NetworkCacheKey.h"
+#include <WebCore/Timer.h>
+#include <wtf/BloomFilter.h>
+#include <wtf/Deque.h>
+#include <wtf/HashSet.h>
+#include <wtf/Optional.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+class IOChannel;
+
+class Storage {
+ WTF_MAKE_NONCOPYABLE(Storage);
+public:
+ static std::unique_ptr<Storage> open(const String& cachePath);
+
+ struct Record {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ Key key;
+ std::chrono::system_clock::time_point timeStamp;
+ Data header;
+ Data body;
+ };
+ // This may call completion handler synchronously on failure.
+ typedef std::function<bool (std::unique_ptr<Record>)> RetrieveCompletionHandler;
+ void retrieve(const Key&, unsigned priority, RetrieveCompletionHandler&&);
+
+ typedef std::function<void (const Data& mappedBody)> MappedBodyHandler;
+ void store(const Record&, MappedBodyHandler&&);
+
+ void remove(const Key&);
+ void clear(const String& type, std::chrono::system_clock::time_point modifiedSinceTime, std::function<void ()>&& completionHandler);
+
+ struct RecordInfo {
+ size_t bodySize;
+ double worth; // 0-1 where 1 is the most valuable.
+ unsigned bodyShareCount;
+ String bodyHash;
+ };
+ enum TraverseFlag {
+ ComputeWorth = 1 << 0,
+ ShareCount = 1 << 1,
+ };
+ typedef unsigned TraverseFlags;
+ typedef std::function<void (const Record*, const RecordInfo&)> TraverseHandler;
+ // Null record signals end.
+ void traverse(const String& type, TraverseFlags, TraverseHandler&&);
+
+ void setCapacity(size_t);
+ size_t capacity() const { return m_capacity; }
+ size_t approximateSize() const;
+
+ static const unsigned version = 5;
+
+ String basePath() const;
+ String versionPath() const;
+ String recordsPath() const;
+
+ ~Storage();
+
+private:
+ Storage(const String& directoryPath);
+
+ String recordDirectoryPathForKey(const Key&) const;
+ String recordPathForKey(const Key&) const;
+ String blobPathForKey(const Key&) const;
+
+ void synchronize();
+ void deleteOldVersions();
+ void shrinkIfNeeded();
+ void shrink();
+
+ struct ReadOperation;
+ void dispatchReadOperation(std::unique_ptr<ReadOperation>);
+ void dispatchPendingReadOperations();
+ void finishReadOperation(ReadOperation&);
+ void cancelAllReadOperations();
+
+ struct WriteOperation;
+ void dispatchWriteOperation(std::unique_ptr<WriteOperation>);
+ void dispatchPendingWriteOperations();
+ void finishWriteOperation(WriteOperation&);
+
+ Optional<BlobStorage::Blob> storeBodyAsBlob(WriteOperation&);
+ Data encodeRecord(const Record&, Optional<BlobStorage::Blob>);
+ void readRecord(ReadOperation&, const Data&);
+
+ void updateFileModificationTime(const String& path);
+ void removeFromPendingWriteOperations(const Key&);
+
+ WorkQueue& ioQueue() { return m_ioQueue.get(); }
+ WorkQueue& backgroundIOQueue() { return m_backgroundIOQueue.get(); }
+ WorkQueue& serialBackgroundIOQueue() { return m_serialBackgroundIOQueue.get(); }
+
+ bool mayContain(const Key&) const;
+ bool mayContainBlob(const Key&) const;
+
+ void addToRecordFilter(const Key&);
+
+ const String m_basePath;
+ const String m_recordsPath;
+
+ size_t m_capacity { std::numeric_limits<size_t>::max() };
+ size_t m_approximateRecordsSize { 0 };
+
+ // 2^18 bit filter can support up to 26000 entries with false positive rate < 1%.
+ using ContentsFilter = BloomFilter<18>;
+ std::unique_ptr<ContentsFilter> m_recordFilter;
+ std::unique_ptr<ContentsFilter> m_blobFilter;
+
+ bool m_synchronizationInProgress { false };
+ bool m_shrinkInProgress { false };
+
+ Vector<Key::HashType> m_recordFilterHashesAddedDuringSynchronization;
+ Vector<Key::HashType> m_blobFilterHashesAddedDuringSynchronization;
+
+ static const int maximumRetrievePriority = 4;
+ Deque<std::unique_ptr<ReadOperation>> m_pendingReadOperationsByPriority[maximumRetrievePriority + 1];
+ HashSet<std::unique_ptr<ReadOperation>> m_activeReadOperations;
+ WebCore::Timer m_readOperationTimeoutTimer;
+
+ Deque<std::unique_ptr<WriteOperation>> m_pendingWriteOperations;
+ HashSet<std::unique_ptr<WriteOperation>> m_activeWriteOperations;
+ WebCore::Timer m_writeOperationDispatchTimer;
+
+ struct TraverseOperation;
+ HashSet<std::unique_ptr<TraverseOperation>> m_activeTraverseOperations;
+
+ Ref<WorkQueue> m_ioQueue;
+ Ref<WorkQueue> m_backgroundIOQueue;
+ Ref<WorkQueue> m_serialBackgroundIOQueue;
+
+ BlobStorage m_blobStorage;
+};
+
+// FIXME: Remove, used by NetworkCacheStatistics only.
+void traverseRecordsFiles(const String& recordsPath, const String& type, const std::function<void (const String& fileName, const String& hashString, const String& type, bool isBodyBlob, const String& recordDirectoryPath)>&);
+
+}
+}
+#endif
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp
new file mode 100644
index 000000000..e762c3b33
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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"
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#include "NetworkCacheSubresourcesEntry.h"
+
+#include "Logging.h"
+#include "NetworkCacheCoders.h"
+#include "NetworkCacheDecoder.h"
+#include "NetworkCacheEncoder.h"
+
+namespace WebKit {
+namespace NetworkCache {
+
+Storage::Record SubresourcesEntry::encodeAsStorageRecord() const
+{
+ Encoder encoder;
+ encoder << m_subresources;
+
+ encoder.encodeChecksum();
+
+ return { m_key, m_timeStamp, { encoder.buffer(), encoder.bufferSize() } , { } };
+}
+
+std::unique_ptr<SubresourcesEntry> SubresourcesEntry::decodeStorageRecord(const Storage::Record& storageEntry)
+{
+ auto entry = std::make_unique<SubresourcesEntry>(storageEntry);
+
+ Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
+ if (!decoder.decode(entry->m_subresources))
+ return nullptr;
+
+ if (!decoder.verifyChecksum()) {
+ LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
+ return nullptr;
+ }
+
+ return entry;
+}
+
+SubresourcesEntry::SubresourcesEntry(const Storage::Record& storageEntry)
+ : m_key(storageEntry.key)
+ , m_timeStamp(storageEntry.timeStamp)
+{
+ ASSERT(m_key.type() == "subresources");
+}
+
+SubresourcesEntry::SubresourcesEntry(Key&& key, const Vector<Key>& subresourceKeys)
+ : m_key(WTFMove(key))
+ , m_timeStamp(std::chrono::system_clock::now())
+{
+ ASSERT(m_key.type() == "subresources");
+ for (auto& key : subresourceKeys)
+ m_subresources.add(key, SubresourceInfo());
+}
+
+void SubresourcesEntry::updateSubresourceKeys(const Vector<Key>& subresourceKeys)
+{
+ auto oldSubresources = WTFMove(m_subresources);
+
+ // Mark keys that are common with last load as non-Transient.
+ for (auto& key : subresourceKeys) {
+ bool isTransient = !oldSubresources.contains(key);
+ m_subresources.add(key, SubresourceInfo(isTransient));
+ }
+}
+
+} // namespace WebKit
+} // namespace NetworkCache
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h
new file mode 100644
index 000000000..d12282ffa
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef NetworkCacheSubresourcesEntry_h
+#define NetworkCacheSubresourcesEntry_h
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#include "NetworkCacheDecoder.h"
+#include "NetworkCacheEncoder.h"
+#include "NetworkCacheStorage.h"
+#include <wtf/HashMap.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+class SubresourcesEntry {
+ WTF_MAKE_NONCOPYABLE(SubresourcesEntry); WTF_MAKE_FAST_ALLOCATED;
+public:
+ struct SubresourceInfo {
+ void encode(Encoder& encoder) const { encoder << isTransient; }
+ static bool decode(Decoder& decoder, SubresourceInfo& info) { return decoder.decode(info.isTransient); }
+
+ SubresourceInfo() = default;
+ SubresourceInfo(bool isTransient) : isTransient(isTransient) { }
+
+ bool isTransient { false };
+ };
+ SubresourcesEntry(Key&&, const Vector<Key>& subresourceKeys);
+ explicit SubresourcesEntry(const Storage::Record&);
+
+ Storage::Record encodeAsStorageRecord() const;
+ static std::unique_ptr<SubresourcesEntry> decodeStorageRecord(const Storage::Record&);
+
+ const Key& key() const { return m_key; }
+ std::chrono::system_clock::time_point timeStamp() const { return m_timeStamp; }
+ const HashMap<Key, SubresourceInfo>& subresources() const { return m_subresources; }
+
+ void updateSubresourceKeys(const Vector<Key>&);
+
+private:
+ Key m_key;
+ std::chrono::system_clock::time_point m_timeStamp;
+ HashMap<Key, SubresourceInfo> m_subresources;
+};
+
+} // namespace WebKit
+} // namespace NetworkCache
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#endif // NetworkCacheSubresourcesEntry_h
diff --git a/Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.mm b/Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.mm
deleted file mode 100644
index 34c81e61d..000000000
--- a/Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.mm
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#import "config.h"
-#import "DiskCacheMonitor.h"
-
-#import "NetworkConnectionToWebProcess.h"
-#import "NetworkProcessConnectionMessages.h"
-#import "NetworkResourceLoader.h"
-#import "WebCoreArgumentCoders.h"
-
-#ifdef __has_include
-#if __has_include(<CFNetwork/CFURLCachePriv.h>)
-#include <CFNetwork/CFURLCachePriv.h>
-#endif
-#endif
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-
-typedef void (^CFCachedURLResponseCallBackBlock)(CFCachedURLResponseRef);
-extern "C" void _CFCachedURLResponseSetBecameFileBackedCallBackBlock(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t);
-
-using namespace WebCore;
-
-namespace WebKit {
-
-// The maximum number of seconds we'll try to wait for a resource to be disk cached before we forget the request.
-static const double diskCacheMonitorTimeout = 20;
-
-void DiskCacheMonitor::monitorFileBackingStoreCreation(CFCachedURLResponseRef cachedResponse, NetworkResourceLoader* loader)
-{
- if (!cachedResponse)
- return;
-
- ASSERT(loader);
-
- new DiskCacheMonitor(cachedResponse, loader); // Balanced by adoptPtr in the blocks setup in the constructor, one of which is guaranteed to run.
-}
-
-DiskCacheMonitor::DiskCacheMonitor(CFCachedURLResponseRef cachedResponse, NetworkResourceLoader* loader)
- : m_connectionToWebProcess(loader->connectionToWebProcess())
- , m_resourceRequest(loader->request())
-{
- ASSERT(isMainThread());
-
- // Set up a delayed callback to cancel this monitor if the resource hasn't been cached yet.
- __block DiskCacheMonitor* rawMonitor = this;
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * diskCacheMonitorTimeout), dispatch_get_main_queue(), ^{
- adoptPtr(rawMonitor); // Balanced by `new DiskCacheMonitor` in monitorFileBackingStoreCreation.
- rawMonitor = 0;
- });
-
- // Set up the disk caching callback to create the ShareableResource and send it to the WebProcess.
- CFCachedURLResponseCallBackBlock block = ^(CFCachedURLResponseRef cachedResponse)
- {
- // If the monitor isn't there then it timed out before this resource was cached to disk.
- if (!rawMonitor)
- return;
-
- OwnPtr<DiskCacheMonitor> monitor = adoptPtr(rawMonitor); // Balanced by `new DiskCacheMonitor` in monitorFileBackingStoreCreation.
- rawMonitor = 0;
-
- ShareableResource::Handle handle;
- NetworkResourceLoader::tryGetShareableHandleFromCFURLCachedResponse(handle, cachedResponse);
- if (handle.isNull())
- return;
-
- monitor->send(Messages::NetworkProcessConnection::DidCacheResource(monitor->resourceRequest(), handle));
- };
-
- _CFCachedURLResponseSetBecameFileBackedCallBackBlock(cachedResponse, block, dispatch_get_main_queue());
-}
-
-CoreIPC::Connection* DiskCacheMonitor::messageSenderConnection()
-{
- return m_connectionToWebProcess->connection();
-}
-
-uint64_t DiskCacheMonitor::messageSenderDestinationID()
-{
- return 0;
-}
-
-} // namespace WebKit
-
-#endif // #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
diff --git a/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm b/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm
deleted file mode 100644
index 3e96fa4dc..000000000
--- a/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm
+++ /dev/null
@@ -1,231 +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 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.
- */
-
-#import "config.h"
-#import "NetworkProcess.h"
-
-#if ENABLE(NETWORK_PROCESS)
-
-#import "NetworkProcessCreationParameters.h"
-#import "NetworkResourceLoader.h"
-#import "PlatformCertificateInfo.h"
-#import "ResourceCachesToClear.h"
-#import "SandboxExtension.h"
-#import "SandboxInitializationParameters.h"
-#import "StringUtilities.h"
-#import <WebCore/FileSystem.h>
-#import <WebCore/LocalizedStrings.h>
-#import <WebKitSystemInterface.h>
-#import <mach/host_info.h>
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-#import <sysexits.h>
-#import <wtf/text/WTFString.h>
-
-#if USE(SECURITY_FRAMEWORK)
-#import "SecItemShim.h"
-#endif
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-typedef struct _CFURLCache* CFURLCacheRef;
-extern "C" CFURLCacheRef CFURLCacheCopySharedURLCache();
-extern "C" void _CFURLCacheSetMinSizeForVMCachedResource(CFURLCacheRef, CFIndex);
-#endif
-
-using namespace WebCore;
-
-@interface NSURLRequest (Details)
-+ (void)setAllowsSpecificHTTPSCertificate:(NSArray *)allow forHost:(NSString *)host;
-@end
-
-namespace WebKit {
-
-void NetworkProcess::initializeProcess(const ChildProcessInitializationParameters&)
-{
- // Having a window server connection in this process would result in spin logs (<rdar://problem/13239119>).
- setApplicationIsDaemon();
-}
-
-void NetworkProcess::initializeProcessName(const ChildProcessInitializationParameters& parameters)
-{
- NSString *applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Networking", "visible name of the network process. The argument is the application name."), (NSString *)parameters.uiProcessName];
- WKSetVisibleApplicationName((CFStringRef)applicationName);
-}
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
-static void overrideSystemProxies(const String& httpProxy, const String& httpsProxy)
-{
- NSMutableDictionary *proxySettings = [NSMutableDictionary dictionary];
-
- if (!httpProxy.isNull()) {
- KURL httpProxyURL(KURL(), httpProxy);
- if (httpProxyURL.isValid()) {
- [proxySettings setObject:nsStringFromWebCoreString(httpProxyURL.host()) forKey:(NSString *)kCFNetworkProxiesHTTPProxy];
- if (httpProxyURL.hasPort()) {
- NSNumber *port = [NSNumber numberWithInt:httpProxyURL.port()];
- [proxySettings setObject:port forKey:(NSString *)kCFNetworkProxiesHTTPPort];
- }
- }
- else
- NSLog(@"Malformed HTTP Proxy URL '%s'. Expected 'http://<hostname>[:<port>]'\n", httpProxy.utf8().data());
- }
-
- if (!httpsProxy.isNull()) {
- KURL httpsProxyURL(KURL(), httpsProxy);
- if (httpsProxyURL.isValid()) {
- [proxySettings setObject:nsStringFromWebCoreString(httpsProxyURL.host()) forKey:(NSString *)kCFNetworkProxiesHTTPSProxy];
- if (httpsProxyURL.hasPort()) {
- NSNumber *port = [NSNumber numberWithInt:httpsProxyURL.port()];
- [proxySettings setObject:port forKey:(NSString *)kCFNetworkProxiesHTTPSPort];
- }
- } else
- NSLog(@"Malformed HTTPS Proxy URL '%s'. Expected 'https://<hostname>[:<port>]'\n", httpsProxy.utf8().data());
- }
-
- if ([proxySettings count] > 0)
- WKCFNetworkSetOverrideSystemProxySettings((CFDictionaryRef)proxySettings);
-}
-#endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
-
-void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreationParameters& parameters)
-{
- m_diskCacheDirectory = parameters.diskCacheDirectory;
-
- if (!m_diskCacheDirectory.isNull()) {
- SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
- [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
- initWithMemoryCapacity:parameters.nsURLCacheMemoryCapacity
- diskCapacity:parameters.nsURLCacheDiskCapacity
- diskPath:parameters.diskCacheDirectory]).get()];
- }
-
-#if USE(SECURITY_FRAMEWORK)
- SecItemShim::shared().initialize(this);
-#endif
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
- if (!parameters.httpProxy.isNull() || !parameters.httpsProxy.isNull())
- overrideSystemProxies(parameters.httpProxy, parameters.httpsProxy);
-#endif
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
- RetainPtr<CFURLCacheRef> cache = adoptCF(CFURLCacheCopySharedURLCache());
- if (!cache)
- return;
-
- _CFURLCacheSetMinSizeForVMCachedResource(cache.get(), NetworkResourceLoader::fileBackedResourceMinimumSize());
-#endif
-}
-
-static uint64_t memorySize()
-{
- static host_basic_info_data_t hostInfo;
-
- static dispatch_once_t once;
- dispatch_once(&once, ^() {
- mach_port_t host = mach_host_self();
- mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
- kern_return_t r = host_info(host, HOST_BASIC_INFO, (host_info_t)&hostInfo, &count);
- mach_port_deallocate(mach_task_self(), host);
-
- if (r != KERN_SUCCESS)
- LOG_ERROR("%s : host_info(%d) : %s.\n", __FUNCTION__, r, mach_error_string(r));
- });
-
- return hostInfo.max_mem;
-}
-
-static uint64_t volumeFreeSize(const String& path)
-{
- NSDictionary *fileSystemAttributesDictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:(NSString *)path error:NULL];
- return [[fileSystemAttributesDictionary objectForKey:NSFileSystemFreeSize] unsignedLongLongValue];
-}
-
-void NetworkProcess::platformSetCacheModel(CacheModel cacheModel)
-{
-
- // As a fudge factor, use 1000 instead of 1024, in case the reported byte
- // count doesn't align exactly to a megabyte boundary.
- uint64_t memSize = memorySize() / 1024 / 1000;
- uint64_t diskFreeSize = volumeFreeSize(m_diskCacheDirectory) / 1024 / 1000;
-
- unsigned cacheTotalCapacity = 0;
- unsigned cacheMinDeadCapacity = 0;
- unsigned cacheMaxDeadCapacity = 0;
- double deadDecodedDataDeletionInterval = 0;
- unsigned pageCacheCapacity = 0;
- unsigned long urlCacheMemoryCapacity = 0;
- unsigned long urlCacheDiskCapacity = 0;
-
- calculateCacheSizes(cacheModel, memSize, diskFreeSize,
- cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval,
- pageCacheCapacity, urlCacheMemoryCapacity, urlCacheDiskCapacity);
-
-
- NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
- [nsurlCache setMemoryCapacity:urlCacheMemoryCapacity];
- [nsurlCache setDiskCapacity:std::max<unsigned long>(urlCacheDiskCapacity, [nsurlCache diskCapacity])]; // Don't shrink a big disk cache, since that would cause churn.
-}
-
-void NetworkProcess::allowSpecificHTTPSCertificateForHost(const PlatformCertificateInfo& certificateInfo, const String& host)
-{
- [NSURLRequest setAllowsSpecificHTTPSCertificate:(NSArray *)certificateInfo.certificateChain() forHost:(NSString *)host];
-}
-
-void NetworkProcess::initializeSandbox(const ChildProcessInitializationParameters& parameters, SandboxInitializationParameters& sandboxParameters)
-{
- // Need to overide the default, because service has a different bundle ID.
- NSBundle *webkit2Bundle = [NSBundle bundleForClass:NSClassFromString(@"WKView")];
- sandboxParameters.setOverrideSandboxProfilePath([webkit2Bundle pathForResource:@"com.apple.WebKit.NetworkProcess" ofType:@"sb"]);
-
- ChildProcess::initializeSandbox(parameters, sandboxParameters);
-}
-
-void NetworkProcess::clearCacheForAllOrigins(uint32_t cachesToClear)
-{
- ResourceCachesToClear resourceCachesToClear = static_cast<ResourceCachesToClear>(cachesToClear);
- if (resourceCachesToClear == InMemoryResourceCachesOnly)
- return;
-
- if (!m_clearCacheDispatchGroup)
- m_clearCacheDispatchGroup = dispatch_group_create();
-
- dispatch_group_async(m_clearCacheDispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [[NSURLCache sharedURLCache] removeAllCachedResponses];
- });
-}
-
-void NetworkProcess::platformTerminate()
-{
- if (m_clearCacheDispatchGroup) {
- dispatch_group_wait(m_clearCacheDispatchGroup, DISPATCH_TIME_FOREVER);
- dispatch_release(m_clearCacheDispatchGroup);
- m_clearCacheDispatchGroup = 0;
- }
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoadSchedulerMac.mm b/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoadSchedulerMac.mm
deleted file mode 100644
index 15f21c47b..000000000
--- a/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoadSchedulerMac.mm
+++ /dev/null
@@ -1,76 +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 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.
- */
-
-#import "config.h"
-#import "NetworkResourceLoadScheduler.h"
-
-#import <WebCore/ResourceRequest.h>
-#import <WebCore/ResourceRequestCFNet.h>
-#import <WebCore/WebCoreSystemInterface.h>
-#import <WebKitSystemInterface.h>
-
-#if ENABLE(NETWORK_PROCESS)
-
-using namespace WebCore;
-
-namespace WebKit {
-
-void NetworkResourceLoadScheduler::platformInitializeMaximumHTTPConnectionCountPerHost()
-{
- wkInitializeMaximumHTTPConnectionCountPerHost = WKInitializeMaximumHTTPConnectionCountPerHost;
- wkSetHTTPPipeliningMaximumPriority = WKSetHTTPPipeliningMaximumPriority;
- wkSetHTTPPipeliningMinimumFastLanePriority = WKSetHTTPPipeliningMinimumFastLanePriority;
-
- // Our preferred connection-per-host limit is the standard 6, but we need to let CFNetwork handle a 7th
- // in case a synchronous XHRs is made while 6 loads are already outstanding.
- static const unsigned preferredConnectionCount = 7;
- static const unsigned unlimitedConnectionCount = 10000;
-
- // Always set the connection count per host, even when pipelining.
- unsigned maximumHTTPConnectionCountPerHost = wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount);
-
- Boolean keyExistsAndHasValidFormat = false;
- Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitEnableHTTPPipelining"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
-
- if (keyExistsAndHasValidFormat)
- ResourceRequest::setHTTPPipeliningEnabled(prefValue);
-
- if (ResourceRequest::httpPipeliningEnabled()) {
- wkSetHTTPPipeliningMaximumPriority(toHTTPPipeliningPriority(ResourceLoadPriorityHighest));
- wkSetHTTPPipeliningMinimumFastLanePriority(toHTTPPipeliningPriority(ResourceLoadPriorityMedium));
-
- // When pipelining do not rate-limit requests sent from WebCore since CFNetwork handles that.
- m_maxRequestsInFlightPerHost = unlimitedConnectionCount;
-
- return;
- }
-
- // We've asked for one more connection per host than we intend to use in most cases so synch XHRs can bypass that limit.
- m_maxRequestsInFlightPerHost = maximumHTTPConnectionCountPerHost - 1;
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_PROCESS)
diff --git a/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm b/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm
deleted file mode 100644
index 84ea149c7..000000000
--- a/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#import "config.h"
-#import "NetworkResourceLoader.h"
-
-#import "DiskCacheMonitor.h"
-#import "ShareableResource.h"
-#import <WebCore/ResourceHandle.h>
-#import <WebCore/SharedBuffer.h>
-
-using namespace WebCore;
-
-#ifdef __has_include
-#if __has_include(<CFNetwork/CFURLCache.h>)
-#include <CFNetwork/CFURLCache.h>
-#endif
-#if __has_include(<CFNetwork/CFURLCachePriv.h>)
-#include <CFNetwork/CFURLCachePriv.h>
-#endif
-#endif
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-typedef const struct _CFURLCache* CFURLCacheRef;
-typedef const struct _CFCachedURLResponse* CFCachedURLResponseRef;
-extern "C" CFURLCacheRef CFURLCacheCopySharedURLCache();
-extern "C" CFCachedURLResponseRef CFURLCacheCopyResponseForRequest(CFURLCacheRef, CFURLRequestRef);
-extern "C" CFDataRef _CFCachedURLResponseGetMemMappedData(CFCachedURLResponseRef);
-extern "C" CFBooleanRef _CFURLCacheIsResponseDataMemMapped(CFURLCacheRef, CFDataRef);
-#endif
-
-@interface NSCachedURLResponse (NSCachedURLResponseDetails)
--(CFCachedURLResponseRef)_CFCachedURLResponse;
-@end
-
-namespace WebKit {
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-
-static void tryGetShareableHandleFromCFData(ShareableResource::Handle& handle, CFDataRef data)
-{
- if (!data || CFDataGetLength(data) < (CFIndex)NetworkResourceLoader::fileBackedResourceMinimumSize())
- return;
-
- RefPtr<SharedMemory> sharedMemory = SharedMemory::createFromVMBuffer((void*)CFDataGetBytePtr(data), CFDataGetLength(data));
- if (!sharedMemory) {
- LOG_ERROR("Failed to create VM shared memory for cached resource.");
- return;
- }
-
- size_t size = sharedMemory->size();
- RefPtr<ShareableResource> resource = ShareableResource::create(sharedMemory.release(), 0, size);
- resource->createHandle(handle);
-}
-
-void NetworkResourceLoader::tryGetShareableHandleFromCFURLCachedResponse(ShareableResource::Handle& handle, CFCachedURLResponseRef cachedResponse)
-{
- CFDataRef data = _CFCachedURLResponseGetMemMappedData(cachedResponse);
-
- tryGetShareableHandleFromCFData(handle, data);
-}
-
-void NetworkResourceLoader::tryGetShareableHandleFromSharedBuffer(ShareableResource::Handle& handle, SharedBuffer* buffer)
-{
- RetainPtr<CFURLCacheRef> cache = adoptCF(CFURLCacheCopySharedURLCache());
- if (!cache)
- return;
-
- RetainPtr<CFDataRef> data = adoptCF(buffer->createCFData());
- if (_CFURLCacheIsResponseDataMemMapped(cache.get(), data.get()) == kCFBooleanFalse)
- return;
-
- tryGetShareableHandleFromCFData(handle, data.get());
-}
-#endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-
-size_t NetworkResourceLoader::fileBackedResourceMinimumSize()
-{
- return SharedMemory::systemPageSize();
-}
-
-void NetworkResourceLoader::willCacheResponseAsync(ResourceHandle* handle, NSCachedURLResponse *nsResponse)
-{
- ASSERT_UNUSED(handle, handle == m_handle);
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
- if (m_bytesReceived >= fileBackedResourceMinimumSize())
- DiskCacheMonitor::monitorFileBackingStoreCreation([nsResponse _CFCachedURLResponse], this);
-#endif
-
- m_handle->continueWillCacheResponse(nsResponse);
-}
-
-} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.mm b/Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.mm
deleted file mode 100644
index 53ec91c5d..000000000
--- a/Source/WebKit2/NetworkProcess/mac/RemoteNetworkingContext.mm
+++ /dev/null
@@ -1,135 +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 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.
- */
-
-#import "config.h"
-#import "RemoteNetworkingContext.h"
-
-#import "WebErrors.h"
-#import <WebCore/ResourceError.h>
-#import <WebKitSystemInterface.h>
-#import <wtf/MainThread.h>
-#import <wtf/PassOwnPtr.h>
-
-using namespace WebCore;
-
-namespace WebKit {
-
-static OwnPtr<NetworkStorageSession>& privateBrowsingStorageSession()
-{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(OwnPtr<NetworkStorageSession>, session, ());
- return session;
-}
-
-bool RemoteNetworkingContext::shouldClearReferrerOnHTTPSToHTTPRedirect() const
-{
- return m_shouldClearReferrerOnHTTPSToHTTPRedirect;
-}
-
-RemoteNetworkingContext::RemoteNetworkingContext(bool needsSiteSpecificQuirks, bool localFileContentSniffingEnabled, bool privateBrowsingEnabled, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
- : m_needsSiteSpecificQuirks(needsSiteSpecificQuirks)
- , m_localFileContentSniffingEnabled(localFileContentSniffingEnabled)
- , m_privateBrowsingEnabled(privateBrowsingEnabled)
- , m_shouldClearReferrerOnHTTPSToHTTPRedirect(shouldClearReferrerOnHTTPSToHTTPRedirect)
-{
-}
-
-RemoteNetworkingContext::~RemoteNetworkingContext()
-{
-}
-
-bool RemoteNetworkingContext::isValid() const
-{
- return true;
-}
-
-bool RemoteNetworkingContext::needsSiteSpecificQuirks() const
-{
- return m_needsSiteSpecificQuirks;
-}
-
-bool RemoteNetworkingContext::localFileContentSniffingEnabled() const
-{
- return m_localFileContentSniffingEnabled;
-}
-
-NetworkStorageSession& RemoteNetworkingContext::storageSession() const
-{
- if (m_privateBrowsingEnabled) {
- NetworkStorageSession* privateSession = privateBrowsingStorageSession().get();
- if (privateSession)
- return *privateSession;
- // Some requests with private browsing mode requested may still be coming shortly after NetworkProcess was told to destroy its session.
- // FIXME: Find a way to track private browsing sessions more rigorously.
- LOG_ERROR("Private browsing was requested, but there was no session for it. Please file a bug unless you just disabled private browsing, in which case it's an expected race.");
- }
-
- return NetworkStorageSession::defaultStorageSession();
-}
-
-NetworkStorageSession* RemoteNetworkingContext::privateBrowsingSession()
-{
- return privateBrowsingStorageSession().get();
-}
-
-RetainPtr<CFDataRef> RemoteNetworkingContext::sourceApplicationAuditData() const
-{
- return nil;
-}
-
-ResourceError RemoteNetworkingContext::blockedError(const ResourceRequest& request) const
-{
- return WebKit::blockedError(request);
-}
-
-static String& privateBrowsingStorageSessionIdentifierBase()
-{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(String, base, ());
- return base;
-}
-
-void RemoteNetworkingContext::setPrivateBrowsingStorageSessionIdentifierBase(const String& identifier)
-{
- privateBrowsingStorageSessionIdentifierBase() = identifier;
-}
-
-void RemoteNetworkingContext::ensurePrivateBrowsingSession()
-{
- if (privateBrowsingStorageSession())
- return;
-
- ASSERT(!privateBrowsingStorageSessionIdentifierBase().isNull());
- RetainPtr<CFStringRef> cfIdentifier = String(privateBrowsingStorageSessionIdentifierBase() + ".PrivateBrowsing").createCFString();
-
- privateBrowsingStorageSession() = NetworkStorageSession::createPrivateBrowsingSession(privateBrowsingStorageSessionIdentifierBase());
-}
-
-void RemoteNetworkingContext::destroyPrivateBrowsingSession()
-{
- privateBrowsingStorageSession() = nullptr;
-}
-
-}
diff --git a/Source/WebKit2/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in b/Source/WebKit2/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in
deleted file mode 100644
index 7ba86c038..000000000
--- a/Source/WebKit2/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in
+++ /dev/null
@@ -1,148 +0,0 @@
-(version 1)
-(deny default (with partial-symbolication))
-(allow system-audit file-read-metadata)
-
-(import "system.sb")
-
-;; Utility functions for home directory relative path filters
-(define (home-regex home-relative-regex)
- (regex (string-append "^" (regex-quote (param "HOME_DIR")) home-relative-regex)))
-
-(define (home-subpath home-relative-subpath)
- (subpath (string-append (param "HOME_DIR") home-relative-subpath)))
-
-(define (home-literal home-relative-literal)
- (literal (string-append (param "HOME_DIR") home-relative-literal)))
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED == 1070
-;; Low level networking. Defined in system.sb on newer OS versions.
-(define (system-network)
- (allow file-read*
- (literal "/Library/Preferences/com.apple.networkd.plist"))
- (allow mach-lookup
- (global-name "com.apple.SystemConfiguration.PPPController")
- (global-name "com.apple.SystemConfiguration.SCNetworkReachability")
- (global-name "com.apple.networkd"))
- (allow network-outbound
- (control-name "com.apple.netsrc")
- (control-name "com.apple.network.statistics"))
- (allow system-socket
- (require-all (socket-domain AF_SYSTEM)
- (socket-protocol 2)) ; SYSPROTO_CONTROL
- (socket-domain AF_ROUTE)))
-#endif
-
-;; Read-only preferences and data
-(allow file-read*
- ;; Basic system paths
- (subpath "/Library/Frameworks")
- (subpath "/Library/Managed Preferences")
-
- ;; System and user preferences
- (literal "/Library/Preferences/.GlobalPreferences.plist")
- (regex #"^/Library/Managed Preferences/[^/]+/com\.apple\.networkConnect\.plist$")
- (home-literal "/Library/Preferences/.GlobalPreferences.plist")
- (home-regex #"/Library/Preferences/ByHost/\.GlobalPreferences\.")
- (home-regex #"/Library/Preferences/ByHost/com\.apple\.networkConnect\.")
- (home-literal "/Library/Preferences/com.apple.DownloadAssessment.plist")
- (home-literal "/Library/Preferences/com.apple.WebFoundation.plist")
-
- ;; On-disk WebKit2 framework location, to account for debug installations
- ;; outside of /System/Library/Frameworks
- (subpath (param "WEBKIT2_FRAMEWORK_DIR")))
-
-;; Sandbox extensions
-(define (apply-read-and-issue-extension op path-filter)
- (op file-read* path-filter)
- (op file-issue-extension (require-all (extension-class "com.apple.app-sandbox.read") path-filter)))
-(define (apply-write-and-issue-extension op path-filter)
- (op file-write* path-filter)
- (op file-issue-extension (require-all (extension-class "com.apple.app-sandbox.read-write") path-filter)))
-(define (read-only-and-issue-extensions path-filter)
- (apply-read-and-issue-extension allow path-filter))
-(define (read-write-and-issue-extensions path-filter)
- (apply-read-and-issue-extension allow path-filter)
- (apply-write-and-issue-extension allow path-filter))
-(read-only-and-issue-extensions (extension "com.apple.app-sandbox.read"))
-(read-write-and-issue-extensions (extension "com.apple.app-sandbox.read-write"))
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
-(allow file-read* file-write* (subpath (param "DARWIN_USER_CACHE_DIR")))
-#else
-(allow file-read* file-write* (subpath (string-append (param "DARWIN_USER_CACHE_DIR") "/mds")))
-#endif
-
-(allow file-read* file-write* (subpath (param "DARWIN_USER_TEMP_DIR")))
-
-;; IOKit user clients
-(allow iokit-open
- (iokit-user-client-class "RootDomainUserClient"))
-
-;; cookied.
-;; FIXME: Update for <rdar://problem/13642852>.
-(allow ipc-posix-shm-read-data
- (ipc-posix-name "FNetwork.defaultStorageSession")
- (ipc-posix-name-regex #"\.PrivateBrowsing-")
- (ipc-posix-name-regex #"^Private WebKit Session-"))
-
-;; Various services required by CFNetwork and other frameworks
-(allow mach-lookup
- (global-name "com.apple.PowerManagement.control")
- (global-name "com.apple.SystemConfiguration.configd")
- (global-name "com.apple.cookied")
- (global-name "com.apple.cfnetwork.AuthBrokerAgent"))
-
-;; Security framework
-(allow mach-lookup
- (global-name "com.apple.ocspd")
- (global-name "com.apple.SecurityServer"))
-(allow file-read* file-write* (home-subpath "/Library/Keychains")) ;; FIXME: This should be removed when <rdar://problem/10479685> is fixed.
-(allow file-read* file-write* (subpath "/private/var/db/mds/system")) ;; FIXME: This should be removed when <rdar://problem/9538414> is fixed.
-(allow file-read*
- (subpath "/Library/Keychains")
- (subpath "/private/var/db/mds")
- (literal "/private/var/db/DetachedSignatures")
- (literal "/Library/Preferences/com.apple.crypto.plist")
- (literal "/Library/Preferences/com.apple.security.plist")
- (literal "/Library/Preferences/com.apple.security.common.plist")
- (literal "/Library/Preferences/com.apple.security.revocation.plist")
- (home-literal "/Library/Application Support/SyncServices/Local/ClientsWithChanges/com.apple.Keychain")
- (home-literal "/Library/Preferences/com.apple.security.plist")
- (home-literal "/Library/Preferences/com.apple.security.revocation.plist"))
-(allow ipc-posix-shm-read* ipc-posix-shm-write-data
- (ipc-posix-name "com.apple.AppleDatabaseChanged"))
-
-(system-network)
-(allow network-outbound
- ;; Local mDNSResponder for DNS, arbitrary outbound TCP
- (literal "/private/var/run/mDNSResponder")
- (remote tcp))
-
-;; FIXME should be removed when <rdar://problem/9347205> + related radar in Safari is fixed
-(allow mach-lookup
- (global-name "org.h5l.kcm")
- (global-name "com.apple.system.logger")
- (global-name "com.apple.system.notification_center"))
-(allow network-outbound
- (remote udp))
-(allow file-read*
- (home-subpath "/Library/Preferences/com.apple.Kerberos.plist")
- (home-subpath "/Library/Preferences/com.apple.GSS.plist")
- (home-subpath "/Library/Preferences/edu.mit.Kerberos")
- (literal "/Library/Preferences/com.apple.Kerberos.plist")
- (literal "/Library/Preferences/com.apple.GSS.plist")
- (literal "/Library/Preferences/edu.mit.Kerberos")
- (literal "/private/etc/krb5.conf")
- (literal "/private/etc/services")
- (literal "/private/etc/host"))
-
-(if (defined? 'vnode-type)
- (deny file-write-create (vnode-type SYMLINK)))
-
-(deny file-read* file-write* (with no-log)
-#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
- (home-literal "/Library/Caches/Cache.db") ;; <rdar://problem/9422957>
-#endif
- ;; FIXME: Should be removed after <rdar://problem/10463881> is fixed.
- (home-literal "/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2")
- (home-literal "/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2-journal"))
diff --git a/Source/WebKit2/NetworkProcess/qt/NetworkProcessMainQt.cpp b/Source/WebKit2/NetworkProcess/qt/NetworkProcessMainQt.cpp
new file mode 100644
index 000000000..d3799bb24
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/qt/NetworkProcessMainQt.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 Konstantin Tokarev <annulen@yandex.ru>
+ * Copyright (C) 2014 Igalia S.L.
+ * Copyright (C) 2013 Company 100 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 THE COPYRIGHT HOLDERS ``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 "NetworkProcess.h"
+
+#include "ChildProcessMain.h"
+
+#include <QCoreApplication>
+#include <QNetworkProxyFactory>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+class EnvHttpProxyFactory : public QNetworkProxyFactory {
+public:
+ EnvHttpProxyFactory() { }
+
+ bool initializeFromEnvironment();
+
+ QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery& = QNetworkProxyQuery());
+
+private:
+ QList<QNetworkProxy> m_httpProxy;
+ QList<QNetworkProxy> m_httpsProxy;
+};
+
+bool EnvHttpProxyFactory::initializeFromEnvironment()
+{
+ bool wasSetByEnvironment = false;
+
+ QUrl proxyUrl = QUrl::fromUserInput(QString::fromLocal8Bit(qgetenv("http_proxy")));
+ if (proxyUrl.isValid() && !proxyUrl.host().isEmpty()) {
+ int proxyPort = (proxyUrl.port() > 0) ? proxyUrl.port() : 8080;
+ m_httpProxy << QNetworkProxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyPort);
+ wasSetByEnvironment = true;
+ } else
+ m_httpProxy << QNetworkProxy::NoProxy;
+
+ proxyUrl = QUrl::fromUserInput(QString::fromLocal8Bit(qgetenv("https_proxy")));
+ if (proxyUrl.isValid() && !proxyUrl.host().isEmpty()) {
+ int proxyPort = (proxyUrl.port() > 0) ? proxyUrl.port() : 8080;
+ m_httpsProxy << QNetworkProxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyPort);
+ wasSetByEnvironment = true;
+ } else
+ m_httpsProxy << QNetworkProxy::NoProxy;
+
+ return wasSetByEnvironment;
+}
+
+QList<QNetworkProxy> EnvHttpProxyFactory::queryProxy(const QNetworkProxyQuery& query)
+{
+ QString protocol = query.protocolTag().toLower();
+ bool localHost = false;
+
+ if (!query.peerHostName().compare(QLatin1String("localhost"), Qt::CaseInsensitive) || !query.peerHostName().compare(QLatin1String("127.0.0.1"), Qt::CaseInsensitive))
+ localHost = true;
+ if (protocol == QLatin1String("http") && !localHost)
+ return m_httpProxy;
+ if (protocol == QLatin1String("https") && !localHost)
+ return m_httpsProxy;
+
+ QList<QNetworkProxy> proxies;
+ proxies << QNetworkProxy::NoProxy;
+ return proxies;
+}
+
+static void initializeProxy()
+{
+ QList<QNetworkProxy> proxylist = QNetworkProxyFactory::systemProxyForQuery();
+ if (proxylist.count() == 1) {
+ QNetworkProxy proxy = proxylist.first();
+ if (proxy == QNetworkProxy::NoProxy || proxy == QNetworkProxy::DefaultProxy) {
+ auto proxyFactory = std::make_unique<EnvHttpProxyFactory>();
+ if (proxyFactory->initializeFromEnvironment()) {
+ QNetworkProxyFactory::setApplicationProxyFactory(proxyFactory.release());
+ return;
+ }
+ }
+ }
+ QNetworkProxyFactory::setUseSystemConfiguration(true);
+}
+
+class NetworkProcessMain final: public ChildProcessMainBase {
+public:
+
+ bool platformInitialize() final
+ {
+ initializeProxy();
+ return true;
+ }
+};
+
+Q_DECL_EXPORT int NetworkProcessMainQt(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+ return ChildProcessMain<NetworkProcess, ChildProcessMainBase>(argc, argv);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/qt/NetworkProcessQt.cpp b/Source/WebKit2/NetworkProcess/qt/NetworkProcessQt.cpp
new file mode 100644
index 000000000..f822b3d20
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/qt/NetworkProcessQt.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 Konstantin Tokarev <annulen@yandex.ru>
+ *
+ * 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 "NetworkProcess.h"
+
+#include "NetworkProcessCreationParameters.h"
+#include "QtNetworkAccessManager.h"
+
+#include <QNetworkDiskCache>
+#include <WebCore/CertificateInfo.h>
+#include <WebCore/CookieJarQt.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreationParameters& parameters)
+{
+ if (!parameters.cookiePersistentStoragePath.isEmpty()) {
+ WebCore::SharedCookieJarQt* jar = WebCore::SharedCookieJarQt::create(parameters.cookiePersistentStoragePath);
+ m_networkAccessManager.setCookieJar(jar);
+ // Do not let QNetworkAccessManager delete the jar.
+ jar->setParent(0);
+ }
+
+ if (!parameters.diskCacheDirectory.isEmpty()) {
+ QNetworkDiskCache* diskCache = new QNetworkDiskCache();
+ diskCache->setCacheDirectory(parameters.diskCacheDirectory);
+ // The m_networkAccessManager takes ownership of the diskCache object upon the following call.
+ m_networkAccessManager.setCache(diskCache);
+ }
+}
+
+void NetworkProcess::platformTerminate()
+{
+}
+
+void NetworkProcess::allowSpecificHTTPSCertificateForHost(const CertificateInfo&, const String&)
+{
+}
+
+void NetworkProcess::clearCacheForAllOrigins(uint32_t)
+{
+}
+
+void NetworkProcess::clearDiskCache(std::chrono::system_clock::time_point, std::function<void()>)
+{
+}
+
+void NetworkProcess::platformSetCacheModel(CacheModel)
+{
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.cpp b/Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.cpp
new file mode 100644
index 000000000..5e38a7717
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011 Zeno Albisser <zeno@webkit.org>
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "QtNetworkAccessManager.h"
+
+#include "WebPage.h"
+#include "WebPageProxyMessages.h"
+#include "WebProcess.h"
+#include <QAuthenticator>
+#include <QNetworkProxy>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+
+namespace WebKit {
+
+QtNetworkAccessManager::QtNetworkAccessManager()
+ : QNetworkAccessManager()
+{
+ connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), SLOT(onAuthenticationRequired(QNetworkReply*, QAuthenticator*)));
+ connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), SLOT(onProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
+#ifndef QT_NO_SSL
+ connect(this, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)), SLOT(onSslErrors(QNetworkReply*, QList<QSslError>)));
+#endif
+}
+
+WebPage* QtNetworkAccessManager::obtainOriginatingWebPage(const QNetworkRequest& request)
+{
+ // QTFIXME: Old process model
+ if (!m_webProcess)
+ return nullptr;
+
+ QObject* originatingObject = request.originatingObject();
+ if (!originatingObject)
+ return 0;
+
+ qulonglong pageID = originatingObject->property("pageID").toULongLong();
+ return m_webProcess->webPage(pageID);
+}
+
+void QtNetworkAccessManager::onProxyAuthenticationRequired(const QNetworkProxy& proxy, QAuthenticator* authenticator)
+{
+ // FIXME: Check if there is a better way to get a reference to the page.
+ WebPage* webPage = m_webProcess->focusedWebPage();
+
+ if (!webPage)
+ return;
+
+ String hostname = proxy.hostName();
+ uint16_t port = static_cast<uint16_t>(proxy.port());
+ String prefilledUsername = authenticator->user();
+ String username;
+ String password;
+
+ if (webPage->sendSync(
+ Messages::WebPageProxy::ProxyAuthenticationRequiredRequest(hostname, port, prefilledUsername),
+ Messages::WebPageProxy::ProxyAuthenticationRequiredRequest::Reply(username, password))) {
+ if (!username.isEmpty())
+ authenticator->setUser(username);
+ if (!password.isEmpty())
+ authenticator->setPassword(password);
+ }
+
+}
+
+void QtNetworkAccessManager::onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator)
+{
+ WebPage* webPage = obtainOriginatingWebPage(reply->request());
+
+ // FIXME: This check can go away once our Qt version is up-to-date. See: QTBUG-23512.
+ if (!webPage)
+ return;
+
+ String hostname = reply->url().toString(QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment | QUrl::StripTrailingSlash);
+ String realm = authenticator->realm();
+ String prefilledUsername = authenticator->user();
+ String username;
+ String password;
+
+ if (webPage->sendSync(
+ Messages::WebPageProxy::AuthenticationRequiredRequest(hostname, realm, prefilledUsername),
+ Messages::WebPageProxy::AuthenticationRequiredRequest::Reply(username, password))) {
+ if (!username.isEmpty())
+ authenticator->setUser(username);
+ if (!password.isEmpty())
+ authenticator->setPassword(password);
+ }
+}
+
+void QtNetworkAccessManager::onSslErrors(QNetworkReply* reply, const QList<QSslError>& qSslErrors)
+{
+#ifndef QT_NO_SSL
+ WebPage* webPage = obtainOriginatingWebPage(reply->request());
+
+ // FIXME: This check can go away once our Qt version is up-to-date. See: QTBUG-23512.
+ if (!webPage)
+ return;
+
+ String hostname = reply->url().host();
+ bool ignoreErrors = false;
+
+ if (webPage->sendSync(
+ Messages::WebPageProxy::CertificateVerificationRequest(hostname),
+ Messages::WebPageProxy::CertificateVerificationRequest::Reply(ignoreErrors))) {
+ if (ignoreErrors)
+ reply->ignoreSslErrors(qSslErrors);
+ }
+#endif
+}
+
+}
+
+#include "moc_QtNetworkAccessManager.cpp"
diff --git a/Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.h b/Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.h
new file mode 100644
index 000000000..5b958f13e
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/qt/QtNetworkAccessManager.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 Zeno Albisser <zeno@webkit.org>
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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.
+ */
+
+#ifndef QtNetworkAccessManager_h
+#define QtNetworkAccessManager_h
+
+#include <QMultiHash>
+#include <QNetworkAccessManager>
+#include <QNetworkProxy>
+#include <QString>
+
+namespace WebKit {
+
+class WebPage;
+class WebProcess;
+
+class QtNetworkAccessManager : public QNetworkAccessManager {
+ Q_OBJECT
+public:
+ QtNetworkAccessManager();
+
+private Q_SLOTS:
+ void onAuthenticationRequired(QNetworkReply *, QAuthenticator *);
+ void onProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator *);
+ void onSslErrors(QNetworkReply*, const QList<QSslError>&);
+
+private:
+ WebPage* obtainOriginatingWebPage(const QNetworkRequest&);
+
+ WebProcess* m_webProcess { nullptr };
+};
+
+} // namespace WebKit
+
+#endif // QtNetworkAccessManager_h
diff --git a/Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h b/Source/WebKit2/NetworkProcess/qt/RemoteNetworkingContextQt.cpp
index c137995e5..96da15886 100644
--- a/Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h
+++ b/Source/WebKit2/NetworkProcess/qt/RemoteNetworkingContextQt.cpp
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 University of Szeged. All rights reserved.
+ * Copyright (C) 2013 Company 100 Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,38 +25,41 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DiskCacheMonitor_h
-#define DiskCacheMonitor_h
+#include "config.h"
+#include "RemoteNetworkingContext.h"
-#include "MessageSender.h"
-#include <WebCore/ResourceRequest.h>
-#include <WebCore/RunLoop.h>
+#include "NetworkProcess.h"
+#include <WebCore/NetworkStorageSession.h>
+#include <WebCore/NotImplemented.h>
+#include <WebCore/ResourceHandle.h>
+#include <wtf/NeverDestroyed.h>
-typedef const struct _CFCachedURLResponse* CFCachedURLResponseRef;
+using namespace WebCore;
namespace WebKit {
-class NetworkConnectionToWebProcess;
-class NetworkResourceLoader;
+RemoteNetworkingContext::~RemoteNetworkingContext()
+{
+}
-class DiskCacheMonitor : public CoreIPC::MessageSender {
-public:
- static void monitorFileBackingStoreCreation(CFCachedURLResponseRef, NetworkResourceLoader*);
+bool RemoteNetworkingContext::isValid() const
+{
+ return true;
+}
- const WebCore::ResourceRequest& resourceRequest() const { return m_resourceRequest; }
+void RemoteNetworkingContext::ensurePrivateBrowsingSession(SessionID)
+{
+ notImplemented();
+}
-private:
- DiskCacheMonitor(CFCachedURLResponseRef, NetworkResourceLoader*);
+NetworkStorageSession& RemoteNetworkingContext::storageSession() const
+{
+ return NetworkStorageSession::defaultStorageSession();
+}
- // CoreIPC::MessageSender
- virtual CoreIPC::Connection* messageSenderConnection() OVERRIDE;
- virtual uint64_t messageSenderDestinationID() OVERRIDE;
+QNetworkAccessManager* RemoteNetworkingContext::networkAccessManager() const
+{
+ return &NetworkProcess::singleton().networkAccessManager();
+}
- RefPtr<NetworkConnectionToWebProcess> m_connectionToWebProcess;
- WebCore::ResourceRequest m_resourceRequest;
-};
-
-
-} // namespace WebKit
-
-#endif // DiskCacheMonitor_h
+}
diff --git a/Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.h b/Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.h
index cb62eda2d..fa064c358 100644
--- a/Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.h
+++ b/Source/WebKit2/NetworkProcess/unix/NetworkProcessMainUnix.h
@@ -27,15 +27,13 @@
#ifndef NetworkProcessMainUnix_h
#define NetworkProcessMainUnix_h
-#include <WebKit2/WKBase.h>
+#include <WebKit/WKBase.h>
namespace WebKit {
-#ifdef __cplusplus
extern "C" {
-WK_EXPORT int NetworkProcessMain(int argc, char* argv[]);
-} // extern "C"
-#endif // __cplusplus
+WK_EXPORT int NetworkProcessMainUnix(int argc, char** argv);
+}
} // namespace WebKit