Make _WKWebsiteDataStoreConfiguration SPI for HSTS storage to replace _WKProcessPoolC...
[WebKit-https.git] / Source / WebKit / NetworkProcess / cocoa / NetworkSessionCocoa.mm
1 /*
2  * Copyright (C) 2015-2020 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/BlockPtr.h>
52 #import <wtf/MainThread.h>
53 #import <wtf/NakedRef.h>
54 #import <wtf/NeverDestroyed.h>
55 #import <wtf/ObjCRuntimeExtras.h>
56 #import <wtf/ProcessPrivilege.h>
57 #import <wtf/SoftLinking.h>
58 #import <wtf/URL.h>
59 #import <wtf/WeakObjCPtr.h>
60 #import <wtf/text/WTFString.h>
61
62 #if USE(APPLE_INTERNAL_SDK)
63 #import <WebKitAdditions/NetworkSessionCocoaAdditions.h>
64 #else
65 #define NETWORK_SESSION_COCOA_ADDITIONS_1
66 #define NETWORK_SESSION_COCOA_ADDITIONS_2 true
67 #endif
68
69 #import "DeviceManagementSoftLink.h"
70
71 // FIXME: Remove this soft link once rdar://problem/50109631 is in a build and bots are updated.
72 SOFT_LINK_FRAMEWORK(CFNetwork)
73 SOFT_LINK_CLASS_OPTIONAL(CFNetwork, _NSHSTSStorage)
74
75 using namespace WebKit;
76
77 CFStringRef const WebKit2HTTPProxyDefaultsKey = static_cast<CFStringRef>(@"WebKit2HTTPProxy");
78 CFStringRef const WebKit2HTTPSProxyDefaultsKey = static_cast<CFStringRef>(@"WebKit2HTTPSProxy");
79
80 constexpr unsigned maxNumberOfIsolatedSessions { 10 };
81
82 static NSURLSessionResponseDisposition toNSURLSessionResponseDisposition(WebCore::PolicyAction disposition)
83 {
84     switch (disposition) {
85     case WebCore::PolicyAction::StopAllLoads:
86         ASSERT_NOT_REACHED();
87 #if !ASSERT_ENABLED
88         FALLTHROUGH;
89 #endif
90     case WebCore::PolicyAction::Ignore:
91         return NSURLSessionResponseCancel;
92     case WebCore::PolicyAction::Use:
93         return NSURLSessionResponseAllow;
94     case WebCore::PolicyAction::Download:
95         return NSURLSessionResponseBecomeDownload;
96     }
97 }
98
99 static NSURLSessionAuthChallengeDisposition toNSURLSessionAuthChallengeDisposition(WebKit::AuthenticationChallengeDisposition disposition)
100 {
101     switch (disposition) {
102     case WebKit::AuthenticationChallengeDisposition::UseCredential:
103         return NSURLSessionAuthChallengeUseCredential;
104     case WebKit::AuthenticationChallengeDisposition::PerformDefaultHandling:
105         return NSURLSessionAuthChallengePerformDefaultHandling;
106     case WebKit::AuthenticationChallengeDisposition::Cancel:
107         return NSURLSessionAuthChallengeCancelAuthenticationChallenge;
108     case WebKit::AuthenticationChallengeDisposition::RejectProtectionSpaceAndContinue:
109         return NSURLSessionAuthChallengeRejectProtectionSpace;
110     }
111 }
112
113 static WebCore::NetworkLoadPriority toNetworkLoadPriority(float priority)
114 {
115     if (priority <= NSURLSessionTaskPriorityLow)
116         return WebCore::NetworkLoadPriority::Low;
117     if (priority >= NSURLSessionTaskPriorityHigh)
118         return WebCore::NetworkLoadPriority::High;
119     return WebCore::NetworkLoadPriority::Medium;
120 }
121
122 #if HAVE(CFNETWORK_NEGOTIATED_SSL_PROTOCOL_CIPHER)
123 #if HAVE(CFNETWORK_METRICS_APIS_V4)
124 static String stringForTLSProtocolVersion(tls_protocol_version_t protocol)
125 {
126     switch (protocol) {
127     case tls_protocol_version_TLSv10:
128         return "TLS 1.0"_s;
129     case tls_protocol_version_TLSv11:
130         return "TLS 1.1"_s;
131     case tls_protocol_version_TLSv12:
132         return "TLS 1.2"_s;
133     case tls_protocol_version_TLSv13:
134         return "TLS 1.3"_s;
135     case tls_protocol_version_DTLSv10:
136         return "DTLS 1.0"_s;
137     case tls_protocol_version_DTLSv12:
138         return "DTLS 1.2"_s;
139     }
140     return { };
141 }
142
143 static String stringForTLSCipherSuite(tls_ciphersuite_t suite)
144 {
145 #define STRINGIFY_CIPHER(cipher) \
146     case tls_ciphersuite_##cipher: \
147         return "" #cipher ""_s
148
149     switch (suite) {
150         STRINGIFY_CIPHER(RSA_WITH_3DES_EDE_CBC_SHA);
151         STRINGIFY_CIPHER(RSA_WITH_AES_128_CBC_SHA);
152         STRINGIFY_CIPHER(RSA_WITH_AES_256_CBC_SHA);
153         STRINGIFY_CIPHER(RSA_WITH_AES_128_GCM_SHA256);
154         STRINGIFY_CIPHER(RSA_WITH_AES_256_GCM_SHA384);
155         STRINGIFY_CIPHER(RSA_WITH_AES_128_CBC_SHA256);
156         STRINGIFY_CIPHER(RSA_WITH_AES_256_CBC_SHA256);
157         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA);
158         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
159         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
160         STRINGIFY_CIPHER(ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
161         STRINGIFY_CIPHER(ECDHE_RSA_WITH_AES_128_CBC_SHA);
162         STRINGIFY_CIPHER(ECDHE_RSA_WITH_AES_256_CBC_SHA);
163         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
164         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
165         STRINGIFY_CIPHER(ECDHE_RSA_WITH_AES_128_CBC_SHA256);
166         STRINGIFY_CIPHER(ECDHE_RSA_WITH_AES_256_CBC_SHA384);
167         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
168         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384);
169         STRINGIFY_CIPHER(ECDHE_RSA_WITH_AES_128_GCM_SHA256);
170         STRINGIFY_CIPHER(ECDHE_RSA_WITH_AES_256_GCM_SHA384);
171         STRINGIFY_CIPHER(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
172         STRINGIFY_CIPHER(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
173         STRINGIFY_CIPHER(AES_128_GCM_SHA256);
174         STRINGIFY_CIPHER(AES_256_GCM_SHA384);
175         STRINGIFY_CIPHER(CHACHA20_POLY1305_SHA256);
176     }
177
178     return { };
179
180 #undef STRINGIFY_CIPHER
181 }
182
183 #else // HAVE(CFNETWORK_METRICS_APIS_V4)
184
185 static String stringForSSLProtocol(SSLProtocol protocol)
186 {
187     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
188     switch (protocol) {
189     case kDTLSProtocol1:
190         return "DTLS 1.0"_s;
191     case kSSLProtocol2:
192         return "SSL 2.0"_s;
193     case kSSLProtocol3:
194         return "SSL 3.0"_s;
195     case kSSLProtocol3Only:
196         return "SSL 3.0 (Only)"_s;
197     case kTLSProtocol1:
198         return "TLS 1.0"_s;
199     case kTLSProtocol1Only:
200         return "TLS 1.0 (Only)"_s;
201     case kTLSProtocol11:
202         return "TLS 1.1"_s;
203     case kTLSProtocol12:
204         return "TLS 1.2"_s;
205     case kTLSProtocol13:
206         return "TLS 1.3"_s;
207     case kSSLProtocolAll:
208         return "All";
209     case kSSLProtocolUnknown:
210         return "Unknown";
211     case kTLSProtocolMaxSupported:
212     default:
213         ASSERT_NOT_REACHED();
214         return emptyString();
215     }
216     ALLOW_DEPRECATED_DECLARATIONS_END
217 }
218
219 static String stringForSSLCipher(SSLCipherSuite cipher)
220 {
221 #define STRINGIFY_CIPHER(cipher) \
222     case cipher: \
223         return "" #cipher ""_s
224
225     switch (cipher) {
226     STRINGIFY_CIPHER(SSL_RSA_EXPORT_WITH_RC4_40_MD5);
227     STRINGIFY_CIPHER(SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5);
228     STRINGIFY_CIPHER(SSL_RSA_WITH_IDEA_CBC_SHA);
229     STRINGIFY_CIPHER(SSL_RSA_EXPORT_WITH_DES40_CBC_SHA);
230     STRINGIFY_CIPHER(SSL_RSA_WITH_DES_CBC_SHA);
231     STRINGIFY_CIPHER(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
232     STRINGIFY_CIPHER(SSL_DH_DSS_WITH_DES_CBC_SHA);
233     STRINGIFY_CIPHER(SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
234     STRINGIFY_CIPHER(SSL_DH_RSA_WITH_DES_CBC_SHA);
235     STRINGIFY_CIPHER(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
236     STRINGIFY_CIPHER(SSL_DHE_DSS_WITH_DES_CBC_SHA);
237     STRINGIFY_CIPHER(SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
238     STRINGIFY_CIPHER(SSL_DHE_RSA_WITH_DES_CBC_SHA);
239     STRINGIFY_CIPHER(SSL_DH_anon_EXPORT_WITH_RC4_40_MD5);
240     STRINGIFY_CIPHER(SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA);
241     STRINGIFY_CIPHER(SSL_DH_anon_WITH_DES_CBC_SHA);
242     STRINGIFY_CIPHER(SSL_FORTEZZA_DMS_WITH_NULL_SHA);
243     STRINGIFY_CIPHER(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA);
244     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_128_CBC_SHA);
245     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_128_CBC_SHA);
246     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_128_CBC_SHA);
247     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
248     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
249     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_128_CBC_SHA);
250     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_256_CBC_SHA);
251     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_256_CBC_SHA);
252     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_256_CBC_SHA);
253     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
254     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
255     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_256_CBC_SHA);
256     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_NULL_SHA);
257     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
258     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA);
259     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA);
260     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA);
261     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_NULL_SHA);
262     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA);
263     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA);
264     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
265     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
266     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_NULL_SHA);
267     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_RC4_128_SHA);
268     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA);
269     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA);
270     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA);
271     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_NULL_SHA);
272     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_RC4_128_SHA);
273     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
274     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
275     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
276     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_NULL_SHA);
277     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_RC4_128_SHA);
278     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA);
279     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
280     STRINGIFY_CIPHER(TLS_ECDH_anon_WITH_AES_256_CBC_SHA);
281     // STRINGIFY_CIPHER(SSL_NULL_WITH_NULL_NULL);
282     STRINGIFY_CIPHER(TLS_NULL_WITH_NULL_NULL);
283     // STRINGIFY_CIPHER(SSL_RSA_WITH_NULL_MD5);
284     STRINGIFY_CIPHER(TLS_RSA_WITH_NULL_MD5);
285     // STRINGIFY_CIPHER(SSL_RSA_WITH_NULL_SHA);
286     STRINGIFY_CIPHER(TLS_RSA_WITH_NULL_SHA);
287     // STRINGIFY_CIPHER(SSL_RSA_WITH_RC4_128_MD5);
288     STRINGIFY_CIPHER(TLS_RSA_WITH_RC4_128_MD5);
289     // STRINGIFY_CIPHER(SSL_RSA_WITH_RC4_128_SHA);
290     STRINGIFY_CIPHER(TLS_RSA_WITH_RC4_128_SHA);
291     // STRINGIFY_CIPHER(SSL_RSA_WITH_3DES_EDE_CBC_SHA);
292     STRINGIFY_CIPHER(TLS_RSA_WITH_3DES_EDE_CBC_SHA);
293     STRINGIFY_CIPHER(TLS_RSA_WITH_NULL_SHA256);
294     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_128_CBC_SHA256);
295     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_256_CBC_SHA256);
296     // STRINGIFY_CIPHER(SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA);
297     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
298     // STRINGIFY_CIPHER(SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA);
299     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
300     // STRINGIFY_CIPHER(SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
301     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
302     // STRINGIFY_CIPHER(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
303     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
304     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_128_CBC_SHA256);
305     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_128_CBC_SHA256);
306     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256);
307     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256);
308     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_256_CBC_SHA256);
309     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_256_CBC_SHA256);
310     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256);
311     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256);
312     // STRINGIFY_CIPHER(SSL_DH_anon_WITH_RC4_128_MD5);
313     STRINGIFY_CIPHER(TLS_DH_anon_WITH_RC4_128_MD5);
314     // STRINGIFY_CIPHER(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA);
315     STRINGIFY_CIPHER(TLS_DH_anon_WITH_3DES_EDE_CBC_SHA);
316     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_128_CBC_SHA256);
317     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_256_CBC_SHA256);
318     STRINGIFY_CIPHER(TLS_PSK_WITH_RC4_128_SHA);
319     STRINGIFY_CIPHER(TLS_PSK_WITH_3DES_EDE_CBC_SHA);
320     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA);
321     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_256_CBC_SHA);
322     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_RC4_128_SHA);
323     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA);
324     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_128_CBC_SHA);
325     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_256_CBC_SHA);
326     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_RC4_128_SHA);
327     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA);
328     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_128_CBC_SHA);
329     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_256_CBC_SHA);
330     STRINGIFY_CIPHER(TLS_PSK_WITH_NULL_SHA);
331     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_NULL_SHA);
332     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_NULL_SHA);
333     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_128_GCM_SHA256);
334     STRINGIFY_CIPHER(TLS_RSA_WITH_AES_256_GCM_SHA384);
335     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256);
336     STRINGIFY_CIPHER(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384);
337     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_128_GCM_SHA256);
338     STRINGIFY_CIPHER(TLS_DH_RSA_WITH_AES_256_GCM_SHA384);
339     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256);
340     STRINGIFY_CIPHER(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384);
341     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_128_GCM_SHA256);
342     STRINGIFY_CIPHER(TLS_DH_DSS_WITH_AES_256_GCM_SHA384);
343     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_128_GCM_SHA256);
344     STRINGIFY_CIPHER(TLS_DH_anon_WITH_AES_256_GCM_SHA384);
345     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_128_GCM_SHA256);
346     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_256_GCM_SHA384);
347     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256);
348     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384);
349     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256);
350     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384);
351     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA256);
352     STRINGIFY_CIPHER(TLS_PSK_WITH_AES_256_CBC_SHA384);
353     STRINGIFY_CIPHER(TLS_PSK_WITH_NULL_SHA256);
354     STRINGIFY_CIPHER(TLS_PSK_WITH_NULL_SHA384);
355     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256);
356     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384);
357     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_NULL_SHA256);
358     STRINGIFY_CIPHER(TLS_DHE_PSK_WITH_NULL_SHA384);
359     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256);
360     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384);
361     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_NULL_SHA256);
362     STRINGIFY_CIPHER(TLS_RSA_PSK_WITH_NULL_SHA384);
363     STRINGIFY_CIPHER(TLS_AES_128_GCM_SHA256);
364     STRINGIFY_CIPHER(TLS_AES_256_GCM_SHA384);
365     STRINGIFY_CIPHER(TLS_CHACHA20_POLY1305_SHA256);
366     STRINGIFY_CIPHER(TLS_AES_128_CCM_SHA256);
367     STRINGIFY_CIPHER(TLS_AES_128_CCM_8_SHA256);
368     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
369     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
370     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256);
371     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384);
372     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);
373     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
374     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256);
375     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384);
376     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
377     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384);
378     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256);
379     STRINGIFY_CIPHER(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384);
380     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256);
381     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384);
382     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256);
383     STRINGIFY_CIPHER(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384);
384     STRINGIFY_CIPHER(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
385     STRINGIFY_CIPHER(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
386     STRINGIFY_CIPHER(TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
387     STRINGIFY_CIPHER(SSL_RSA_WITH_RC2_CBC_MD5);
388     STRINGIFY_CIPHER(SSL_RSA_WITH_IDEA_CBC_MD5);
389     STRINGIFY_CIPHER(SSL_RSA_WITH_DES_CBC_MD5);
390     STRINGIFY_CIPHER(SSL_RSA_WITH_3DES_EDE_CBC_MD5);
391     STRINGIFY_CIPHER(SSL_NO_SUCH_CIPHERSUITE);
392     default:
393         ASSERT_NOT_REACHED();
394         return emptyString();
395     }
396
397 #undef STRINGIFY_CIPHER
398 }
399 #endif // HAVE(CFNETWORK_METRICS_APIS_V4)
400 #endif // HAVE(CFNETWORK_NEGOTIATED_SSL_PROTOCOL_CIPHER)
401
402 @interface WKNetworkSessionDelegate : NSObject <NSURLSessionDataDelegate
403 #if HAVE(NSURLSESSION_WEBSOCKET)
404     , NSURLSessionWebSocketDelegate
405 #endif
406 > {
407     WeakPtr<WebKit::NetworkSessionCocoa> _session;
408     WeakPtr<WebKit::SessionWrapper> _sessionWrapper;
409     bool _withCredentials;
410 }
411
412 - (id)initWithNetworkSession:(NakedRef<WebKit::NetworkSessionCocoa>)session wrapper:(WebKit::SessionWrapper&)sessionWrapper withCredentials:(bool)withCredentials;
413 - (void)sessionInvalidated;
414
415 @end
416
417 @implementation WKNetworkSessionDelegate
418
419 - (id)initWithNetworkSession:(NakedRef<WebKit::NetworkSessionCocoa>)session wrapper:(WebKit::SessionWrapper&)sessionWrapper withCredentials:(bool)withCredentials
420 {
421     self = [super init];
422     if (!self)
423         return nil;
424
425     _session = makeWeakPtr(session.get());
426     _sessionWrapper = makeWeakPtr(sessionWrapper);
427     _withCredentials = withCredentials;
428
429     return self;
430 }
431
432 - (void)sessionInvalidated
433 {
434     _sessionWrapper = nullptr;
435 }
436
437 - (NetworkDataTaskCocoa*)existingTask:(NSURLSessionTask *)task
438 {
439     if (!_sessionWrapper)
440         return nullptr;
441
442     if (!task)
443         return nullptr;
444
445     return _sessionWrapper->dataTaskMap.get(task.taskIdentifier);
446 }
447
448 - (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
449 {
450     ASSERT(!_sessionWrapper);
451 }
452
453 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
454 {
455     if (auto* networkDataTask = [self existingTask:task])
456         networkDataTask->didSendData(totalBytesSent, totalBytesExpectedToSend);
457 }
458
459 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
460 {
461     auto* networkDataTask = [self existingTask:task];
462     if (!networkDataTask) {
463         completionHandler(nil);
464         return;
465     }
466
467     auto* body = networkDataTask->firstRequest().httpBody();
468     if (!body) {
469         completionHandler(nil);
470         return;
471     }
472
473     completionHandler(WebCore::createHTTPBodyNSInputStream(*body).get());
474 }
475
476 #if ENABLE(RESOURCE_LOAD_STATISTICS)
477 static NSURLRequest* downgradeRequest(NSURLRequest *request)
478 {
479     NSMutableURLRequest *nsMutableRequest = [[request mutableCopy] autorelease];
480     if ([nsMutableRequest.URL.scheme isEqualToString:@"https"]) {
481         NSURLComponents *components = [NSURLComponents componentsWithURL:nsMutableRequest.URL resolvingAgainstBaseURL:NO];
482         components.scheme = @"http";
483         [nsMutableRequest setURL:components.URL];
484         ASSERT([nsMutableRequest.URL.scheme isEqualToString:@"http"]);
485         return nsMutableRequest;
486     }
487
488     ASSERT_NOT_REACHED();
489     return request;
490 }
491
492 static bool schemeWasUpgradedDueToDynamicHSTS(NSURLRequest *request)
493 {
494     return [request respondsToSelector:@selector(_schemeWasUpgradedDueToDynamicHSTS)]
495         && [request _schemeWasUpgradedDueToDynamicHSTS];
496 }
497 #endif
498
499 static void setIgnoreHSTS(NSMutableURLRequest *request, bool ignoreHSTS)
500 {
501     if ([request respondsToSelector:@selector(_setIgnoreHSTS:)])
502         [request _setIgnoreHSTS:ignoreHSTS];
503 }
504
505 static bool ignoreHSTS(NSURLRequest *request)
506 {
507     return [request respondsToSelector:@selector(_ignoreHSTS)]
508         && [request _ignoreHSTS];
509 }
510
511 static NSURLRequest* updateIgnoreStrictTransportSecuritySettingIfNecessary(NSURLRequest *request, bool shouldIgnoreHSTS)
512 {
513     if ([request.URL.scheme isEqualToString:@"https"] && shouldIgnoreHSTS && ignoreHSTS(request)) {
514         // The request was upgraded for some other reason than HSTS.
515         // Don't ignore HSTS to avoid the risk of another downgrade.
516         NSMutableURLRequest *nsMutableRequest = [[request mutableCopy] autorelease];
517         setIgnoreHSTS(nsMutableRequest, false);
518         return nsMutableRequest;
519     }
520     
521     if ([request.URL.scheme isEqualToString:@"http"] && ignoreHSTS(request) != shouldIgnoreHSTS) {
522         NSMutableURLRequest *nsMutableRequest = [[request mutableCopy] autorelease];
523         setIgnoreHSTS(nsMutableRequest, shouldIgnoreHSTS);
524         return nsMutableRequest;
525     }
526
527     return request;
528 }
529
530 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
531 {
532     auto taskIdentifier = task.taskIdentifier;
533     LOG(NetworkSession, "%llu willPerformHTTPRedirection from %s to %s", taskIdentifier, response.URL.absoluteString.UTF8String, request.URL.absoluteString.UTF8String);
534
535     if (auto* networkDataTask = [self existingTask:task]) {
536         auto completionHandlerCopy = Block_copy(completionHandler);
537
538         if (auto* sessionCocoa = [self sessionFromTask:task])
539             sessionCocoa->taskServerConnectionSucceeded(taskIdentifier);
540
541         bool shouldIgnoreHSTS = false;
542 #if ENABLE(RESOURCE_LOAD_STATISTICS)
543         if (auto* sessionCocoa = networkDataTask->networkSession()) {
544             shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && sessionCocoa->networkProcess().storageSession(sessionCocoa->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID(), networkDataTask->shouldRelaxThirdPartyCookieBlocking());
545             if (shouldIgnoreHSTS) {
546                 request = downgradeRequest(request);
547                 ASSERT([request.URL.scheme isEqualToString:@"http"]);
548                 LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
549             }
550         } else
551             ASSERT_NOT_REACHED();
552 #endif
553
554         networkDataTask->willPerformHTTPRedirection(response, request, [completionHandlerCopy, taskIdentifier, shouldIgnoreHSTS](auto&& request) {
555 #if !LOG_DISABLED
556             LOG(NetworkSession, "%llu willPerformHTTPRedirection completionHandler (%s)", taskIdentifier, request.url().string().utf8().data());
557 #else
558             UNUSED_PARAM(taskIdentifier);
559 #endif
560             auto nsRequest = request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::UpdateHTTPBody);
561             nsRequest = updateIgnoreStrictTransportSecuritySettingIfNecessary(nsRequest, shouldIgnoreHSTS);
562             completionHandlerCopy(nsRequest);
563             Block_release(completionHandlerCopy);
564         });
565     } else {
566         LOG(NetworkSession, "%llu willPerformHTTPRedirection completionHandler (nil)", taskIdentifier);
567         completionHandler(nil);
568     }
569 }
570
571 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask*)task _schemeUpgraded:(NSURLRequest*)request completionHandler:(void (^)(NSURLRequest*))completionHandler
572 {
573     auto taskIdentifier = task.taskIdentifier;
574     LOG(NetworkSession, "%llu _schemeUpgraded %s", taskIdentifier, request.URL.absoluteString.UTF8String);
575
576     if (auto* networkDataTask = [self existingTask:task]) {
577         bool shouldIgnoreHSTS = false;
578 #if ENABLE(RESOURCE_LOAD_STATISTICS)
579         if (auto* sessionCocoa = networkDataTask->networkSession()) {
580             shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && sessionCocoa->networkProcess().storageSession(sessionCocoa->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID(), networkDataTask->shouldRelaxThirdPartyCookieBlocking());
581             if (shouldIgnoreHSTS) {
582                 request = downgradeRequest(request);
583                 ASSERT([request.URL.scheme isEqualToString:@"http"]);
584                 LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
585             }
586         } else
587             ASSERT_NOT_REACHED();
588 #endif
589
590         auto completionHandlerCopy = Block_copy(completionHandler);
591         networkDataTask->willPerformHTTPRedirection(WebCore::synthesizeRedirectResponseIfNecessary([task currentRequest], request, nil), request, [completionHandlerCopy, taskIdentifier, shouldIgnoreHSTS](auto&& request) {
592 #if !LOG_DISABLED
593             LOG(NetworkSession, "%llu _schemeUpgraded completionHandler (%s)", taskIdentifier, request.url().string().utf8().data());
594 #else
595             UNUSED_PARAM(taskIdentifier);
596 #endif
597             auto nsRequest = request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::UpdateHTTPBody);
598             nsRequest = updateIgnoreStrictTransportSecuritySettingIfNecessary(nsRequest, shouldIgnoreHSTS);
599             completionHandlerCopy(nsRequest);
600             Block_release(completionHandlerCopy);
601         });
602     } else {
603         LOG(NetworkSession, "%llu _schemeUpgraded completionHandler (nil)", taskIdentifier);
604         completionHandler(nil);
605     }
606 }
607
608 #if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
609 static inline void processServerTrustEvaluation(NetworkSessionCocoa& session, SessionWrapper& sessionWrapper, NSURLAuthenticationChallenge *challenge, NegotiatedLegacyTLS negotiatedLegacyTLS, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential)>&& completionHandler)
610 {
611     session.continueDidReceiveChallenge(sessionWrapper, challenge, negotiatedLegacyTLS, taskIdentifier, networkDataTask, [completionHandler = WTFMove(completionHandler), secTrust = retainPtr(challenge.protectionSpace.serverTrust)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
612         // FIXME: UIProcess should send us back non nil credentials but the credential IPC encoder currently only serializes ns credentials for username/password.
613         if (disposition == WebKit::AuthenticationChallengeDisposition::UseCredential && !credential.nsCredential()) {
614             completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust: secTrust.get()]);
615             return;
616         }
617         completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), credential.nsCredential());
618     });
619 }
620 #endif
621
622 - (NetworkSessionCocoa*)sessionFromTask:(NSURLSessionTask *)task {
623     if (auto* networkDataTask = [self existingTask:task])
624         return static_cast<NetworkSessionCocoa*>(networkDataTask->networkSession());
625
626     if (!_sessionWrapper)
627         return nullptr;
628
629     if (auto downloadID = _sessionWrapper->downloadMap.get(task.taskIdentifier)) {
630         if (auto download = _session->networkProcess().downloadManager().download(downloadID))
631             return static_cast<NetworkSessionCocoa*>(_session->networkProcess().networkSession(download->sessionID()));
632         return nullptr;
633     }
634
635 #if HAVE(NSURLSESSION_WEBSOCKET)
636     if (auto* webSocketTask = _sessionWrapper->webSocketDataTaskMap.get(task.taskIdentifier))
637         return webSocketTask->networkSession();
638 #endif
639
640     return nullptr;
641 }
642
643 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
644 {
645     auto* sessionCocoa = [self sessionFromTask: task];
646     if (!sessionCocoa || [task state] == NSURLSessionTaskStateCanceling) {
647         completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
648         return;
649     }
650
651     auto taskIdentifier = task.taskIdentifier;
652     LOG(NetworkSession, "%llu didReceiveChallenge", taskIdentifier);
653     
654     // Proxy authentication is handled by CFNetwork internally. We can get here if the user cancels
655     // CFNetwork authentication dialog, and we shouldn't ask the client to display another one in that case.
656     if (challenge.protectionSpace.isProxy && !sessionCocoa->preventsSystemHTTPProxyAuthentication()) {
657         completionHandler(NSURLSessionAuthChallengeUseCredential, nil);
658         return;
659     }
660
661     NegotiatedLegacyTLS negotiatedLegacyTLS = NegotiatedLegacyTLS::No;
662
663     if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
664         if (NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(challenge))
665             return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
666
667 #if HAVE(TLS_PROTOCOL_VERSION_T)
668         NSURLSessionTaskTransactionMetrics *metrics = task._incompleteTaskMetrics.transactionMetrics.lastObject;
669         auto tlsVersion = (tls_protocol_version_t)metrics.negotiatedTLSProtocolVersion.unsignedShortValue;
670         if (tlsVersion == tls_protocol_version_TLSv10 || tlsVersion == tls_protocol_version_TLSv11)
671             negotiatedLegacyTLS = NegotiatedLegacyTLS::Yes;
672 #endif
673         ALLOW_DEPRECATED_DECLARATIONS_BEGIN
674         if (negotiatedLegacyTLS == NegotiatedLegacyTLS::No && [task respondsToSelector:@selector(_TLSNegotiatedProtocolVersion)]) {
675             SSLProtocol tlsVersion = [task _TLSNegotiatedProtocolVersion];
676             if (tlsVersion == kTLSProtocol11 || tlsVersion == kTLSProtocol1)
677                 negotiatedLegacyTLS = NegotiatedLegacyTLS::Yes;
678         }
679         ALLOW_DEPRECATED_DECLARATIONS_END
680
681         // Handle server trust evaluation at platform-level if requested, for performance reasons and to use ATS defaults.
682         if (sessionCocoa->fastServerTrustEvaluationEnabled() && negotiatedLegacyTLS == NegotiatedLegacyTLS::No) {
683             auto* networkDataTask = [self existingTask:task];
684             if (networkDataTask)
685                 networkDataTask->didNegotiateModernTLS(challenge);
686 #if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
687             auto decisionHandler = makeBlockPtr([weakSelf = WeakObjCPtr<WKNetworkSessionDelegate>(self), sessionCocoa = makeWeakPtr(sessionCocoa), completionHandler = makeBlockPtr(completionHandler), taskIdentifier, networkDataTask = makeRefPtr(networkDataTask), negotiatedLegacyTLS](NSURLAuthenticationChallenge *challenge, OSStatus trustResult) mutable {
688                 auto strongSelf = weakSelf.get();
689                 if (!strongSelf)
690                     return completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
691                 auto task = WTFMove(networkDataTask);
692                 auto* session = sessionCocoa.get();
693                 if (trustResult == noErr || !session) {
694                     completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
695                     return;
696                 }
697                 processServerTrustEvaluation(*session, *strongSelf->_sessionWrapper, challenge, negotiatedLegacyTLS, taskIdentifier, task.get(), WTFMove(completionHandler));
698             });
699             [NSURLSession _strictTrustEvaluate:challenge queue:[NSOperationQueue mainQueue].underlyingQueue completionHandler:decisionHandler.get()];
700             return;
701 #else
702             return completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
703 #endif
704         }
705     }
706
707     if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
708         HostAndPort key { challenge.protectionSpace.host, challenge.protectionSpace.port };
709         if (auto* credential = sessionCocoa->successfulClientCertificateForHost(challenge.protectionSpace.host, challenge.protectionSpace.port))
710             return completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
711         sessionCocoa->continueDidReceiveChallenge(*_sessionWrapper, challenge, negotiatedLegacyTLS, taskIdentifier, [self existingTask:task], [completionHandler = makeBlockPtr(completionHandler), key, weakSessionCocoa = makeWeakPtr(sessionCocoa), taskIdentifier] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
712             NSURLCredential *nsCredential = credential.nsCredential();
713             if (disposition == WebKit::AuthenticationChallengeDisposition::UseCredential && nsCredential && weakSessionCocoa)
714                 weakSessionCocoa->clientCertificateSuggestedForHost(taskIdentifier, nsCredential, key.first, key.second);
715             completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), nsCredential);
716         });
717         return;
718     }
719
720     sessionCocoa->continueDidReceiveChallenge(*_sessionWrapper, challenge, negotiatedLegacyTLS, taskIdentifier, [self existingTask:task], [completionHandler = makeBlockPtr(completionHandler)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
721         completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), credential.nsCredential());
722     });
723 }
724
725 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
726 {
727     LOG(NetworkSession, "%llu didCompleteWithError %@", task.taskIdentifier, error);
728
729     if (error) {
730         NSDictionary *oldUserInfo = [error userInfo];
731         NSMutableDictionary *newUserInfo = oldUserInfo ? [NSMutableDictionary dictionaryWithDictionary:oldUserInfo] : [NSMutableDictionary dictionary];
732         newUserInfo[@"networkTaskDescription"] = [task description];
733         error = [NSError errorWithDomain:[error domain] code:[error code] userInfo:newUserInfo];
734     }
735
736     if (auto* networkDataTask = [self existingTask:task]) {
737         if (auto* sessionCocoa = [self sessionFromTask:task]) {
738             if (error)
739                 sessionCocoa->taskFailed(task.taskIdentifier);
740             else
741                 sessionCocoa->taskServerConnectionSucceeded(task.taskIdentifier);
742         }
743         networkDataTask->didCompleteWithError(error, networkDataTask->networkLoadMetrics());
744     } else if (error) {
745         if (!_sessionWrapper)
746             return;
747         auto downloadID = _sessionWrapper->downloadMap.take(task.taskIdentifier);
748         if (!downloadID.downloadID())
749             return;
750         if (!_session)
751             return;
752         auto* download = _session->networkProcess().downloadManager().download(downloadID);
753         if (!download)
754             return;
755
756         NSData *resumeData = nil;
757         if (id userInfo = error.userInfo) {
758             if ([userInfo isKindOfClass:[NSDictionary class]]) {
759                 resumeData = userInfo[@"NSURLSessionDownloadTaskResumeData"];
760                 if (resumeData && ![resumeData isKindOfClass:[NSData class]]) {
761                     RELEASE_LOG(NetworkSession, "Download task %llu finished with resume data of wrong class: %s", (unsigned long long)task.taskIdentifier, NSStringFromClass([resumeData class]).UTF8String);
762                     ASSERT_NOT_REACHED();
763                     resumeData = nil;
764                 }
765             }
766         }
767
768         auto resumeDataReference = resumeData ? IPC::DataReference { static_cast<const uint8_t*>(resumeData.bytes), resumeData.length } : IPC::DataReference { };
769
770         if (download->wasCanceled())
771             download->didCancel(resumeDataReference);
772         else
773             download->didFail(error, resumeDataReference);
774     }
775 }
776
777 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
778 {
779     LOG(NetworkSession, "%llu didFinishCollectingMetrics", task.taskIdentifier);
780     if (auto* networkDataTask = [self existingTask:task]) {
781         NSURLSessionTaskTransactionMetrics *m = metrics.transactionMetrics.lastObject;
782         NSDate *fetchStartDate = m.fetchStartDate;
783         NSTimeInterval domainLookupStartInterval = m.domainLookupStartDate ? [m.domainLookupStartDate timeIntervalSinceDate:fetchStartDate] : -1;
784         NSTimeInterval domainLookupEndInterval = m.domainLookupEndDate ? [m.domainLookupEndDate timeIntervalSinceDate:fetchStartDate] : -1;
785         NSTimeInterval connectStartInterval = m.connectStartDate ? [m.connectStartDate timeIntervalSinceDate:fetchStartDate] : -1;
786         NSTimeInterval secureConnectionStartInterval = m.secureConnectionStartDate ? [m.secureConnectionStartDate timeIntervalSinceDate:fetchStartDate] : -1;
787         NSTimeInterval connectEndInterval = m.connectEndDate ? [m.connectEndDate timeIntervalSinceDate:fetchStartDate] : -1;
788         NSTimeInterval requestStartInterval = [m.requestStartDate timeIntervalSinceDate:fetchStartDate];
789         NSTimeInterval responseStartInterval = [m.responseStartDate timeIntervalSinceDate:fetchStartDate];
790         NSTimeInterval responseEndInterval = [m.responseEndDate timeIntervalSinceDate:fetchStartDate];
791
792         auto& networkLoadMetrics = networkDataTask->networkLoadMetrics();
793         networkLoadMetrics.fetchStart = Seconds(fetchStartDate.timeIntervalSince1970);
794         networkLoadMetrics.domainLookupStart = Seconds(domainLookupStartInterval);
795         networkLoadMetrics.domainLookupEnd = Seconds(domainLookupEndInterval);
796         networkLoadMetrics.connectStart = Seconds(connectStartInterval);
797         networkLoadMetrics.secureConnectionStart = Seconds(secureConnectionStartInterval);
798         networkLoadMetrics.connectEnd = Seconds(connectEndInterval);
799         networkLoadMetrics.requestStart = Seconds(requestStartInterval);
800         networkLoadMetrics.responseStart = Seconds(responseStartInterval);
801         networkLoadMetrics.responseEnd = Seconds(responseEndInterval);
802         networkLoadMetrics.markComplete();
803         networkLoadMetrics.protocol = String(m.networkProtocolName);
804 #if HAVE(CFNETWORK_METRICS_CONNECTION_PROPERTIES)
805         networkLoadMetrics.cellular = m.cellular;
806         networkLoadMetrics.expensive = m.expensive;
807         networkLoadMetrics.constrained = m.constrained;
808         networkLoadMetrics.multipath = m.multipath;
809 #endif
810         networkLoadMetrics.isReusedConnection = m.isReusedConnection;
811
812         if (networkDataTask->shouldCaptureExtraNetworkLoadMetrics()) {
813             networkLoadMetrics.priority = toNetworkLoadPriority(task.priority);
814
815 #if HAVE(CFNETWORK_METRICS_APIS_V4)
816             if (auto port = [m.remotePort unsignedIntValue])
817                 networkLoadMetrics.remoteAddress = makeString(String(m.remoteAddress), ':', port);
818             else
819                 networkLoadMetrics.remoteAddress = m.remoteAddress;
820 #else
821             ALLOW_DEPRECATED_DECLARATIONS_BEGIN
822             networkLoadMetrics.remoteAddress = String(m._remoteAddressAndPort);
823             ALLOW_DEPRECATED_DECLARATIONS_END
824 #endif
825             networkLoadMetrics.connectionIdentifier = String([m._connectionIdentifier UUIDString]);
826
827 #if HAVE(CFNETWORK_NEGOTIATED_SSL_PROTOCOL_CIPHER)
828 #if HAVE(CFNETWORK_METRICS_APIS_V4)
829             networkLoadMetrics.tlsProtocol = stringForTLSProtocolVersion((tls_protocol_version_t)[m.negotiatedTLSProtocolVersion unsignedShortValue]);
830             networkLoadMetrics.tlsCipher = stringForTLSCipherSuite((tls_ciphersuite_t)[m.negotiatedTLSCipherSuite unsignedShortValue]);
831 #else
832             ALLOW_DEPRECATED_DECLARATIONS_BEGIN
833             networkLoadMetrics.tlsProtocol = stringForSSLProtocol(m._negotiatedTLSProtocol);
834             networkLoadMetrics.tlsCipher = stringForSSLCipher(m._negotiatedTLSCipher);
835             ALLOW_DEPRECATED_DECLARATIONS_END
836 #endif
837 #endif
838
839             __block WebCore::HTTPHeaderMap requestHeaders;
840             [m.request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *) {
841                 requestHeaders.set(String(name), String(value));
842             }];
843             networkLoadMetrics.requestHeaders = WTFMove(requestHeaders);
844
845             uint64_t requestHeaderBytesSent = 0;
846             uint64_t responseHeaderBytesReceived = 0;
847             uint64_t responseBodyBytesReceived = 0;
848             uint64_t responseBodyDecodedSize = 0;
849
850             for (NSURLSessionTaskTransactionMetrics *transactionMetrics in metrics.transactionMetrics) {
851 #if HAVE(CFNETWORK_METRICS_APIS_V4)
852                 requestHeaderBytesSent += transactionMetrics.countOfRequestHeaderBytesSent;
853                 responseHeaderBytesReceived += transactionMetrics.countOfResponseHeaderBytesReceived;
854                 responseBodyBytesReceived += transactionMetrics.countOfResponseBodyBytesReceived;
855                 responseBodyDecodedSize += transactionMetrics.countOfResponseBodyBytesAfterDecoding ? transactionMetrics.countOfResponseBodyBytesAfterDecoding : transactionMetrics.countOfResponseBodyBytesReceived;
856 #else
857                 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
858                 requestHeaderBytesSent += transactionMetrics._requestHeaderBytesSent;
859                 responseHeaderBytesReceived += transactionMetrics._responseHeaderBytesReceived;
860                 responseBodyBytesReceived += transactionMetrics._responseBodyBytesReceived;
861                 responseBodyDecodedSize += transactionMetrics._responseBodyBytesDecoded ? transactionMetrics._responseBodyBytesDecoded : transactionMetrics._responseBodyBytesReceived;
862                 ALLOW_DEPRECATED_DECLARATIONS_END
863 #endif
864             }
865
866             networkLoadMetrics.requestHeaderBytesSent = requestHeaderBytesSent;
867             networkLoadMetrics.requestBodyBytesSent = task.countOfBytesSent;
868             networkLoadMetrics.responseHeaderBytesReceived = responseHeaderBytesReceived;
869             networkLoadMetrics.responseBodyBytesReceived = responseBodyBytesReceived;
870             networkLoadMetrics.responseBodyDecodedSize = responseBodyDecodedSize;
871         }
872     }
873 }
874
875 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
876 {
877     auto taskIdentifier = dataTask.taskIdentifier;
878     LOG(NetworkSession, "%llu didReceiveResponse", taskIdentifier);
879     if (auto* networkDataTask = [self existingTask:dataTask]) {
880         ASSERT(RunLoop::isMain());
881
882         if (auto* sessionCocoa = [self sessionFromTask:dataTask])
883             sessionCocoa->taskServerConnectionSucceeded(taskIdentifier);
884
885         NegotiatedLegacyTLS negotiatedLegacyTLS = NegotiatedLegacyTLS::No;
886 #if HAVE(TLS_PROTOCOL_VERSION_T)
887         NSURLSessionTaskTransactionMetrics *metrics = dataTask._incompleteTaskMetrics.transactionMetrics.lastObject;
888         auto tlsVersion = (tls_protocol_version_t)metrics.negotiatedTLSProtocolVersion.unsignedShortValue;
889         if (tlsVersion == tls_protocol_version_TLSv10 || tlsVersion == tls_protocol_version_TLSv11)
890             negotiatedLegacyTLS = NegotiatedLegacyTLS::Yes;
891         UNUSED_PARAM(metrics);
892 #else // We do not need to check _TLSNegotiatedProtocolVersion if we have metrics.negotiatedTLSProtocolVersion because it works at response time even before rdar://problem/56522601
893         ALLOW_DEPRECATED_DECLARATIONS_BEGIN
894         if ([dataTask respondsToSelector:@selector(_TLSNegotiatedProtocolVersion)]) {
895             SSLProtocol tlsVersion = [dataTask _TLSNegotiatedProtocolVersion];
896             if (tlsVersion == kTLSProtocol11 || tlsVersion == kTLSProtocol1)
897                 negotiatedLegacyTLS = NegotiatedLegacyTLS::Yes;
898         }
899         ALLOW_DEPRECATED_DECLARATIONS_END
900 #endif
901         
902         // Avoid MIME type sniffing if the response comes back as 304 Not Modified.
903         int statusCode = [response isKindOfClass:NSHTTPURLResponse.class] ? [(NSHTTPURLResponse *)response statusCode] : 0;
904         if (statusCode != 304) {
905             bool isMainResourceLoad = networkDataTask->firstRequest().requester() == WebCore::ResourceRequest::Requester::Main;
906             WebCore::adjustMIMETypeIfNecessary(response._CFURLResponse, isMainResourceLoad);
907         }
908
909         WebCore::ResourceResponse resourceResponse(response);
910         // Lazy initialization is not helpful in the WebKit2 case because we always end up initializing
911         // all the fields when sending the response to the WebContent process over IPC.
912         resourceResponse.disableLazyInitialization();
913
914         // FIXME: This cannot be eliminated until other code no longer relies on ResourceResponse's
915         // NetworkLoadMetrics. For example, PerformanceTiming.
916         resourceResponse.setDeprecatedNetworkLoadMetrics(WebCore::copyTimingData([dataTask _timingData]));
917
918         auto completionHandlerCopy = Block_copy(completionHandler);
919         networkDataTask->didReceiveResponse(WTFMove(resourceResponse), negotiatedLegacyTLS, [completionHandlerCopy, taskIdentifier](WebCore::PolicyAction policyAction) {
920 #if !LOG_DISABLED
921             LOG(NetworkSession, "%llu didReceiveResponse completionHandler (%d)", taskIdentifier, policyAction);
922 #else
923             UNUSED_PARAM(taskIdentifier);
924 #endif
925             completionHandlerCopy(toNSURLSessionResponseDisposition(policyAction));
926             Block_release(completionHandlerCopy);
927         });
928     } else {
929         LOG(NetworkSession, "%llu didReceiveResponse completionHandler (cancel)", taskIdentifier);
930         completionHandler(NSURLSessionResponseCancel);
931     }
932 }
933
934 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
935 {
936     if (auto* networkDataTask = [self existingTask:dataTask])
937         networkDataTask->didReceiveData(WebCore::SharedBuffer::create(data));
938 }
939
940 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
941 {
942     if (!_sessionWrapper)
943         return;
944     auto downloadID = _sessionWrapper->downloadMap.take([downloadTask taskIdentifier]);
945     if (!downloadID.downloadID())
946         return;
947     if (!_session)
948         return;
949     auto* download = _session->networkProcess().downloadManager().download(downloadID);
950     if (!download)
951         return;
952     download->didFinish();
953 }
954
955 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
956 {
957     ASSERT_WITH_MESSAGE(![self existingTask:downloadTask], "The NetworkDataTask should be destroyed immediately after didBecomeDownloadTask returns");
958
959     if (!_sessionWrapper)
960         return;
961     auto downloadID = _sessionWrapper->downloadMap.get([downloadTask taskIdentifier]);
962     if (!downloadID.downloadID())
963         return;
964     if (!_session)
965         return;
966     auto* download = _session->networkProcess().downloadManager().download(downloadID);
967     if (!download)
968         return;
969     download->didReceiveData(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
970 }
971
972 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
973 {
974 #if HAVE(BROKEN_DOWNLOAD_RESUME_UNLINK)
975     // This is to work around rdar://problem/63249830
976     if ([downloadTask respondsToSelector:@selector(downloadFile)] && [downloadTask.downloadFile respondsToSelector:@selector(setSkipUnlink:)])
977         downloadTask.downloadFile.skipUnlink = YES;
978 #endif
979 }
980
981 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
982 {
983     auto* networkDataTask = [self existingTask:dataTask];
984     if (!networkDataTask)
985         return;
986     auto* sessionCocoa = networkDataTask->networkSession();
987     if (!sessionCocoa)
988         return;
989
990     Ref<NetworkDataTaskCocoa> protectedNetworkDataTask(*networkDataTask);
991     auto downloadID = networkDataTask->pendingDownloadID();
992     auto& downloadManager = sessionCocoa->networkProcess().downloadManager();
993     auto download = makeUnique<WebKit::Download>(downloadManager, downloadID, downloadTask, *sessionCocoa, networkDataTask->suggestedFilename());
994     networkDataTask->transferSandboxExtensionToDownload(*download);
995     ASSERT(FileSystem::fileExists(networkDataTask->pendingDownloadLocation()));
996     download->didCreateDestination(networkDataTask->pendingDownloadLocation());
997     downloadManager.dataTaskBecameDownloadTask(downloadID, WTFMove(download));
998
999     RELEASE_ASSERT(!_sessionWrapper->downloadMap.contains(downloadTask.taskIdentifier));
1000     _sessionWrapper->downloadMap.add(downloadTask.taskIdentifier, downloadID);
1001 }
1002
1003 #if HAVE(NSURLSESSION_WEBSOCKET)
1004 - (WebSocketTask*)existingWebSocketTask:(NSURLSessionWebSocketTask *)task
1005 {
1006     if (!_sessionWrapper)
1007         return nullptr;
1008
1009     if (!task)
1010         return nullptr;
1011
1012     return _sessionWrapper->webSocketDataTaskMap.get(task.taskIdentifier);
1013 }
1014
1015
1016 - (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)task didOpenWithProtocol:(NSString *) protocol
1017 {
1018     if (auto* webSocketTask = [self existingWebSocketTask:task])
1019         webSocketTask->didConnect(protocol);
1020 }
1021
1022 - (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)task didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode reason:(NSData *)reason
1023 {
1024     if (auto* webSocketTask = [self existingWebSocketTask:task]) {
1025         auto reason = adoptNS([[NSString alloc] initWithData:[task closeReason] encoding:NSUTF8StringEncoding]);
1026         webSocketTask->didClose(closeCode, reason.get());
1027     }
1028 }
1029 #endif
1030
1031 @end
1032
1033 namespace WebKit {
1034
1035 #if ASSERT_ENABLED
1036 static bool sessionsCreated = false;
1037 #endif
1038
1039 static NSURLSessionConfiguration *configurationForSessionID(const PAL::SessionID& session)
1040 {
1041 #if HAVE(LOGGING_PRIVACY_LEVEL)
1042     auto loggingPrivacyLevel = nw_context_privacy_level_sensitive;
1043 #endif
1044
1045     NSURLSessionConfiguration *configuration;
1046     if (session.isEphemeral()) {
1047         configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
1048         configuration._shouldSkipPreferredClientCertificateLookup = YES;
1049 #if HAVE(LOGGING_PRIVACY_LEVEL) && defined(NW_CONTEXT_HAS_PRIVACY_LEVEL_SILENT)
1050         loggingPrivacyLevel = nw_context_privacy_level_silent;
1051 #endif
1052     } else
1053         configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
1054
1055 #if HAVE(LOGGING_PRIVACY_LEVEL)
1056     auto setLoggingPrivacyLevel = NSSelectorFromString(@"_setLoggingPrivacyLevel:");
1057     if ([configuration respondsToSelector:setLoggingPrivacyLevel])
1058         wtfObjCMsgSend<void>(configuration, setLoggingPrivacyLevel, loggingPrivacyLevel);
1059 #elif HAVE(ALLOWS_SENSITIVE_LOGGING)
1060 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1061     configuration._allowsSensitiveLogging = NO;
1062 ALLOW_DEPRECATED_DECLARATIONS_END
1063 #endif
1064     return configuration;
1065 }
1066
1067 void NetworkSessionCocoa::clientCertificateSuggestedForHost(NetworkDataTaskCocoa::TaskIdentifier taskID, NSURLCredential *credential, const String& host, uint16_t port)
1068 {
1069     m_suggestedClientCertificates.set(taskID, SuggestedClientCertificate { host, port, credential });
1070 }
1071
1072 void NetworkSessionCocoa::taskServerConnectionSucceeded(NetworkDataTaskCocoa::TaskIdentifier identifier)
1073 {
1074     if (LIKELY(m_suggestedClientCertificates.isEmpty()))
1075         return;
1076
1077     auto suggestedClientCertificate = m_suggestedClientCertificates.take(identifier);
1078     HostAndPort key { suggestedClientCertificate.host, suggestedClientCertificate.port };
1079     if (suggestedClientCertificate.credential && decltype(m_successfulClientCertificates)::isValidKey(key))
1080         m_successfulClientCertificates.add(key, suggestedClientCertificate.credential);
1081 }
1082
1083 void NetworkSessionCocoa::taskFailed(NetworkDataTaskCocoa::TaskIdentifier identifier)
1084 {
1085     if (LIKELY(m_suggestedClientCertificates.isEmpty()))
1086         return;
1087
1088     m_suggestedClientCertificates.take(identifier);
1089 }
1090
1091 NSURLCredential *NetworkSessionCocoa::successfulClientCertificateForHost(const String& host, uint16_t port) const
1092 {
1093     HostAndPort key { host, port };
1094     if (!decltype(m_successfulClientCertificates)::isValidKey(key))
1095         return nil;
1096     return m_successfulClientCertificates.get(key).get();
1097 }
1098
1099 _NSHSTSStorage *NetworkSessionCocoa::hstsStorage() const
1100 {
1101 #if HAVE(HSTS_STORAGE)
1102     NSURLSessionConfiguration *configuration = m_sessionWithCredentialStorage.session.get().configuration;
1103     // FIXME: Remove this respondsToSelector check once rdar://problem/50109631 is in a build and bots are updated.
1104     if ([configuration respondsToSelector:@selector(_hstsStorage)])
1105         return m_sessionWithCredentialStorage.session.get().configuration._hstsStorage;
1106 #endif
1107     return nil;
1108 }
1109
1110 const String& NetworkSessionCocoa::boundInterfaceIdentifier() const
1111 {
1112     return m_boundInterfaceIdentifier;
1113 }
1114
1115 const String& NetworkSessionCocoa::sourceApplicationBundleIdentifier() const
1116 {
1117     return m_sourceApplicationBundleIdentifier;
1118 }
1119
1120 const String& NetworkSessionCocoa::sourceApplicationSecondaryIdentifier() const
1121 {
1122     return m_sourceApplicationSecondaryIdentifier;
1123 }
1124
1125 #if PLATFORM(IOS_FAMILY)
1126 const String& NetworkSessionCocoa::dataConnectionServiceType() const
1127 {
1128     return m_dataConnectionServiceType;
1129 }
1130 #endif
1131
1132 std::unique_ptr<NetworkSession> NetworkSessionCocoa::create(NetworkProcess& networkProcess, NetworkSessionCreationParameters&& parameters)
1133 {
1134     return makeUnique<NetworkSessionCocoa>(networkProcess, WTFMove(parameters));
1135 }
1136
1137 static NSDictionary *proxyDictionary(const URL& httpProxy, const URL& httpsProxy)
1138 {
1139     if (!httpProxy.isValid() && !httpsProxy.isValid())
1140         return nil;
1141
1142     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1143
1144     NSMutableDictionary *dictionary = [[[NSMutableDictionary alloc] init] autorelease];
1145     if (httpProxy.isValid()) {
1146         [dictionary setObject:httpProxy.host().toString() forKey:(NSString *)kCFStreamPropertyHTTPProxyHost];
1147         if (auto port = httpProxy.port())
1148             [dictionary setObject:@(*port) forKey:(NSString *)kCFStreamPropertyHTTPProxyPort];
1149     }
1150     if (httpsProxy.isValid()) {
1151         [dictionary setObject:httpsProxy.host().toString() forKey:(NSString *)kCFStreamPropertyHTTPSProxyHost];
1152         if (auto port = httpsProxy.port())
1153             [dictionary setObject:@(*port) forKey:(NSString *)kCFStreamPropertyHTTPSProxyPort];
1154     }
1155     return dictionary;
1156
1157     ALLOW_DEPRECATED_DECLARATIONS_END
1158 }
1159
1160 void SessionWrapper::initialize(NSURLSessionConfiguration *configuration, NetworkSessionCocoa& networkSession, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, NavigatingToAppBoundDomain isNavigatingToAppBoundDomain)
1161 {
1162     UNUSED_PARAM(isNavigatingToAppBoundDomain);
1163 #if PLATFORM(IOS_FAMILY)
1164     NETWORK_SESSION_COCOA_ADDITIONS_1
1165 #endif
1166     delegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:networkSession wrapper:*this withCredentials:storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use]);
1167     session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate.get() delegateQueue:[NSOperationQueue mainQueue]];
1168 }
1169
1170 NetworkSessionCocoa::NetworkSessionCocoa(NetworkProcess& networkProcess, NetworkSessionCreationParameters&& parameters)
1171     : NetworkSession(networkProcess, parameters)
1172     , m_boundInterfaceIdentifier(parameters.boundInterfaceIdentifier)
1173     , m_sourceApplicationBundleIdentifier(parameters.sourceApplicationBundleIdentifier)
1174     , m_sourceApplicationSecondaryIdentifier(parameters.sourceApplicationSecondaryIdentifier)
1175     , m_proxyConfiguration(parameters.proxyConfiguration)
1176     , m_shouldLogCookieInformation(parameters.shouldLogCookieInformation)
1177     , m_loadThrottleLatency(parameters.loadThrottleLatency)
1178     , m_fastServerTrustEvaluationEnabled(parameters.fastServerTrustEvaluationEnabled)
1179     , m_dataConnectionServiceType(parameters.dataConnectionServiceType)
1180     , m_preventsSystemHTTPProxyAuthentication(parameters.preventsSystemHTTPProxyAuthentication)
1181 {
1182     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
1183
1184 #if ASSERT_ENABLED
1185     sessionsCreated = true;
1186 #endif
1187
1188     NSURLSessionConfiguration *configuration = configurationForSessionID(m_sessionID);
1189
1190 #if HAVE(HSTS_STORAGE)
1191     if (!!parameters.hstsStorageDirectory && !m_sessionID.isEphemeral()) {
1192         SandboxExtension::consumePermanently(parameters.hstsStorageDirectoryExtensionHandle);
1193         // FIXME: Remove this respondsToSelector check once rdar://problem/50109631 is in a build and bots are updated.
1194         if ([configuration respondsToSelector:@selector(_hstsStorage)])
1195             configuration._hstsStorage = [[alloc_NSHSTSStorageInstance() initPersistentStoreWithURL:[NSURL fileURLWithPath:parameters.hstsStorageDirectory isDirectory:YES]] autorelease];
1196     }
1197 #endif
1198
1199 #if HAVE(APP_SSO) || PLATFORM(MACCATALYST)
1200     configuration._preventsAppSSO = true;
1201 #endif
1202
1203     // Without this, CFNetwork would sometimes add a Content-Type header to our requests (rdar://problem/34748470).
1204     configuration._suppressedAutoAddedHTTPHeaders = [NSSet setWithObject:@"Content-Type"];
1205
1206     if (parameters.allowsCellularAccess == AllowsCellularAccess::No)
1207         configuration.allowsCellularAccess = NO;
1208
1209     // The WebKit network cache was already queried.
1210     configuration.URLCache = nil;
1211
1212     if (auto data = networkProcess.sourceApplicationAuditData())
1213         configuration._sourceApplicationAuditTokenData = (__bridge NSData *)data.get();
1214
1215     if (!m_sourceApplicationBundleIdentifier.isEmpty()) {
1216         configuration._sourceApplicationBundleIdentifier = m_sourceApplicationBundleIdentifier;
1217         configuration._sourceApplicationAuditTokenData = nil;
1218     }
1219
1220     if (!m_sourceApplicationSecondaryIdentifier.isEmpty())
1221         configuration._sourceApplicationSecondaryIdentifier = m_sourceApplicationSecondaryIdentifier;
1222
1223 #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
1224     if (!parameters.alternativeServiceDirectory.isEmpty()) {
1225         SandboxExtension::consumePermanently(parameters.alternativeServiceDirectoryExtensionHandle);
1226         configuration._alternativeServicesStorage = [[[_NSHTTPAlternativeServicesStorage alloc] initPersistentStoreWithURL:[[NSURL fileURLWithPath:parameters.alternativeServiceDirectory isDirectory:YES] URLByAppendingPathComponent:@"AlternativeService.sqlite"]] autorelease];
1227     }
1228     if (parameters.http3Enabled)
1229         configuration._allowsHTTP3 = YES;
1230 #endif
1231
1232     configuration._preventsSystemHTTPProxyAuthentication = parameters.preventsSystemHTTPProxyAuthentication;
1233     configuration._requiresSecureHTTPSProxyConnection = parameters.requiresSecureHTTPSProxyConnection;
1234     configuration.connectionProxyDictionary = (NSDictionary *)parameters.proxyConfiguration.get() ?: proxyDictionary(parameters.httpProxy, parameters.httpsProxy);
1235
1236 #if PLATFORM(IOS_FAMILY)
1237     if (!m_dataConnectionServiceType.isEmpty())
1238         configuration._CTDataConnectionServiceType = m_dataConnectionServiceType;
1239 #endif
1240
1241 #if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
1242     networkProcess.supplement<LegacyCustomProtocolManager>()->registerProtocolClass(configuration);
1243 #endif
1244
1245     configuration._timingDataOptions = _TimingDataOptionsEnableW3CNavigationTiming;
1246
1247     // FIXME: Replace @"kCFStreamPropertyAutoErrorOnSystemChange" with a constant from the SDK once rdar://problem/40650244 is in a build.
1248     if (parameters.suppressesConnectionTerminationOnSystemChange)
1249         configuration._socketStreamProperties = @{ @"kCFStreamPropertyAutoErrorOnSystemChange" : @NO };
1250
1251 #if PLATFORM(WATCHOS)
1252     configuration._companionProxyPreference = NSURLSessionCompanionProxyPreferencePreferDirectToCloud;
1253 #endif
1254
1255     auto* storageSession = networkProcess.storageSession(parameters.sessionID);
1256     RELEASE_ASSERT(storageSession);
1257
1258     NSHTTPCookieStorage* cookieStorage;
1259     if (CFHTTPCookieStorageRef storage = storageSession->cookieStorage().get()) {
1260         cookieStorage = [[[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:storage] autorelease];
1261         configuration.HTTPCookieStorage = cookieStorage;
1262     } else
1263         cookieStorage = storageSession->nsCookieStorage();
1264
1265 #if HAVE(CFNETWORK_OVERRIDE_SESSION_COOKIE_ACCEPT_POLICY)
1266     // We still need to check the selector since CFNetwork updates and WebKit updates are separate
1267     // on older macOS.
1268     if ([cookieStorage respondsToSelector:@selector(_overrideSessionCookieAcceptPolicy)])
1269         cookieStorage._overrideSessionCookieAcceptPolicy = YES;
1270 #endif
1271
1272     m_sessionWithCredentialStorage.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::Use, NavigatingToAppBoundDomain::No);
1273     LOG(NetworkSession, "Created NetworkSession with cookieAcceptPolicy %lu", configuration.HTTPCookieStorage.cookieAcceptPolicy);
1274
1275     configuration.URLCredentialStorage = nil;
1276     configuration._shouldSkipPreferredClientCertificateLookup = YES;
1277     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=177394
1278     // configuration.HTTPCookieStorage = nil;
1279     // configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
1280
1281     m_sessionWithoutCredentialStorage.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::DoNotUse, NavigatingToAppBoundDomain::No);
1282
1283     m_deviceManagementRestrictionsEnabled = parameters.deviceManagementRestrictionsEnabled;
1284     m_allLoadsBlockedByDeviceManagementRestrictionsForTesting = parameters.allLoadsBlockedByDeviceManagementRestrictionsForTesting;
1285
1286     if (m_resourceLoadStatistics && !parameters.resourceLoadStatisticsParameters.appBoundDomains.isEmpty())
1287         m_resourceLoadStatistics->setAppBoundDomains(WTFMove(parameters.resourceLoadStatisticsParameters.appBoundDomains), [] { });
1288 #if HAVE(SESSION_CLEANUP)
1289     activateSessionCleanup(*this, parameters);
1290 #endif
1291 }
1292
1293 NetworkSessionCocoa::~NetworkSessionCocoa() = default;
1294
1295 void NetworkSessionCocoa::initializeEphemeralStatelessSession(NavigatingToAppBoundDomain isNavigatingToAppBoundDomain)
1296 {
1297     NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
1298     NSURLSessionConfiguration *existingConfiguration = m_sessionWithoutCredentialStorage.session.get().configuration;
1299
1300     configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
1301     configuration.URLCredentialStorage = nil;
1302     configuration.URLCache = nil;
1303     configuration.allowsCellularAccess = existingConfiguration.allowsCellularAccess;
1304     configuration.connectionProxyDictionary = existingConfiguration.connectionProxyDictionary;
1305
1306     configuration._shouldSkipPreferredClientCertificateLookup = YES;
1307     configuration._sourceApplicationAuditTokenData = existingConfiguration._sourceApplicationAuditTokenData;
1308     configuration._sourceApplicationSecondaryIdentifier = existingConfiguration._sourceApplicationSecondaryIdentifier;
1309 #if PLATFORM(IOS_FAMILY)
1310     configuration._CTDataConnectionServiceType = existingConfiguration._CTDataConnectionServiceType;
1311 #endif
1312
1313     m_ephemeralStatelessSession.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::EphemeralStateless, isNavigatingToAppBoundDomain);
1314 }
1315
1316 SessionWrapper& NetworkSessionCocoa::sessionWrapperForTask(const WebCore::ResourceRequest& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain)
1317 {
1318     auto shouldBeConsideredAppBound = isNavigatingToAppBoundDomain ? *isNavigatingToAppBoundDomain : NavigatingToAppBoundDomain::Yes;
1319     if (NETWORK_SESSION_COCOA_ADDITIONS_2)
1320         shouldBeConsideredAppBound = NavigatingToAppBoundDomain::No;
1321 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1322     if (auto* storageSession = networkStorageSession()) {
1323         auto firstParty = WebCore::RegistrableDomain(request.firstPartyForCookies());
1324         if (storageSession->shouldBlockThirdPartyCookiesButKeepFirstPartyCookiesFor(firstParty))
1325             return isolatedSession(storedCredentialsPolicy, firstParty, shouldBeConsideredAppBound);
1326     } else
1327         ASSERT_NOT_REACHED();
1328 #endif
1329
1330 #if PLATFORM(IOS_FAMILY)
1331     if (shouldBeConsideredAppBound == NavigatingToAppBoundDomain::Yes)
1332         return appBoundSession(storedCredentialsPolicy);
1333 #endif
1334
1335     switch (storedCredentialsPolicy) {
1336     case WebCore::StoredCredentialsPolicy::Use:
1337         return m_sessionWithCredentialStorage;
1338     case WebCore::StoredCredentialsPolicy::DoNotUse:
1339         return m_sessionWithoutCredentialStorage;
1340     case WebCore::StoredCredentialsPolicy::EphemeralStateless:
1341         if (!m_ephemeralStatelessSession.session)
1342             initializeEphemeralStatelessSession(NavigatingToAppBoundDomain::No);
1343         return m_ephemeralStatelessSession;
1344     }
1345 }
1346
1347 SessionWrapper& NetworkSessionCocoa::appBoundSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
1348 {
1349     if (!m_appBoundSession) {
1350         m_appBoundSession = makeUnique<IsolatedSession>();
1351         m_appBoundSession->sessionWithCredentialStorage.initialize(m_sessionWithCredentialStorage.session.get().configuration, *this, WebCore::StoredCredentialsPolicy::Use, NavigatingToAppBoundDomain::Yes);
1352         m_appBoundSession->sessionWithoutCredentialStorage.initialize(m_sessionWithoutCredentialStorage.session.get().configuration, *this, WebCore::StoredCredentialsPolicy::DoNotUse, NavigatingToAppBoundDomain::Yes);
1353     }
1354
1355     auto& sessionWrapper = [&] (auto storedCredentialsPolicy) -> SessionWrapper& {
1356         switch (storedCredentialsPolicy) {
1357         case WebCore::StoredCredentialsPolicy::Use:
1358             LOG(NetworkSession, "Using app-bound NSURLSession with credential storage.");
1359             return m_appBoundSession->sessionWithCredentialStorage;
1360         case WebCore::StoredCredentialsPolicy::DoNotUse:
1361             LOG(NetworkSession, "Using app-bound NSURLSession without credential storage.");
1362             return m_appBoundSession->sessionWithoutCredentialStorage;
1363         case WebCore::StoredCredentialsPolicy::EphemeralStateless:
1364             if (!m_ephemeralStatelessSession.session)
1365                 initializeEphemeralStatelessSession(NavigatingToAppBoundDomain::Yes);
1366             return m_ephemeralStatelessSession;
1367         }
1368     } (storedCredentialsPolicy);
1369
1370     return sessionWrapper;
1371 }
1372
1373 SessionWrapper& NetworkSessionCocoa::isolatedSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy, const WebCore::RegistrableDomain firstPartyDomain, NavigatingToAppBoundDomain isNavigatingToAppBoundDomain)
1374 {
1375     auto& entry = m_isolatedSessions.ensure(firstPartyDomain, [this, isNavigatingToAppBoundDomain] {
1376         auto newEntry = makeUnique<IsolatedSession>();
1377         newEntry->sessionWithCredentialStorage.initialize(m_sessionWithCredentialStorage.session.get().configuration, *this, WebCore::StoredCredentialsPolicy::Use, isNavigatingToAppBoundDomain);
1378         newEntry->sessionWithoutCredentialStorage.initialize(m_sessionWithoutCredentialStorage.session.get().configuration, *this, WebCore::StoredCredentialsPolicy::DoNotUse, isNavigatingToAppBoundDomain);
1379         return newEntry;
1380     }).iterator->value;
1381
1382     entry->lastUsed = WallTime::now();
1383
1384     auto& sessionWrapper = [&] (auto storedCredentialsPolicy) -> SessionWrapper& {
1385         switch (storedCredentialsPolicy) {
1386         case WebCore::StoredCredentialsPolicy::Use:
1387             LOG(NetworkSession, "Using isolated NSURLSession with credential storage.");
1388             return entry->sessionWithCredentialStorage;
1389         case WebCore::StoredCredentialsPolicy::DoNotUse:
1390             LOG(NetworkSession, "Using isolated NSURLSession without credential storage.");
1391             return entry->sessionWithoutCredentialStorage;
1392         case WebCore::StoredCredentialsPolicy::EphemeralStateless:
1393             if (!m_ephemeralStatelessSession.session)
1394                 initializeEphemeralStatelessSession(isNavigatingToAppBoundDomain);
1395             return m_ephemeralStatelessSession;
1396         }
1397     } (storedCredentialsPolicy);
1398     
1399     if (m_isolatedSessions.size() > maxNumberOfIsolatedSessions) {
1400         WebCore::RegistrableDomain keyToRemove;
1401         auto oldestTimestamp = WallTime::now();
1402         for (auto& key : m_isolatedSessions.keys()) {
1403             auto timestamp = m_isolatedSessions.get(key)->lastUsed;
1404             if (timestamp < oldestTimestamp) {
1405                 oldestTimestamp = timestamp;
1406                 keyToRemove = key;
1407             }
1408         }
1409         LOG(NetworkSession, "About to remove isolated NSURLSession.");
1410         m_isolatedSessions.remove(keyToRemove);
1411     }
1412
1413     RELEASE_ASSERT(m_isolatedSessions.size() <= maxNumberOfIsolatedSessions);
1414
1415     return sessionWrapper;
1416 }
1417
1418 bool NetworkSessionCocoa::hasIsolatedSession(const WebCore::RegistrableDomain domain) const
1419 {
1420     return m_isolatedSessions.contains(domain);
1421 }
1422
1423 void NetworkSessionCocoa::clearIsolatedSessions()
1424 {
1425     m_isolatedSessions.clear();
1426 }
1427
1428 void NetworkSessionCocoa::clearAppBoundSession()
1429 {
1430     m_appBoundSession = nullptr;
1431 }
1432
1433 void NetworkSessionCocoa::invalidateAndCancel()
1434 {
1435     NetworkSession::invalidateAndCancel();
1436
1437     [m_sessionWithCredentialStorage.session invalidateAndCancel];
1438     [m_sessionWithoutCredentialStorage.session invalidateAndCancel];
1439     [m_ephemeralStatelessSession.session invalidateAndCancel];
1440     [m_sessionWithCredentialStorage.delegate sessionInvalidated];
1441     [m_sessionWithoutCredentialStorage.delegate sessionInvalidated];
1442     [m_ephemeralStatelessSession.delegate sessionInvalidated];
1443
1444     for (auto& session : m_isolatedSessions.values()) {
1445         [session->sessionWithCredentialStorage.session invalidateAndCancel];
1446         [session->sessionWithCredentialStorage.delegate sessionInvalidated];
1447         [session->sessionWithoutCredentialStorage.session invalidateAndCancel];
1448         [session->sessionWithoutCredentialStorage.delegate sessionInvalidated];
1449     }
1450     m_isolatedSessions.clear();
1451
1452     if (m_appBoundSession) {
1453         [m_appBoundSession->sessionWithCredentialStorage.session invalidateAndCancel];
1454         [m_appBoundSession->sessionWithCredentialStorage.delegate sessionInvalidated];
1455         [m_appBoundSession->sessionWithoutCredentialStorage.session invalidateAndCancel];
1456         [m_appBoundSession->sessionWithoutCredentialStorage.delegate sessionInvalidated];
1457     }
1458 }
1459
1460 void NetworkSessionCocoa::clearCredentials()
1461 {
1462 #if !USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
1463     ASSERT(m_dataTaskMapWithCredentials.isEmpty());
1464     ASSERT(m_dataTaskMapWithoutState.isEmpty());
1465     ASSERT(m_downloadMap.isEmpty());
1466     // FIXME: Use resetWithCompletionHandler instead.
1467     m_sessionWithCredentialStorage = [NSURLSession sessionWithConfiguration:m_sessionWithCredentialStorage.get().configuration delegate:static_cast<id>(m_sessionWithCredentialStorageDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1468     m_statelessSession = [NSURLSession sessionWithConfiguration:m_statelessSession.get().configuration delegate:static_cast<id>(m_statelessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1469     for (auto& entry : m_isolatedSessions.values())
1470         entry.session = [NSURLSession sessionWithConfiguration:entry.session.get().configuration delegate:static_cast<id>(entry.delegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1471     m_appBoundSession.session = [NSURLSession sessionWithConfiguration:m_appBoundSession.session.get().configuration delegate:static_cast<id>(m_appBoundSession.delegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
1472 #endif
1473 }
1474
1475 static bool certificatesMatch(SecTrustRef trust1, SecTrustRef trust2)
1476 {
1477     if (!trust1 || !trust2)
1478         return false;
1479
1480     CFIndex count1 = SecTrustGetCertificateCount(trust1);
1481     CFIndex count2 = SecTrustGetCertificateCount(trust2);
1482     if (count1 != count2)
1483         return false;
1484
1485     for (CFIndex i = 0; i < count1; i++) {
1486         auto cert1 = SecTrustGetCertificateAtIndex(trust1, i);
1487         auto cert2 = SecTrustGetCertificateAtIndex(trust2, i);
1488         RELEASE_ASSERT(cert1);
1489         RELEASE_ASSERT(cert2);
1490         if (!CFEqual(cert1, cert2))
1491             return false;
1492     }
1493
1494     return true;
1495 }
1496
1497 bool NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge& challenge)
1498 {
1499     const String& host = challenge.protectionSpace().host();
1500     NSArray *certificates = [NSURLRequest allowsSpecificHTTPSCertificateForHost:host];
1501     if (!certificates)
1502         return false;
1503
1504     bool requireServerCertificates = challenge.protectionSpace().authenticationScheme() == WebCore::ProtectionSpaceAuthenticationScheme::ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
1505     RetainPtr<SecPolicyRef> policy = adoptCF(SecPolicyCreateSSL(requireServerCertificates, host.createCFString().get()));
1506
1507     SecTrustRef trustRef = nullptr;
1508     if (SecTrustCreateWithCertificates((CFArrayRef)certificates, policy.get(), &trustRef) != noErr)
1509         return false;
1510     RetainPtr<SecTrustRef> trust = adoptCF(trustRef);
1511
1512     return certificatesMatch(trust.get(), challenge.nsURLAuthenticationChallenge().protectionSpace.serverTrust);
1513 }
1514
1515 void NetworkSessionCocoa::continueDidReceiveChallenge(SessionWrapper& sessionWrapper, const WebCore::AuthenticationChallenge& challenge, NegotiatedLegacyTLS negotiatedLegacyTLS, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&& completionHandler)
1516 {
1517     if (!networkDataTask) {
1518 #if HAVE(NSURLSESSION_WEBSOCKET)
1519         if (auto* webSocketTask = sessionWrapper.webSocketDataTaskMap.get(taskIdentifier)) {
1520             // FIXME: Handle challenges for web socket.
1521             completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, { });
1522             return;
1523         }
1524 #endif
1525         auto downloadID = sessionWrapper.downloadMap.get(taskIdentifier);
1526         if (downloadID.downloadID()) {
1527             if (auto* download = networkProcess().downloadManager().download(downloadID)) {
1528                 WebCore::AuthenticationChallenge authenticationChallenge { challenge };
1529                 // Received an authentication challenge for a download being resumed.
1530                 download->didReceiveChallenge(authenticationChallenge, WTFMove(completionHandler));
1531                 return;
1532             }
1533         }
1534         LOG(NetworkSession, "%llu didReceiveChallenge completionHandler (cancel)", taskIdentifier);
1535         completionHandler(AuthenticationChallengeDisposition::Cancel, { });
1536         return;
1537     }
1538
1539     auto sessionID = this->sessionID();
1540     WebCore::AuthenticationChallenge authenticationChallenge { challenge };
1541     auto challengeCompletionHandler = [completionHandler = WTFMove(completionHandler), networkProcess = makeRef(networkProcess()), sessionID, authenticationChallenge, taskIdentifier, partition = networkDataTask->partition()](WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
1542 #if !LOG_DISABLED
1543         LOG(NetworkSession, "%llu didReceiveChallenge completionHandler %d", taskIdentifier, disposition);
1544 #else
1545         UNUSED_PARAM(taskIdentifier);
1546 #endif
1547 #if !USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
1548         UNUSED_PARAM(sessionID);
1549         UNUSED_PARAM(authenticationChallenge);
1550 #else
1551         if (credential.persistence() == WebCore::CredentialPersistenceForSession && authenticationChallenge.protectionSpace().isPasswordBased()) {
1552             WebCore::Credential nonPersistentCredential(credential.user(), credential.password(), WebCore::CredentialPersistenceNone);
1553             URL urlToStore;
1554             if (authenticationChallenge.failureResponse().httpStatusCode() == 401)
1555                 urlToStore = authenticationChallenge.failureResponse().url();
1556             if (auto storageSession = networkProcess->storageSession(sessionID))
1557                 storageSession->credentialStorage().set(partition, nonPersistentCredential, authenticationChallenge.protectionSpace(), urlToStore);
1558             else
1559                 ASSERT_NOT_REACHED();
1560
1561             completionHandler(disposition, nonPersistentCredential);
1562             return;
1563         }
1564 #endif
1565         completionHandler(disposition, credential);
1566     };
1567     networkDataTask->didReceiveChallenge(WTFMove(authenticationChallenge), negotiatedLegacyTLS, WTFMove(challengeCompletionHandler));
1568 }
1569
1570 DMFWebsitePolicyMonitor *NetworkSessionCocoa::deviceManagementPolicyMonitor()
1571 {
1572 #if HAVE(DEVICE_MANAGEMENT)
1573     ASSERT(m_deviceManagementRestrictionsEnabled);
1574     if (!m_deviceManagementPolicyMonitor)
1575         m_deviceManagementPolicyMonitor = adoptNS([allocDMFWebsitePolicyMonitorInstance() initWithPolicyChangeHandler:nil]);
1576     return m_deviceManagementPolicyMonitor.get();
1577 #else
1578     RELEASE_ASSERT_NOT_REACHED();
1579     return nil;
1580 #endif
1581 }
1582
1583 #if HAVE(NSURLSESSION_WEBSOCKET)
1584 std::unique_ptr<WebSocketTask> NetworkSessionCocoa::createWebSocketTask(NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol)
1585 {
1586     // FIXME: Use protocol.
1587     RetainPtr<NSURLSessionWebSocketTask> task = [m_sessionWithCredentialStorage.session webSocketTaskWithRequest:request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)];
1588     return makeUnique<WebSocketTask>(channel, WTFMove(task));
1589 }
1590
1591 void NetworkSessionCocoa::addWebSocketTask(WebSocketTask& task)
1592 {
1593     RELEASE_ASSERT(!m_sessionWithCredentialStorage.webSocketDataTaskMap.contains(task.identifier()));
1594     m_sessionWithCredentialStorage.webSocketDataTaskMap.add(task.identifier(), &task);
1595 }
1596
1597 void NetworkSessionCocoa::removeWebSocketTask(WebSocketTask& task)
1598 {
1599     RELEASE_ASSERT(m_sessionWithCredentialStorage.webSocketDataTaskMap.contains(task.identifier()));
1600     m_sessionWithCredentialStorage.webSocketDataTaskMap.remove(task.identifier());
1601 }
1602
1603 #endif // HAVE(NSURLSESSION_WEBSOCKET)
1604
1605 Vector<WebCore::SecurityOriginData> NetworkSessionCocoa::hostNamesWithAlternativeServices() const
1606 {
1607 #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
1608     Vector<WebCore::SecurityOriginData> origins;
1609     _NSHTTPAlternativeServicesStorage* storage = m_sessionWithCredentialStorage.session.get().configuration._alternativeServicesStorage;
1610     NSArray<_NSHTTPAlternativeServiceEntry *> *entries = [storage HTTPServiceEntriesWithFilter:_NSHTTPAlternativeServicesFilter.emptyFilter];
1611
1612     for (_NSHTTPAlternativeServiceEntry* entry in entries) {
1613         WebCore::SecurityOriginData origin = { "https"_s, entry.host, entry.port };
1614         origins.append(origin);
1615     }
1616     return origins;
1617 #else
1618     return { };
1619 #endif
1620 }
1621
1622 void NetworkSessionCocoa::deleteAlternativeServicesForHostNames(const Vector<String>& hosts)
1623 {
1624 #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
1625     _NSHTTPAlternativeServicesStorage* storage = m_sessionWithCredentialStorage.session.get().configuration._alternativeServicesStorage;
1626     for (auto& host : hosts)
1627         [storage removeHTTPAlternativeServiceEntriesWithRegistrableDomain:host];
1628 #else
1629     UNUSED_PARAM(hosts);
1630 #endif
1631 }
1632
1633 void NetworkSessionCocoa::clearAlternativeServices(WallTime modifiedSince)
1634 {
1635 #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
1636     _NSHTTPAlternativeServicesStorage* storage = m_sessionWithCredentialStorage.session.get().configuration._alternativeServicesStorage;
1637     NSTimeInterval timeInterval = modifiedSince.secondsSinceEpoch().seconds();
1638     NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
1639     [storage removeHTTPAlternativeServiceEntriesCreatedAfterDate:date];
1640 #else
1641     UNUSED_PARAM(modifiedSince);
1642 #endif
1643 }
1644
1645 } // namespace WebKit