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 "DownloadProxy.h"
28
29#include "APIData.h"
30#include "APIDownloadClient.h"
31#include "AuthenticationChallengeProxy.h"
32#include "DataReference.h"
33#include "DownloadProxyMap.h"
34#include "NetworkProcessMessages.h"
35#include "NetworkProcessProxy.h"
36#include "WebProcessMessages.h"
37#include "WebProcessPool.h"
38#include "WebProtectionSpace.h"
39#include <WebCore/MIMETypeRegistry.h>
40#include <wtf/FileSystem.h>
41#include <wtf/text/CString.h>
42#include <wtf/text/WTFString.h>
43
44namespace WebKit {
45using namespace WebCore;
46
47static uint64_t generateDownloadID()
48{
49 static uint64_t uniqueDownloadID = 0;
50 return ++uniqueDownloadID;
51}
52
53Ref<DownloadProxy> DownloadProxy::create(DownloadProxyMap& downloadProxyMap, WebProcessPool& processPool, const ResourceRequest& resourceRequest)
54{
55 return adoptRef(*new DownloadProxy(downloadProxyMap, processPool, resourceRequest));
56}
57
58DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebProcessPool& processPool, const ResourceRequest& resourceRequest)
59 : m_downloadProxyMap(downloadProxyMap)
60 , m_processPool(&processPool)
61 , m_downloadID(generateDownloadID())
62 , m_request(resourceRequest)
63{
64}
65
66DownloadProxy::~DownloadProxy()
67{
68 ASSERT(!m_processPool);
69}
70
71void DownloadProxy::cancel()
72{
73 if (!m_processPool)
74 return;
75
76 if (NetworkProcessProxy* networkProcess = m_processPool->networkProcess())
77 networkProcess->send(Messages::NetworkProcess::CancelDownload(m_downloadID), 0);
78}
79
80void DownloadProxy::invalidate()
81{
82 ASSERT(m_processPool);
83 m_processPool = nullptr;
84}
85
86void DownloadProxy::processDidClose()
87{
88 if (!m_processPool)
89 return;
90
91 m_processPool->downloadClient().processDidCrash(*m_processPool, *this);
92}
93
94WebPageProxy* DownloadProxy::originatingPage() const
95{
96 return m_originatingPage.get();
97}
98
99void DownloadProxy::setOriginatingPage(WebPageProxy* page)
100{
101 m_originatingPage = makeWeakPtr(page);
102}
103
104#if PLATFORM(COCOA)
105void DownloadProxy::publishProgress(const URL& URL)
106{
107 if (!m_processPool)
108 return;
109
110 if (auto* networkProcess = m_processPool->networkProcess()) {
111 SandboxExtension::Handle handle;
112 bool createdSandboxExtension = SandboxExtension::createHandle(URL.fileSystemPath(), SandboxExtension::Type::ReadWrite, handle);
113 ASSERT_UNUSED(createdSandboxExtension, createdSandboxExtension);
114 networkProcess->send(Messages::NetworkProcess::PublishDownloadProgress(m_downloadID, URL, handle), 0);
115 }
116}
117#endif // PLATFORM(COCOA)
118
119void DownloadProxy::didStart(const ResourceRequest& request, const String& suggestedFilename)
120{
121 m_request = request;
122 m_suggestedFilename = suggestedFilename;
123
124 if (m_redirectChain.isEmpty() || m_redirectChain.last() != request.url())
125 m_redirectChain.append(request.url());
126
127 if (!m_processPool)
128 return;
129
130 m_processPool->downloadClient().didStart(*m_processPool, *this);
131}
132
133void DownloadProxy::didReceiveAuthenticationChallenge(AuthenticationChallenge&& authenticationChallenge, uint64_t challengeID)
134{
135 if (!m_processPool)
136 return;
137
138 auto authenticationChallengeProxy = AuthenticationChallengeProxy::create(WTFMove(authenticationChallenge), challengeID, makeRef(*m_processPool->networkingProcessConnection()), nullptr);
139
140 m_processPool->downloadClient().didReceiveAuthenticationChallenge(*m_processPool, *this, authenticationChallengeProxy.get());
141}
142
143void DownloadProxy::willSendRequest(ResourceRequest&& proposedRequest, const ResourceResponse& redirectResponse)
144{
145 if (!m_processPool)
146 return;
147
148 m_processPool->downloadClient().willSendRequest(*m_processPool, *this, WTFMove(proposedRequest), redirectResponse, [this, protectedThis = makeRef(*this)](ResourceRequest&& newRequest) {
149 m_redirectChain.append(newRequest.url());
150
151 if (!protectedThis->m_processPool)
152 return;
153
154 auto* networkProcessProxy = protectedThis->m_processPool->networkProcess();
155 if (!networkProcessProxy)
156 return;
157
158 networkProcessProxy->send(Messages::NetworkProcess::ContinueWillSendRequest(protectedThis->m_downloadID, newRequest), 0);
159 });
160}
161
162void DownloadProxy::didReceiveResponse(const ResourceResponse& response)
163{
164 if (!m_processPool)
165 return;
166
167 m_processPool->downloadClient().didReceiveResponse(*m_processPool, *this, response);
168}
169
170void DownloadProxy::didReceiveData(uint64_t length)
171{
172 if (!m_processPool)
173 return;
174
175 m_processPool->downloadClient().didReceiveData(*m_processPool, *this, length);
176}
177
178void DownloadProxy::decideDestinationWithSuggestedFilenameAsync(DownloadID downloadID, const String& suggestedFilename)
179{
180 if (!m_processPool)
181 return;
182
183 m_processPool->downloadClient().decideDestinationWithSuggestedFilename(*m_processPool, *this, suggestedFilename, [this, protectedThis = makeRef(*this), downloadID = downloadID] (AllowOverwrite allowOverwrite, String destination) {
184 SandboxExtension::Handle sandboxExtensionHandle;
185 if (!destination.isNull())
186 SandboxExtension::createHandle(destination, SandboxExtension::Type::ReadWrite, sandboxExtensionHandle);
187
188 if (!m_processPool)
189 return;
190
191 if (auto* networkProcess = m_processPool->networkProcess())
192 networkProcess->send(Messages::NetworkProcess::ContinueDecidePendingDownloadDestination(downloadID, destination, sandboxExtensionHandle, allowOverwrite == AllowOverwrite::Yes), 0);
193 });
194}
195
196void DownloadProxy::didCreateDestination(const String& path)
197{
198 if (!m_processPool)
199 return;
200
201 m_processPool->downloadClient().didCreateDestination(*m_processPool, *this, path);
202}
203
204void DownloadProxy::didFinish()
205{
206 if (!m_processPool)
207 return;
208
209 m_processPool->downloadClient().didFinish(*m_processPool, *this);
210
211 // This can cause the DownloadProxy object to be deleted.
212 m_downloadProxyMap.downloadFinished(*this);
213}
214
215static RefPtr<API::Data> createData(const IPC::DataReference& data)
216{
217 if (data.isEmpty())
218 return 0;
219
220 return API::Data::create(data.data(), data.size());
221}
222
223void DownloadProxy::didFail(const ResourceError& error, const IPC::DataReference& resumeData)
224{
225 if (!m_processPool)
226 return;
227
228 m_resumeData = createData(resumeData);
229
230 m_processPool->downloadClient().didFail(*m_processPool, *this, error);
231
232 // This can cause the DownloadProxy object to be deleted.
233 m_downloadProxyMap.downloadFinished(*this);
234}
235
236void DownloadProxy::didCancel(const IPC::DataReference& resumeData)
237{
238 m_resumeData = createData(resumeData);
239
240 m_processPool->downloadClient().didCancel(*m_processPool, *this);
241
242 // This can cause the DownloadProxy object to be deleted.
243 m_downloadProxyMap.downloadFinished(*this);
244}
245
246} // namespace WebKit
247
248