370ac3479dbdfe36ec6cf073199eedcfe3699b3f
[WebKit-https.git] / Source / WebKit / NetworkProcess / cocoa / NetworkSessionCocoa.mm
1 /*
2  * Copyright (C) 2015-2019 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 #import "config.h"
27 #import "NetworkSessionCocoa.h"
28
29 #import "AuthenticationChallengeDisposition.h"
30 #import "AuthenticationManager.h"
31 #import "DataReference.h"
32 #import "Download.h"
33 #import "LegacyCustomProtocolManager.h"
34 #import "Logging.h"
35 #import "NetworkLoad.h"
36 #import "NetworkProcess.h"
37 #import "NetworkSessionCreationParameters.h"
38 #import "WebSocketTask.h"
39 #import <Foundation/NSURLSession.h>
40 #import <WebCore/Credential.h>
41 #import <WebCore/FormDataStreamMac.h>
42 #import <WebCore/FrameLoaderTypes.h>
43 #import <WebCore/NetworkStorageSession.h>
44 #import <WebCore/NotImplemented.h>
45 #import <WebCore/ResourceError.h>
46 #import <WebCore/ResourceRequest.h>
47 #import <WebCore/ResourceResponse.h>
48 #import <WebCore/SharedBuffer.h>
49 #import <WebCore/WebCoreURLResponse.h>
50 #import <pal/spi/cf/CFNetworkSPI.h>
51 #import <wtf/MainThread.h>
52 #import <wtf/NeverDestroyed.h>
53 #import <wtf/ObjCRuntimeExtras.h>
54 #import <wtf/ProcessPrivilege.h>
55 #import <wtf/SoftLinking.h>
56 #import <wtf/URL.h>
57 #import <wtf/text/WTFString.h>
58
59 #if USE(APPLE_INTERNAL_SDK)
60 #include <WebKitAdditions/NetworkSessionCocoaAdditions.h>
61 #endif
62
63 #import "DeviceManagementSoftLink.h"
64
65 using namespace WebKit;
66
67 CFStringRef const WebKit2HTTPProxyDefaultsKey = static_cast<CFStringRef>(@"WebKit2HTTPProxy");
68 CFStringRef const WebKit2HTTPSProxyDefaultsKey = static_cast<CFStringRef>(@"WebKit2HTTPSProxy");
69
70 constexpr unsigned maxNumberOfIsolatedSessions { 10 };
71
72 static NSURLSessionResponseDisposition toNSURLSessionResponseDisposition(WebCore::PolicyAction disposition)
73 {
74     switch (disposition) {
75     case WebCore::PolicyAction::StopAllLoads:
76         ASSERT_NOT_REACHED();
77 #if ASSERT_DISABLED
78         FALLTHROUGH;
79 #endif
80     case WebCore::PolicyAction::Ignore:
81         return NSURLSessionResponseCancel;
82     case WebCore::PolicyAction::Use:
83         return NSURLSessionResponseAllow;
84     case WebCore::PolicyAction::Download:
85         return NSURLSessionResponseBecomeDownload;
86     }
87 }
88
89 static NSURLSessionAuthChallengeDisposition toNSURLSessionAuthChallengeDisposition(WebKit::AuthenticationChallengeDisposition disposition)
90 {
91     switch (disposition) {
92     case WebKit::AuthenticationChallengeDisposition::UseCredential:
93         return NSURLSessionAuthChallengeUseCredential;
94     case WebKit::AuthenticationChallengeDisposition::PerformDefaultHandling:
95         return NSURLSessionAuthChallengePerformDefaultHandling;
96     case WebKit::AuthenticationChallengeDisposition::Cancel:
97         return NSURLSessionAuthChallengeCancelAuthenticationChallenge;
98     case WebKit::AuthenticationChallengeDisposition::RejectProtectionSpaceAndContinue:
99         return NSURLSessionAuthChallengeRejectProtectionSpace;
100     }
101 }
102
103 static WebCore::NetworkLoadPriority toNetworkLoadPriority(float priority)
104 {
105     if (priority <= NSURLSessionTaskPriorityLow)
106         return WebCore::NetworkLoadPriority::Low;
107     if (priority >= NSURLSessionTaskPriorityHigh)
108         return WebCore::NetworkLoadPriority::High;
109     return WebCore::NetworkLoadPriority::Medium;
110 }
111
112 #if HAVE(CFNETWORK_NEGOTIATED_SSL_PROTOCOL_CIPHER)
113 static String stringForSSLProtocol(SSLProtocol protocol)
114 {
115     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
116     switch (protocol) {
117     case kDTLSProtocol1:
118         return "DTLS 1.0"_s;
119     case kSSLProtocol2:
120         return "SSL 2.0"_s;
121     case kSSLProtocol3:
122         return "SSL 3.0"_s;
123     case kSSLProtocol3Only:
124         return "SSL 3.0 (Only)"_s;
125     case kTLSProtocol1:
126         return "TLS 1.0"_s;
127     case kTLSProtocol1Only:
128         return "TLS 1.0 (Only)"_s;
129     case kTLSProtocol11:
130         return "TLS 1.1"_s;
131     case kTLSProtocol12:
132         return "TLS 1.2"_s;
133     case kTLSProtocol13:
134         return "TLS 1.3"_s;
135     case kSSLProtocolAll:
136         return "All";
137     case kSSLProtocolUnknown:
138         return "Unknown";
139     case kTLSProtocolMaxSupported:
140     default:
141         ASSERT_NOT_REACHED();
142         return emptyString();
143     }
144     ALLOW_DEPRECATED_DECLARATIONS_END
145 }
146
147 static String stringForSSLCipher(SSLCipherSuite cipher)
148 {
149 #define STRINGIFY_CIPHER(cipher) \
150     case cipher: \
151         return "" #cipher ""_s
152
153     switch (cipher) {
154     STRINGIFY_CIPHER(SSL_RSA_EXPORT_WITH_RC4_40_MD5);
155     STRINGIFY_CIPHER(SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5);
156     STRINGIFY_CIPHER(SSL_RSA_WITH_IDEA_CBC_SHA);
157     STRINGIFY_CIPHER(SSL_RSA_EXPORT_WITH_DES40_CBC_SHA);
158     STRINGIFY_CIPHER(SSL_RSA_WITH_DES_CBC_SHA);
159     STRINGIFY_CIPHER(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
160     STRINGIFY_CIPHER(SSL_DH_DSS_WITH_DES_CBC_SHA);
161     STRINGIFY_CIPHER(SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
162     STRINGIFY_CIPHER(SSL_DH_RSA_WITH_DES_CBC_SHA);
163     STRINGIFY_CIPHER(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
164     STRINGIFY_CIPHER(SSL_DHE_DSS_WITH_DES_CBC_SHA);
165     STRINGIFY_CIPHER(SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
166     STRINGIFY_CIPHER(SSL_DHE_RSA_WITH_DES_CBC_SHA);
167     STRINGIFY_CIPHER(SSL_DH_anon_EXPORT_WITH_RC4_40_MD5);
168     STRINGIFY_CIPHER(SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA);
169     STRINGIFY_CIPHER(SSL_DH_anon_WITH_DES_CBC_SHA);
170     STRINGIFY_CIPHER(SSL_FORTEZZA_DMS_WITH_NULL_SHA);
171     STRINGIFY_CIPHER(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA);
172     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_128_CBC_SHA);
173     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_128_CBC_SHA);
174     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_128_CBC_SHA);
175     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
176     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
177     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_128_CBC_SHA);
178     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_256_CBC_SHA);
179     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_256_CBC_SHA);
180     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_256_CBC_SHA);
181     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
182     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
183     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_256_CBC_SHA);
184     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_NULL_SHA);
185     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
186     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA);
187     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA);
188     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA);
189     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_NULL_SHA);
190     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA);
191     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA);
192     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
193     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
194     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_NULL_SHA);
195     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_RC4_128_SHA);
196     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA);
197     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA);
198     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA);
199     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_NULL_SHA);
200     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_RC4_128_SHA);
201     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
202     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
203     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
204     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_NULL_SHA);
205     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_RC4_128_SHA);
206     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA);
207     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
208     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_AES_256_CBC_SHA);
209     // STRINGIFY_CIPHER(SSL_NULL_WITH_NULL_NULL);
210     STRINGIFY_CIPHER(TLS_NULL_WITH_NULL_NULL);
211     // STRINGIFY_CIPHER(SSL_RSA_WITH_NULL_MD5);
212     STRINGIFY_CIPHER(TLS_RSA_WITH_NULL_MD5);
213     // STRINGIFY_CIPHER(SSL_RSA_WITH_NULL_SHA);
214     STRINGIFY_CIPHER(TLS_RSA_WITH_NULL_SHA);
215     // STRINGIFY_CIPHER(SSL_RSA_WITH_RC4_128_MD5);
216     STRINGIFY_CIPHER(TLS_RSA_WITH_RC4_128_MD5);
217     // STRINGIFY_CIPHER(SSL_RSA_WITH_RC4_128_SHA);
218     STRINGIFY_CIPHER(TLS_RSA_WITH_RC4_128_SHA);
219     // STRINGIFY_CIPHER(SSL_RSA_WITH_3DES_EDE_CBC_SHA);
220     STRINGIFY_CIPHER(TLS_RSA_WITH_3DES_EDE_CBC_SHA);
221     STRINGIFY_CIPHER(TLS_RSA_WITH_NULL_SHA256);
222     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_128_CBC_SHA256);
223     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_256_CBC_SHA256);
224     // STRINGIFY_CIPHER(SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA);
225     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
226     // STRINGIFY_CIPHER(SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA);
227     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
228     // STRINGIFY_CIPHER(SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
229     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
230     // STRINGIFY_CIPHER(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
231     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
232     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_128_CBC_SHA256);
233     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_128_CBC_SHA256);
234     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256);
235     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256);
236     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_256_CBC_SHA256);
237     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_256_CBC_SHA256);
238     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256);
239     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256);
240     // STRINGIFY_CIPHER(SSL_DH_anon_WITH_RC4_128_MD5);
241     STRINGIFY_CIPHER(TLS_DH_anon_WITH_RC4_128_MD5);
242     // STRINGIFY_CIPHER(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA);
243     STRINGIFY_CIPHER(TLS_DH_anon_WITH_3DES_EDE_CBC_SHA);
244     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_128_CBC_SHA256);
245     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_256_CBC_SHA256);
246     STRINGIFY_CIPHER(TLS_PSK_WITH_RC4_128_SHA);
247     STRINGIFY_CIPHER(TLS_PSK_WITH_3DES_EDE_CBC_SHA);
248     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA);
249     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_256_CBC_SHA);
250     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_RC4_128_SHA);
251     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA);
252     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_128_CBC_SHA);
253     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_256_CBC_SHA);
254     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_RC4_128_SHA);
255     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA);
256     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_128_CBC_SHA);
257     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_256_CBC_SHA);
258     STRINGIFY_CIPHER(TLS_PSK_WITH_NULL_SHA);
259     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_NULL_SHA);
260     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_NULL_SHA);
261     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_128_GCM_SHA256);
262     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_256_GCM_SHA384);
263     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256);
264     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384);
265     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_128_GCM_SHA256);
266     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_256_GCM_SHA384);
267     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256);
268     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384);
269     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_128_GCM_SHA256);
270     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_256_GCM_SHA384);
271     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_128_GCM_SHA256);
272     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_256_GCM_SHA384);
273     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_128_GCM_SHA256);
274     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_256_GCM_SHA384);
275     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256);
276     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384);
277     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256);
278     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384);
279     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA256);
280     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_256_CBC_SHA384);
281     STRINGIFY_CIPHER(TLS_PSK_WITH_NULL_SHA256);
282     STRINGIFY_CIPHER(TLS_PSK_WITH_NULL_SHA384);
283     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256);
284     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384);
285     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_NULL_SHA256);
286     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_NULL_SHA384);
287     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256);
288     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384);
289     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_NULL_SHA256);
290     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_NULL_SHA384);
291     STRINGIFY_CIPHER(TLS_AES_128_GCM_SHA256);
292     STRINGIFY_CIPHER(TLS_AES_256_GCM_SHA384);
293     STRINGIFY_CIPHER(TLS_CHACHA20_POLY1305_SHA256);
294     STRINGIFY_CIPHER(TLS_AES_128_CCM_SHA256);
295     STRINGIFY_CIPHER(TLS_AES_128_CCM_8_SHA256);
296     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
297     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
298     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256);
299     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384);
300     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);
301     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
302     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256);
303     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384);
304     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
305     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384);
306     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256);
307     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384);
308     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256);
309     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384);
310     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256);
311     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384);
312     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
313     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
314     STRINGIFY_CIPHER(TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
315     STRINGIFY_CIPHER(SSL_RSA_WITH_RC2_CBC_MD5);
316     STRINGIFY_CIPHER(SSL_RSA_WITH_IDEA_CBC_MD5);
317     STRINGIFY_CIPHER(SSL_RSA_WITH_DES_CBC_MD5);
318     STRINGIFY_CIPHER(SSL_RSA_WITH_3DES_EDE_CBC_MD5);
319     STRINGIFY_CIPHER(SSL_NO_SUCH_CIPHERSUITE);
320     default:
321         ASSERT_NOT_REACHED();
322         return emptyString();
323     }
324
325 #undef STRINGIFY_CIPHER
326 }
327 #endif
328
329 @interface WKNetworkSessionDelegate : NSObject <NSURLSessionDataDelegate
330 #if HAVE(NSURLSESSION_WEBSOCKET)
331     , NSURLSessionWebSocketDelegate
332 #endif
333 > {
334     WeakPtr<WebKit::NetworkSessionCocoa> _session;
335     bool _withCredentials;
336 }
337
338 - (id)initWithNetworkSession:(WebKit::NetworkSessionCocoa&)session withCredentials:(bool)withCredentials;
339 - (void)sessionInvalidated;
340
341 @end
342
343 @implementation WKNetworkSessionDelegate
344
345 - (id)initWithNetworkSession:(WebKit::NetworkSessionCocoa&)session withCredentials:(bool)withCredentials
346 {
347     self = [super init];
348     if (!self)
349         return nil;
350
351     _session = makeWeakPtr(session);
352     _withCredentials = withCredentials;
353
354     return self;
355 }
356
357 - (void)sessionInvalidated
358 {
359     _session = nullptr;
360 }
361
362 - (NetworkDataTaskCocoa*)existingTask:(NSURLSessionTask *)task
363 {
364     if (!_session)
365         return nullptr;
366
367     if (!task)
368         return nullptr;
369
370     auto storedCredentialsPolicy = _withCredentials ? WebCore::StoredCredentialsPolicy::Use : WebCore::StoredCredentialsPolicy::DoNotUse;
371     return _session->dataTaskForIdentifier(task.taskIdentifier, storedCredentialsPolicy);
372 }
373
374 - (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
375 {
376     ASSERT(!_session);
377 }
378
379 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
380 {
381     if (auto* networkDataTask = [self existingTask:task])
382         networkDataTask->didSendData(totalBytesSent, totalBytesExpectedToSend);
383 }
384
385 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
386 {
387     auto* networkDataTask = [self existingTask:task];
388     if (!networkDataTask) {
389         completionHandler(nil);
390         return;
391     }
392
393     auto* body = networkDataTask->firstRequest().httpBody();
394     if (!body) {
395         completionHandler(nil);
396         return;
397     }
398
399     completionHandler(WebCore::createHTTPBodyNSInputStream(*body).get());
400 }
401
402 #if ENABLE(RESOURCE_LOAD_STATISTICS)
403 static NSURLRequest* downgradeRequest(NSURLRequest *request)
404 {
405     NSMutableURLRequest *nsMutableRequest = [[request mutableCopy] autorelease];
406     if ([nsMutableRequest.URL.scheme isEqualToString:@"https"]) {
407         NSURLComponents *components = [NSURLComponents componentsWithURL:nsMutableRequest.URL resolvingAgainstBaseURL:NO];
408         components.scheme = @"http";
409         [nsMutableRequest setURL:components.URL];
410         ASSERT([nsMutableRequest.URL.scheme isEqualToString:@"http"]);
411         return nsMutableRequest;
412     }
413
414     ASSERT_NOT_REACHED();
415     return request;
416 }
417
418 static bool schemeWasUpgradedDueToDynamicHSTS(NSURLRequest *request)
419 {
420     return [request respondsToSelector:@selector(_schemeWasUpgradedDueToDynamicHSTS)]
421         && [request _schemeWasUpgradedDueToDynamicHSTS];
422 }
423 #endif
424
425 static void setIgnoreHSTS(NSMutableURLRequest *request, bool ignoreHSTS)
426 {
427     if ([request respondsToSelector:@selector(_setIgnoreHSTS:)])
428         [request _setIgnoreHSTS:ignoreHSTS];
429 }
430
431 static bool ignoreHSTS(NSURLRequest *request)
432 {
433     return [request respondsToSelector:@selector(_ignoreHSTS)]
434         && [request _ignoreHSTS];
435 }
436
437 static NSURLRequest* updateIgnoreStrictTransportSecuritySettingIfNecessary(NSURLRequest *request, bool shouldIgnoreHSTS)
438 {
439     if ([request.URL.scheme isEqualToString:@"https"] && shouldIgnoreHSTS && ignoreHSTS(request)) {
440         // The request was upgraded for some other reason than HSTS.
441         // Don't ignore HSTS to avoid the risk of another downgrade.
442         NSMutableURLRequest *nsMutableRequest = [[request mutableCopy] autorelease];
443         setIgnoreHSTS(nsMutableRequest, false);
444         return nsMutableRequest;
445     }
446     
447     if ([request.URL.scheme isEqualToString:@"http"] && ignoreHSTS(request) != shouldIgnoreHSTS) {
448         NSMutableURLRequest *nsMutableRequest = [[request mutableCopy] autorelease];
449         setIgnoreHSTS(nsMutableRequest, shouldIgnoreHSTS);
450         return nsMutableRequest;
451     }
452
453     return request;
454 }
455
456 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
457 {
458     auto taskIdentifier = task.taskIdentifier;
459     LOG(NetworkSession, "%llu willPerformHTTPRedirection from %s to %s", taskIdentifier, response.URL.absoluteString.UTF8String, request.URL.absoluteString.UTF8String);
460
461     if (auto* networkDataTask = [self existingTask:task]) {
462         auto completionHandlerCopy = Block_copy(completionHandler);
463
464         bool shouldIgnoreHSTS = false;
465 #if ENABLE(RESOURCE_LOAD_STATISTICS)
466         shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && _session->networkProcess().storageSession(_session->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID());
467         if (shouldIgnoreHSTS) {
468             request = downgradeRequest(request);
469             ASSERT([request.URL.scheme isEqualToString:@"http"]);
470             LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
471         }
472 #endif
473
474         networkDataTask->willPerformHTTPRedirection(response, request, [completionHandlerCopy, taskIdentifier, shouldIgnoreHSTS](auto&& request) {
475 #if !LOG_DISABLED
476             LOG(NetworkSession, "%llu willPerformHTTPRedirection completionHandler (%s)", taskIdentifier, request.url().string().utf8().data());
477 #else
478             UNUSED_PARAM(taskIdentifier);
479 #endif
480             auto nsRequest = request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::UpdateHTTPBody);
481             nsRequest = updateIgnoreStrictTransportSecuritySettingIfNecessary(nsRequest, shouldIgnoreHSTS);
482             completionHandlerCopy(nsRequest);
483             Block_release(completionHandlerCopy);
484         });
485     } else {
486         LOG(NetworkSession, "%llu willPerformHTTPRedirection completionHandler (nil)", taskIdentifier);
487         completionHandler(nil);
488     }
489 }
490
491 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask*)task _schemeUpgraded:(NSURLRequest*)request completionHandler:(void (^)(NSURLRequest*))completionHandler
492 {
493     auto taskIdentifier = task.taskIdentifier;
494     LOG(NetworkSession, "%llu _schemeUpgraded %s", taskIdentifier, request.URL.absoluteString.UTF8String);
495
496     if (auto* networkDataTask = [self existingTask:task]) {
497         bool shouldIgnoreHSTS = false;
498 #if ENABLE(RESOURCE_LOAD_STATISTICS)
499         shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && _session->networkProcess().storageSession(_session->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID());
500         if (shouldIgnoreHSTS) {
501             request = downgradeRequest(request);
502             ASSERT([request.URL.scheme isEqualToString:@"http"]);
503             LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
504         }
505 #endif
506
507         auto completionHandlerCopy = Block_copy(completionHandler);
508         networkDataTask->willPerformHTTPRedirection(WebCore::synthesizeRedirectResponseIfNecessary([task currentRequest], request, nil), request, [completionHandlerCopy, taskIdentifier, shouldIgnoreHSTS](auto&& request) {
509 #if !LOG_DISABLED
510             LOG(NetworkSession, "%llu _schemeUpgraded completionHandler (%s)", taskIdentifier, request.url().string().utf8().data());
511 #else
512             UNUSED_PARAM(taskIdentifier);
513 #endif
514             auto nsRequest = request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::UpdateHTTPBody);
515             nsRequest = updateIgnoreStrictTransportSecuritySettingIfNecessary(nsRequest, shouldIgnoreHSTS);
516             completionHandlerCopy(nsRequest);
517             Block_release(completionHandlerCopy);
518         });
519     } else {
520         LOG(NetworkSession, "%llu _schemeUpgraded completionHandler (nil)", taskIdentifier);
521         completionHandler(nil);
522     }
523 }
524
525 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
526 {
527     if (!_session) {
528         completionHandler(nil);
529         return;
530     }
531
532     // FIXME: remove if <rdar://problem/20001985> is ever resolved.
533     if ([proposedResponse.response respondsToSelector:@selector(allHeaderFields)]
534         && [[(id)proposedResponse.response allHeaderFields] objectForKey:@"Content-Range"])
535         completionHandler(nil);
536     else
537         completionHandler(proposedResponse);
538 }
539
540 #if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
541 static bool canNSURLSessionTrustEvaluate()
542 {
543     return [NSURLSession respondsToSelector:@selector(_strictTrustEvaluate: queue: completionHandler:)];
544 }
545
546 static inline void processServerTrustEvaluation(NetworkSessionCocoa *session, NSURLAuthenticationChallenge *challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential)>&& completionHandler)
547 {
548     session->continueDidReceiveChallenge(challenge, taskIdentifier, networkDataTask, [completionHandler = WTFMove(completionHandler), secTrust = retainPtr(challenge.protectionSpace.serverTrust)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
549         // FIXME: UIProcess should send us back non nil credentials but the credential IPC encoder currently only serializes ns credentials for username/password.
550         if (disposition == WebKit::AuthenticationChallengeDisposition::UseCredential && !credential.nsCredential()) {
551             completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust: secTrust.get()]);
552             return;
553         }
554         completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), credential.nsCredential());
555     });
556 }
557 #endif
558
559 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
560 {
561     if (!_session || [task state] == NSURLSessionTaskStateCanceling) {
562         completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
563         return;
564     }
565
566     auto taskIdentifier = task.taskIdentifier;
567     LOG(NetworkSession, "%llu didReceiveChallenge", taskIdentifier);
568     
569     // Proxy authentication is handled by CFNetwork internally. We can get here if the user cancels
570     // CFNetwork authentication dialog, and we shouldn't ask the client to display another one in that case.
571     if (challenge.protectionSpace.isProxy) {
572         completionHandler(NSURLSessionAuthChallengeUseCredential, nil);
573         return;
574     }
575
576     if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
577         if (NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(challenge))
578             return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
579
580         // Handle server trust evaluation at platform-level if requested, for performance reasons and to use ATS defaults.
581         if (!_session->networkProcess().canHandleHTTPSServerTrustEvaluation() || _session->fastServerTrustEvaluationEnabled()) {
582 #if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
583             if (canNSURLSessionTrustEvaluate()) {
584                 auto* networkDataTask = [self existingTask:task];
585                 ASSERT(networkDataTask);
586                 auto decisionHandler = makeBlockPtr([_session = makeWeakPtr(_session.get()), completionHandler = makeBlockPtr(completionHandler), taskIdentifier, networkDataTask = RefPtr<NetworkDataTaskCocoa>(networkDataTask)](NSURLAuthenticationChallenge *challenge, OSStatus trustResult) mutable {
587                     auto task = WTFMove(networkDataTask);
588                     auto* session = _session.get();
589                     if (trustResult == noErr || !session) {
590                         completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
591                         return;
592                     }
593                     processServerTrustEvaluation(session, challenge, taskIdentifier, task.get(), WTFMove(completionHandler));
594                 });
595                 [NSURLSession _strictTrustEvaluate:challenge queue:[NSOperationQueue mainQueue].underlyingQueue completionHandler:decisionHandler.get()];
596                 return;
597             }
598 #endif
599             return completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
600         }
601     }
602     _session->continueDidReceiveChallenge(challenge, taskIdentifier, [self existingTask:task], [completionHandler = makeBlockPtr(completionHandler)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
603         completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), credential.nsCredential());
604     });
605 }
606
607 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
608 {
609     if (!_session)
610         return;
611
612     LOG(NetworkSession, "%llu didCompleteWithError %@", task.taskIdentifier, error);
613
614     if (error) {
615         NSDictionary *oldUserInfo = [error userInfo];
616         NSMutableDictionary *newUserInfo = oldUserInfo ? [NSMutableDictionary dictionaryWithDictionary:oldUserInfo] : [NSMutableDictionary dictionary];
617         newUserInfo[@"networkTaskDescription"] = [task description];
618         error = [NSError errorWithDomain:[error domain] code:[error code] userInfo:newUserInfo];
619     }
620
621     if (auto* networkDataTask = [self existingTask:task])
622         networkDataTask->didCompleteWithError(error, networkDataTask->networkLoadMetrics());
623     else if (error) {
624         auto downloadID = _session->takeDownloadID(task.taskIdentifier);
625         if (downloadID.downloadID()) {
626             if (auto* download = _session->networkProcess().downloadManager().download(downloadID)) {
627                 NSData *resumeData = nil;
628                 if (id userInfo = error.userInfo) {
629                     if ([userInfo isKindOfClass:[NSDictionary class]]) {
630                         resumeData = userInfo[@"NSURLSessionDownloadTaskResumeData"];
631                         if (resumeData && ![resumeData isKindOfClass:[NSData class]]) {
632                             RELEASE_LOG(NetworkSession, "Download task %llu finished with resume data of wrong class: %s", (unsigned long long)task.taskIdentifier, NSStringFromClass([resumeData class]).UTF8String);
633                             ASSERT_NOT_REACHED();
634                             resumeData = nil;
635                         }
636                     }
637                 }
638
639                 auto resumeDataReference = resumeData ? IPC::DataReference { static_cast<const uint8_t*>(resumeData.bytes), resumeData.length } : IPC::DataReference { };
640
641                 if (download->wasCanceled())
642                     download->didCancel(resumeDataReference);
643                 else
644                     download->didFail(error, resumeDataReference);
645             }
646         }
647     }
648 }
649
650 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
651 {
652     LOG(NetworkSession, "%llu didFinishCollectingMetrics", task.taskIdentifier);
653     if (auto* networkDataTask = [self existingTask:task]) {
654         NSURLSessionTaskTransactionMetrics *m = metrics.transactionMetrics.lastObject;
655         NSDate *fetchStartDate = m.fetchStartDate;
656         NSTimeInterval domainLookupStartInterval = m.domainLookupStartDate ? [m.domainLookupStartDate timeIntervalSinceDate:fetchStartDate] : -1;
657         NSTimeInterval domainLookupEndInterval = m.domainLookupEndDate ? [m.domainLookupEndDate timeIntervalSinceDate:fetchStartDate] : -1;
658         NSTimeInterval connectStartInterval = m.connectStartDate ? [m.connectStartDate timeIntervalSinceDate:fetchStartDate] : -1;
659         NSTimeInterval secureConnectionStartInterval = m.secureConnectionStartDate ? [m.secureConnectionStartDate timeIntervalSinceDate:fetchStartDate] : -1;
660         NSTimeInterval connectEndInterval = m.connectEndDate ? [m.connectEndDate timeIntervalSinceDate:fetchStartDate] : -1;
661         NSTimeInterval requestStartInterval = [m.requestStartDate timeIntervalSinceDate:fetchStartDate];
662         NSTimeInterval responseStartInterval = [m.responseStartDate timeIntervalSinceDate:fetchStartDate];
663         NSTimeInterval responseEndInterval = [m.responseEndDate timeIntervalSinceDate:fetchStartDate];
664
665         auto& networkLoadMetrics = networkDataTask->networkLoadMetrics();
666         networkLoadMetrics.domainLookupStart = Seconds(domainLookupStartInterval);
667         networkLoadMetrics.domainLookupEnd = Seconds(domainLookupEndInterval);
668         networkLoadMetrics.connectStart = Seconds(connectStartInterval);
669         networkLoadMetrics.secureConnectionStart = Seconds(secureConnectionStartInterval);
670         networkLoadMetrics.connectEnd = Seconds(connectEndInterval);
671         networkLoadMetrics.requestStart = Seconds(requestStartInterval);
672         networkLoadMetrics.responseStart = Seconds(responseStartInterval);
673         networkLoadMetrics.responseEnd = Seconds(responseEndInterval);
674         networkLoadMetrics.markComplete();
675         networkLoadMetrics.protocol = String(m.networkProtocolName);
676
677         if (networkDataTask->shouldCaptureExtraNetworkLoadMetrics()) {
678             networkLoadMetrics.priority = toNetworkLoadPriority(task.priority);
679
680             networkLoadMetrics.remoteAddress = String(m._remoteAddressAndPort);
681             networkLoadMetrics.connectionIdentifier = String([m._connectionIdentifier UUIDString]);
682
683 #if HAVE(CFNETWORK_NEGOTIATED_SSL_PROTOCOL_CIPHER)
684             networkLoadMetrics.tlsProtocol = stringForSSLProtocol(m._negotiatedTLSProtocol);
685             networkLoadMetrics.tlsCipher = stringForSSLCipher(m._negotiatedTLSCipher);
686 #endif
687
688             __block WebCore::HTTPHeaderMap requestHeaders;
689             [m.request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *) {
690                 requestHeaders.set(String(name), String(value));
691             }];
692             networkLoadMetrics.requestHeaders = WTFMove(requestHeaders);
693
694             uint64_t requestHeaderBytesSent = 0;
695             uint64_t responseHeaderBytesReceived = 0;
696             uint64_t responseBodyBytesReceived = 0;
697             uint64_t responseBodyDecodedSize = 0;
698
699             for (NSURLSessionTaskTransactionMetrics *transactionMetrics in metrics.transactionMetrics) {
700                 requestHeaderBytesSent += transactionMetrics._requestHeaderBytesSent;
701                 responseHeaderBytesReceived += transactionMetrics._responseHeaderBytesReceived;
702                 responseBodyBytesReceived += transactionMetrics._responseBodyBytesReceived;
703                 responseBodyDecodedSize += transactionMetrics._responseBodyBytesDecoded ? transactionMetrics._responseBodyBytesDecoded : transactionMetrics._responseBodyBytesReceived;
704             }
705
706             networkLoadMetrics.requestHeaderBytesSent = requestHeaderBytesSent;
707             networkLoadMetrics.requestBodyBytesSent = task.countOfBytesSent;
708             networkLoadMetrics.responseHeaderBytesReceived = responseHeaderBytesReceived;
709             networkLoadMetrics.responseBodyBytesReceived = responseBodyBytesReceived;
710             networkLoadMetrics.responseBodyDecodedSize = responseBodyDecodedSize;
711         }
712     }
713 }
714
715 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
716 {
717     auto taskIdentifier = dataTask.taskIdentifier;
718     LOG(NetworkSession, "%llu didReceiveResponse", taskIdentifier);
719     if (auto* networkDataTask = [self existingTask:dataTask]) {
720         ASSERT(RunLoop::isMain());
721         
722         // Avoid MIME type sniffing if the response comes back as 304 Not Modified.
723         int statusCode = [response isKindOfClass:NSHTTPURLResponse.class] ? [(NSHTTPURLResponse *)response statusCode] : 0;
724         if (statusCode != 304) {
725             bool isMainResourceLoad = networkDataTask->firstRequest().requester() == WebCore::ResourceRequest::Requester::Main;
726             WebCore::adjustMIMETypeIfNecessary(response._CFURLResponse, isMainResourceLoad);
727         }
728
729         WebCore::ResourceResponse resourceResponse(response);
730         // Lazy initialization is not helpful in the WebKit2 case because we always end up initializing
731         // all the fields when sending the response to the WebContent process over IPC.
732         resourceResponse.disableLazyInitialization();
733
734         // FIXME: This cannot be eliminated until other code no longer relies on ResourceResponse's
735         // NetworkLoadMetrics. For example, PerformanceTiming.
736         copyTimingData([dataTask _timingData], resourceResponse.deprecatedNetworkLoadMetrics());
737
738         auto completionHandlerCopy = Block_copy(completionHandler);
739         networkDataTask->didReceiveResponse(WTFMove(resourceResponse), [completionHandlerCopy, taskIdentifier](WebCore::PolicyAction policyAction) {
740 #if !LOG_DISABLED
741             LOG(NetworkSession, "%llu didReceiveResponse completionHandler (%d)", taskIdentifier, policyAction);
742 #else
743             UNUSED_PARAM(taskIdentifier);
744 #endif
745             completionHandlerCopy(toNSURLSessionResponseDisposition(policyAction));
746             Block_release(completionHandlerCopy);
747         });
748     } else {
749         LOG(NetworkSession, "%llu didReceiveResponse completionHandler (cancel)", taskIdentifier);
750         completionHandler(NSURLSessionResponseCancel);
751     }
752 }
753
754 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
755 {
756     if (auto* networkDataTask = [self existingTask:dataTask])
757         networkDataTask->didReceiveData(WebCore::SharedBuffer::create(data));
758 }
759
760 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
761 {
762     if (!_session)
763         return;
764
765     auto downloadID = _session->takeDownloadID([downloadTask taskIdentifier]);
766     if (auto* download = _session->networkProcess().downloadManager().download(downloadID))
767         download->didFinish();
768 }
769
770 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
771 {
772     if (!_session)
773         return;
774
775     ASSERT_WITH_MESSAGE(![self existingTask:downloadTask], "The NetworkDataTask should be destroyed immediately after didBecomeDownloadTask returns");
776
777     auto downloadID = _session->downloadID([downloadTask taskIdentifier]);
778     if (auto* download = _session->networkProcess().downloadManager().download(downloadID))
779         download->didReceiveData(bytesWritten);
780 }
781
782 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
783 {
784     if (!_session)
785         return;
786
787     notImplemented();
788 }
789
790 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
791 {
792     if (auto* networkDataTask = [self existingTask:dataTask]) {
793         Ref<NetworkDataTaskCocoa> protectedNetworkDataTask(*networkDataTask);
794         auto downloadID = networkDataTask->pendingDownloadID();
795         auto& downloadManager = _session->networkProcess().downloadManager();
796         auto download = makeUnique<WebKit::Download>(downloadManager, downloadID, downloadTask, _session->sessionID(), networkDataTask->suggestedFilename());
797         networkDataTask->transferSandboxExtensionToDownload(*download);
798         ASSERT(FileSystem::fileExists(networkDataTask->pendingDownloadLocation()));
799         download->didCreateDestination(networkDataTask->pendingDownloadLocation());
800         downloadManager.dataTaskBecameDownloadTask(downloadID, WTFMove(download));
801
802         _session->addDownloadID([downloadTask taskIdentifier], downloadID);
803     }
804 }
805
806 #if HAVE(NSURLSESSION_WEBSOCKET)
807 - (WebSocketTask*)existingWebSocketTask:(NSURLSessionWebSocketTask *)task
808 {
809     if (!_session)
810         return nullptr;
811
812     if (!task)
813         return nullptr;
814
815     return _session->webSocketDataTaskForIdentifier(task.taskIdentifier);
816 }
817
818
819 - (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)task didOpenWithProtocol:(NSString *) protocol
820 {
821     if (auto* webSocketTask = [self existingWebSocketTask:task])
822         webSocketTask->didConnect(protocol);
823 }
824
825 - (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)task didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode reason:(NSData *)reason
826 {
827     if (auto* webSocketTask = [self existingWebSocketTask:task]) {
828         auto reason = adoptNS([[NSString alloc] initWithData:[task closeReason] encoding:NSUTF8StringEncoding]);
829         webSocketTask->didClose(closeCode, reason.get());
830     }
831 }
832 #endif
833
834 @end
835
836 namespace WebKit {
837
838 #if !ASSERT_DISABLED
839 static bool sessionsCreated = false;
840 #endif
841
842 static NSURLSessionConfiguration *configurationForSessionID(const PAL::SessionID& session)
843 {
844     if (session.isEphemeral()) {
845         NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
846         configuration._shouldSkipPreferredClientCertificateLookup = YES;
847 #if HAVE(ALLOWS_SENSITIVE_LOGGING)
848         configuration._allowsSensitiveLogging = NO;
849 #endif
850         return configuration;
851     }
852     return [NSURLSessionConfiguration defaultSessionConfiguration];
853 }
854
855 const String& NetworkSessionCocoa::boundInterfaceIdentifier() const
856 {
857     return m_boundInterfaceIdentifier;
858 }
859
860 const String& NetworkSessionCocoa::sourceApplicationBundleIdentifier() const
861 {
862     return m_sourceApplicationBundleIdentifier;
863 }
864
865 const String& NetworkSessionCocoa::sourceApplicationSecondaryIdentifier() const
866 {
867     return m_sourceApplicationSecondaryIdentifier;
868 }
869
870 #if PLATFORM(IOS_FAMILY)
871 static String& globalCTDataConnectionServiceType()
872 {
873     static NeverDestroyed<String> ctDataConnectionServiceType;
874     return ctDataConnectionServiceType.get();
875 }
876
877 const String& NetworkSessionCocoa::ctDataConnectionServiceType() const
878 {
879     return globalCTDataConnectionServiceType();
880 }
881
882 void NetworkSessionCocoa::setCTDataConnectionServiceType(const String& type)
883 {
884     ASSERT(!sessionsCreated);
885     globalCTDataConnectionServiceType() = type;
886 }
887 #endif
888
889 std::unique_ptr<NetworkSession> NetworkSessionCocoa::create(NetworkProcess& networkProcess, NetworkSessionCreationParameters&& parameters)
890 {
891     return makeUnique<NetworkSessionCocoa>(networkProcess, WTFMove(parameters));
892 }
893
894 static NSDictionary *proxyDictionary(const URL& httpProxy, const URL& httpsProxy)
895 {
896     if (!httpProxy.isValid() && !httpsProxy.isValid())
897         return nil;
898
899     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
900
901     NSMutableDictionary *dictionary = [[[NSMutableDictionary alloc] init] autorelease];
902     if (httpProxy.isValid()) {
903         [dictionary setObject:httpProxy.host().toString() forKey:(NSString *)kCFStreamPropertyHTTPProxyHost];
904         if (auto port = httpProxy.port())
905             [dictionary setObject:@(*port) forKey:(NSString *)kCFStreamPropertyHTTPProxyPort];
906     }
907     if (httpsProxy.isValid()) {
908         [dictionary setObject:httpsProxy.host().toString() forKey:(NSString *)kCFStreamPropertyHTTPSProxyHost];
909         if (auto port = httpsProxy.port())
910             [dictionary setObject:@(*port) forKey:(NSString *)kCFStreamPropertyHTTPSProxyPort];
911     }
912     return dictionary;
913
914     ALLOW_DEPRECATED_DECLARATIONS_END
915 }
916
917 NetworkSessionCocoa::NetworkSessionCocoa(NetworkProcess& networkProcess, NetworkSessionCreationParameters&& parameters)
918     : NetworkSession(networkProcess, parameters)
919     , m_boundInterfaceIdentifier(parameters.boundInterfaceIdentifier)
920     , m_sourceApplicationBundleIdentifier(parameters.sourceApplicationBundleIdentifier)
921     , m_sourceApplicationSecondaryIdentifier(parameters.sourceApplicationSecondaryIdentifier)
922     , m_proxyConfiguration(parameters.proxyConfiguration)
923     , m_shouldLogCookieInformation(parameters.shouldLogCookieInformation)
924     , m_loadThrottleLatency(parameters.loadThrottleLatency)
925     , m_fastServerTrustEvaluationEnabled(parameters.fastServerTrustEvaluationEnabled)
926 {
927     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
928
929 #if !ASSERT_DISABLED
930     sessionsCreated = true;
931 #endif
932
933     NSURLSessionConfiguration *configuration = configurationForSessionID(m_sessionID);
934
935     if (!parameters.enableLegacyTLS) {
936 #if HAVE(TLS_PROTOCOL_VERSION_T)
937         configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12;
938 #else
939         configuration.TLSMinimumSupportedProtocol = kTLSProtocol12;
940 #endif
941     }
942
943 #if HAVE(APP_SSO)
944     configuration._preventsAppSSO = true;
945 #endif
946
947     // Without this, CFNetwork would sometimes add a Content-Type header to our requests (rdar://problem/34748470).
948     configuration._suppressedAutoAddedHTTPHeaders = [NSSet setWithObject:@"Content-Type"];
949
950     if (parameters.allowsCellularAccess == AllowsCellularAccess::No)
951         configuration.allowsCellularAccess = NO;
952
953     // The WebKit network cache was already queried.
954     configuration.URLCache = nil;
955
956     if (auto data = networkProcess.sourceApplicationAuditData())
957         configuration._sourceApplicationAuditTokenData = (__bridge NSData *)data.get();
958
959     if (!m_sourceApplicationBundleIdentifier.isEmpty()) {
960         configuration._sourceApplicationBundleIdentifier = m_sourceApplicationBundleIdentifier;
961         configuration._sourceApplicationAuditTokenData = nil;
962     }
963
964     if (!m_sourceApplicationSecondaryIdentifier.isEmpty())
965         configuration._sourceApplicationSecondaryIdentifier = m_sourceApplicationSecondaryIdentifier;
966
967     configuration.connectionProxyDictionary = proxyDictionary(parameters.httpProxy, parameters.httpsProxy);
968
969 #if PLATFORM(IOS_FAMILY)
970     String ctDataConnectionServiceType = parameters.dataConnectionServiceType;
971     if (ctDataConnectionServiceType.isEmpty())
972         ctDataConnectionServiceType = globalCTDataConnectionServiceType();
973     if (!ctDataConnectionServiceType.isEmpty())
974         configuration._CTDataConnectionServiceType = ctDataConnectionServiceType;
975 #endif
976
977 #if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
978     networkProcess.supplement<LegacyCustomProtocolManager>()->registerProtocolClass(configuration);
979 #endif
980
981 #if HAVE(TIMINGDATAOPTIONS)
982     configuration._timingDataOptions = _TimingDataOptionsEnableW3CNavigationTiming;
983 #else
984     setCollectsTimingData();
985 #endif
986
987 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || PLATFORM(IOS_FAMILY)
988     // FIXME: Replace @"kCFStreamPropertyAutoErrorOnSystemChange" with a constant from the SDK once rdar://problem/40650244 is in a build.
989     if (networkProcess.suppressesConnectionTerminationOnSystemChange())
990         configuration._socketStreamProperties = @{ @"kCFStreamPropertyAutoErrorOnSystemChange" : @NO };
991 #endif
992
993 #if PLATFORM(WATCHOS)
994     configuration._companionProxyPreference = NSURLSessionCompanionProxyPreferencePreferDirectToCloud;
995 #endif
996
997     auto* storageSession = networkProcess.storageSession(parameters.sessionID);
998     RELEASE_ASSERT(storageSession);
999
1000     NSHTTPCookieStorage* cookieStorage;
1001     if (CFHTTPCookieStorageRef storage = storageSession->cookieStorage().get()) {
1002         cookieStorage = [[[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:storage] autorelease];
1003         configuration.HTTPCookieStorage = cookieStorage;
1004     } else
1005         cookieStorage = storageSession->nsCookieStorage();
1006
1007 #if HAVE(CFNETWORK_OVERRIDE_SESSION_COOKIE_ACCEPT_POLICY)
1008     // We still need to check the selector since CFNetwork updates and WebKit updates are separate
1009     // on older macOS.
1010     if ([cookieStorage respondsToSelector:@selector(_overrideSessionCookieAcceptPolicy)])
1011         cookieStorage._overrideSessionCookieAcceptPolicy = YES;
1012 #endif
1013
1014     m_sessionWithCredentialStorageDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:true]);
1015     m_sessionWithCredentialStorage = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_sessionWithCredentialStorageDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1016     LOG(NetworkSession, "Created NetworkSession with cookieAcceptPolicy %lu", configuration.HTTPCookieStorage.cookieAcceptPolicy);
1017
1018     configuration.URLCredentialStorage = nil;
1019     configuration._shouldSkipPreferredClientCertificateLookup = YES;
1020     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=177394
1021     // configuration.HTTPCookieStorage = nil;
1022     // configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
1023
1024     m_statelessSessionDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:false]);
1025     m_statelessSession = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_statelessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1026
1027     m_deviceManagementRestrictionsEnabled = parameters.deviceManagementRestrictionsEnabled;
1028     m_allLoadsBlockedByDeviceManagementRestrictionsForTesting = parameters.allLoadsBlockedByDeviceManagementRestrictionsForTesting;
1029
1030 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1031     m_resourceLoadStatisticsDirectory = parameters.resourceLoadStatisticsDirectory;
1032     m_shouldIncludeLocalhostInResourceLoadStatistics = parameters.shouldIncludeLocalhostInResourceLoadStatistics ? ShouldIncludeLocalhost::Yes : ShouldIncludeLocalhost::No;
1033     m_enableResourceLoadStatisticsDebugMode = parameters.enableResourceLoadStatisticsDebugMode ? EnableResourceLoadStatisticsDebugMode::Yes : EnableResourceLoadStatisticsDebugMode::No;
1034     m_resourceLoadStatisticsManualPrevalentResource = parameters.resourceLoadStatisticsManualPrevalentResource;
1035     m_enableResourceLoadStatisticsNSURLSessionSwitching = parameters.enableResourceLoadStatisticsNSURLSessionSwitching ? EnableResourceLoadStatisticsNSURLSessionSwitching::Yes : EnableResourceLoadStatisticsNSURLSessionSwitching::No;
1036     setResourceLoadStatisticsEnabled(parameters.enableResourceLoadStatistics);
1037 #endif
1038
1039 #if HAVE(SESSION_CLEANUP)
1040     activateSessionCleanup(*this);
1041 #endif
1042 }
1043
1044 NetworkSessionCocoa::~NetworkSessionCocoa()
1045 {
1046 }
1047
1048 void NetworkSessionCocoa::initializeEphemeralStatelessCookielessSession()
1049 {
1050     NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
1051     NSURLSessionConfiguration *existingConfiguration = m_statelessSession.get().configuration;
1052
1053     configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
1054     configuration.URLCredentialStorage = nil;
1055     configuration.URLCache = nil;
1056     configuration.allowsCellularAccess = existingConfiguration.allowsCellularAccess;
1057     configuration.connectionProxyDictionary = existingConfiguration.connectionProxyDictionary;
1058
1059     configuration._shouldSkipPreferredClientCertificateLookup = YES;
1060     configuration._sourceApplicationAuditTokenData = existingConfiguration._sourceApplicationAuditTokenData;
1061     configuration._sourceApplicationSecondaryIdentifier = existingConfiguration._sourceApplicationSecondaryIdentifier;
1062 #if PLATFORM(IOS_FAMILY)
1063     configuration._CTDataConnectionServiceType = existingConfiguration._CTDataConnectionServiceType;
1064 #endif
1065
1066     m_ephemeralStatelessCookielessSessionDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:false]);
1067     m_ephemeralStatelessCookielessSession = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_ephemeralStatelessCookielessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1068 }
1069
1070 NSURLSession* NetworkSessionCocoa::session(WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
1071 {
1072     switch (storedCredentialsPolicy) {
1073     case WebCore::StoredCredentialsPolicy::Use:
1074         return m_sessionWithCredentialStorage.get();
1075     case WebCore::StoredCredentialsPolicy::DoNotUse:
1076         return m_statelessSession.get();
1077     case WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless:
1078         if (!m_ephemeralStatelessCookielessSession)
1079             initializeEphemeralStatelessCookielessSession();
1080         return m_ephemeralStatelessCookielessSession.get();
1081     }
1082 }
1083
1084 NSURLSession* NetworkSessionCocoa::isolatedSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy, const WebCore::RegistrableDomain firstPartyDomain)
1085 {
1086     auto entry = m_isolatedSessions.ensure(firstPartyDomain, [this] {
1087         IsolatedSession newEntry { };
1088         newEntry.sessionWithCredentialStorageDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:true]);
1089         newEntry.sessionWithCredentialStorage = [NSURLSession sessionWithConfiguration:m_sessionWithCredentialStorage.get().configuration delegate:static_cast<id>(newEntry.sessionWithCredentialStorageDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1090
1091         newEntry.statelessSessionDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:false]);
1092         newEntry.statelessSession = [NSURLSession sessionWithConfiguration:m_statelessSession.get().configuration delegate:static_cast<id>(newEntry.statelessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1093
1094         return newEntry;
1095     }).iterator->value;
1096
1097     entry.lastUsed = WallTime::now();
1098
1099     if (m_isolatedSessions.size() > maxNumberOfIsolatedSessions) {
1100         WebCore::RegistrableDomain keyToRemove;
1101         auto oldestTimestamp = WallTime::now();
1102         for (auto& key : m_isolatedSessions.keys()) {
1103             auto timestamp = m_isolatedSessions.get(key).lastUsed;
1104             if (timestamp < oldestTimestamp) {
1105                 oldestTimestamp = timestamp;
1106                 keyToRemove = key;
1107             }
1108         }
1109         LOG(NetworkSession, "About to remove isolated NSURLSession.");
1110         m_isolatedSessions.remove(keyToRemove);
1111     }
1112
1113     RELEASE_ASSERT(m_isolatedSessions.size() <= maxNumberOfIsolatedSessions);
1114
1115     switch (storedCredentialsPolicy) {
1116     case WebCore::StoredCredentialsPolicy::Use:
1117         LOG(NetworkSession, "Using isolated NSURLSession with credential storage.");
1118         return entry.sessionWithCredentialStorage.get();
1119     case WebCore::StoredCredentialsPolicy::DoNotUse:
1120         LOG(NetworkSession, "Using isolated NSURLSession without credential storage.");
1121         return entry.statelessSession.get();
1122     case WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless:
1123         if (!m_ephemeralStatelessCookielessSession)
1124             initializeEphemeralStatelessCookielessSession();
1125         return m_ephemeralStatelessCookielessSession.get();
1126     }
1127 }
1128
1129 bool NetworkSessionCocoa::hasIsolatedSession(const WebCore::RegistrableDomain domain) const
1130 {
1131     return m_isolatedSessions.contains(domain);
1132 }
1133
1134 void NetworkSessionCocoa::clearIsolatedSessions()
1135 {
1136     m_isolatedSessions.clear();
1137 }
1138
1139 void NetworkSessionCocoa::invalidateAndCancel()
1140 {
1141     NetworkSession::invalidateAndCancel();
1142
1143     [m_sessionWithCredentialStorage invalidateAndCancel];
1144     [m_statelessSession invalidateAndCancel];
1145     [m_ephemeralStatelessCookielessSession invalidateAndCancel];
1146     [m_sessionWithCredentialStorageDelegate sessionInvalidated];
1147     [m_statelessSessionDelegate sessionInvalidated];
1148     [m_ephemeralStatelessCookielessSessionDelegate sessionInvalidated];
1149
1150     for (auto& session : m_isolatedSessions.values()) {
1151         [session.sessionWithCredentialStorage invalidateAndCancel];
1152         [session.sessionWithCredentialStorageDelegate sessionInvalidated];
1153     }
1154     m_isolatedSessions.clear();
1155 }
1156
1157 void NetworkSessionCocoa::clearCredentials()
1158 {
1159 #if !USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
1160     ASSERT(m_dataTaskMapWithCredentials.isEmpty());
1161     ASSERT(m_dataTaskMapWithoutState.isEmpty());
1162     ASSERT(m_downloadMap.isEmpty());
1163     // FIXME: Use resetWithCompletionHandler instead.
1164     m_sessionWithCredentialStorage = [NSURLSession sessionWithConfiguration:m_sessionWithCredentialStorage.get().configuration delegate:static_cast<id>(m_sessionWithCredentialStorageDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1165     m_statelessSession = [NSURLSession sessionWithConfiguration:m_statelessSession.get().configuration delegate:static_cast<id>(m_statelessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1166     for (auto& entry : m_isolatedSessions.values())
1167         entry.session = [NSURLSession sessionWithConfiguration:entry.session.get().configuration delegate:static_cast<id>(entry.delegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1168 #endif
1169 }
1170
1171 NetworkDataTaskCocoa* NetworkSessionCocoa::dataTaskForIdentifier(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
1172 {
1173     ASSERT(RunLoop::isMain());
1174     if (storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use)
1175         return m_dataTaskMapWithCredentials.get(taskIdentifier);
1176     return m_dataTaskMapWithoutState.get(taskIdentifier);
1177 }
1178
1179 NSURLSessionDownloadTask* NetworkSessionCocoa::downloadTaskWithResumeData(NSData* resumeData)
1180 {
1181     return [m_sessionWithCredentialStorage downloadTaskWithResumeData:resumeData];
1182 }
1183
1184 void NetworkSessionCocoa::addDownloadID(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, DownloadID downloadID)
1185 {
1186 #ifndef NDEBUG
1187     ASSERT(!m_downloadMap.contains(taskIdentifier));
1188     for (auto idInMap : m_downloadMap.values())
1189         ASSERT(idInMap != downloadID);
1190 #endif
1191     m_downloadMap.add(taskIdentifier, downloadID);
1192 }
1193
1194 DownloadID NetworkSessionCocoa::downloadID(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier)
1195 {
1196     ASSERT(m_downloadMap.get(taskIdentifier).downloadID());
1197     return m_downloadMap.get(taskIdentifier);
1198 }
1199
1200 DownloadID NetworkSessionCocoa::takeDownloadID(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier)
1201 {
1202     auto downloadID = m_downloadMap.take(taskIdentifier);
1203     return downloadID;
1204 }
1205
1206 static bool certificatesMatch(SecTrustRef trust1, SecTrustRef trust2)
1207 {
1208     if (!trust1 || !trust2)
1209         return false;
1210
1211     CFIndex count1 = SecTrustGetCertificateCount(trust1);
1212     CFIndex count2 = SecTrustGetCertificateCount(trust2);
1213     if (count1 != count2)
1214         return false;
1215
1216     for (CFIndex i = 0; i < count1; i++) {
1217         auto cert1 = SecTrustGetCertificateAtIndex(trust1, i);
1218         auto cert2 = SecTrustGetCertificateAtIndex(trust2, i);
1219         RELEASE_ASSERT(cert1);
1220         RELEASE_ASSERT(cert2);
1221         if (!CFEqual(cert1, cert2))
1222             return false;
1223     }
1224
1225     return true;
1226 }
1227
1228 bool NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge& challenge)
1229 {
1230     const String& host = challenge.protectionSpace().host();
1231     NSArray *certificates = [NSURLRequest allowsSpecificHTTPSCertificateForHost:host];
1232     if (!certificates)
1233         return false;
1234
1235     bool requireServerCertificates = challenge.protectionSpace().authenticationScheme() == WebCore::ProtectionSpaceAuthenticationScheme::ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
1236     RetainPtr<SecPolicyRef> policy = adoptCF(SecPolicyCreateSSL(requireServerCertificates, host.createCFString().get()));
1237
1238     SecTrustRef trustRef = nullptr;
1239     if (SecTrustCreateWithCertificates((CFArrayRef)certificates, policy.get(), &trustRef) != noErr)
1240         return false;
1241     RetainPtr<SecTrustRef> trust = adoptCF(trustRef);
1242
1243     return certificatesMatch(trust.get(), challenge.nsURLAuthenticationChallenge().protectionSpace.serverTrust);
1244 }
1245
1246 void NetworkSessionCocoa::continueDidReceiveChallenge(const WebCore::AuthenticationChallenge& challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&& completionHandler)
1247 {
1248     if (!networkDataTask) {
1249 #if HAVE(NSURLSESSION_WEBSOCKET)
1250         if (auto* webSocketTask = webSocketDataTaskForIdentifier(taskIdentifier)) {
1251             // FIXME: Handle challenges for web socket.
1252             completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, { });
1253             return;
1254         }
1255 #endif
1256
1257         auto downloadID = this->downloadID(taskIdentifier);
1258         if (downloadID.downloadID()) {
1259             if (auto* download = networkProcess().downloadManager().download(downloadID)) {
1260                 WebCore::AuthenticationChallenge authenticationChallenge { challenge };
1261                 // Received an authentication challenge for a download being resumed.
1262                 download->didReceiveChallenge(authenticationChallenge, WTFMove(completionHandler));
1263                 return;
1264             }
1265         }
1266         LOG(NetworkSession, "%llu didReceiveChallenge completionHandler (cancel)", taskIdentifier);
1267         completionHandler(AuthenticationChallengeDisposition::Cancel, { });
1268         return;
1269     }
1270
1271     auto sessionID = this->sessionID();
1272     WebCore::AuthenticationChallenge authenticationChallenge { challenge };
1273     auto challengeCompletionHandler = [completionHandler = WTFMove(completionHandler), networkProcess = makeRef(networkProcess()), sessionID, authenticationChallenge, taskIdentifier, partition = networkDataTask->partition()](WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
1274 #if !LOG_DISABLED
1275         LOG(NetworkSession, "%llu didReceiveChallenge completionHandler %d", taskIdentifier, disposition);
1276 #else
1277         UNUSED_PARAM(taskIdentifier);
1278 #endif
1279 #if !USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
1280         UNUSED_PARAM(sessionID);
1281         UNUSED_PARAM(authenticationChallenge);
1282 #else
1283         if (credential.persistence() == WebCore::CredentialPersistenceForSession && authenticationChallenge.protectionSpace().isPasswordBased()) {
1284             WebCore::Credential nonPersistentCredential(credential.user(), credential.password(), WebCore::CredentialPersistenceNone);
1285             URL urlToStore;
1286             if (authenticationChallenge.failureResponse().httpStatusCode() == 401)
1287                 urlToStore = authenticationChallenge.failureResponse().url();
1288             if (auto storageSession = networkProcess->storageSession(sessionID))
1289                 storageSession->credentialStorage().set(partition, nonPersistentCredential, authenticationChallenge.protectionSpace(), urlToStore);
1290             else
1291                 ASSERT_NOT_REACHED();
1292
1293             completionHandler(disposition, nonPersistentCredential);
1294             return;
1295         }
1296 #endif
1297         completionHandler(disposition, credential);
1298     };
1299     networkDataTask->didReceiveChallenge(WTFMove(authenticationChallenge), WTFMove(challengeCompletionHandler));
1300 }
1301
1302 DMFWebsitePolicyMonitor *NetworkSessionCocoa::deviceManagementPolicyMonitor()
1303 {
1304 #if HAVE(DEVICE_MANAGEMENT)
1305     ASSERT(m_deviceManagementRestrictionsEnabled);
1306     if (!m_deviceManagementPolicyMonitor)
1307         m_deviceManagementPolicyMonitor = adoptNS([allocDMFWebsitePolicyMonitorInstance() initWithPolicyChangeHandler:nil]);
1308     return m_deviceManagementPolicyMonitor.get();
1309 #else
1310     RELEASE_ASSERT_NOT_REACHED();
1311     return nil;
1312 #endif
1313 }
1314
1315 #if HAVE(NSURLSESSION_WEBSOCKET)
1316 std::unique_ptr<WebSocketTask> NetworkSessionCocoa::createWebSocketTask(NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol)
1317 {
1318     // FIXME: Use protocol.
1319     RetainPtr<NSURLSessionWebSocketTask> task = [m_sessionWithCredentialStorage.get() webSocketTaskWithRequest: request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)];
1320     return makeUnique<WebSocketTask>(channel, WTFMove(task));
1321 }
1322
1323 void NetworkSessionCocoa::addWebSocketTask(WebSocketTask& task)
1324 {
1325     ASSERT(!m_webSocketDataTaskMap.contains(task.identifier()));
1326     m_webSocketDataTaskMap.add(task.identifier(), &task);
1327 }
1328
1329 void NetworkSessionCocoa::removeWebSocketTask(WebSocketTask& task)
1330 {
1331     ASSERT(m_webSocketDataTaskMap.contains(task.identifier()));
1332     m_webSocketDataTaskMap.remove(task.identifier());
1333 }
1334
1335 WebSocketTask* NetworkSessionCocoa::webSocketDataTaskForIdentifier(WebSocketTask::TaskIdentifier identifier)
1336 {
1337     return m_webSocketDataTaskMap.get(identifier);
1338 }
1339
1340 #endif
1341 }