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 | |
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 | |
248 | |