[SOUP] Add NetworkSession implementation and switch to use it
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Oct 2016 06:42:24 +0000 (06:42 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Oct 2016 06:42:24 +0000 (06:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163597

Reviewed by Alex Christensen.

Basically move the ResourceHandle implementation to the network process, but modernized, cleaned up, and adapted
to the NetworkSession model.

* CMakeLists.txt: Add new files to compilation.
* NetworkProcess/Downloads/Download.cpp:
(WebKit::Download::Download): Use the same code for all ports using NetworkSession and add missing
initialization of m_sessionID.
* NetworkProcess/Downloads/Download.h:
(WebKit::Download::Download): Define PlatformDownloadTaskRef on every platform to make the constructor common to
all ports using NetworkSession.
* NetworkProcess/Downloads/soup/DownloadSoup.cpp:
(WebKit::Download::cancelNetworkLoad):
(WebKit::Download::platformDidFinish):
* NetworkProcess/NetworkDataTask.h:
(WebKit::NetworkDataTask::pendingDownloadID): Make const.
(WebKit::NetworkDataTask::pendingDownload): Ditto.
(WebKit::NetworkDataTask::pendingDownloadLocation): Ditto.
(WebKit::NetworkDataTask::isDownload): Helper to check if the task is a download.
* NetworkProcess/NetworkLoad.cpp:
(WebKit::NetworkLoad::didReceiveResponseNetworkSession): Use NetworkDataTask::isDownload().
* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::NetworkProcess): NetworkSession::setCustomProtocolManager() is Cocoa only.
* NetworkProcess/NetworkSession.h:
* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(WebKit::NetworkSession::networkStorageSession): Make const.
* NetworkProcess/soup/NetworkDataTaskSoup.cpp: Added.
(WebKit::NetworkDataTask::NetworkDataTask):
(WebKit::NetworkDataTask::~NetworkDataTask):
(WebKit::NetworkDataTask::scheduleFailure):
(WebKit::NetworkDataTask::failureTimerFired):
(WebKit::NetworkDataTask::suggestedFilename):
(WebKit::NetworkDataTask::setSuggestedFilename):
(WebKit::NetworkDataTask::setPendingDownloadLocation):
(WebKit::NetworkDataTask::allowsSpecificHTTPSCertificateForHost):
(WebKit::NetworkDataTask::createRequest):
(WebKit::NetworkDataTask::clearRequest):
(WebKit::NetworkDataTask::resume):
(WebKit::NetworkDataTask::suspend):
(WebKit::NetworkDataTask::cancel):
(WebKit::NetworkDataTask::invalidateAndCancel):
(WebKit::NetworkDataTask::state):
(WebKit::NetworkDataTask::timeoutFired):
(WebKit::NetworkDataTask::startTimeout):
(WebKit::NetworkDataTask::stopTimeout):
(WebKit::NetworkDataTask::sendRequestCallback):
(WebKit::NetworkDataTask::didSendRequest):
(WebKit::NetworkDataTask::didReceiveResponse):
(WebKit::NetworkDataTask::tlsErrorsChangedCallback):
(WebKit::NetworkDataTask::tlsErrorsChanged):
(WebKit::NetworkDataTask::applyAuthenticationToRequest):
(WebKit::NetworkDataTask::authenticateCallback):
(WebKit::isAuthenticationFailureStatusCode):
(WebKit::NetworkDataTask::authenticate):
(WebKit::NetworkDataTask::continueAuthenticate):
(WebKit::NetworkDataTask::skipInputStreamForRedirectionCallback):
(WebKit::NetworkDataTask::skipInputStreamForRedirection):
(WebKit::NetworkDataTask::didFinishSkipInputStreamForRedirection):
(WebKit::shouldRedirectAsGET):
(WebKit::NetworkDataTask::shouldStartHTTPRedirection):
(WebKit::NetworkDataTask::continueHTTPRedirection):
(WebKit::NetworkDataTask::readCallback):
(WebKit::NetworkDataTask::read):
(WebKit::NetworkDataTask::didRead):
(WebKit::NetworkDataTask::didFinishRead):
(WebKit::NetworkDataTask::requestNextPartCallback):
(WebKit::NetworkDataTask::requestNextPart):
(WebKit::NetworkDataTask::didRequestNextPart):
(WebKit::NetworkDataTask::didFinishRequestNextPart):
(WebKit::NetworkDataTask::gotHeadersCallback):
(WebKit::NetworkDataTask::didGetHeaders):
(WebKit::NetworkDataTask::wroteBodyDataCallback):
(WebKit::NetworkDataTask::didWriteBodyData):
(WebKit::NetworkDataTask::download):
(WebKit::NetworkDataTask::writeDownloadCallback):
(WebKit::NetworkDataTask::writeDownload):
(WebKit::NetworkDataTask::didWriteDownload):
(WebKit::NetworkDataTask::didFinishDownload):
(WebKit::NetworkDataTask::didFailDownload):
(WebKit::NetworkDataTask::cleanDownloadFiles):
(WebKit::NetworkDataTask::didFail):
(WebKit::NetworkDataTask::networkEventCallback):
(WebKit::NetworkDataTask::networkEvent):
(WebKit::NetworkDataTask::startingCallback):
(WebKit::NetworkDataTask::requestStartedCallback):
(WebKit::NetworkDataTask::didStartRequest):
(WebKit::NetworkDataTask::restartedCallback):
(WebKit::NetworkDataTask::didRestart):
* NetworkProcess/soup/NetworkSessionSoup.cpp:
(WebKit::NetworkSession::create):
(WebKit::NetworkSession::defaultSession):
(WebKit::NetworkSession::networkStorageSession):
(WebKit::NetworkSession::NetworkSession):
(WebKit::NetworkSession::~NetworkSession):
(WebKit::NetworkSession::soupSession):
(WebKit::NetworkSession::invalidateAndCancel):
(WebKit::NetworkSession::clearCredentials):
* NetworkProcess/soup/RemoteNetworkingContextSoup.cpp:
(WebKit::RemoteNetworkingContext::ensurePrivateBrowsingSession): Add implementation matching
WebFrameNetworkingContext::ensurePrivateBrowsingSession().
(WebKit::RemoteNetworkingContext::storageSession): Do not always return the default session if the given one is
in the global map.
* PlatformEfl.cmake: Ad new files to compilation.
* PlatformGTK.cmake: Ditto.
* WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp:
(WebKit::WebFrameNetworkingContext::ensurePrivateBrowsingSession): Also create a NetworkSession.
* config.h: Enable NetworkSession unconditionally for Soup based ports.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207586 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
Source/WebKit2/CMakeLists.txt
Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/Downloads/Download.cpp
Source/WebKit2/NetworkProcess/Downloads/Download.h
Source/WebKit2/NetworkProcess/Downloads/soup/DownloadSoup.cpp
Source/WebKit2/NetworkProcess/NetworkDataTask.h
Source/WebKit2/NetworkProcess/NetworkLoad.cpp
Source/WebKit2/NetworkProcess/NetworkProcess.cpp
Source/WebKit2/NetworkProcess/NetworkSession.h
Source/WebKit2/NetworkProcess/PingLoad.h
Source/WebKit2/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
Source/WebKit2/NetworkProcess/cocoa/NetworkSessionCocoa.mm
Source/WebKit2/NetworkProcess/soup/NetworkDataTaskSoup.cpp [new file with mode: 0644]
Source/WebKit2/NetworkProcess/soup/NetworkSessionSoup.cpp [new file with mode: 0644]
Source/WebKit2/NetworkProcess/soup/RemoteNetworkingContextSoup.cpp
Source/WebKit2/PlatformEfl.cmake
Source/WebKit2/PlatformGTK.cmake
Source/WebKit2/Shared/Authentication/AuthenticationManager.h
Source/WebKit2/WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp
Source/WebKit2/WebProcess/WebProcess.cpp
Source/WebKit2/config.h

index 9b433de..1ac106c 100644 (file)
@@ -217,6 +217,7 @@ set(WebKit2_SOURCES
     NetworkProcess/Downloads/BlobDownloadClient.cpp
     NetworkProcess/Downloads/Download.cpp
     NetworkProcess/Downloads/DownloadManager.cpp
+    NetworkProcess/Downloads/PendingDownload.cpp
 
     Platform/Logging.cpp
     Platform/Module.cpp
index 019c3b1..e9aa21b 100644 (file)
@@ -1,3 +1,117 @@
+2016-10-19  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [SOUP] Add NetworkSession implementation and switch to use it
+        https://bugs.webkit.org/show_bug.cgi?id=163597
+
+        Reviewed by Alex Christensen.
+
+        Basically move the ResourceHandle implementation to the network process, but modernized, cleaned up, and adapted
+        to the NetworkSession model.
+
+        * CMakeLists.txt: Add new files to compilation.
+        * NetworkProcess/Downloads/Download.cpp:
+        (WebKit::Download::Download): Use the same code for all ports using NetworkSession and add missing
+        initialization of m_sessionID.
+        * NetworkProcess/Downloads/Download.h:
+        (WebKit::Download::Download): Define PlatformDownloadTaskRef on every platform to make the constructor common to
+        all ports using NetworkSession.
+        * NetworkProcess/Downloads/soup/DownloadSoup.cpp:
+        (WebKit::Download::cancelNetworkLoad):
+        (WebKit::Download::platformDidFinish):
+        * NetworkProcess/NetworkDataTask.h:
+        (WebKit::NetworkDataTask::pendingDownloadID): Make const.
+        (WebKit::NetworkDataTask::pendingDownload): Ditto.
+        (WebKit::NetworkDataTask::pendingDownloadLocation): Ditto.
+        (WebKit::NetworkDataTask::isDownload): Helper to check if the task is a download.
+        * NetworkProcess/NetworkLoad.cpp:
+        (WebKit::NetworkLoad::didReceiveResponseNetworkSession): Use NetworkDataTask::isDownload().
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::NetworkProcess): NetworkSession::setCustomProtocolManager() is Cocoa only.
+        * NetworkProcess/NetworkSession.h:
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (WebKit::NetworkSession::networkStorageSession): Make const.
+        * NetworkProcess/soup/NetworkDataTaskSoup.cpp: Added.
+        (WebKit::NetworkDataTask::NetworkDataTask):
+        (WebKit::NetworkDataTask::~NetworkDataTask):
+        (WebKit::NetworkDataTask::scheduleFailure):
+        (WebKit::NetworkDataTask::failureTimerFired):
+        (WebKit::NetworkDataTask::suggestedFilename):
+        (WebKit::NetworkDataTask::setSuggestedFilename):
+        (WebKit::NetworkDataTask::setPendingDownloadLocation):
+        (WebKit::NetworkDataTask::allowsSpecificHTTPSCertificateForHost):
+        (WebKit::NetworkDataTask::createRequest):
+        (WebKit::NetworkDataTask::clearRequest):
+        (WebKit::NetworkDataTask::resume):
+        (WebKit::NetworkDataTask::suspend):
+        (WebKit::NetworkDataTask::cancel):
+        (WebKit::NetworkDataTask::invalidateAndCancel):
+        (WebKit::NetworkDataTask::state):
+        (WebKit::NetworkDataTask::timeoutFired):
+        (WebKit::NetworkDataTask::startTimeout):
+        (WebKit::NetworkDataTask::stopTimeout):
+        (WebKit::NetworkDataTask::sendRequestCallback):
+        (WebKit::NetworkDataTask::didSendRequest):
+        (WebKit::NetworkDataTask::didReceiveResponse):
+        (WebKit::NetworkDataTask::tlsErrorsChangedCallback):
+        (WebKit::NetworkDataTask::tlsErrorsChanged):
+        (WebKit::NetworkDataTask::applyAuthenticationToRequest):
+        (WebKit::NetworkDataTask::authenticateCallback):
+        (WebKit::isAuthenticationFailureStatusCode):
+        (WebKit::NetworkDataTask::authenticate):
+        (WebKit::NetworkDataTask::continueAuthenticate):
+        (WebKit::NetworkDataTask::skipInputStreamForRedirectionCallback):
+        (WebKit::NetworkDataTask::skipInputStreamForRedirection):
+        (WebKit::NetworkDataTask::didFinishSkipInputStreamForRedirection):
+        (WebKit::shouldRedirectAsGET):
+        (WebKit::NetworkDataTask::shouldStartHTTPRedirection):
+        (WebKit::NetworkDataTask::continueHTTPRedirection):
+        (WebKit::NetworkDataTask::readCallback):
+        (WebKit::NetworkDataTask::read):
+        (WebKit::NetworkDataTask::didRead):
+        (WebKit::NetworkDataTask::didFinishRead):
+        (WebKit::NetworkDataTask::requestNextPartCallback):
+        (WebKit::NetworkDataTask::requestNextPart):
+        (WebKit::NetworkDataTask::didRequestNextPart):
+        (WebKit::NetworkDataTask::didFinishRequestNextPart):
+        (WebKit::NetworkDataTask::gotHeadersCallback):
+        (WebKit::NetworkDataTask::didGetHeaders):
+        (WebKit::NetworkDataTask::wroteBodyDataCallback):
+        (WebKit::NetworkDataTask::didWriteBodyData):
+        (WebKit::NetworkDataTask::download):
+        (WebKit::NetworkDataTask::writeDownloadCallback):
+        (WebKit::NetworkDataTask::writeDownload):
+        (WebKit::NetworkDataTask::didWriteDownload):
+        (WebKit::NetworkDataTask::didFinishDownload):
+        (WebKit::NetworkDataTask::didFailDownload):
+        (WebKit::NetworkDataTask::cleanDownloadFiles):
+        (WebKit::NetworkDataTask::didFail):
+        (WebKit::NetworkDataTask::networkEventCallback):
+        (WebKit::NetworkDataTask::networkEvent):
+        (WebKit::NetworkDataTask::startingCallback):
+        (WebKit::NetworkDataTask::requestStartedCallback):
+        (WebKit::NetworkDataTask::didStartRequest):
+        (WebKit::NetworkDataTask::restartedCallback):
+        (WebKit::NetworkDataTask::didRestart):
+        * NetworkProcess/soup/NetworkSessionSoup.cpp:
+        (WebKit::NetworkSession::create):
+        (WebKit::NetworkSession::defaultSession):
+        (WebKit::NetworkSession::networkStorageSession):
+        (WebKit::NetworkSession::NetworkSession):
+        (WebKit::NetworkSession::~NetworkSession):
+        (WebKit::NetworkSession::soupSession):
+        (WebKit::NetworkSession::invalidateAndCancel):
+        (WebKit::NetworkSession::clearCredentials):
+        * NetworkProcess/soup/RemoteNetworkingContextSoup.cpp:
+        (WebKit::RemoteNetworkingContext::ensurePrivateBrowsingSession): Add implementation matching
+        WebFrameNetworkingContext::ensurePrivateBrowsingSession().
+        (WebKit::RemoteNetworkingContext::storageSession): Do not always return the default session if the given one is
+        in the global map.
+        * PlatformEfl.cmake: Ad new files to compilation.
+        * PlatformGTK.cmake: Ditto.
+        * WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp:
+        (WebKit::WebFrameNetworkingContext::ensurePrivateBrowsingSession): Also create a NetworkSession.
+        * config.h: Enable NetworkSession unconditionally for Soup based ports.
+
 2016-10-19  Alex Christensen  <achristensen@webkit.org>
 
         Revert r207151
index 9be22ef..64948e2 100644 (file)
@@ -33,6 +33,7 @@
 #include "DownloadManager.h"
 #include "DownloadProxyMessages.h"
 #include "Logging.h"
+#include "NetworkDataTask.h"
 #include "SandboxExtension.h"
 #include "WebCoreArgumentCoders.h"
 #include <WebCore/NotImplemented.h>
@@ -43,11 +44,12 @@ using namespace WebCore;
 
 namespace WebKit {
 
-#if USE(NETWORK_SESSION) && PLATFORM(COCOA)
-Download::Download(DownloadManager& downloadManager, DownloadID downloadID, NSURLSessionDownloadTask* download, const WebCore::SessionID& sessionID, const String& suggestedName)
+#if USE(NETWORK_SESSION)
+Download::Download(DownloadManager& downloadManager, DownloadID downloadID, PlatformDownloadTaskRef download, const WebCore::SessionID& sessionID, const String& suggestedName)
     : m_downloadManager(downloadManager)
     , m_downloadID(downloadID)
     , m_download(download)
+    , m_sessionID(sessionID)
     , m_suggestedName(suggestedName)
 {
     ASSERT(m_downloadID.downloadID());
index ef2a7bd..c3fbf09 100644 (file)
 #include <WebCore/SessionID.h>
 #include <memory>
 #include <wtf/Noncopyable.h>
-
-#if PLATFORM(COCOA)
 #include <wtf/RetainPtr.h>
 
 #if USE(NETWORK_SESSION)
+#if PLATFORM(COCOA)
 OBJC_CLASS NSURLSessionDownloadTask;
-#else
+typedef NSURLSessionDownloadTask* PlatformDownloadTaskRef;
+#elif USE(SOUP)
+namespace WebKit {
+class NetworkDataTask;
+}
+typedef WebKit::NetworkDataTask* PlatformDownloadTaskRef;
+#endif
+#else // USE(NETWORK_SESSION)
+#if PLATFORM(COCOA)
 OBJC_CLASS NSURLDownload;
 OBJC_CLASS WKDownloadAsDelegate;
 #endif
-#endif
+#endif // USE(NETWORK_SESSION)
 
 #if USE(CFURLCONNECTION)
 #include <CFNetwork/CFURLDownloadPriv.h>
@@ -72,8 +79,8 @@ class WebPage;
 class Download : public IPC::MessageSender {
     WTF_MAKE_NONCOPYABLE(Download); WTF_MAKE_FAST_ALLOCATED;
 public:
-#if USE(NETWORK_SESSION) && PLATFORM(COCOA)
-    Download(DownloadManager&, DownloadID, NSURLSessionDownloadTask*, const WebCore::SessionID& sessionID, const String& suggestedFilename = { });
+#if USE(NETWORK_SESSION)
+    Download(DownloadManager&, DownloadID, PlatformDownloadTaskRef, const WebCore::SessionID& sessionID, const String& suggestedFilename = { });
 #endif
     Download(DownloadManager&, DownloadID, const WebCore::ResourceRequest&, const String& suggestedFilename = { });
 
@@ -130,15 +137,19 @@ private:
 
     RefPtr<SandboxExtension> m_sandboxExtension;
 
-#if PLATFORM(COCOA)
 #if USE(NETWORK_SESSION)
+#if PLATFORM(COCOA)
     RetainPtr<NSURLSessionDownloadTask> m_download;
+#elif USE(SOUP)
+    RefPtr<NetworkDataTask> m_download;
+#endif
     WebCore::SessionID m_sessionID;
-#else
+#else // USE(NETWORK_SESSION)
+#if PLATFORM(COCOA)
     RetainPtr<NSURLDownload> m_nsURLDownload;
     RetainPtr<WKDownloadAsDelegate> m_delegate;
 #endif
-#endif
+#endif // USE(NETWORK_SESSION)
 #if USE(CFURLCONNECTION)
     RetainPtr<CFURLDownloadRef> m_download;
 #endif
index 6807917..82e8c5c 100644 (file)
 #include "Download.h"
 
 #include "DataReference.h"
-#include "DownloadSoupErrors.h"
+#include "NetworkDataTask.h"
 #include <WebCore/NotImplemented.h>
-#include <WebCore/ResourceHandleInternal.h>
-#include <gio/gio.h>
-#include <wtf/RunLoop.h>
-#include <wtf/glib/GRefPtr.h>
-#include <wtf/glib/GUniquePtr.h>
-#include <wtf/text/CString.h>
-
-#if PLATFORM(GTK)
-#include <glib/gi18n-lib.h>
-#endif
 
 using namespace WebCore;
 
 namespace WebKit {
 
-class DownloadClient final : public ResourceHandleClient {
-    WTF_MAKE_NONCOPYABLE(DownloadClient);
-public:
-    DownloadClient(Download& download)
-        : m_download(download)
-        , m_handleResponseLater(RunLoop::main(), this, &DownloadClient::handleResponse)
-        , m_allowOverwrite(false)
-    {
-    }
-
-    ~DownloadClient()
-    {
-    }
-
-    void deleteFilesIfNeeded()
-    {
-        if (m_destinationFile)
-            g_file_delete(m_destinationFile.get(), nullptr, nullptr);
-
-        if (m_intermediateFile) {
-            ASSERT(m_destinationFile);
-            g_file_delete(m_intermediateFile.get(), nullptr, nullptr);
-        }
-    }
-
-    void downloadFailed(const ResourceError& error)
-    {
-        deleteFilesIfNeeded();
-        m_download.didFail(error, IPC::DataReference());
-    }
-
-    void didReceiveResponse(ResourceHandle*, ResourceResponse&& response) override
-    {
-        m_response = WTFMove(response);
-        m_download.didReceiveResponse(m_response);
-
-        if (m_response.httpStatusCode() >= 400) {
-            downloadFailed(platformDownloadNetworkError(m_response.httpStatusCode(), m_response.url(), m_response.httpStatusText()));
-            return;
-        }
-
-        String suggestedFilename = m_response.suggestedFilename();
-        if (suggestedFilename.isEmpty()) {
-            URL url = m_response.url();
-            url.setQuery(String());
-            url.removeFragmentIdentifier();
-            suggestedFilename = decodeURLEscapeSequences(url.lastPathComponent());
-        }
-
-        String destinationURI = m_download.decideDestinationWithSuggestedFilename(suggestedFilename, m_allowOverwrite);
-        if (destinationURI.isEmpty()) {
-#if PLATFORM(GTK)
-            GUniquePtr<char> buffer(g_strdup_printf(_("Cannot determine destination URI for download with suggested filename %s"), suggestedFilename.utf8().data()));
-            String errorMessage = String::fromUTF8(buffer.get());
-#else
-            String errorMessage = makeString("Cannot determine destination URI for download with suggested filename ", suggestedFilename);
-#endif
-            downloadFailed(platformDownloadDestinationError(m_response, errorMessage));
-            return;
-        }
-
-        m_destinationFile = adoptGRef(g_file_new_for_uri(destinationURI.utf8().data()));
-        GRefPtr<GFileOutputStream> outputStream;
-        GUniqueOutPtr<GError> error;
-        if (m_allowOverwrite)
-            outputStream = adoptGRef(g_file_replace(m_destinationFile.get(), nullptr, FALSE, G_FILE_CREATE_NONE, nullptr, &error.outPtr()));
-        else
-            outputStream = adoptGRef(g_file_create(m_destinationFile.get(), G_FILE_CREATE_NONE, nullptr, &error.outPtr()));
-        if (!outputStream) {
-            m_destinationFile.clear();
-            downloadFailed(platformDownloadDestinationError(m_response, error->message));
-            return;
-        }
-
-        String intermediateURI = destinationURI + ".wkdownload";
-        m_intermediateFile = adoptGRef(g_file_new_for_uri(intermediateURI.utf8().data()));
-        m_outputStream = adoptGRef(g_file_replace(m_intermediateFile.get(), 0, TRUE, G_FILE_CREATE_NONE, 0, &error.outPtr()));
-        if (!m_outputStream) {
-            downloadFailed(platformDownloadDestinationError(m_response, error->message));
-            return;
-        }
-
-        m_download.didCreateDestination(destinationURI);
-    }
-
-    void didReceiveData(ResourceHandle*, const char* data, unsigned length, int /*encodedDataLength*/) override
-    {
-        if (m_handleResponseLater.isActive()) {
-            m_handleResponseLater.stop();
-            handleResponse();
-        }
-
-        gsize bytesWritten;
-        GUniqueOutPtr<GError> error;
-        g_output_stream_write_all(G_OUTPUT_STREAM(m_outputStream.get()), data, length, &bytesWritten, 0, &error.outPtr());
-        if (error) {
-            downloadFailed(platformDownloadDestinationError(m_response, error->message));
-            return;
-        }
-        m_download.didReceiveData(bytesWritten);
-    }
-
-    void didFinishLoading(ResourceHandle*, double) override
-    {
-        m_outputStream = nullptr;
-
-        ASSERT(m_destinationFile);
-        ASSERT(m_intermediateFile);
-        GUniqueOutPtr<GError> error;
-        if (!g_file_move(m_intermediateFile.get(), m_destinationFile.get(), G_FILE_COPY_OVERWRITE, nullptr, nullptr, nullptr, &error.outPtr())) {
-            downloadFailed(platformDownloadDestinationError(m_response, error->message));
-            return;
-        }
-
-        GRefPtr<GFileInfo> info = adoptGRef(g_file_info_new());
-        CString uri = m_response.url().string().utf8();
-        g_file_info_set_attribute_string(info.get(), "metadata::download-uri", uri.data());
-        g_file_info_set_attribute_string(info.get(), "xattr::xdg.origin.url", uri.data());
-        g_file_set_attributes_async(m_destinationFile.get(), info.get(), G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, nullptr, nullptr, nullptr);
-
-        m_download.didFinish();
-    }
-
-    void didFail(ResourceHandle*, const ResourceError& error) override
-    {
-        downloadFailed(platformDownloadNetworkError(error.errorCode(), error.failingURL(), error.localizedDescription()));
-    }
-
-    void cancel(ResourceHandle* handle)
-    {
-        handle->cancel();
-        deleteFilesIfNeeded();
-        m_download.didCancel(IPC::DataReference());
-    }
-
-    void handleResponse()
-    {
-        didReceiveResponse(nullptr, WTFMove(m_delayedResponse));
-    }
-
-    void handleResponseLater(const ResourceResponse& response)
-    {
-        ASSERT(m_response.isNull());
-        ASSERT(!m_handleResponseLater.isActive());
-
-        m_delayedResponse = response;
-
-        // Call didReceiveResponse in an idle to make sure the download is added
-        // to the DownloadManager downloads map.
-        m_handleResponseLater.startOneShot(0);
-    }
-
-    Download& m_download;
-    GRefPtr<GFileOutputStream> m_outputStream;
-    ResourceResponse m_response;
-    GRefPtr<GFile> m_destinationFile;
-    GRefPtr<GFile> m_intermediateFile;
-    ResourceResponse m_delayedResponse;
-    RunLoop::Timer<DownloadClient> m_handleResponseLater;
-    bool m_allowOverwrite;
-};
-
-void Download::startNetworkLoad()
-{
-    ASSERT(!m_downloadClient);
-    ASSERT(!m_resourceHandle);
-    m_downloadClient = std::make_unique<DownloadClient>(*this);
-    m_resourceHandle = ResourceHandle::create(0, m_request, m_downloadClient.get(), false, true);
-    didStart();
-}
-
-void Download::startNetworkLoadWithHandle(ResourceHandle* resourceHandle, const ResourceResponse& response)
-{
-    ASSERT(!m_downloadClient);
-    ASSERT(!m_resourceHandle);
-    m_downloadClient = std::make_unique<DownloadClient>(*this);
-    m_resourceHandle = resourceHandle->releaseForDownload(m_downloadClient.get());
-    didStart();
-    static_cast<DownloadClient*>(m_downloadClient.get())->handleResponseLater(response);
-}
-
 void Download::resume(const IPC::DataReference&, const String&, const SandboxExtension::Handle&)
 {
     notImplemented();
@@ -233,14 +42,8 @@ void Download::resume(const IPC::DataReference&, const String&, const SandboxExt
 
 void Download::cancelNetworkLoad()
 {
-    if (!m_resourceHandle)
-        return;
-
-    // Cancelling the download will delete it and platformInvalidate() will be called by the destructor.
-    // So, we need to set m_resourceHandle to nullptr before actually cancelling the download to make sure
-    // it won't be cancelled again by platformInvalidate. See https://bugs.webkit.org/show_bug.cgi?id=127650.
-    RefPtr<ResourceHandle> resourceHandle = m_resourceHandle.release();
-    static_cast<DownloadClient*>(m_downloadClient.get())->cancel(resourceHandle.get());
+    m_download->cancel();
+    didCancel({ });
 }
 
 void Download::platformInvalidate()
@@ -249,7 +52,6 @@ void Download::platformInvalidate()
 
 void Download::platformDidFinish()
 {
-    m_resourceHandle = nullptr;
 }
 
 } // namespace WebKit
index 3242c7e..b62758b 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef NetworkDataTask_h
-#define NetworkDataTask_h
+#pragma once
 
+#if USE(NETWORK_SESSION)
+
+#include "DownloadID.h"
 #include "SandboxExtension.h"
 #include <WebCore/Credential.h>
 #include <WebCore/FrameLoaderTypes.h>
 OBJC_CLASS NSURLSessionDataTask;
 #endif
 
+#if USE(SOUP)
+#include <WebCore/ProtectionSpace.h>
+#include <WebCore/ResourceResponse.h>
+#include <wtf/RunLoop.h>
+#include <wtf/glib/GRefPtr.h>
+#endif
+
 namespace WebCore {
 class AuthenticationChallenge;
 class Credential;
@@ -55,14 +64,8 @@ namespace WebKit {
 class Download;
 class NetworkSession;
 class PendingDownload;
+enum class AuthenticationChallengeDisposition;
 
-enum class AuthenticationChallengeDisposition {
-    UseCredential,
-    PerformDefaultHandling,
-    Cancel,
-    RejectProtectionSpace
-};
-    
 typedef Function<void(const WebCore::ResourceRequest&)> RedirectCompletionHandler;
 typedef Function<void(AuthenticationChallengeDisposition, const WebCore::Credential&)> ChallengeCompletionHandler;
 typedef Function<void(WebCore::PolicyAction)> ResponseCompletionHandler;
@@ -105,19 +108,23 @@ public:
     typedef uint64_t TaskIdentifier;
     
     ~NetworkDataTask();
-    
+
+#if PLATFORM(COCOA)
     void didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend);
     void didReceiveChallenge(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler&&);
     void didCompleteWithError(const WebCore::ResourceError&);
     void didReceiveResponse(WebCore::ResourceResponse&&, ResponseCompletionHandler&&);
     void didReceiveData(Ref<WebCore::SharedBuffer>&&);
     void didBecomeDownload();
-    
+
+    void willPerformHTTPRedirection(WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, RedirectCompletionHandler&&);
+    void transferSandboxExtensionToDownload(Download&);
+#endif
     NetworkDataTaskClient* client() const { return m_client; }
     void clearClient() { m_client = nullptr; }
     
-    DownloadID pendingDownloadID() { return m_pendingDownloadID; }
-    PendingDownload* pendingDownload() { return m_pendingDownload; }
+    DownloadID pendingDownloadID() const { return m_pendingDownloadID; }
+    PendingDownload* pendingDownload() const { return m_pendingDownload; }
     void setPendingDownloadID(DownloadID downloadID)
     {
         ASSERT(!m_pendingDownloadID.downloadID());
@@ -130,19 +137,73 @@ public:
         m_pendingDownload = &pendingDownload;
     }
     void setPendingDownloadLocation(const String& filename, const SandboxExtension::Handle&, bool allowOverwrite);
-    const String& pendingDownloadLocation() { return m_pendingDownloadLocation; }
+    const String& pendingDownloadLocation() const { return m_pendingDownloadLocation; }
+    bool isDownload() const { return !!m_pendingDownloadID.downloadID(); }
 
     const WebCore::ResourceRequest& firstRequest() const { return m_firstRequest; }
     String suggestedFilename();
     void setSuggestedFilename(const String&);
-    void willPerformHTTPRedirection(WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, RedirectCompletionHandler&&);
-    void transferSandboxExtensionToDownload(Download&);
     bool allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge&);
     
 private:
     NetworkDataTask(NetworkSession&, NetworkDataTaskClient&, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ContentSniffingPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect);
 
     bool tryPasswordBasedAuthentication(const WebCore::AuthenticationChallenge&, const ChallengeCompletionHandler&);
+
+#if USE(SOUP)
+    void timeoutFired();
+    void startTimeout();
+    void stopTimeout();
+    void invalidateAndCancel();
+    void createRequest(const WebCore::ResourceRequest&);
+    void clearRequest();
+    static void sendRequestCallback(SoupRequest*, GAsyncResult*, NetworkDataTask*);
+    void didSendRequest(GRefPtr<GInputStream>&&);
+    void didReceiveResponse();
+    static void tlsErrorsChangedCallback(SoupMessage*, GParamSpec*, NetworkDataTask*);
+    void tlsErrorsChanged();
+    void applyAuthenticationToRequest(WebCore::ResourceRequest&);
+    static void authenticateCallback(SoupSession*, SoupMessage*, SoupAuth*, gboolean retrying, NetworkDataTask*);
+    void authenticate(WebCore::AuthenticationChallenge&&);
+    void continueAuthenticate(WebCore::AuthenticationChallenge&&);
+    static void skipInputStreamForRedirectionCallback(GInputStream*, GAsyncResult*, NetworkDataTask*);
+    void skipInputStreamForRedirection();
+    void didFinishSkipInputStreamForRedirection();
+    bool shouldStartHTTPRedirection();
+    void continueHTTPRedirection();
+    static void readCallback(GInputStream*, GAsyncResult*, NetworkDataTask*);
+    void read();
+    void didRead(gssize bytesRead);
+    void didFinishRead();
+    static void requestNextPartCallback(SoupMultipartInputStream*, GAsyncResult*, NetworkDataTask*);
+    void requestNextPart();
+    void didRequestNextPart(GRefPtr<GInputStream>&&);
+    void didFinishRequestNextPart();
+    static void gotHeadersCallback(SoupMessage*, NetworkDataTask*);
+    void didGetHeaders();
+    static void wroteBodyDataCallback(SoupMessage*, SoupBuffer*, NetworkDataTask*);
+    void didWriteBodyData(uint64_t bytesSent);
+    void download();
+    static void writeDownloadCallback(GOutputStream*, GAsyncResult*, NetworkDataTask*);
+    void writeDownload();
+    void didWriteDownload(gsize bytesWritten);
+    void didFailDownload(const WebCore::ResourceError&);
+    void didFinishDownload();
+    void cleanDownloadFiles();
+    void didFail(const WebCore::ResourceError&);
+#if ENABLE(WEB_TIMING)
+    static void networkEventCallback(SoupMessage*, GSocketClientEvent, GIOStream*, NetworkDataTask*);
+    void networkEvent(GSocketClientEvent);
+#if SOUP_CHECK_VERSION(2, 49, 91)
+    static void startingCallback(SoupMessage*, NetworkDataTask*);
+#else
+    static void requestStartedCallback(SoupSession*, SoupMessage*, SoupSocket*, NetworkDataTask*);
+#endif
+    void didStartRequest();
+    static void restartedCallback(SoupMessage*, NetworkDataTask*);
+    void didRestart();
+#endif
+#endif
     
     enum FailureType {
         NoFailure,
@@ -172,6 +233,30 @@ private:
 #if PLATFORM(COCOA)
     RetainPtr<NSURLSessionDataTask> m_task;
 #endif
+#if USE(SOUP)
+    State m_state { State::Suspended };
+    WebCore::ContentSniffingPolicy m_shouldContentSniff;
+    GRefPtr<SoupRequest> m_soupRequest;
+    GRefPtr<SoupMessage> m_soupMessage;
+    GRefPtr<GInputStream> m_inputStream;
+    GRefPtr<SoupMultipartInputStream> m_multipartInputStream;
+    GRefPtr<GCancellable> m_cancellable;
+    GRefPtr<GAsyncResult> m_pendingResult;
+    WebCore::ProtectionSpace m_protectionSpaceForPersistentStorage;
+    WebCore::Credential m_credentialForPersistentStorage;
+    WebCore::ResourceResponse m_response;
+    Vector<char> m_readBuffer;
+    unsigned m_redirectCount { 0 };
+    uint64_t m_bodyDataTotalBytesSent { 0 };
+    GRefPtr<GFile> m_downloadDestinationFile;
+    GRefPtr<GFile> m_downloadIntermediateFile;
+    GRefPtr<GOutputStream> m_downloadOutputStream;
+    bool m_allowOverwriteDownload { false };
+#if ENABLE(WEB_TIMING)
+    double m_startTime { 0 };
+#endif
+    RunLoop::Timer<NetworkDataTask> m_timeoutSource;
+#endif
     String m_suggestedFilename;
 };
 
@@ -181,4 +266,4 @@ WebCore::Credential serverTrustCredential(const WebCore::AuthenticationChallenge
     
 }
 
-#endif
+#endif // USE(NETWORK_SESSION)
index bb299f6..8fd4acd 100644 (file)
@@ -271,7 +271,7 @@ void NetworkLoad::completeAuthenticationChallenge(ChallengeCompletionHandler&& c
 void NetworkLoad::didReceiveResponseNetworkSession(ResourceResponse&& response, ResponseCompletionHandler&& completionHandler)
 {
     ASSERT(isMainThread());
-    if (m_task && m_task->pendingDownloadID().downloadID())
+    if (m_task && m_task->isDownload())
         NetworkProcess::singleton().findPendingDownloadLocation(*m_task.get(), WTFMove(completionHandler), response);
     else if (sharedDidReceiveResponse(WTFMove(response)) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
         completionHandler(PolicyUse);
index 3b395d6..6ef1744 100644 (file)
@@ -39,6 +39,7 @@
 #include "NetworkProcessPlatformStrategies.h"
 #include "NetworkProcessProxyMessages.h"
 #include "NetworkResourceLoader.h"
+#include "NetworkSession.h"
 #include "RemoteNetworkingContext.h"
 #include "SessionTracker.h"
 #include "StatisticsData.h"
@@ -100,7 +101,7 @@ NetworkProcess::NetworkProcess()
     addSupplement<AuthenticationManager>();
     addSupplement<WebCookieManager>();
     addSupplement<CustomProtocolManager>();
-#if USE(NETWORK_SESSION)
+#if USE(NETWORK_SESSION) && PLATFORM(COCOA)
     NetworkSession::setCustomProtocolManager(supplement<CustomProtocolManager>());
 #endif
 }
index a840f1d..b0882f2 100644 (file)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#if USE(NETWORK_SESSION)
+
 #if PLATFORM(COCOA)
 OBJC_CLASS NSURLSession;
 OBJC_CLASS NSOperationQueue;
@@ -35,9 +37,14 @@ OBJC_CLASS WKNetworkSessionDelegate;
 #include "NetworkDataTask.h"
 #include <WebCore/SessionID.h>
 #include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
 
+#if USE(SOUP)
+typedef struct _SoupSession SoupSession;
+#endif
+
 namespace WebCore {
 class NetworkStorageSession;
 }
@@ -62,9 +69,13 @@ public:
 
     WebCore::SessionID sessionID() const { return m_sessionID; }
 
+#if USE(SOUP)
+    SoupSession* soupSession() const;
+#endif
+
+#if PLATFORM(COCOA)
     // Must be called before any NetworkSession has been created.
     static void setCustomProtocolManager(CustomProtocolManager*);
-#if PLATFORM(COCOA)
     static void setSourceApplicationAuditTokenData(RetainPtr<CFDataRef>&&);
     static void setSourceApplicationBundleIdentifier(const String&);
     static void setSourceApplicationSecondaryIdentifier(const String&);
@@ -74,29 +85,34 @@ public:
 #endif
 
     void clearCredentials();
-
+#if PLATFORM(COCOA)
     NetworkDataTask* dataTaskForIdentifier(NetworkDataTask::TaskIdentifier, WebCore::StoredCredentials);
 
     void addDownloadID(NetworkDataTask::TaskIdentifier, DownloadID);
     DownloadID downloadID(NetworkDataTask::TaskIdentifier);
     DownloadID takeDownloadID(NetworkDataTask::TaskIdentifier);
-    
+#endif
+
 private:
     NetworkSession(Type, WebCore::SessionID, CustomProtocolManager*);
-    WebCore::NetworkStorageSession& networkStorageSession();
+    WebCore::NetworkStorageSession& networkStorageSession() const;
 
     WebCore::SessionID m_sessionID;
 
+#if PLATFORM(COCOA)
     HashMap<NetworkDataTask::TaskIdentifier, NetworkDataTask*> m_dataTaskMapWithCredentials;
     HashMap<NetworkDataTask::TaskIdentifier, NetworkDataTask*> m_dataTaskMapWithoutCredentials;
     HashMap<NetworkDataTask::TaskIdentifier, DownloadID> m_downloadMap;
 
-#if PLATFORM(COCOA)
     RetainPtr<NSURLSession> m_sessionWithCredentialStorage;
     RetainPtr<WKNetworkSessionDelegate> m_sessionWithCredentialStorageDelegate;
     RetainPtr<NSURLSession> m_sessionWithoutCredentialStorage;
     RetainPtr<WKNetworkSessionDelegate> m_sessionWithoutCredentialStorageDelegate;
+#elif USE(SOUP)
+    HashSet<NetworkDataTask*> m_dataTaskSet;
 #endif
 };
 
 } // namespace WebKit
+
+#endif // USE(NETWORK_SESSION)
index 7a7a3ad..5f3da3a 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef PingLoad_h
 #define PingLoad_h
 
+#include "AuthenticationManager.h"
 #include "NetworkDataTask.h"
 #include "SessionTracker.h"
 
index 9450986..62cb0d7 100644 (file)
@@ -28,6 +28,7 @@
 
 #if USE(NETWORK_SESSION)
 
+#import "AuthenticationManager.h"
 #import "Download.h"
 #import "DownloadProxyMessages.h"
 #import "Logging.h"
index cedfc39..01f2a39 100644 (file)
@@ -28,6 +28,7 @@
 
 #if USE(NETWORK_SESSION)
 
+#import "AuthenticationManager.h"
 #import "CustomProtocolManager.h"
 #import "DataReference.h"
 #import "Download.h"
@@ -475,7 +476,7 @@ void NetworkSession::invalidateAndCancel()
 }
 
 
-WebCore::NetworkStorageSession& NetworkSession::networkStorageSession()
+WebCore::NetworkStorageSession& NetworkSession::networkStorageSession() const
 {
     auto* storageSession = WebCore::NetworkStorageSession::storageSession(m_sessionID);
     RELEASE_ASSERT(storageSession);
diff --git a/Source/WebKit2/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit2/NetworkProcess/soup/NetworkDataTaskSoup.cpp
new file mode 100644 (file)
index 0000000..e6872e3
--- /dev/null
@@ -0,0 +1,1153 @@
+/*
+ * Copyright (C) 2016 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 "NetworkDataTask.h"
+
+#include "AuthenticationManager.h"
+#include "DataReference.h"
+#include "Download.h"
+#include "DownloadSoupErrors.h"
+#include "NetworkLoad.h"
+#include "NetworkProcess.h"
+#include "NetworkSession.h"
+#include "WebErrors.h"
+#include <WebCore/AuthenticationChallenge.h>
+#include <WebCore/HTTPParsers.h>
+#include <WebCore/NetworkStorageSession.h>
+#include <WebCore/SharedBuffer.h>
+#include <WebCore/SoupNetworkSession.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+static const size_t gDefaultReadBufferSize = 8192;
+
+NetworkDataTask::NetworkDataTask(NetworkSession& session, NetworkDataTaskClient& client, const ResourceRequest& requestWithCredentials, StoredCredentials storedCredentials, ContentSniffingPolicy shouldContentSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
+    : m_failureTimer(*this, &NetworkDataTask::failureTimerFired)
+    , m_session(&session)
+    , m_client(&client)
+    , m_storedCredentials(storedCredentials)
+    , m_lastHTTPMethod(requestWithCredentials.httpMethod())
+    , m_firstRequest(requestWithCredentials)
+    , m_shouldClearReferrerOnHTTPSToHTTPRedirect(shouldClearReferrerOnHTTPSToHTTPRedirect)
+    , m_shouldContentSniff(shouldContentSniff)
+    , m_timeoutSource(RunLoop::main(), this, &NetworkDataTask::timeoutFired)
+{
+    ASSERT(isMainThread());
+
+    m_session->m_dataTaskSet.add(this);
+
+    if (!requestWithCredentials.url().isValid()) {
+        scheduleFailure(InvalidURLFailure);
+        return;
+    }
+
+    if (!portAllowed(requestWithCredentials.url())) {
+        scheduleFailure(BlockedFailure);
+        return;
+    }
+
+    auto request = requestWithCredentials;
+    if (request.url().protocolIsInHTTPFamily()) {
+#if ENABLE(WEB_TIMING)
+        m_startTime = monotonicallyIncreasingTimeMS();
+#endif
+        auto url = request.url();
+        if (m_storedCredentials == AllowStoredCredentials) {
+            m_user = url.user();
+            m_password = url.pass();
+            request.removeCredentials();
+
+            if (m_user.isEmpty() && m_password.isEmpty())
+                m_initialCredential = m_session->networkStorageSession().credentialStorage().get(request.url());
+            else
+                m_session->networkStorageSession().credentialStorage().set(Credential(m_user, m_password, CredentialPersistenceNone), request.url());
+        }
+        applyAuthenticationToRequest(request);
+    }
+    createRequest(request);
+}
+
+NetworkDataTask::~NetworkDataTask()
+{
+    ASSERT(isMainThread());
+    ASSERT(!m_client);
+    clearRequest();
+    m_session->m_dataTaskSet.remove(this);
+}
+
+void NetworkDataTask::scheduleFailure(FailureType type)
+{
+    ASSERT(type != NoFailure);
+    m_scheduledFailureType = type;
+    m_failureTimer.startOneShot(0);
+}
+
+void NetworkDataTask::failureTimerFired()
+{
+    RefPtr<NetworkDataTask> protectedThis(this);
+
+    switch (m_scheduledFailureType) {
+    case BlockedFailure:
+        m_scheduledFailureType = NoFailure;
+        if (m_client)
+            m_client->wasBlocked();
+        return;
+    case InvalidURLFailure:
+        m_scheduledFailureType = NoFailure;
+        if (m_client)
+            m_client->cannotShowURL();
+        return;
+    case NoFailure:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+    ASSERT_NOT_REACHED();
+}
+
+String NetworkDataTask::suggestedFilename()
+{
+    if (!m_suggestedFilename.isEmpty())
+        return m_suggestedFilename;
+
+    String suggestedFilename = m_response.suggestedFilename();
+    if (!suggestedFilename.isEmpty())
+        return suggestedFilename;
+
+    return decodeURLEscapeSequences(m_response.url().lastPathComponent());
+}
+
+void NetworkDataTask::setSuggestedFilename(const String& suggestedName)
+{
+    m_suggestedFilename = suggestedName;
+}
+
+void NetworkDataTask::setPendingDownloadLocation(const String& filename, const SandboxExtension::Handle&, bool allowOverwrite)
+{
+    m_pendingDownloadLocation = filename;
+    m_allowOverwriteDownload = allowOverwrite;
+}
+
+bool NetworkDataTask::allowsSpecificHTTPSCertificateForHost(const AuthenticationChallenge&)
+{
+    return false;
+}
+
+void NetworkDataTask::createRequest(const ResourceRequest& request)
+{
+    GUniquePtr<SoupURI> soupURI = request.createSoupURI();
+    if (!soupURI) {
+        scheduleFailure(InvalidURLFailure);
+        return;
+    }
+
+    GRefPtr<SoupRequest> soupRequest = adoptGRef(soup_session_request_uri(m_session->soupSession(), soupURI.get(), nullptr));
+    if (!soupRequest) {
+        scheduleFailure(InvalidURLFailure);
+        return;
+    }
+
+    request.updateSoupRequest(soupRequest.get());
+
+    if (!request.url().protocolIsInHTTPFamily()) {
+        m_soupRequest = WTFMove(soupRequest);
+        return;
+    }
+
+    // HTTP request.
+    GRefPtr<SoupMessage> soupMessage = adoptGRef(soup_request_http_get_message(SOUP_REQUEST_HTTP(soupRequest.get())));
+    if (!soupMessage) {
+        scheduleFailure(InvalidURLFailure);
+        return;
+    }
+
+    request.updateSoupMessage(soupMessage.get());
+    if (m_shouldContentSniff == DoNotSniffContent)
+        soup_message_disable_feature(soupMessage.get(), SOUP_TYPE_CONTENT_SNIFFER);
+    if (m_user.isEmpty() && m_password.isEmpty() && m_storedCredentials == DoNotAllowStoredCredentials) {
+        // In case credential is not available and credential storage should not to be used,
+        // disable authentication manager so that credentials stored in libsoup are not used.
+        soup_message_disable_feature(soupMessage.get(), SOUP_TYPE_AUTH_MANAGER);
+    }
+
+    // Make sure we have an Accept header for subresources; some sites want this to serve some of their subresources.
+    if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept"))
+        soup_message_headers_append(soupMessage->request_headers, "Accept", "*/*");
+
+    // In the case of XHR .send() and .send("") explicitly tell libsoup to send a zero content-lenght header
+    // for consistency with other UA implementations like Firefox. It's done in the backend here instead of
+    // in XHR code since in XHR CORS checking prevents us from this kind of late header manipulation.
+    if ((soupMessage->method == SOUP_METHOD_POST || soupMessage->method == SOUP_METHOD_PUT) && !soupMessage->request_body->length)
+        soup_message_headers_set_content_length(soupMessage->request_headers, 0);
+
+    unsigned flags = SOUP_MESSAGE_NO_REDIRECT;
+    soup_message_set_flags(soupMessage.get(), static_cast<SoupMessageFlags>(soup_message_get_flags(soupMessage.get()) | flags));
+
+#if SOUP_CHECK_VERSION(2, 43, 1)
+    soup_message_set_priority(soupMessage.get(), toSoupMessagePriority(request.priority()));
+#endif
+
+    m_soupRequest = WTFMove(soupRequest);
+    m_soupMessage = WTFMove(soupMessage);
+
+    g_signal_connect(m_soupMessage.get(), "notify::tls-errors", G_CALLBACK(tlsErrorsChangedCallback), this);
+    g_signal_connect(m_soupMessage.get(), "got-headers", G_CALLBACK(gotHeadersCallback), this);
+    g_signal_connect(m_soupMessage.get(), "wrote-body-data", G_CALLBACK(wroteBodyDataCallback), this);
+    g_signal_connect(m_session->soupSession(), "authenticate",  G_CALLBACK(authenticateCallback), this);
+#if ENABLE(WEB_TIMING)
+    g_signal_connect(m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), this);
+    g_signal_connect(m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), this);
+#if SOUP_CHECK_VERSION(2, 49, 91)
+    g_signal_connect(m_soupMessage.get(), "starting", G_CALLBACK(startingCallback), this);
+#else
+    g_signal_connect(m_session->soupSession(), "request-started", G_CALLBACK(requestStartedCallback), this);
+#endif
+#endif
+}
+
+void NetworkDataTask::clearRequest()
+{
+    if (m_state == State::Completed)
+        return;
+
+    m_state = State::Completed;
+
+    stopTimeout();
+    m_pendingResult = nullptr;
+    m_soupRequest = nullptr;
+    m_inputStream = nullptr;
+    m_multipartInputStream = nullptr;
+    m_downloadOutputStream = nullptr;
+    g_cancellable_cancel(m_cancellable.get());
+    m_cancellable = nullptr;
+    if (m_soupMessage) {
+        g_signal_handlers_disconnect_matched(m_soupMessage.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+        soup_session_cancel_message(m_session->soupSession(), m_soupMessage.get(), SOUP_STATUS_CANCELLED);
+        m_soupMessage = nullptr;
+    }
+    g_signal_handlers_disconnect_matched(m_session->soupSession(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+}
+
+void NetworkDataTask::resume()
+{
+    ASSERT(m_state != State::Running);
+    if (m_state == State::Canceling || m_state == State::Completed)
+        return;
+
+    m_state = State::Running;
+
+    if (m_scheduledFailureType != NoFailure) {
+        ASSERT(m_failureTimer.isActive());
+        return;
+    }
+
+    startTimeout();
+
+    RefPtr<NetworkDataTask> protectedThis(this);
+    if (m_soupRequest && !m_cancellable) {
+        m_cancellable = adoptGRef(g_cancellable_new());
+        soup_request_send_async(m_soupRequest.get(), m_cancellable.get(), reinterpret_cast<GAsyncReadyCallback>(sendRequestCallback), protectedThis.leakRef());
+        return;
+    }
+
+    if (m_pendingResult) {
+        GRefPtr<GAsyncResult> pendingResult = WTFMove(m_pendingResult);
+        if (m_inputStream)
+            readCallback(m_inputStream.get(), pendingResult.get(), protectedThis.leakRef());
+        else if (m_multipartInputStream)
+            requestNextPartCallback(m_multipartInputStream.get(), pendingResult.get(), protectedThis.leakRef());
+        else if (m_soupRequest)
+            sendRequestCallback(m_soupRequest.get(), pendingResult.get(), protectedThis.leakRef());
+        else
+            ASSERT_NOT_REACHED();
+    }
+}
+
+void NetworkDataTask::suspend()
+{
+    ASSERT(m_state != State::Suspended);
+    if (m_state == State::Canceling || m_state == State::Completed)
+        return;
+    m_state = State::Suspended;
+
+    stopTimeout();
+}
+
+void NetworkDataTask::cancel()
+{
+    if (m_state == State::Canceling || m_state == State::Completed)
+        return;
+
+    m_state = State::Canceling;
+
+    if (m_soupMessage)
+        soup_session_cancel_message(m_session->soupSession(), m_soupMessage.get(), SOUP_STATUS_CANCELLED);
+
+    g_cancellable_cancel(m_cancellable.get());
+
+    if (isDownload())
+        cleanDownloadFiles();
+}
+
+void NetworkDataTask::invalidateAndCancel()
+{
+    cancel();
+    clearRequest();
+}
+
+NetworkDataTask::State NetworkDataTask::state() const
+{
+    return m_state;
+}
+
+void NetworkDataTask::timeoutFired()
+{
+    if (m_state == State::Canceling || m_state == State::Completed || !m_client) {
+        clearRequest();
+        return;
+    }
+
+    RefPtr<NetworkDataTask> protectedThis(this);
+    invalidateAndCancel();
+    m_client->didCompleteWithError(ResourceError::timeoutError(m_firstRequest.url()));
+}
+
+void NetworkDataTask::startTimeout()
+{
+    if (m_firstRequest.timeoutInterval() > 0)
+        m_timeoutSource.startOneShot(m_firstRequest.timeoutInterval());
+}
+
+void NetworkDataTask::stopTimeout()
+{
+    m_timeoutSource.stop();
+}
+
+void NetworkDataTask::sendRequestCallback(SoupRequest* soupRequest, GAsyncResult* result, NetworkDataTask* task)
+{
+    RefPtr<NetworkDataTask> protectedThis = adoptRef(task);
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(soupRequest == task->m_soupRequest.get());
+
+    if (task->state() == State::Suspended) {
+        ASSERT(!task->m_pendingResult);
+        task->m_pendingResult = result;
+        return;
+    }
+
+    GUniqueOutPtr<GError> error;
+    GRefPtr<GInputStream> inputStream = adoptGRef(soup_request_send_finish(soupRequest, result, &error.outPtr()));
+    if (error)
+        task->didFail(ResourceError::httpError(task->m_soupMessage.get(), error.get(), soupRequest));
+    else
+        task->didSendRequest(WTFMove(inputStream));
+}
+
+void NetworkDataTask::didSendRequest(GRefPtr<GInputStream>&& inputStream)
+{
+    if (m_soupMessage) {
+        if (m_shouldContentSniff == SniffContent && m_soupMessage->status_code != SOUP_STATUS_NOT_MODIFIED)
+            m_response.setSniffedContentType(soup_request_get_content_type(m_soupRequest.get()));
+        m_response.updateFromSoupMessage(m_soupMessage.get());
+
+        if (shouldStartHTTPRedirection()) {
+            m_inputStream = WTFMove(inputStream);
+            skipInputStreamForRedirection();
+            return;
+        }
+
+        if (m_response.isMultipart())
+            m_multipartInputStream = adoptGRef(soup_multipart_input_stream_new(m_soupMessage.get(), inputStream.get()));
+        else
+            m_inputStream = WTFMove(inputStream);
+
+#if ENABLE(WEB_TIMING)
+        m_response.networkLoadTiming().responseStart = monotonicallyIncreasingTimeMS() - m_startTime;
+#endif
+    } else {
+        m_response.setURL(m_firstRequest.url());
+        const gchar* contentType = soup_request_get_content_type(m_soupRequest.get());
+        m_response.setMimeType(extractMIMETypeFromMediaType(contentType));
+        m_response.setTextEncodingName(extractCharsetFromMediaType(contentType));
+        m_response.setExpectedContentLength(soup_request_get_content_length(m_soupRequest.get()));
+
+        m_inputStream = WTFMove(inputStream);
+    }
+
+    didReceiveResponse();
+}
+
+void NetworkDataTask::didReceiveResponse()
+{
+    ASSERT(!m_response.isNull());
+
+    auto response = ResourceResponse(m_response);
+    m_client->didReceiveResponseNetworkSession(WTFMove(response), [this, protectedThis = makeRef(*this)](PolicyAction policyAction) {
+        if (m_state == State::Canceling || m_state == State::Completed) {
+            clearRequest();
+            return;
+        }
+
+        switch (policyAction) {
+        case PolicyAction::PolicyUse:
+            if (m_inputStream)
+                read();
+            else if (m_multipartInputStream)
+                requestNextPart();
+            else
+                ASSERT_NOT_REACHED();
+
+            break;
+        case PolicyAction::PolicyIgnore:
+            clearRequest();
+            break;
+        case PolicyAction::PolicyDownload:
+            download();
+            break;
+        }
+    });
+}
+
+void NetworkDataTask::tlsErrorsChangedCallback(SoupMessage* soupMessage, GParamSpec*, NetworkDataTask* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+
+    ASSERT(soupMessage == task->m_soupMessage.get());
+    task->tlsErrorsChanged();
+}
+
+void NetworkDataTask::tlsErrorsChanged()
+{
+    ASSERT(m_soupRequest);
+    SoupNetworkSession::checkTLSErrors(m_soupRequest.get(), m_soupMessage.get(), [this] (const ResourceError& error) {
+        if (error.isNull())
+            return;
+
+        RefPtr<NetworkDataTask> protectedThis(this);
+        invalidateAndCancel();
+        m_client->didCompleteWithError(error);
+    });
+}
+
+void NetworkDataTask::applyAuthenticationToRequest(ResourceRequest& request)
+{
+    // We always put the credentials into the URL. In the Coca port HTTP family credentials are applied in
+    // the didReceiveChallenge callback, but libsoup requires us to use this method to override
+    // any previously remembered credentials. It has its own per-session credential storage.
+    auto url = request.url();
+    if (!m_initialCredential.isEmpty()) {
+        url.setUser(m_initialCredential.user());
+        url.setPass(m_initialCredential.password());
+    } else {
+        url.setUser(m_user);
+        url.setPass(m_password);
+    }
+
+    m_user = String();
+    m_password = String();
+
+    request.setURL(url);
+}
+
+void NetworkDataTask::authenticateCallback(SoupSession* session, SoupMessage* soupMessage, SoupAuth* soupAuth, gboolean retrying, NetworkDataTask* task)
+{
+    ASSERT(session == task->m_session->soupSession());
+    if (soupMessage != task->m_soupMessage.get())
+        return;
+
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+
+    task->authenticate(AuthenticationChallenge(soupMessage, soupAuth, retrying));
+}
+
+static inline bool isAuthenticationFailureStatusCode(int httpStatusCode)
+{
+    return httpStatusCode == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || httpStatusCode == SOUP_STATUS_UNAUTHORIZED;
+}
+
+void NetworkDataTask::authenticate(AuthenticationChallenge&& challenge)
+{
+    ASSERT(m_soupMessage);
+    if (m_storedCredentials == AllowStoredCredentials) {
+        if (!m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
+            // The stored credential wasn't accepted, stop using it. There is a race condition
+            // here, since a different credential might have already been stored by another
+            // NetworkDataTask, but the observable effect should be very minor, if any.
+            m_session->networkStorageSession().credentialStorage().remove(challenge.protectionSpace());
+        }
+
+        if (!challenge.previousFailureCount()) {
+            auto credential = m_session->networkStorageSession().credentialStorage().get(challenge.protectionSpace());
+            if (!credential.isEmpty() && credential != m_initialCredential) {
+                ASSERT(credential.persistence() == CredentialPersistenceNone);
+
+                if (isAuthenticationFailureStatusCode(challenge.failureResponse().httpStatusCode())) {
+                    // Store the credential back, possibly adding it as a default for this directory.
+                    m_session->networkStorageSession().credentialStorage().set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
+                }
+                soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
+                return;
+            }
+        }
+    }
+
+    soup_session_pause_message(m_session->soupSession(), m_soupMessage.get());
+
+    // We could also do this before we even start the request, but that would be at the expense
+    // of all request latency, versus a one-time latency for the small subset of requests that
+    // use HTTP authentication. In the end, this doesn't matter much, because persistent credentials
+    // will become session credentials after the first use.
+    if (m_storedCredentials == AllowStoredCredentials) {
+        auto protectionSpace = challenge.protectionSpace();
+        m_session->networkStorageSession().getCredentialFromPersistentStorage(protectionSpace,
+            [this, protectedThis = makeRef(*this), authChallenge = WTFMove(challenge)] (Credential&& credential) mutable {
+                if (m_state == State::Canceling || m_state == State::Completed || !m_client) {
+                    clearRequest();
+                    return;
+                }
+
+                authChallenge.setProposedCredential(WTFMove(credential));
+                continueAuthenticate(WTFMove(authChallenge));
+        });
+    } else
+        continueAuthenticate(WTFMove(challenge));
+}
+
+void NetworkDataTask::continueAuthenticate(AuthenticationChallenge&& challenge)
+{
+    m_client->didReceiveChallenge(challenge, [this, protectedThis = makeRef(*this), challenge](AuthenticationChallengeDisposition disposition, const Credential& credential) {
+        if (m_state == State::Canceling || m_state == State::Completed) {
+            clearRequest();
+            return;
+        }
+
+        if (disposition == AuthenticationChallengeDisposition::Cancel) {
+            cancel();
+            didFail(cancelledError(m_soupRequest.get()));
+            return;
+        }
+
+        if (disposition == AuthenticationChallengeDisposition::UseCredential && !credential.isEmpty()) {
+            if (m_storedCredentials == AllowStoredCredentials) {
+                // Eventually we will manage per-session credentials only internally or use some newly-exposed API from libsoup,
+                // because once we authenticate via libsoup, there is no way to ignore it for a particular request. Right now,
+                // we place the credentials in the store even though libsoup will never fire the authenticate signal again for
+                // this protection space.
+                if (credential.persistence() == CredentialPersistenceForSession || credential.persistence() == CredentialPersistencePermanent)
+                    m_session->networkStorageSession().credentialStorage().set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
+
+                if (credential.persistence() == CredentialPersistencePermanent) {
+                    m_protectionSpaceForPersistentStorage = challenge.protectionSpace();
+                    m_credentialForPersistentStorage = credential;
+                }
+            }
+
+            soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
+        }
+
+        soup_session_unpause_message(m_session->soupSession(), m_soupMessage.get());
+    });
+}
+
+void NetworkDataTask::skipInputStreamForRedirectionCallback(GInputStream* inputStream, GAsyncResult* result, NetworkDataTask* task)
+{
+    RefPtr<NetworkDataTask> protectedThis = adoptRef(task);
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(inputStream == task->m_inputStream.get());
+
+    GUniqueOutPtr<GError> error;
+    gssize bytesSkipped = g_input_stream_skip_finish(inputStream, result, &error.outPtr());
+    if (error)
+        task->didFail(ResourceError::genericGError(error.get(), task->m_soupRequest.get()));
+    else if (bytesSkipped > 0)
+        task->skipInputStreamForRedirection();
+    else
+        task->didFinishSkipInputStreamForRedirection();
+}
+
+void NetworkDataTask::skipInputStreamForRedirection()
+{
+    ASSERT(m_inputStream);
+    RefPtr<NetworkDataTask> protectedThis(this);
+    g_input_stream_skip_async(m_inputStream.get(), gDefaultReadBufferSize, G_PRIORITY_DEFAULT, m_cancellable.get(),
+        reinterpret_cast<GAsyncReadyCallback>(skipInputStreamForRedirectionCallback), protectedThis.leakRef());
+}
+
+void NetworkDataTask::didFinishSkipInputStreamForRedirection()
+{
+    g_input_stream_close(m_inputStream.get(), nullptr, nullptr);
+    continueHTTPRedirection();
+}
+
+static bool shouldRedirectAsGET(SoupMessage* message, bool crossOrigin)
+{
+    if (message->method == SOUP_METHOD_GET || message->method == SOUP_METHOD_HEAD)
+        return false;
+
+    switch (message->status_code) {
+    case SOUP_STATUS_SEE_OTHER:
+        return true;
+    case SOUP_STATUS_FOUND:
+    case SOUP_STATUS_MOVED_PERMANENTLY:
+        if (message->method == SOUP_METHOD_POST)
+            return true;
+        break;
+    }
+
+    if (crossOrigin && message->method == SOUP_METHOD_DELETE)
+        return true;
+
+    return false;
+}
+
+bool NetworkDataTask::shouldStartHTTPRedirection()
+{
+    ASSERT(m_soupMessage);
+    ASSERT(!m_response.isNull());
+
+    auto status = m_response.httpStatusCode();
+    if (!SOUP_STATUS_IS_REDIRECTION(status))
+        return false;
+
+    // Some 3xx status codes aren't actually redirects.
+    if (status == 300 || status == 304 || status == 305 || status == 306)
+        return false;
+
+    if (m_response.httpHeaderField(HTTPHeaderName::Location).isEmpty())
+        return false;
+
+    return true;
+}
+
+void NetworkDataTask::continueHTTPRedirection()
+{
+    ASSERT(m_soupMessage);
+    ASSERT(!m_response.isNull());
+
+    static const unsigned maxRedirects = 20;
+    if (m_redirectCount++ > maxRedirects) {
+        didFail(ResourceError::transportError(m_soupRequest.get(), SOUP_STATUS_TOO_MANY_REDIRECTS, "Too many redirects"));
+        return;
+    }
+
+    ResourceRequest request = m_firstRequest;
+    request.setURL(URL(m_response.url(), m_response.httpHeaderField(HTTPHeaderName::Location)));
+    request.setFirstPartyForCookies(request.url());
+
+    // Should not set Referer after a redirect from a secure resource to non-secure one.
+    if (m_shouldClearReferrerOnHTTPSToHTTPRedirect && !request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https"))
+        request.clearHTTPReferrer();
+
+    bool isCrossOrigin = !protocolHostAndPortAreEqual(m_firstRequest.url(), request.url());
+    if (!equalLettersIgnoringASCIICase(request.httpMethod(), "GET")) {
+        // Change newRequest method to GET if change was made during a previous redirection or if current redirection says so.
+        if (m_soupMessage->method == SOUP_METHOD_GET || !request.url().protocolIsInHTTPFamily() || shouldRedirectAsGET(m_soupMessage.get(), isCrossOrigin)) {
+            request.setHTTPMethod("GET");
+            request.setHTTPBody(nullptr);
+            request.clearHTTPContentType();
+        }
+    }
+
+    const auto& url = request.url();
+    m_user = url.user();
+    m_password = url.pass();
+    m_lastHTTPMethod = request.httpMethod();
+    request.removeCredentials();
+
+    if (isCrossOrigin) {
+        // The network layer might carry over some headers from the original request that
+        // we want to strip here because the redirect is cross-origin.
+        request.clearHTTPAuthorization();
+        request.clearHTTPOrigin();
+    } else if (url.protocolIsInHTTPFamily() && m_storedCredentials == AllowStoredCredentials) {
+        if (m_user.isEmpty() && m_password.isEmpty()) {
+            auto credential = m_session->networkStorageSession().credentialStorage().get(request.url());
+            if (!credential.isEmpty())
+                m_initialCredential = credential;
+        }
+    }
+
+    clearRequest();
+
+    auto response = ResourceResponse(m_response);
+    m_client->willPerformHTTPRedirection(WTFMove(response), WTFMove(request), [this, protectedThis = makeRef(*this), isCrossOrigin](const ResourceRequest& newRequest) {
+        if (newRequest.isNull() || m_state == State::Canceling)
+            return;
+
+        auto request = newRequest;
+        if (request.url().protocolIsInHTTPFamily()) {
+#if ENABLE(WEB_TIMING)
+            if (isCrossOrigin)
+                m_startTime = monotonicallyIncreasingTimeMS();
+#endif
+            applyAuthenticationToRequest(request);
+        }
+        createRequest(request);
+        if (m_soupRequest && m_state != State::Suspended) {
+            m_state = State::Suspended;
+            resume();
+        }
+    });
+}
+
+void NetworkDataTask::readCallback(GInputStream* inputStream, GAsyncResult* result, NetworkDataTask* task)
+{
+    RefPtr<NetworkDataTask> protectedThis = adoptRef(task);
+    if (task->state() == State::Canceling || task->state() == State::Completed || (!task->m_client && !task->isDownload())) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(inputStream == task->m_inputStream.get());
+
+    if (task->state() == State::Suspended) {
+        ASSERT(!task->m_pendingResult);
+        task->m_pendingResult = result;
+        return;
+    }
+
+    GUniqueOutPtr<GError> error;
+    gssize bytesRead = g_input_stream_read_finish(inputStream, result, &error.outPtr());
+    if (error)
+        task->didFail(ResourceError::genericGError(error.get(), task->m_soupRequest.get()));
+    else if (bytesRead > 0)
+        task->didRead(bytesRead);
+    else
+        task->didFinishRead();
+}
+
+void NetworkDataTask::read()
+{
+    RefPtr<NetworkDataTask> protectedThis(this);
+    ASSERT(m_inputStream);
+    m_readBuffer.grow(gDefaultReadBufferSize);
+    g_input_stream_read_async(m_inputStream.get(), m_readBuffer.data(), m_readBuffer.size(), G_PRIORITY_DEFAULT, m_cancellable.get(),
+        reinterpret_cast<GAsyncReadyCallback>(readCallback), protectedThis.leakRef());
+}
+
+void NetworkDataTask::didRead(gssize bytesRead)
+{
+    m_readBuffer.shrink(bytesRead);
+    if (m_downloadOutputStream) {
+        ASSERT(isDownload());
+        writeDownload();
+    } else {
+        ASSERT(m_client);
+        m_client->didReceiveData(SharedBuffer::adoptVector(m_readBuffer));
+        read();
+    }
+}
+
+void NetworkDataTask::didFinishRead()
+{
+    ASSERT(m_inputStream);
+    g_input_stream_close(m_inputStream.get(), nullptr, nullptr);
+    m_inputStream = nullptr;
+    if (m_multipartInputStream) {
+        requestNextPart();
+        return;
+    }
+
+    if (m_downloadOutputStream) {
+        didFinishDownload();
+        return;
+    }
+
+    clearRequest();
+    ASSERT(m_client);
+    m_client->didCompleteWithError({ });
+}
+
+void NetworkDataTask::requestNextPartCallback(SoupMultipartInputStream* multipartInputStream, GAsyncResult* result, NetworkDataTask* task)
+{
+    RefPtr<NetworkDataTask> protectedThis = adoptRef(task);
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(multipartInputStream == task->m_multipartInputStream.get());
+
+    if (task->state() == State::Suspended) {
+        ASSERT(!task->m_pendingResult);
+        task->m_pendingResult = result;
+        return;
+    }
+
+    GUniqueOutPtr<GError> error;
+    GRefPtr<GInputStream> inputStream = adoptGRef(soup_multipart_input_stream_next_part_finish(multipartInputStream, result, &error.outPtr()));
+    if (error)
+        task->didFail(ResourceError::httpError(task->m_soupMessage.get(), error.get(), task->m_soupRequest.get()));
+    else if (inputStream)
+        task->didRequestNextPart(WTFMove(inputStream));
+    else
+        task->didFinishRequestNextPart();
+}
+
+void NetworkDataTask::requestNextPart()
+{
+    RefPtr<NetworkDataTask> protectedThis(this);
+    ASSERT(m_multipartInputStream);
+    ASSERT(!m_inputStream);
+    soup_multipart_input_stream_next_part_async(m_multipartInputStream.get(), G_PRIORITY_DEFAULT, m_cancellable.get(),
+        reinterpret_cast<GAsyncReadyCallback>(requestNextPartCallback), protectedThis.leakRef());
+}
+
+void NetworkDataTask::didRequestNextPart(GRefPtr<GInputStream>&& inputStream)
+{
+    ASSERT(!m_inputStream);
+    m_inputStream = WTFMove(inputStream);
+    m_response = ResourceResponse();
+    m_response.setURL(m_firstRequest.url());
+    m_response.updateFromSoupMessageHeaders(soup_multipart_input_stream_get_headers(m_multipartInputStream.get()));
+    didReceiveResponse();
+}
+
+void NetworkDataTask::didFinishRequestNextPart()
+{
+    ASSERT(!m_inputStream);
+    ASSERT(m_multipartInputStream);
+    g_input_stream_close(G_INPUT_STREAM(m_multipartInputStream.get()), nullptr, nullptr);
+    clearRequest();
+    m_client->didCompleteWithError({ });
+}
+
+void NetworkDataTask::gotHeadersCallback(SoupMessage* soupMessage, NetworkDataTask* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->didGetHeaders();
+}
+
+void NetworkDataTask::didGetHeaders()
+{
+    // We are a bit more conservative with the persistent credential storage than the session store,
+    // since we are waiting until we know that this authentication succeeded before actually storing.
+    // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
+    // incorrect credentials or polluting the keychain with invalid credentials.
+    if (!isAuthenticationFailureStatusCode(m_soupMessage->status_code) && m_soupMessage->status_code < 500) {
+        m_session->networkStorageSession().saveCredentialToPersistentStorage(m_protectionSpaceForPersistentStorage, m_credentialForPersistentStorage);
+        m_protectionSpaceForPersistentStorage = ProtectionSpace();
+        m_credentialForPersistentStorage = Credential();
+    }
+}
+
+void NetworkDataTask::wroteBodyDataCallback(SoupMessage* soupMessage, SoupBuffer* buffer, NetworkDataTask* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->didWriteBodyData(buffer->length);
+}
+
+void NetworkDataTask::didWriteBodyData(uint64_t bytesSent)
+{
+    RefPtr<NetworkDataTask> protectedThis(this);
+    m_bodyDataTotalBytesSent += bytesSent;
+    m_client->didSendData(m_bodyDataTotalBytesSent, m_soupMessage->request_body->length);
+}
+
+void NetworkDataTask::download()
+{
+    ASSERT(isDownload());
+    ASSERT(m_pendingDownloadLocation);
+    ASSERT(!m_response.isNull());
+
+    if (m_response.httpStatusCode() >= 400) {
+        didFailDownload(platformDownloadNetworkError(m_response.httpStatusCode(), m_response.url(), m_response.httpStatusText()));
+        return;
+    }
+
+    m_downloadDestinationFile = adoptGRef(g_file_new_for_uri(m_pendingDownloadLocation.utf8().data()));
+    GRefPtr<GFileOutputStream> outputStream;
+    GUniqueOutPtr<GError> error;
+    if (m_allowOverwriteDownload)
+        outputStream = adoptGRef(g_file_replace(m_downloadDestinationFile.get(), nullptr, FALSE, G_FILE_CREATE_NONE, nullptr, &error.outPtr()));
+    else
+        outputStream = adoptGRef(g_file_create(m_downloadDestinationFile.get(), G_FILE_CREATE_NONE, nullptr, &error.outPtr()));
+    if (!outputStream) {
+        didFailDownload(platformDownloadDestinationError(m_response, error->message));
+        return;
+    }
+
+    String intermediateURI = m_pendingDownloadLocation + ".wkdownload";
+    m_downloadIntermediateFile = adoptGRef(g_file_new_for_uri(intermediateURI.utf8().data()));
+    outputStream = adoptGRef(g_file_replace(m_downloadIntermediateFile.get(), 0, TRUE, G_FILE_CREATE_NONE, 0, &error.outPtr()));
+    if (!outputStream) {
+        didFailDownload(platformDownloadDestinationError(m_response, error->message));
+        return;
+    }
+    m_downloadOutputStream = adoptGRef(G_OUTPUT_STREAM(outputStream.leakRef()));
+
+    auto& downloadManager = NetworkProcess::singleton().downloadManager();
+    auto download = std::make_unique<Download>(downloadManager, m_pendingDownloadID, this, m_session->sessionID(), suggestedFilename());
+    auto* downloadPtr = download.get();
+    downloadManager.dataTaskBecameDownloadTask(m_pendingDownloadID, WTFMove(download));
+    downloadPtr->didCreateDestination(m_pendingDownloadLocation);
+
+    ASSERT(m_client);
+    m_client->didBecomeDownload();
+
+    read();
+}
+
+void NetworkDataTask::writeDownloadCallback(GOutputStream* outputStream, GAsyncResult* result, NetworkDataTask* task)
+{
+    RefPtr<NetworkDataTask> protectedThis = adoptRef(task);
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->isDownload()) {
+        task->clearRequest();
+        return;
+    }
+    ASSERT(outputStream == task->m_downloadOutputStream.get());
+
+    GUniqueOutPtr<GError> error;
+    gsize bytesWritten;
+#if GLIB_CHECK_VERSION(2, 44, 0)
+    g_output_stream_write_all_finish(outputStream, result, &bytesWritten, &error.outPtr());
+#else
+    gssize writeTaskResult = g_task_propagate_int(G_TASK(result), &error.outPtr());
+    if (writeTaskResult != -1)
+        bytesWritten = writeTaskResult;
+#endif
+    if (error)
+        task->didFailDownload(platformDownloadDestinationError(task->m_response, error->message));
+    else
+        task->didWriteDownload(bytesWritten);
+}
+
+void NetworkDataTask::writeDownload()
+{
+    RefPtr<NetworkDataTask> protectedThis(this);
+#if GLIB_CHECK_VERSION(2, 44, 0)
+    g_output_stream_write_all_async(m_downloadOutputStream.get(), m_readBuffer.data(), m_readBuffer.size(), G_PRIORITY_DEFAULT, m_cancellable.get(),
+        reinterpret_cast<GAsyncReadyCallback>(writeDownloadCallback), protectedThis.leakRef());
+#else
+    GRefPtr<GTask> writeTask = adoptGRef(g_task_new(m_downloadOutputStream.get(), m_cancellable.get(),
+        reinterpret_cast<GAsyncReadyCallback>(writeDownloadCallback), protectedThis.leakRef()));
+    g_task_set_task_data(writeTask.get(), this, nullptr);
+    g_task_run_in_thread(writeTask.get(), [](GTask* writeTask, gpointer source, gpointer userData, GCancellable* cancellable) {
+        auto* task = static_cast<NetworkDataTask*>(userData);
+        GOutputStream* outputStream = G_OUTPUT_STREAM(source);
+        RELEASE_ASSERT(task->m_downloadOutputStream.get() == outputStream);
+        RELEASE_ASSERT(task->m_cancellable.get() == cancellable);
+        GError* error = nullptr;
+        if (g_cancellable_set_error_if_cancelled(cancellable, &error)) {
+            g_task_return_error(writeTask, error);
+            return;
+        }
+
+        gsize bytesWritten;
+        if (g_output_stream_write_all(outputStream, task->m_readBuffer.data(), task->m_readBuffer.size(), &bytesWritten, cancellable, &error))
+            g_task_return_int(writeTask, bytesWritten);
+        else
+            g_task_return_error(writeTask, error);
+    });
+#endif
+}
+
+void NetworkDataTask::didWriteDownload(gsize bytesWritten)
+{
+    ASSERT(bytesWritten == m_readBuffer.size());
+    auto* download = NetworkProcess::singleton().downloadManager().download(m_pendingDownloadID);
+    ASSERT(download);
+    download->didReceiveData(bytesWritten);
+    read();
+}
+
+void NetworkDataTask::didFinishDownload()
+{
+    ASSERT(!m_response.isNull());
+    ASSERT(m_downloadOutputStream);
+    g_output_stream_close(m_downloadOutputStream.get(), nullptr, nullptr);
+    m_downloadOutputStream = nullptr;
+
+    ASSERT(m_downloadDestinationFile);
+    ASSERT(m_downloadIntermediateFile);
+    GUniqueOutPtr<GError> error;
+    if (!g_file_move(m_downloadIntermediateFile.get(), m_downloadDestinationFile.get(), G_FILE_COPY_OVERWRITE, m_cancellable.get(), nullptr, nullptr, &error.outPtr())) {
+        didFailDownload(platformDownloadDestinationError(m_response, error->message));
+        return;
+    }
+
+    GRefPtr<GFileInfo> info = adoptGRef(g_file_info_new());
+    CString uri = m_response.url().string().utf8();
+    g_file_info_set_attribute_string(info.get(), "metadata::download-uri", uri.data());
+    g_file_info_set_attribute_string(info.get(), "xattr::xdg.origin.url", uri.data());
+    g_file_set_attributes_async(m_downloadDestinationFile.get(), info.get(), G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, nullptr, nullptr, nullptr);
+
+    clearRequest();
+    auto* download = NetworkProcess::singleton().downloadManager().download(m_pendingDownloadID);
+    ASSERT(download);
+    download->didFinish();
+}
+
+void NetworkDataTask::didFailDownload(const ResourceError& error)
+{
+    clearRequest();
+    cleanDownloadFiles();
+    if (m_client)
+        m_client->didCompleteWithError(error);
+    else {
+        auto* download = NetworkProcess::singleton().downloadManager().download(m_pendingDownloadID);
+        ASSERT(download);
+        download->didFail(error, IPC::DataReference());
+    }
+}
+
+void NetworkDataTask::cleanDownloadFiles()
+{
+    if (m_downloadDestinationFile) {
+        g_file_delete(m_downloadDestinationFile.get(), nullptr, nullptr);
+        m_downloadDestinationFile = nullptr;
+    }
+    if (m_downloadIntermediateFile) {
+        g_file_delete(m_downloadIntermediateFile.get(), nullptr, nullptr);
+        m_downloadIntermediateFile = nullptr;
+    }
+}
+
+void NetworkDataTask::didFail(const ResourceError& error)
+{
+    if (isDownload()) {
+        didFailDownload(platformDownloadNetworkError(error.errorCode(), error.failingURL(), error.localizedDescription()));
+        return;
+    }
+
+    clearRequest();
+    ASSERT(m_client);
+    m_client->didCompleteWithError(error);
+}
+
+#if ENABLE(WEB_TIMING)
+void NetworkDataTask::networkEventCallback(SoupMessage* soupMessage, GSocketClientEvent event, GIOStream*, NetworkDataTask* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
+        return;
+
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->networkEvent(event);
+}
+
+void NetworkDataTask::networkEvent(GSocketClientEvent event)
+{
+    double deltaTime = monotonicallyIncreasingTimeMS() - m_startTime;
+    auto& loadTiming = m_response.networkLoadTiming();
+    switch (event) {
+    case G_SOCKET_CLIENT_RESOLVING:
+        loadTiming.domainLookupStart = deltaTime;
+        break;
+    case G_SOCKET_CLIENT_RESOLVED:
+        loadTiming.domainLookupEnd = deltaTime;
+        break;
+    case G_SOCKET_CLIENT_CONNECTING:
+        loadTiming.connectStart = deltaTime;
+        break;
+    case G_SOCKET_CLIENT_CONNECTED:
+        // Web Timing considers that connection time involves dns, proxy & TLS negotiation...
+        // so we better pick G_SOCKET_CLIENT_COMPLETE for connectEnd
+        break;
+    case G_SOCKET_CLIENT_PROXY_NEGOTIATING:
+        break;
+    case G_SOCKET_CLIENT_PROXY_NEGOTIATED:
+        break;
+    case G_SOCKET_CLIENT_TLS_HANDSHAKING:
+        loadTiming.secureConnectionStart = deltaTime;
+        break;
+    case G_SOCKET_CLIENT_TLS_HANDSHAKED:
+        break;
+    case G_SOCKET_CLIENT_COMPLETE:
+        loadTiming.connectEnd = deltaTime;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+#if SOUP_CHECK_VERSION(2, 49, 91)
+void NetworkDataTask::startingCallback(SoupMessage* soupMessage, NetworkDataTask* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
+        return;
+
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->didStartRequest();
+}
+#else
+void NetworkDataTask::requestStartedCallback(SoupSession* session, SoupMessage* soupMessage, SoupSocket*, NetworkDataTask* task)
+{
+    ASSERT(session == task->m_session->soupSession());
+    if (soupMessage != task->m_soupMessage.get())
+        return;
+
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
+        return;
+
+    task->didStartRequest();
+}
+#endif
+
+void NetworkDataTask::didStartRequest()
+{
+    m_response.networkLoadTiming().requestStart = monotonicallyIncreasingTimeMS() - m_startTime;
+}
+
+void NetworkDataTask::restartedCallback(SoupMessage* soupMessage, NetworkDataTask* task)
+{
+    // Called each time the message is going to be sent again except the first time.
+    // This happens when libsoup handles HTTP authentication.
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
+        return;
+
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->didRestart();
+}
+
+void NetworkDataTask::didRestart()
+{
+    m_startTime = monotonicallyIncreasingTimeMS();
+}
+#endif // ENABLE(WEB_TIMING)
+
+} // namespace WebKit
+
diff --git a/Source/WebKit2/NetworkProcess/soup/NetworkSessionSoup.cpp b/Source/WebKit2/NetworkProcess/soup/NetworkSessionSoup.cpp
new file mode 100644 (file)
index 0000000..34c2c77
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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 "NetworkSession.h"
+
+#include <WebCore/NetworkStorageSession.h>
+#include <WebCore/SoupNetworkSession.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+Ref<NetworkSession> NetworkSession::create(Type type, SessionID sessionID, CustomProtocolManager*)
+{
+    return adoptRef(*new NetworkSession(type, sessionID, nullptr));
+}
+
+NetworkSession& NetworkSession::defaultSession()
+{
+    ASSERT(isMainThread());
+    static NetworkSession* session = &NetworkSession::create(NetworkSession::Type::Normal, SessionID::defaultSessionID(), nullptr).leakRef();
+    return *session;
+}
+
+NetworkStorageSession& NetworkSession::networkStorageSession() const
+{
+    auto* storageSession = NetworkStorageSession::storageSession(m_sessionID);
+    RELEASE_ASSERT(storageSession);
+    return *storageSession;
+}
+
+NetworkSession::NetworkSession(Type type, SessionID sessionID, CustomProtocolManager*)
+    : m_sessionID(sessionID)
+{
+}
+
+NetworkSession::~NetworkSession()
+{
+}
+
+SoupSession* NetworkSession::soupSession() const
+{
+    return networkStorageSession().soupNetworkSession().soupSession();
+}
+
+void NetworkSession::invalidateAndCancel()
+{
+    for (auto* task : m_dataTaskSet)
+        task->invalidateAndCancel();
+}
+
+void NetworkSession::clearCredentials()
+{
+}
+
+} // namespace WebKit
index 6aecb7f..8fb64fa 100644 (file)
@@ -28,6 +28,8 @@
 #include "config.h"
 #include "RemoteNetworkingContext.h"
 
+#include "NetworkSession.h"
+#include "SessionTracker.h"
 #include <WebCore/NetworkStorageSession.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/ResourceHandle.h>
@@ -45,13 +47,21 @@ bool RemoteNetworkingContext::isValid() const
     return true;
 }
 
-void RemoteNetworkingContext::ensurePrivateBrowsingSession(SessionID)
+void RemoteNetworkingContext::ensurePrivateBrowsingSession(SessionID sessionID)
 {
-    notImplemented();
+    ASSERT(sessionID.isEphemeral());
+
+    if (NetworkStorageSession::storageSession(sessionID))
+        return;
+
+    NetworkStorageSession::ensurePrivateBrowsingSession(sessionID, String::number(sessionID.sessionID()));
+    SessionTracker::setSession(sessionID, NetworkSession::create(NetworkSession::Type::Ephemeral, sessionID, nullptr));
 }
 
 NetworkStorageSession& RemoteNetworkingContext::storageSession() const
 {
+    if (auto session = NetworkStorageSession::storageSession(m_sessionID))
+        return *session;
     return NetworkStorageSession::defaultStorageSession();
 }
 
index f125951..babf2a7 100644 (file)
@@ -14,7 +14,9 @@ list(APPEND WebKit2_SOURCES
 
     NetworkProcess/efl/NetworkProcessMainEfl.cpp
 
+    NetworkProcess/soup/NetworkDataTaskSoup.cpp
     NetworkProcess/soup/NetworkProcessSoup.cpp
+    NetworkProcess/soup/NetworkSessionSoup.cpp
     NetworkProcess/soup/RemoteNetworkingContextSoup.cpp
 
     Platform/IPC/unix/AttachmentUnix.cpp
index beea00e..6fbda22 100644 (file)
@@ -39,8 +39,10 @@ list(APPEND WebKit2_SOURCES
     NetworkProcess/cache/NetworkCacheDataSoup.cpp
     NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp
 
+    NetworkProcess/soup/NetworkDataTaskSoup.cpp
     NetworkProcess/soup/NetworkProcessMainSoup.cpp
     NetworkProcess/soup/NetworkProcessSoup.cpp
+    NetworkProcess/soup/NetworkSessionSoup.cpp
     NetworkProcess/soup/RemoteNetworkingContextSoup.cpp
 
     Platform/IPC/glib/GSocketMonitor.cpp
index 7fc1614..6372cd2 100644 (file)
 
 #include "MessageReceiver.h"
 #include "NetworkProcessSupplement.h"
-#include "NetworkSession.h"
 #include "WebProcessSupplement.h"
 #include <WebCore/AuthenticationChallenge.h>
 #include <wtf/Forward.h>
+#include <wtf/Function.h>
 #include <wtf/HashMap.h>
 
 namespace WebCore {
@@ -48,6 +48,14 @@ class DownloadID;
 class PendingDownload;
 class WebFrame;
 
+enum class AuthenticationChallengeDisposition {
+    UseCredential,
+    PerformDefaultHandling,
+    Cancel,
+    RejectProtectionSpace
+};
+typedef Function<void(AuthenticationChallengeDisposition, const WebCore::Credential&)> ChallengeCompletionHandler;
+
 class AuthenticationManager : public WebProcessSupplement, public NetworkProcessSupplement, public IPC::MessageReceiver {
     WTF_MAKE_NONCOPYABLE(AuthenticationManager);
 public:
index 201d4a8..2f9871c 100644 (file)
@@ -27,6 +27,7 @@
 #include "config.h"
 #include "WebFrameNetworkingContext.h"
 
+#include "NetworkSession.h"
 #include "SessionTracker.h"
 #include "WebFrame.h"
 #include "WebPage.h"
@@ -43,11 +44,13 @@ namespace WebKit {
 void WebFrameNetworkingContext::ensurePrivateBrowsingSession(SessionID sessionID)
 {
     ASSERT(isMainThread());
+    ASSERT(sessionID.isEphemeral());
 
     if (NetworkStorageSession::storageSession(sessionID))
         return;
 
     NetworkStorageSession::ensurePrivateBrowsingSession(sessionID, String::number(sessionID.sessionID()));
+    SessionTracker::setSession(sessionID, NetworkSession::create(NetworkSession::Type::Ephemeral, sessionID, nullptr));
 }
 
 void WebFrameNetworkingContext::setCookieAcceptPolicyForAllContexts(HTTPCookieAcceptPolicy policy)
index 83d9ce3..e1fe3ef 100644 (file)
@@ -37,6 +37,7 @@
 #include "Logging.h"
 #include "NetworkConnectionToWebProcessMessages.h"
 #include "NetworkProcessConnection.h"
+#include "NetworkSession.h"
 #include "PluginProcessConnectionManager.h"
 #include "SessionTracker.h"
 #include "StatisticsData.h"
index 1d91fbd..a97dd4c 100644 (file)
@@ -75,7 +75,7 @@
 #endif
 #endif
 
-#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || USE(SOUP)
 #ifndef USE_NETWORK_SESSION
 #define USE_NETWORK_SESSION 1
 #endif