Progress towards implementing downloads with NetworkSession
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Jan 2016 21:28:42 +0000 (21:28 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Jan 2016 21:28:42 +0000 (21:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=152760

Reviewed by Brady Eidson.

* NetworkProcess/Downloads/Download.cpp:
(WebKit::Download::Download):
There's no need to store the unused NetworkSession&.
(WebKit::Download::didStart):
(WebKit::Download::didReceiveAuthenticationChallenge):
Downloads with NetworkSession are NetworkLoads until the response is received, which is after authentication
challenges are handled by NetworkLoad's code.
(WebKit::Download::didReceiveResponse):
* NetworkProcess/Downloads/Download.h:
* NetworkProcess/Downloads/DownloadManager.cpp:
(WebKit::DownloadManager::startDownload):
Create a PendingDownload, which is basically a NetworkLoad that knows that it will become a Download
when the response is received, regardless of whether or not there is a Content-Disposition header.
(WebKit::DownloadManager::dataTaskBecameDownloadTask):
* NetworkProcess/Downloads/DownloadManager.h:
* NetworkProcess/Downloads/PendingDownload.h: Added.
(WebKit::PendingDownload::PendingDownload):
Added a new NetworkLoadClient for requests that will become downloads.
A PendingDownload contains a NetworkLoad so we can always keep them together
and so it can handle setting its pending download id.
* WebKit2.xcodeproj/project.pbxproj:
* NetworkProcess/NetworkLoad.cpp:
(WebKit::NetworkLoad::NetworkLoad):
Avoid dereferencing a pointer if the NetworkSession hadn't been created when a NetworkLoad starts.
This shouldn't be possible, but it's good to not assume that all pointers are non-null.
(WebKit::NetworkLoad::cancel):
Add a null check in case the constructor doesn't make m_task.
(WebKit::NetworkLoad::convertTaskToDownload):
(WebKit::NetworkLoad::setPendingDownloadID):
Added for downloads that start with startDownload.  The pending DownloadID is used to indicate that
this request should always become a download, regardless of whether or not the response has a
Content-Disposition header.
(WebKit::NetworkLoad::willPerformHTTPRedirection):
(WebKit::NetworkLoad::didReceiveResponse):
* NetworkProcess/NetworkLoad.h:
There's no need to store a DownloadID here.  It's stored in the NetworkDataTask (m_task).
* NetworkProcess/NetworkSession.h:
(WebKit::NetworkDataTask::client):
(WebKit::NetworkDataTask::pendingDownloadID):
(WebKit::NetworkDataTask::setPendingDownloadID):
(WebKit::NetworkDataTask::downloadID): Deleted.
(WebKit::NetworkDataTask::setDownloadID): Deleted.
Renamed downloadID and setDownloadID to pendingDownloadID and setPendingDownloadID, respectively,
to indicate their use.  They are not the current downloadID, but they are the downloadID of the download
that will happen once the response is received and PolicyDownload will be returned in the completion handler.
* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(-[WKNetworkSessionDelegate URLSession:dataTask:didBecomeDownloadTask:]):
Call dataTaskBecameDownloadTask after didBecomeDownload because the networkDataTask is deleted by removing it
from m_pendingDownloads in dataTaskBecameDownloadTask.

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

Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/Downloads/Download.cpp
Source/WebKit2/NetworkProcess/Downloads/Download.h
Source/WebKit2/NetworkProcess/Downloads/DownloadManager.cpp
Source/WebKit2/NetworkProcess/Downloads/DownloadManager.h
Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h [new file with mode: 0644]
Source/WebKit2/NetworkProcess/NetworkLoad.cpp
Source/WebKit2/NetworkProcess/NetworkLoad.h
Source/WebKit2/NetworkProcess/NetworkSession.h
Source/WebKit2/NetworkProcess/cocoa/NetworkSessionCocoa.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj

index 407fc4c..c7c2e7e 100644 (file)
@@ -1,3 +1,60 @@
+2016-01-07  Alex Christensen  <achristensen@webkit.org>
+
+        Progress towards implementing downloads with NetworkSession
+        https://bugs.webkit.org/show_bug.cgi?id=152760
+
+        Reviewed by Brady Eidson.
+
+        * NetworkProcess/Downloads/Download.cpp:
+        (WebKit::Download::Download):
+        There's no need to store the unused NetworkSession&.
+        (WebKit::Download::didStart):
+        (WebKit::Download::didReceiveAuthenticationChallenge):
+        Downloads with NetworkSession are NetworkLoads until the response is received, which is after authentication
+        challenges are handled by NetworkLoad's code.
+        (WebKit::Download::didReceiveResponse):
+        * NetworkProcess/Downloads/Download.h:
+        * NetworkProcess/Downloads/DownloadManager.cpp:
+        (WebKit::DownloadManager::startDownload):
+        Create a PendingDownload, which is basically a NetworkLoad that knows that it will become a Download 
+        when the response is received, regardless of whether or not there is a Content-Disposition header.
+        (WebKit::DownloadManager::dataTaskBecameDownloadTask):
+        * NetworkProcess/Downloads/DownloadManager.h:
+        * NetworkProcess/Downloads/PendingDownload.h: Added.
+        (WebKit::PendingDownload::PendingDownload):
+        Added a new NetworkLoadClient for requests that will become downloads.
+        A PendingDownload contains a NetworkLoad so we can always keep them together
+        and so it can handle setting its pending download id.
+        * WebKit2.xcodeproj/project.pbxproj:
+        * NetworkProcess/NetworkLoad.cpp:
+        (WebKit::NetworkLoad::NetworkLoad):
+        Avoid dereferencing a pointer if the NetworkSession hadn't been created when a NetworkLoad starts.
+        This shouldn't be possible, but it's good to not assume that all pointers are non-null.
+        (WebKit::NetworkLoad::cancel):
+        Add a null check in case the constructor doesn't make m_task.
+        (WebKit::NetworkLoad::convertTaskToDownload):
+        (WebKit::NetworkLoad::setPendingDownloadID):
+        Added for downloads that start with startDownload.  The pending DownloadID is used to indicate that
+        this request should always become a download, regardless of whether or not the response has a 
+        Content-Disposition header.
+        (WebKit::NetworkLoad::willPerformHTTPRedirection):
+        (WebKit::NetworkLoad::didReceiveResponse):
+        * NetworkProcess/NetworkLoad.h:
+        There's no need to store a DownloadID here.  It's stored in the NetworkDataTask (m_task).
+        * NetworkProcess/NetworkSession.h:
+        (WebKit::NetworkDataTask::client):
+        (WebKit::NetworkDataTask::pendingDownloadID):
+        (WebKit::NetworkDataTask::setPendingDownloadID):
+        (WebKit::NetworkDataTask::downloadID): Deleted.
+        (WebKit::NetworkDataTask::setDownloadID): Deleted.
+        Renamed downloadID and setDownloadID to pendingDownloadID and setPendingDownloadID, respectively,
+        to indicate their use.  They are not the current downloadID, but they are the downloadID of the download
+        that will happen once the response is received and PolicyDownload will be returned in the completion handler.
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (-[WKNetworkSessionDelegate URLSession:dataTask:didBecomeDownloadTask:]):
+        Call dataTaskBecameDownloadTask after didBecomeDownload because the networkDataTask is deleted by removing it 
+        from m_pendingDownloads in dataTaskBecameDownloadTask.
+
 2016-01-06  Simon Fraser  <simon.fraser@apple.com>
 
         Add a setting and preferences to enable display-list drawing. Does nothing yet.
index 0adb87f..4d2398a 100644 (file)
@@ -44,15 +44,13 @@ using namespace WebCore;
 namespace WebKit {
 
 #if USE(NETWORK_SESSION)
-Download::Download(DownloadManager& downloadManager, const NetworkSession& session, DownloadID downloadID)
+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_session(session)
-#else
+#if !USE(NETWORK_SESSION)
     , m_request(request)
 #endif
 {
@@ -80,14 +78,12 @@ void Download::didStart()
 }
 #endif
 
+#if !USE(NETWORK_SESSION)
 void Download::didReceiveAuthenticationChallenge(const AuthenticationChallenge& authenticationChallenge)
 {
-#if USE(NETWORK_SESSION)
-    notImplemented();
-#else
     m_downloadManager.downloadsAuthenticationManager().didReceiveAuthenticationChallenge(*this, authenticationChallenge);
-#endif
 }
+#endif
 
 void Download::didReceiveResponse(const ResourceResponse& response)
 {
index ff8a85d..1f5b979 100644 (file)
@@ -76,7 +76,7 @@ class Download : public IPC::MessageSender {
     WTF_MAKE_NONCOPYABLE(Download);
 public:
 #if USE(NETWORK_SESSION)
-    Download(DownloadManager&, const NetworkSession&, DownloadID);
+    Download(DownloadManager&, DownloadID);
 #else
     Download(DownloadManager&, DownloadID, const WebCore::ResourceRequest&);
 #endif
@@ -97,8 +97,8 @@ public:
     void didStart(const WebCore::ResourceRequest&);
 #else
     void didStart();
-#endif
     void didReceiveAuthenticationChallenge(const WebCore::AuthenticationChallenge&);
+#endif
     void didReceiveResponse(const WebCore::ResourceResponse&);
     void didReceiveData(uint64_t length);
     bool shouldDecodeSourceDataOfMIMEType(const String& mimeType);
@@ -141,7 +141,6 @@ private:
 
 #if PLATFORM(COCOA)
 #if USE(NETWORK_SESSION)
-    const NetworkSession& m_session;
     RetainPtr<NSURLSessionDownloadTask> m_download;
 #else
     RetainPtr<NSURLDownload> m_nsURLDownload;
index 8339b64..e1de93d 100644 (file)
@@ -27,6 +27,8 @@
 #include "DownloadManager.h"
 
 #include "Download.h"
+#include "NetworkSession.h"
+#include "PendingDownload.h"
 #include "SessionTracker.h"
 #include <WebCore/NotImplemented.h>
 #include <WebCore/SessionID.h>
@@ -47,21 +49,27 @@ void DownloadManager::startDownload(SessionID sessionID, DownloadID downloadID,
     auto* networkSession = SessionTracker::networkSession(sessionID);
     if (!networkSession)
         return;
-    auto download = std::make_unique<Download>(*this, *networkSession, downloadID);
-    download->didStart(request);
+    NetworkLoadParameters parameters;
+    parameters.sessionID = sessionID;
+    parameters.request = request;
+    m_pendingDownloads.add(downloadID, std::make_unique<PendingDownload>(parameters, downloadID));
 #else
     auto download = std::make_unique<Download>(*this, downloadID, request);
     download->start();
-#endif
 
     ASSERT(!m_downloads.contains(downloadID));
     m_downloads.add(downloadID, WTFMove(download));
+#endif
 }
 
 #if USE(NETWORK_SESSION)
-void DownloadManager::dataTaskBecameDownloadTask(DownloadID downloadID, std::unique_ptr<Download>&& download)
+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;
 }
 #else
 void DownloadManager::convertHandleToDownload(DownloadID downloadID, ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& response)
index 7eef79d..21dd7df 100644 (file)
@@ -27,6 +27,7 @@
 #define DownloadManager_h
 
 #include "DownloadID.h"
+#include "PendingDownload.h"
 #include "SandboxExtension.h"
 #include <WebCore/NotImplemented.h>
 #include <wtf/Forward.h>
@@ -51,6 +52,7 @@ namespace WebKit {
 
 class AuthenticationManager;
 class Download;
+class PendingDownload;
 
 class DownloadManager {
     WTF_MAKE_NONCOPYABLE(DownloadManager);
@@ -70,7 +72,7 @@ public:
 
     void startDownload(WebCore::SessionID, DownloadID, const WebCore::ResourceRequest&);
 #if USE(NETWORK_SESSION)
-    void dataTaskBecameDownloadTask(DownloadID, std::unique_ptr<Download>&&);
+    std::unique_ptr<PendingDownload> dataTaskBecameDownloadTask(DownloadID, std::unique_ptr<Download>&&);
 #else
     void convertHandleToDownload(DownloadID, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
 #endif
@@ -93,6 +95,9 @@ public:
 
 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;
 };
 
diff --git a/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h b/Source/WebKit2/NetworkProcess/Downloads/PendingDownload.h
new file mode 100644 (file)
index 0000000..9fa75ff
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 "NetworkLoad.h"
+
+namespace WebKit {
+
+class PendingDownload : public NetworkLoadClient {
+public:
+    PendingDownload(const NetworkLoadParameters& parameters, DownloadID downloadID)
+        : m_networkLoad(std::make_unique<NetworkLoad>(*this, parameters))
+    {
+        m_networkLoad->setPendingDownloadID(downloadID);
+    }
+
+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
+    {
+        // FIXME: We should ask the UI process directly if we actually want to continue this request.
+        m_networkLoad->continueWillSendRequest(redirectRequest);
+    };
+    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 { m_networkLoad = nullptr; }
+#if PLATFORM(COCOA)
+    virtual void willCacheResponseAsync(CFCachedURLResponseRef) override { }
+#endif
+private:
+    std::unique_ptr<NetworkLoad> m_networkLoad;
+};
+
+}
+
+#endif
+
+#endif
index 57081fe..d2b4a9f 100644 (file)
@@ -47,14 +47,16 @@ NetworkLoad::NetworkLoad(NetworkLoadClient& client, const NetworkLoadParameters&
     : m_client(client)
     , m_parameters(parameters)
     , m_networkingContext(RemoteNetworkingContext::create(parameters.sessionID, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect))
-#if USE(NETWORK_SESSION)
-    , m_task(SessionTracker::networkSession(parameters.sessionID)->createDataTaskWithRequest(parameters.request, *this))
-#endif
     , m_currentRequest(parameters.request)
 {
 #if USE(NETWORK_SESSION)
-    if (!parameters.defersLoading)
-        m_task->resume();
+    if (!parameters.defersLoading) {
+        if (auto* networkSession = SessionTracker::networkSession(parameters.sessionID)) {
+            m_task = networkSession->createDataTaskWithRequest(parameters.request, *this);
+            m_task->resume();
+        } else
+            ASSERT_NOT_REACHED();
+    }
 #else
     m_handle = ResourceHandle::create(m_networkingContext.get(), parameters.request, this, parameters.defersLoading, parameters.contentSniffingPolicy == SniffContent);
 #endif
@@ -88,7 +90,8 @@ void NetworkLoad::setDefersLoading(bool defers)
 void NetworkLoad::cancel()
 {
 #if USE(NETWORK_SESSION)
-    m_task->cancel();
+    if (m_task)
+        m_task->cancel();
 #else
     if (m_handle)
         m_handle->cancel();
@@ -160,13 +163,18 @@ void NetworkLoad::sharedWillSendRedirectedRequest(const ResourceRequest& request
 
 void NetworkLoad::convertTaskToDownload(DownloadID downloadID)
 {
-    m_task->setDownloadID(downloadID);
+    m_task->setPendingDownloadID(downloadID);
     
     ASSERT(m_responseCompletionHandler);
     m_responseCompletionHandler(PolicyDownload);
     m_responseCompletionHandler = nullptr;
 }
 
+void NetworkLoad::setPendingDownloadID(DownloadID downloadID)
+{
+    m_task->setPendingDownloadID(downloadID);
+}
+
 void NetworkLoad::willPerformHTTPRedirection(const ResourceResponse& response, const ResourceRequest& request, RedirectCompletionHandler completionHandler)
 {
     ASSERT(!m_redirectCompletionHandler);
@@ -202,7 +210,9 @@ void NetworkLoad::didReceiveChallenge(const AuthenticationChallenge& challenge,
 void NetworkLoad::didReceiveResponse(const ResourceResponse& response, ResponseCompletionHandler completionHandler)
 {
     ASSERT(isMainThread());
-    if (sharedDidReceiveResponse(response) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
+    if (m_task && m_task->pendingDownloadID().downloadID())
+        completionHandler(PolicyDownload);
+    else if (sharedDidReceiveResponse(response) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
         completionHandler(PolicyUse);
     else
         m_responseCompletionHandler = completionHandler;
index f9223b9..ee6354d 100644 (file)
@@ -62,6 +62,7 @@ public:
 
 #if USE(NETWORK_SESSION)
     void convertTaskToDownload(DownloadID);
+    void setPendingDownloadID(DownloadID);
     
     // NetworkSessionTaskClient.
     virtual void willPerformHTTPRedirection(const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, std::function<void(const WebCore::ResourceRequest&)>) final override;
@@ -125,7 +126,6 @@ private:
     ChallengeCompletionHandler m_challengeCompletionHandler;
     ResponseCompletionHandler m_responseCompletionHandler;
     RedirectCompletionHandler m_redirectCompletionHandler;
-    DownloadID m_downloadID;
 #else
     RefPtr<WebCore::ResourceHandle> m_handle;
 #endif
index 666b10a..2958855 100644 (file)
@@ -97,18 +97,18 @@ public:
 
     NetworkSessionTaskClient& client() { return m_client; }
 
-    DownloadID downloadID() { return m_downloadID; }
-    void setDownloadID(DownloadID downloadID)
+    DownloadID pendingDownloadID() { return m_pendingDownloadID; }
+    void setPendingDownloadID(DownloadID downloadID)
     {
-        ASSERT(!m_downloadID.downloadID());
+        ASSERT(!m_pendingDownloadID.downloadID());
         ASSERT(downloadID.downloadID());
-        m_downloadID = downloadID;
+        m_pendingDownloadID = downloadID;
     }
     
 private:
     NetworkSession& m_session;
     NetworkSessionTaskClient& m_client;
-    DownloadID m_downloadID;
+    DownloadID m_pendingDownloadID;
 #if PLATFORM(COCOA)
     RetainPtr<NSURLSessionDataTask> m_task;
 #endif
index fae1cc1..9b92c5e 100644 (file)
@@ -166,12 +166,12 @@ static NSURLSessionAuthChallengeDisposition toNSURLSessionAuthChallengeDispositi
 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
 {
     if (auto* networkDataTask = _session->dataTaskForIdentifier([dataTask taskIdentifier])) {
-        auto downloadID = networkDataTask->downloadID();
+        auto downloadID = networkDataTask->pendingDownloadID();
         auto& downloadManager = WebKit::NetworkProcess::singleton().downloadManager();
-        auto download = std::make_unique<WebKit::Download>(downloadManager, *_session, downloadID);
+        auto download = std::make_unique<WebKit::Download>(downloadManager, downloadID);
         download->didStart([downloadTask currentRequest]);
         download->didReceiveResponse([downloadTask response]);
-        downloadManager.dataTaskBecameDownloadTask(downloadID, WTFMove(download));
+        auto pendingDownload = downloadManager.dataTaskBecameDownloadTask(downloadID, WTFMove(download));
 
         networkDataTask->client().didBecomeDownload();
 
index eca5260..579de47 100644 (file)
                5C14271D1C23F8CF00D41183 /* CustomProtocolManagerCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C14271B1C23F8CC00D41183 /* CustomProtocolManagerCocoa.mm */; };
                5C20CB9D1BB0DCFA00895BB1 /* NetworkSessionCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C20CB9B1BB0DCD200895BB1 /* NetworkSessionCocoa.mm */; };
                5C20CBA01BB1ECD800895BB1 /* NetworkSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C20CB9E1BB0DD1800895BB1 /* NetworkSession.h */; };
+               5C298DA01C3DF02100470AFE /* PendingDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C298D9E1C3DEF2900470AFE /* PendingDownload.h */; };
                5DA6ED0A1490606900B41D12 /* DynamicLinkerEnvironmentExtractor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DA6ED081490606900B41D12 /* DynamicLinkerEnvironmentExtractor.h */; };
                5DA6ED0B1490606900B41D12 /* DynamicLinkerEnvironmentExtractor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5DA6ED091490606900B41D12 /* DynamicLinkerEnvironmentExtractor.mm */; };
                6501BD1A12F1243400E9F248 /* WKBundleInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65B86F1712F11D7B00B7DD8A /* WKBundleInspector.cpp */; };
                5C14271B1C23F8CC00D41183 /* CustomProtocolManagerCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CustomProtocolManagerCocoa.mm; path = NetworkProcess/CustomProtocols/Cocoa/CustomProtocolManagerCocoa.mm; sourceTree = "<group>"; };
                5C20CB9B1BB0DCD200895BB1 /* NetworkSessionCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkSessionCocoa.mm; path = NetworkProcess/cocoa/NetworkSessionCocoa.mm; sourceTree = "<group>"; };
                5C20CB9E1BB0DD1800895BB1 /* NetworkSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkSession.h; path = NetworkProcess/NetworkSession.h; sourceTree = "<group>"; };
+               5C298D9E1C3DEF2900470AFE /* PendingDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PendingDownload.h; path = NetworkProcess/Downloads/PendingDownload.h; sourceTree = "<group>"; };
                5D442A5516D5856700AC3331 /* PluginService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PluginService.entitlements; sourceTree = "<group>"; };
                5DA6ED081490606900B41D12 /* DynamicLinkerEnvironmentExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLinkerEnvironmentExtractor.h; sourceTree = "<group>"; };
                5DA6ED091490606900B41D12 /* DynamicLinkerEnvironmentExtractor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DynamicLinkerEnvironmentExtractor.mm; sourceTree = "<group>"; };
                5C1426F11C23F81700D41183 /* Downloads */ = {
                        isa = PBXGroup;
                        children = (
+                               5C298D9E1C3DEF2900470AFE /* PendingDownload.h */,
                                5C14270C1C23F87700D41183 /* ios */,
                                5C14270B1C23F87100D41183 /* mac */,
                                5C1427081C23F85200D41183 /* cocoa */,
                                1ABC3DFC1899F51C004F0626 /* WKNavigationDelegate.h in Headers */,
                                1AA20D5118AD50E0005D1ED4 /* WKNavigationDelegatePrivate.h in Headers */,
                                1ABC3DF11899C6B6004F0626 /* WKNavigationInternal.h in Headers */,
+                               5C298DA01C3DF02100470AFE /* PendingDownload.h in Headers */,
                                1ACC87BA1981C341003D1AF4 /* WKNavigationPrivate.h in Headers */,
                                2D3A65E31A7C3A9300CAC637 /* WKNavigationRef.h in Headers */,
                                1A1B0EB618A424950038481A /* WKNavigationResponse.h in Headers */,