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