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