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