WKWebView should ask WKNavigationDelegate about bad ssl certificates
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / NetworkLoad.cpp
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
28 #include "NetworkLoad.h"
29
30 #include "AuthenticationManager.h"
31 #include "NetworkProcess.h"
32 #include "SessionTracker.h"
33 #include "WebErrors.h"
34 #include <WebCore/NotImplemented.h>
35 #include <WebCore/ResourceHandle.h>
36 #include <WebCore/SessionID.h>
37 #include <WebCore/SharedBuffer.h>
38 #include <wtf/MainThread.h>
39
40 namespace WebKit {
41
42 using namespace WebCore;
43
44 NetworkLoad::NetworkLoad(NetworkLoadClient& client, NetworkLoadParameters&& parameters)
45     : m_client(client)
46     , m_parameters(WTFMove(parameters))
47 #if !USE(NETWORK_SESSION)
48     , m_networkingContext(RemoteNetworkingContext::create(m_parameters.sessionID, m_parameters.shouldClearReferrerOnHTTPSToHTTPRedirect))
49 #endif
50     , m_currentRequest(m_parameters.request)
51 {
52 #if USE(NETWORK_SESSION)
53     if (m_parameters.request.url().protocolIsBlob()) {
54         m_handle = ResourceHandle::create(nullptr, m_parameters.request, this, m_parameters.defersLoading, m_parameters.contentSniffingPolicy == SniffContent);
55         return;
56     }
57     if (auto* networkSession = SessionTracker::networkSession(m_parameters.sessionID)) {
58         m_task = NetworkDataTask::create(*networkSession, *this, m_parameters.request, m_parameters.allowStoredCredentials, m_parameters.contentSniffingPolicy, m_parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
59         if (!m_parameters.defersLoading)
60             m_task->resume();
61     } else {
62         WTFLogAlways("Attempted to create a NetworkLoad with a session (id=%" PRIu64 ") that does not exist.", m_parameters.sessionID.sessionID());
63         RunLoop::current().dispatch([this, url = m_parameters.request.url()] {
64             didCompleteWithError(internalError(url));
65         });
66     }
67 #else
68     m_handle = ResourceHandle::create(m_networkingContext.get(), m_parameters.request, this, m_parameters.defersLoading, m_parameters.contentSniffingPolicy == SniffContent);
69 #endif
70 }
71
72 NetworkLoad::~NetworkLoad()
73 {
74     ASSERT(RunLoop::isMain());
75 #if USE(NETWORK_SESSION)
76     if (m_responseCompletionHandler)
77         m_responseCompletionHandler(PolicyIgnore);
78     if (m_challengeCompletionHandler)
79         m_challengeCompletionHandler(AuthenticationChallengeDisposition::Cancel, { });
80     if (m_task)
81         m_task->clearClient();
82 #endif
83     if (m_handle)
84         m_handle->clearClient();
85 }
86
87 void NetworkLoad::setDefersLoading(bool defers)
88 {
89 #if USE(NETWORK_SESSION)
90     if (m_task) {
91         if (defers)
92             m_task->suspend();
93         else
94             m_task->resume();
95     }
96 #endif
97     if (m_handle)
98         m_handle->setDefersLoading(defers);
99 }
100
101 void NetworkLoad::cancel()
102 {
103 #if USE(NETWORK_SESSION)
104     if (m_task)
105         m_task->cancel();
106 #endif
107     if (m_handle)
108         m_handle->cancel();
109 }
110
111 void NetworkLoad::continueWillSendRequest(WebCore::ResourceRequest&& newRequest)
112 {
113 #if PLATFORM(COCOA)
114     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(DoNotUpdateHTTPBody));
115 #elif USE(SOUP)
116     // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127.
117     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest);
118 #endif
119
120 #if USE(NETWORK_SESSION)
121     auto redirectCompletionHandler = std::exchange(m_redirectCompletionHandler, nullptr);    
122     ASSERT(redirectCompletionHandler);
123 #endif
124     
125     if (m_currentRequest.isNull()) {
126         if (m_handle)
127             m_handle->cancel();
128         didFail(m_handle.get(), cancelledError(m_currentRequest));
129 #if USE(NETWORK_SESSION)
130         if (redirectCompletionHandler)
131             redirectCompletionHandler({ });
132 #endif
133         return;
134     } else if (m_handle) {
135         auto currentRequestCopy = m_currentRequest;
136         m_handle->continueWillSendRequest(WTFMove(currentRequestCopy));
137     }
138
139 #if USE(NETWORK_SESSION)
140     if (redirectCompletionHandler)
141         redirectCompletionHandler(m_currentRequest);
142 #endif
143 }
144
145 void NetworkLoad::continueDidReceiveResponse()
146 {
147 #if USE(NETWORK_SESSION)
148     ASSERT(m_responseCompletionHandler);
149     if (m_responseCompletionHandler) {
150         m_responseCompletionHandler(PolicyUse);
151         m_responseCompletionHandler = nullptr;
152     }
153 #endif
154     if (m_handle)
155         m_handle->continueDidReceiveResponse();
156 }
157
158 NetworkLoadClient::ShouldContinueDidReceiveResponse NetworkLoad::sharedDidReceiveResponse(ResourceResponse&& response)
159 {
160     response.setSource(ResourceResponse::Source::Network);
161     if (m_parameters.needsCertificateInfo)
162         response.includeCertificateInfo();
163
164     return m_client.didReceiveResponse(WTFMove(response));
165 }
166
167 void NetworkLoad::sharedWillSendRedirectedRequest(ResourceRequest&& request, ResourceResponse&& redirectResponse)
168 {
169     // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect.
170     ASSERT(!redirectResponse.isNull());
171     ASSERT(RunLoop::isMain());
172
173     auto oldRequest = WTFMove(m_currentRequest);
174     m_currentRequest = request;
175     m_client.willSendRedirectedRequest(WTFMove(oldRequest), WTFMove(request), WTFMove(redirectResponse));
176 }
177
178 #if USE(NETWORK_SESSION)
179
180 void NetworkLoad::convertTaskToDownload(DownloadID downloadID, const ResourceRequest& updatedRequest)
181 {
182     if (!m_task)
183         return;
184
185     m_task->setPendingDownloadID(downloadID);
186     
187     ASSERT(m_responseCompletionHandler);
188     if (m_responseCompletionHandler)
189         NetworkProcess::singleton().findPendingDownloadLocation(*m_task.get(), std::exchange(m_responseCompletionHandler, nullptr), updatedRequest);
190 }
191
192 void NetworkLoad::setPendingDownloadID(DownloadID downloadID)
193 {
194     if (!m_task)
195         return;
196
197     m_task->setPendingDownloadID(downloadID);
198 }
199
200 void NetworkLoad::setPendingDownload(PendingDownload& pendingDownload)
201 {
202     if (!m_task)
203         return;
204
205     m_task->setPendingDownload(pendingDownload);
206 }
207
208 void NetworkLoad::willPerformHTTPRedirection(ResourceResponse&& response, ResourceRequest&& request, RedirectCompletionHandler&& completionHandler)
209 {
210     ASSERT(!m_redirectCompletionHandler);
211     m_redirectCompletionHandler = WTFMove(completionHandler);
212     sharedWillSendRedirectedRequest(WTFMove(request), WTFMove(response));
213 }
214
215 void NetworkLoad::didReceiveChallenge(const AuthenticationChallenge& challenge, ChallengeCompletionHandler&& completionHandler)
216 {
217     // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
218     ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
219
220     // Handle server trust evaluation at platform-level if requested, for performance reasons.
221     if (challenge.protectionSpace().authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
222         && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
223         if (m_task && m_task->allowsSpecificHTTPSCertificateForHost(challenge))
224             completionHandler(AuthenticationChallengeDisposition::UseCredential, serverTrustCredential(challenge));
225         else
226             completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpace, { });
227         return;
228     }
229
230     m_challengeCompletionHandler = WTFMove(completionHandler);
231     m_challenge = challenge;
232
233     m_client.canAuthenticateAgainstProtectionSpaceAsync(challenge.protectionSpace());
234 }
235
236 void NetworkLoad::didReceiveResponseNetworkSession(ResourceResponse&& response, ResponseCompletionHandler&& completionHandler)
237 {
238     ASSERT(isMainThread());
239     if (m_task && m_task->pendingDownloadID().downloadID())
240         NetworkProcess::singleton().findPendingDownloadLocation(*m_task.get(), WTFMove(completionHandler), m_task->currentRequest());
241     else if (sharedDidReceiveResponse(WTFMove(response)) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
242         completionHandler(PolicyUse);
243     else
244         m_responseCompletionHandler = WTFMove(completionHandler);
245 }
246
247 void NetworkLoad::didReceiveData(Ref<SharedBuffer>&& buffer)
248 {
249     // FIXME: This should be the encoded data length, not the decoded data length.
250     auto size = buffer->size();
251     m_client.didReceiveBuffer(WTFMove(buffer), size);
252 }
253
254 void NetworkLoad::didCompleteWithError(const ResourceError& error)
255 {
256     if (error.isNull())
257         m_client.didFinishLoading(WTF::monotonicallyIncreasingTime());
258     else
259         m_client.didFailLoading(error);
260 }
261
262 void NetworkLoad::didBecomeDownload()
263 {
264     m_client.didBecomeDownload();
265 }
266
267 void NetworkLoad::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend)
268 {
269     m_client.didSendData(totalBytesSent, totalBytesExpectedToSend);
270 }
271
272 void NetworkLoad::wasBlocked()
273 {
274     m_client.didFailLoading(blockedError(m_currentRequest));
275 }
276
277 void NetworkLoad::cannotShowURL()
278 {
279     m_client.didFailLoading(cannotShowURLError(m_currentRequest));
280 }
281     
282 #endif
283
284 void NetworkLoad::didReceiveResponseAsync(ResourceHandle* handle, ResourceResponse&& receivedResponse)
285 {
286     ASSERT_UNUSED(handle, handle == m_handle);
287     if (sharedDidReceiveResponse(WTFMove(receivedResponse)) == NetworkLoadClient::ShouldContinueDidReceiveResponse::Yes)
288         m_handle->continueDidReceiveResponse();
289 }
290
291 void NetworkLoad::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int /* encodedDataLength */)
292 {
293     // The NetworkProcess should never get a didReceiveData callback.
294     // We should always be using didReceiveBuffer.
295     ASSERT_NOT_REACHED();
296 }
297
298 void NetworkLoad::didReceiveBuffer(ResourceHandle* handle, Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
299 {
300     ASSERT_UNUSED(handle, handle == m_handle);
301     m_client.didReceiveBuffer(WTFMove(buffer), reportedEncodedDataLength);
302 }
303
304 void NetworkLoad::didFinishLoading(ResourceHandle* handle, double finishTime)
305 {
306     ASSERT_UNUSED(handle, handle == m_handle);
307     m_client.didFinishLoading(finishTime);
308 }
309
310 void NetworkLoad::didFail(ResourceHandle* handle, const ResourceError& error)
311 {
312     ASSERT_UNUSED(handle, !handle || handle == m_handle);
313     ASSERT(!error.isNull());
314
315     m_client.didFailLoading(error);
316 }
317
318 void NetworkLoad::willSendRequestAsync(ResourceHandle* handle, ResourceRequest&& request, ResourceResponse&& redirectResponse)
319 {
320     ASSERT_UNUSED(handle, handle == m_handle);
321     sharedWillSendRedirectedRequest(WTFMove(request), WTFMove(redirectResponse));
322 }
323
324 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
325 void NetworkLoad::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace)
326 {
327     ASSERT(RunLoop::isMain());
328     ASSERT_UNUSED(handle, handle == m_handle);
329
330     // Handle server trust evaluation at platform-level if requested, for performance reasons.
331     if (protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
332         && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
333         continueCanAuthenticateAgainstProtectionSpace(false);
334         return;
335     }
336
337     m_client.canAuthenticateAgainstProtectionSpaceAsync(protectionSpace);
338 }
339 #endif
340
341 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
342 void NetworkLoad::continueCanAuthenticateAgainstProtectionSpace(bool result)
343 {
344 #if USE(NETWORK_SESSION)
345     ASSERT_WITH_MESSAGE(!m_handle, "Blobs should never give authentication challenges");
346     ASSERT(m_challengeCompletionHandler);
347     auto completionHandler = std::exchange(m_challengeCompletionHandler, nullptr);
348     if (!result) {
349         if (m_task && m_task->allowsSpecificHTTPSCertificateForHost(*m_challenge))
350             completionHandler(AuthenticationChallengeDisposition::UseCredential, serverTrustCredential(*m_challenge));
351         else
352             completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpace, { });
353         return;
354     }
355
356     if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
357         completionHandler(AuthenticationChallengeDisposition::UseCredential, { });
358         return;
359     }
360     
361     if (m_task) {
362         if (auto* pendingDownload = m_task->pendingDownload())
363             NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(*pendingDownload, *m_challenge, WTFMove(completionHandler));
364         else
365             NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, *m_challenge, WTFMove(completionHandler));
366     }
367 #endif
368     if (m_handle)
369         m_handle->continueCanAuthenticateAgainstProtectionSpace(result);
370 }
371 #endif
372
373 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
374 bool NetworkLoad::supportsDataArray()
375 {
376     notImplemented();
377     return false;
378 }
379
380 void NetworkLoad::didReceiveDataArray(ResourceHandle*, CFArrayRef)
381 {
382     ASSERT_NOT_REACHED();
383     notImplemented();
384 }
385 #endif
386
387 void NetworkLoad::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
388 {
389     ASSERT_UNUSED(handle, handle == m_handle);
390
391     m_client.didSendData(bytesSent, totalBytesToBeSent);
392 }
393
394 void NetworkLoad::wasBlocked(ResourceHandle* handle)
395 {
396     ASSERT_UNUSED(handle, handle == m_handle);
397
398     didFail(handle, WebKit::blockedError(m_currentRequest));
399 }
400
401 void NetworkLoad::cannotShowURL(ResourceHandle* handle)
402 {
403     ASSERT_UNUSED(handle, handle == m_handle);
404
405     didFail(handle, WebKit::cannotShowURLError(m_currentRequest));
406 }
407
408 bool NetworkLoad::shouldUseCredentialStorage(ResourceHandle* handle)
409 {
410     ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start().
411
412     // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked.
413     // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer.
414
415     // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one.
416
417     return m_parameters.allowStoredCredentials == AllowStoredCredentials;
418 }
419
420 void NetworkLoad::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
421 {
422     ASSERT_UNUSED(handle, handle == m_handle);
423     // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
424     ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
425
426     if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
427         challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
428         return;
429     }
430
431     NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, challenge);
432 }
433
434 void NetworkLoad::receivedCancellation(ResourceHandle* handle, const AuthenticationChallenge&)
435 {
436     ASSERT_UNUSED(handle, handle == m_handle);
437
438     m_handle->cancel();
439     didFail(m_handle.get(), cancelledError(m_currentRequest));
440 }
441
442 } // namespace WebKit