1/*
2 * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DownloadManager.h"
28
29#include "Download.h"
30#include "NetworkBlobRegistry.h"
31#include "NetworkConnectionToWebProcess.h"
32#include "NetworkLoad.h"
33#include "NetworkSession.h"
34#include "PendingDownload.h"
35#include <WebCore/NotImplemented.h>
36#include <pal/SessionID.h>
37#include <wtf/StdLibExtras.h>
38
39namespace WebKit {
40using namespace WebCore;
41
42DownloadManager::DownloadManager(Client& client)
43 : m_client(client)
44{
45}
46
47void DownloadManager::startDownload(PAL::SessionID sessionID, DownloadID downloadID, const ResourceRequest& request, const String& suggestedName)
48{
49 auto* networkSession = client().networkSession(sessionID);
50 if (!networkSession)
51 return;
52
53 NetworkLoadParameters parameters;
54 parameters.sessionID = sessionID;
55 parameters.request = request;
56 parameters.clientCredentialPolicy = ClientCredentialPolicy::MayAskClientForCredentials;
57 if (request.url().protocolIsBlob())
58 parameters.blobFileReferences = client().networkBlobRegistry().filesInBlob(request.url());
59 parameters.storedCredentialsPolicy = sessionID.isEphemeral() ? StoredCredentialsPolicy::DoNotUse : StoredCredentialsPolicy::Use;
60
61 m_pendingDownloads.add(downloadID, std::make_unique<PendingDownload>(m_client.parentProcessConnectionForDownloads(), WTFMove(parameters), downloadID, *networkSession, &client().networkBlobRegistry().blobRegistry(), suggestedName));
62}
63
64void DownloadManager::dataTaskBecameDownloadTask(DownloadID downloadID, std::unique_ptr<Download>&& download)
65{
66 ASSERT(m_pendingDownloads.contains(downloadID));
67 if (auto pendingDownload = m_pendingDownloads.take(downloadID)) {
68#if PLATFORM(COCOA)
69 pendingDownload->didBecomeDownload(download);
70#endif
71 }
72 ASSERT(!m_downloads.contains(downloadID));
73 m_downloadsAfterDestinationDecided.remove(downloadID);
74 m_downloads.add(downloadID, WTFMove(download));
75}
76
77void DownloadManager::continueWillSendRequest(DownloadID downloadID, WebCore::ResourceRequest&& request)
78{
79 auto* pendingDownload = m_pendingDownloads.get(downloadID);
80 ASSERT(pendingDownload);
81 if (pendingDownload)
82 pendingDownload->continueWillSendRequest(WTFMove(request));
83}
84
85void DownloadManager::willDecidePendingDownloadDestination(NetworkDataTask& networkDataTask, ResponseCompletionHandler&& completionHandler)
86{
87 auto downloadID = networkDataTask.pendingDownloadID();
88 auto addResult = m_downloadsWaitingForDestination.set(downloadID, std::make_pair<RefPtr<NetworkDataTask>, ResponseCompletionHandler>(&networkDataTask, WTFMove(completionHandler)));
89 ASSERT_UNUSED(addResult, addResult.isNewEntry);
90}
91
92void DownloadManager::convertNetworkLoadToDownload(DownloadID downloadID, std::unique_ptr<NetworkLoad>&& networkLoad, ResponseCompletionHandler&& completionHandler, Vector<RefPtr<WebCore::BlobDataFileReference>>&& blobFileReferences, const ResourceRequest& request, const ResourceResponse& response)
93{
94 ASSERT(!m_pendingDownloads.contains(downloadID));
95 m_pendingDownloads.add(downloadID, std::make_unique<PendingDownload>(m_client.parentProcessConnectionForDownloads(), WTFMove(networkLoad), WTFMove(completionHandler), downloadID, request, response));
96}
97
98void DownloadManager::continueDecidePendingDownloadDestination(DownloadID downloadID, String destination, SandboxExtension::Handle&& sandboxExtensionHandle, bool allowOverwrite)
99{
100 if (m_downloadsWaitingForDestination.contains(downloadID)) {
101 auto pair = m_downloadsWaitingForDestination.take(downloadID);
102 auto networkDataTask = WTFMove(pair.first);
103 auto completionHandler = WTFMove(pair.second);
104 ASSERT(networkDataTask);
105 ASSERT(completionHandler);
106 ASSERT(m_pendingDownloads.contains(downloadID));
107
108 networkDataTask->setPendingDownloadLocation(destination, WTFMove(sandboxExtensionHandle), allowOverwrite);
109 completionHandler(PolicyAction::Download);
110 if (networkDataTask->state() == NetworkDataTask::State::Canceling || networkDataTask->state() == NetworkDataTask::State::Completed)
111 return;
112
113 if (m_downloads.contains(downloadID)) {
114 // The completion handler already called dataTaskBecameDownloadTask().
115 return;
116 }
117
118 ASSERT(!m_downloadsAfterDestinationDecided.contains(downloadID));
119 m_downloadsAfterDestinationDecided.set(downloadID, networkDataTask);
120 }
121}
122
123void DownloadManager::resumeDownload(PAL::SessionID sessionID, DownloadID downloadID, const IPC::DataReference& resumeData, const String& path, SandboxExtension::Handle&& sandboxExtensionHandle)
124{
125#if !PLATFORM(COCOA)
126 notImplemented();
127#else
128 auto download = std::make_unique<Download>(*this, downloadID, nullptr, sessionID);
129
130 download->resume(resumeData, path, WTFMove(sandboxExtensionHandle));
131 ASSERT(!m_downloads.contains(downloadID));
132 m_downloads.add(downloadID, WTFMove(download));
133#endif
134}
135
136void DownloadManager::cancelDownload(DownloadID downloadID)
137{
138 if (Download* download = m_downloads.get(downloadID)) {
139 ASSERT(!m_downloadsWaitingForDestination.contains(downloadID));
140 ASSERT(!m_pendingDownloads.contains(downloadID));
141 download->cancel();
142 return;
143 }
144 auto pendingDownload = m_pendingDownloads.take(downloadID);
145 if (m_downloadsWaitingForDestination.contains(downloadID)) {
146 auto pair = m_downloadsWaitingForDestination.take(downloadID);
147 auto networkDataTask = WTFMove(pair.first);
148 auto completionHandler = WTFMove(pair.second);
149 ASSERT(networkDataTask);
150 ASSERT(completionHandler);
151
152 networkDataTask->cancel();
153 completionHandler(PolicyAction::Ignore);
154 m_client.pendingDownloadCanceled(downloadID);
155 return;
156 }
157
158 if (pendingDownload)
159 pendingDownload->cancel();
160}
161
162#if PLATFORM(COCOA)
163void DownloadManager::publishDownloadProgress(DownloadID downloadID, const URL& url, SandboxExtension::Handle&& sandboxExtensionHandle)
164{
165 if (auto* download = m_downloads.get(downloadID))
166 download->publishProgress(url, WTFMove(sandboxExtensionHandle));
167 else if (auto* pendingDownload = m_pendingDownloads.get(downloadID))
168 pendingDownload->publishProgress(url, WTFMove(sandboxExtensionHandle));
169}
170#endif // PLATFORM(COCOA)
171
172void DownloadManager::downloadFinished(Download& download)
173{
174 ASSERT(m_downloads.contains(download.downloadID()));
175 m_downloads.remove(download.downloadID());
176}
177
178void DownloadManager::didCreateDownload()
179{
180 m_client.didCreateDownload();
181}
182
183void DownloadManager::didDestroyDownload()
184{
185 m_client.didDestroyDownload();
186}
187
188IPC::Connection* DownloadManager::downloadProxyConnection()
189{
190 return m_client.downloadProxyConnection();
191}
192
193AuthenticationManager& DownloadManager::downloadsAuthenticationManager()
194{
195 return m_client.downloadsAuthenticationManager();
196}
197
198void DownloadManager::applicationDidEnterBackground()
199{
200 for (auto& download : m_downloads.values())
201 download->applicationDidEnterBackground();
202}
203
204void DownloadManager::applicationWillEnterForeground()
205{
206 for (auto& download : m_downloads.values())
207 download->applicationWillEnterForeground();
208}
209
210} // namespace WebKit
211