Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebKit / UIProcess / Downloads / DownloadProxy.cpp
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/FileSystem.h>
40 #include <WebCore/MIMETypeRegistry.h>
41 #include <wtf/text/CString.h>
42 #include <wtf/text/WTFString.h>
43
44 namespace WebKit {
45 using namespace WebCore;
46
47 static uint64_t generateDownloadID()
48 {
49     static uint64_t uniqueDownloadID = 0;
50     return ++uniqueDownloadID;
51 }
52     
53 Ref<DownloadProxy> DownloadProxy::create(DownloadProxyMap& downloadProxyMap, WebProcessPool& processPool, const ResourceRequest& resourceRequest)
54 {
55     return adoptRef(*new DownloadProxy(downloadProxyMap, processPool, resourceRequest));
56 }
57
58 DownloadProxy::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
66 DownloadProxy::~DownloadProxy()
67 {
68     ASSERT(!m_processPool);
69 }
70
71 void 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
80 void DownloadProxy::invalidate()
81 {
82     ASSERT(m_processPool);
83     m_processPool = nullptr;
84 }
85
86 void DownloadProxy::processDidClose()
87 {
88     if (!m_processPool)
89         return;
90
91     m_processPool->downloadClient().processDidCrash(*m_processPool, *this);
92 }
93
94 WebPageProxy* DownloadProxy::originatingPage() const
95 {
96     return m_originatingPage.get();
97 }
98
99 void DownloadProxy::setOriginatingPage(WebPageProxy* page)
100 {
101     m_originatingPage = makeWeakPtr(page);
102 }
103
104 #if PLATFORM(COCOA)
105 void 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
119 void 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
133 void 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
143 void 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
162 void DownloadProxy::didReceiveResponse(const ResourceResponse& response)
163 {
164     if (!m_processPool)
165         return;
166
167     m_processPool->downloadClient().didReceiveResponse(*m_processPool, *this, response);
168 }
169
170 void DownloadProxy::didReceiveData(uint64_t length)
171 {
172     if (!m_processPool)
173         return;
174
175     m_processPool->downloadClient().didReceiveData(*m_processPool, *this, length);
176 }
177
178 void 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
196 void DownloadProxy::didCreateDestination(const String& path)
197 {
198     if (!m_processPool)
199         return;
200
201     m_processPool->downloadClient().didCreateDestination(*m_processPool, *this, path);
202 }
203
204 void 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
215 static 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
223 void 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
236 void 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