1 | /* |
2 | * Copyright (C) 2015 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 "NetworkLoad.h" |
28 | |
29 | #include "AuthenticationChallengeDisposition.h" |
30 | #include "AuthenticationManager.h" |
31 | #include "NetworkDataTaskBlob.h" |
32 | #include "NetworkProcess.h" |
33 | #include "NetworkSession.h" |
34 | #include "WebErrors.h" |
35 | #include <WebCore/ResourceRequest.h> |
36 | #include <WebCore/SharedBuffer.h> |
37 | #include <wtf/Seconds.h> |
38 | |
39 | namespace WebKit { |
40 | |
41 | using namespace WebCore; |
42 | |
43 | struct NetworkLoad::Throttle { |
44 | WTF_MAKE_STRUCT_FAST_ALLOCATED; |
45 | |
46 | Throttle(NetworkLoad& load, Seconds delay, ResourceResponse&& response, ResponseCompletionHandler&& handler) |
47 | : timer(load, &NetworkLoad::throttleDelayCompleted) |
48 | , response(WTFMove(response)) |
49 | , responseCompletionHandler(WTFMove(handler)) |
50 | { |
51 | timer.startOneShot(delay); |
52 | } |
53 | Timer timer; |
54 | ResourceResponse response; |
55 | ResponseCompletionHandler responseCompletionHandler; |
56 | }; |
57 | |
58 | NetworkLoad::NetworkLoad(NetworkLoadClient& client, BlobRegistryImpl* blobRegistry, NetworkLoadParameters&& parameters, NetworkSession& networkSession) |
59 | : m_client(client) |
60 | , m_networkProcess(networkSession.networkProcess()) |
61 | , m_parameters(WTFMove(parameters)) |
62 | , m_loadThrottleLatency(networkSession.loadThrottleLatency()) |
63 | , m_currentRequest(m_parameters.request) |
64 | { |
65 | initialize(networkSession, blobRegistry); |
66 | } |
67 | |
68 | void NetworkLoad::initialize(NetworkSession& networkSession, WebCore::BlobRegistryImpl* blobRegistry) |
69 | { |
70 | if (blobRegistry && m_parameters.request.url().protocolIsBlob()) |
71 | m_task = NetworkDataTaskBlob::create(networkSession, *blobRegistry, *this, m_parameters.request, m_parameters.contentSniffingPolicy, m_parameters.blobFileReferences); |
72 | else |
73 | m_task = NetworkDataTask::create(networkSession, *this, m_parameters); |
74 | |
75 | m_task->resume(); |
76 | } |
77 | |
78 | NetworkLoad::~NetworkLoad() |
79 | { |
80 | ASSERT(RunLoop::isMain()); |
81 | if (m_redirectCompletionHandler) |
82 | m_redirectCompletionHandler({ }); |
83 | if (m_task) |
84 | m_task->clearClient(); |
85 | } |
86 | |
87 | void NetworkLoad::cancel() |
88 | { |
89 | if (m_task) |
90 | m_task->cancel(); |
91 | } |
92 | |
93 | static inline void updateRequest(ResourceRequest& currentRequest, const ResourceRequest& newRequest) |
94 | { |
95 | #if PLATFORM(COCOA) |
96 | currentRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)); |
97 | #else |
98 | // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127. |
99 | currentRequest.updateFromDelegatePreservingOldProperties(newRequest); |
100 | #endif |
101 | } |
102 | |
103 | void NetworkLoad::updateRequestAfterRedirection(WebCore::ResourceRequest& newRequest) const |
104 | { |
105 | ResourceRequest updatedRequest = m_currentRequest; |
106 | updateRequest(updatedRequest, newRequest); |
107 | newRequest = WTFMove(updatedRequest); |
108 | } |
109 | |
110 | void NetworkLoad::continueWillSendRequest(WebCore::ResourceRequest&& newRequest) |
111 | { |
112 | updateRequest(m_currentRequest, newRequest); |
113 | |
114 | auto redirectCompletionHandler = std::exchange(m_redirectCompletionHandler, nullptr); |
115 | ASSERT(redirectCompletionHandler); |
116 | if (m_currentRequest.isNull()) { |
117 | NetworkLoadMetrics emptyMetrics; |
118 | didCompleteWithError(cancelledError(m_currentRequest), emptyMetrics); |
119 | if (redirectCompletionHandler) |
120 | redirectCompletionHandler({ }); |
121 | return; |
122 | } |
123 | |
124 | if (redirectCompletionHandler) |
125 | redirectCompletionHandler(ResourceRequest(m_currentRequest)); |
126 | } |
127 | |
128 | bool NetworkLoad::() const |
129 | { |
130 | return m_client.get().shouldCaptureExtraNetworkLoadMetrics(); |
131 | } |
132 | |
133 | bool NetworkLoad::isAllowedToAskUserForCredentials() const |
134 | { |
135 | return m_client.get().isAllowedToAskUserForCredentials(); |
136 | } |
137 | |
138 | void NetworkLoad::convertTaskToDownload(PendingDownload& pendingDownload, const ResourceRequest& updatedRequest, const ResourceResponse& response, ResponseCompletionHandler&& completionHandler) |
139 | { |
140 | if (!m_task) |
141 | return completionHandler(PolicyAction::Ignore); |
142 | |
143 | m_client = pendingDownload; |
144 | m_currentRequest = updatedRequest; |
145 | m_task->setPendingDownload(pendingDownload); |
146 | |
147 | m_networkProcess->findPendingDownloadLocation(*m_task.get(), WTFMove(completionHandler), response); |
148 | } |
149 | |
150 | void NetworkLoad::setPendingDownloadID(DownloadID downloadID) |
151 | { |
152 | if (!m_task) |
153 | return; |
154 | |
155 | m_task->setPendingDownloadID(downloadID); |
156 | } |
157 | |
158 | void NetworkLoad::setSuggestedFilename(const String& suggestedName) |
159 | { |
160 | if (!m_task) |
161 | return; |
162 | |
163 | m_task->setSuggestedFilename(suggestedName); |
164 | } |
165 | |
166 | void NetworkLoad::setPendingDownload(PendingDownload& pendingDownload) |
167 | { |
168 | if (!m_task) |
169 | return; |
170 | |
171 | m_task->setPendingDownload(pendingDownload); |
172 | } |
173 | |
174 | void NetworkLoad::willPerformHTTPRedirection(ResourceResponse&& redirectResponse, ResourceRequest&& request, RedirectCompletionHandler&& completionHandler) |
175 | { |
176 | ASSERT(!redirectResponse.isNull()); |
177 | ASSERT(RunLoop::isMain()); |
178 | ASSERT(!m_redirectCompletionHandler); |
179 | |
180 | redirectResponse.setSource(ResourceResponse::Source::Network); |
181 | m_redirectCompletionHandler = WTFMove(completionHandler); |
182 | |
183 | auto oldRequest = WTFMove(m_currentRequest); |
184 | request.setRequester(oldRequest.requester()); |
185 | |
186 | m_currentRequest = request; |
187 | m_client.get().willSendRedirectedRequest(WTFMove(oldRequest), WTFMove(request), WTFMove(redirectResponse)); |
188 | } |
189 | |
190 | void NetworkLoad::didReceiveChallenge(AuthenticationChallenge&& challenge, ChallengeCompletionHandler&& completionHandler) |
191 | { |
192 | auto scheme = challenge.protectionSpace().authenticationScheme(); |
193 | bool isTLSHandshake = scheme == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested |
194 | || scheme == ProtectionSpaceAuthenticationSchemeClientCertificateRequested; |
195 | if (!isAllowedToAskUserForCredentials() && !isTLSHandshake) { |
196 | m_client.get().didBlockAuthenticationChallenge(); |
197 | completionHandler(AuthenticationChallengeDisposition::UseCredential, { }); |
198 | return; |
199 | } |
200 | |
201 | if (auto* pendingDownload = m_task->pendingDownload()) |
202 | m_networkProcess->authenticationManager().didReceiveAuthenticationChallenge(*pendingDownload, challenge, WTFMove(completionHandler)); |
203 | else |
204 | m_networkProcess->authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, challenge, WTFMove(completionHandler)); |
205 | } |
206 | |
207 | void NetworkLoad::didReceiveResponse(ResourceResponse&& response, ResponseCompletionHandler&& completionHandler) |
208 | { |
209 | ASSERT(RunLoop::isMain()); |
210 | ASSERT(!m_throttle); |
211 | |
212 | if (m_task && m_task->isDownload()) { |
213 | m_networkProcess->findPendingDownloadLocation(*m_task.get(), WTFMove(completionHandler), response); |
214 | return; |
215 | } |
216 | |
217 | if (m_loadThrottleLatency > 0_s) { |
218 | m_throttle = std::make_unique<Throttle>(*this, m_loadThrottleLatency, WTFMove(response), WTFMove(completionHandler)); |
219 | return; |
220 | } |
221 | |
222 | notifyDidReceiveResponse(WTFMove(response), WTFMove(completionHandler)); |
223 | } |
224 | |
225 | void NetworkLoad::notifyDidReceiveResponse(ResourceResponse&& response, ResponseCompletionHandler&& completionHandler) |
226 | { |
227 | ASSERT(RunLoop::isMain()); |
228 | |
229 | response.setSource(ResourceResponse::Source::Network); |
230 | if (m_parameters.needsCertificateInfo) |
231 | response.includeCertificateInfo(); |
232 | |
233 | m_client.get().didReceiveResponse(WTFMove(response), WTFMove(completionHandler)); |
234 | } |
235 | |
236 | void NetworkLoad::didReceiveData(Ref<SharedBuffer>&& buffer) |
237 | { |
238 | ASSERT(!m_throttle); |
239 | |
240 | // FIXME: This should be the encoded data length, not the decoded data length. |
241 | auto size = buffer->size(); |
242 | m_client.get().didReceiveBuffer(WTFMove(buffer), size); |
243 | } |
244 | |
245 | void NetworkLoad::didCompleteWithError(const ResourceError& error, const WebCore::NetworkLoadMetrics& networkLoadMetrics) |
246 | { |
247 | ASSERT(!m_throttle); |
248 | |
249 | if (error.isNull()) |
250 | m_client.get().didFinishLoading(networkLoadMetrics); |
251 | else |
252 | m_client.get().didFailLoading(error); |
253 | } |
254 | |
255 | void NetworkLoad::throttleDelayCompleted() |
256 | { |
257 | ASSERT(m_throttle); |
258 | |
259 | auto throttle = WTFMove(m_throttle); |
260 | |
261 | notifyDidReceiveResponse(WTFMove(throttle->response), WTFMove(throttle->responseCompletionHandler)); |
262 | } |
263 | |
264 | void NetworkLoad::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend) |
265 | { |
266 | m_client.get().didSendData(totalBytesSent, totalBytesExpectedToSend); |
267 | } |
268 | |
269 | void NetworkLoad::wasBlocked() |
270 | { |
271 | m_client.get().didFailLoading(blockedError(m_currentRequest)); |
272 | } |
273 | |
274 | void NetworkLoad::cannotShowURL() |
275 | { |
276 | m_client.get().didFailLoading(cannotShowURLError(m_currentRequest)); |
277 | } |
278 | |
279 | void NetworkLoad::wasBlockedByRestrictions() |
280 | { |
281 | m_client.get().didFailLoading(wasBlockedByRestrictionsError(m_currentRequest)); |
282 | } |
283 | |
284 | String NetworkLoad::description() const |
285 | { |
286 | if (m_task.get()) |
287 | return m_task->description(); |
288 | return emptyString(); |
289 | } |
290 | |
291 | } // namespace WebKit |
292 | |