Add IGNORE_WARNING_.* macros
[WebKit-https.git] / Source / WebKit / NetworkProcess / cocoa / NetworkDataTaskCocoa.mm
1 /*
2  * Copyright (C) 2016-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 "NetworkDataTaskCocoa.h"
28
29 #import "AuthenticationManager.h"
30 #import "Download.h"
31 #import "DownloadProxyMessages.h"
32 #import "Logging.h"
33 #import "NetworkProcess.h"
34 #import "NetworkProximityManager.h"
35 #import "NetworkSessionCocoa.h"
36 #import "SessionTracker.h"
37 #import "WebCoreArgumentCoders.h"
38 #import <WebCore/AuthenticationChallenge.h>
39 #import <WebCore/FileSystem.h>
40 #import <WebCore/NetworkStorageSession.h>
41 #import <WebCore/NotImplemented.h>
42 #import <WebCore/ResourceRequest.h>
43 #import <pal/spi/cf/CFNetworkSPI.h>
44 #import <wtf/MainThread.h>
45 #import <wtf/ProcessPrivilege.h>
46 #import <wtf/text/Base64.h>
47
48 #if HAVE(NW_ACTIVITY)
49 #import <CFNetwork/CFNSURLConnection.h>
50 #endif
51
52 namespace WebKit {
53
54 #if USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
55 static void applyBasicAuthorizationHeader(WebCore::ResourceRequest& request, const WebCore::Credential& credential)
56 {
57     String authenticationHeader = "Basic " + base64Encode(String(credential.user() + ":" + credential.password()).utf8());
58     request.setHTTPHeaderField(WebCore::HTTPHeaderName::Authorization, authenticationHeader);
59 }
60 #endif
61
62 static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
63 {
64     switch (priority) {
65     case WebCore::ResourceLoadPriority::VeryLow:
66         return 0;
67     case WebCore::ResourceLoadPriority::Low:
68         return 0.25;
69     case WebCore::ResourceLoadPriority::Medium:
70         return 0.5;
71     case WebCore::ResourceLoadPriority::High:
72         return 0.75;
73     case WebCore::ResourceLoadPriority::VeryHigh:
74         return 1;
75     }
76
77     ASSERT_NOT_REACHED();
78     return NSURLSessionTaskPriorityDefault;
79 }
80
81 void NetworkDataTaskCocoa::applySniffingPoliciesAndBindRequestToInferfaceIfNeeded(__strong NSURLRequest *& nsRequest, bool shouldContentSniff, bool shouldContentEncodingSniff)
82 {
83 #if !PLATFORM(MAC)
84     UNUSED_PARAM(shouldContentEncodingSniff);
85 #elif __MAC_OS_X_VERSION_MIN_REQUIRED < 101302
86     shouldContentEncodingSniff = true;
87 #endif
88     auto& cocoaSession = static_cast<NetworkSessionCocoa&>(m_session.get());
89     if (shouldContentSniff
90         && shouldContentEncodingSniff
91         && cocoaSession.m_boundInterfaceIdentifier.isNull()
92         && !cocoaSession.m_proxyConfiguration)
93         return;
94
95     auto mutableRequest = adoptNS([nsRequest mutableCopy]);
96
97 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101302
98     if (!shouldContentEncodingSniff)
99         [mutableRequest _setProperty:@(YES) forKey:(NSString *)kCFURLRequestContentDecoderSkipURLCheck];
100 #endif
101
102     if (!shouldContentSniff)
103         [mutableRequest _setProperty:@(NO) forKey:(NSString *)_kCFURLConnectionPropertyShouldSniff];
104
105     if (!cocoaSession.m_boundInterfaceIdentifier.isNull())
106         [mutableRequest setBoundInterfaceIdentifier:cocoaSession.m_boundInterfaceIdentifier];
107
108     if (cocoaSession.m_proxyConfiguration)
109         CFURLRequestSetProxySettings([mutableRequest _CFURLRequest], cocoaSession.m_proxyConfiguration.get());
110
111     nsRequest = mutableRequest.autorelease();
112 }
113
114 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
115
116 NSHTTPCookieStorage *NetworkDataTaskCocoa::statelessCookieStorage()
117 {
118     static NeverDestroyed<RetainPtr<NSHTTPCookieStorage>> statelessCookieStorage;
119     if (!statelessCookieStorage.get()) {
120 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300)
121         IGNORE_NULL_CHECK_WARNINGS_BEGIN
122 #endif
123         statelessCookieStorage.get() = adoptNS([[NSHTTPCookieStorage alloc] _initWithIdentifier:nil private:YES]);
124 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300)
125         IGNORE_NULL_CHECK_WARNINGS_END
126 #endif
127         statelessCookieStorage.get().get().cookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
128     }
129     ASSERT(statelessCookieStorage.get().get().cookies.count == 0);
130     return statelessCookieStorage.get().get();
131 }
132
133 void NetworkDataTaskCocoa::applyCookieBlockingPolicy(bool shouldBlock)
134 {
135     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
136
137     if (shouldBlock == m_hasBeenSetToUseStatelessCookieStorage)
138         return;
139
140     NSHTTPCookieStorage *storage = shouldBlock ? statelessCookieStorage() : m_session->networkStorageSession().nsCookieStorage();
141     [m_task _setExplicitCookieStorage:storage._cookieStorage];
142     m_hasBeenSetToUseStatelessCookieStorage = shouldBlock;
143 }
144
145 #endif
146
147 bool NetworkDataTaskCocoa::isThirdPartyRequest(const WebCore::ResourceRequest& request)
148 {
149     return !WebCore::registrableDomainsAreEqual(request.url(), request.firstPartyForCookies());
150 }
151
152 static void updateTaskWithFirstPartyForSameSiteCookies(NSURLSessionDataTask* task, const WebCore::ResourceRequest& request)
153 {
154     if (request.isSameSiteUnspecified())
155         return;
156 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
157     static NSURL *emptyURL = [[NSURL alloc] initWithString:@""];
158     if ([task respondsToSelector:@selector(set_siteForCookies:)])
159         task._siteForCookies = request.isSameSite() ? task.currentRequest.URL : emptyURL;
160     if ([task respondsToSelector:@selector(set_isTopLevelNavigation:)])
161         task._isTopLevelNavigation = request.isTopSite();
162 #else
163     UNUSED_PARAM(task);
164 #endif
165 }
166
167 NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& requestWithCredentials, uint64_t frameID, uint64_t pageID, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ContentSniffingPolicy shouldContentSniff, WebCore::ContentEncodingSniffingPolicy shouldContentEncodingSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect, PreconnectOnly shouldPreconnectOnly, bool dataTaskIsForMainFrameNavigation, std::optional<NetworkActivityTracker> networkActivityTracker)
168     : NetworkDataTask(session, client, requestWithCredentials, storedCredentialsPolicy, shouldClearReferrerOnHTTPSToHTTPRedirect, dataTaskIsForMainFrameNavigation)
169     , m_frameID(frameID)
170     , m_pageID(pageID)
171 {
172     if (m_scheduledFailureType != NoFailure)
173         return;
174
175     auto request = requestWithCredentials;
176     auto url = request.url();
177     if (storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use && url.protocolIsInHTTPFamily()) {
178         m_user = url.user();
179         m_password = url.pass();
180         request.removeCredentials();
181         url = request.url();
182     
183 #if USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
184         if (m_user.isEmpty() && m_password.isEmpty())
185             m_initialCredential = m_session->networkStorageSession().credentialStorage().get(m_partition, url);
186         else
187             m_session->networkStorageSession().credentialStorage().set(m_partition, WebCore::Credential(m_user, m_password, WebCore::CredentialPersistenceNone), url);
188 #endif
189     }
190
191 #if USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
192     if (!m_initialCredential.isEmpty()) {
193         // FIXME: Support Digest authentication, and Proxy-Authorization.
194         applyBasicAuthorizationHeader(request, m_initialCredential);
195     }
196 #endif
197
198     bool shouldBlockCookies = false;
199 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
200     shouldBlockCookies = session.networkStorageSession().shouldBlockCookies(request, frameID, pageID);
201 #endif
202     if (shouldBlockCookies || (m_session->sessionID().isEphemeral() && isThirdPartyRequest(request)))
203         request.setExistingHTTPReferrerToOriginString();
204
205     NSURLRequest *nsRequest = request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::UpdateHTTPBody);
206     applySniffingPoliciesAndBindRequestToInferfaceIfNeeded(nsRequest, shouldContentSniff == WebCore::ContentSniffingPolicy::SniffContent && !url.isLocalFile(), shouldContentEncodingSniff == WebCore::ContentEncodingSniffingPolicy::Sniff);
207 #if ENABLE(PROXIMITY_NETWORKING)
208     NetworkProcess::singleton().proximityManager().applyProperties(request, *this, nsRequest);
209 #endif
210
211     auto& cocoaSession = static_cast<NetworkSessionCocoa&>(m_session.get());
212     if (storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use) {
213         m_task = [cocoaSession.m_sessionWithCredentialStorage dataTaskWithRequest:nsRequest];
214         ASSERT(!cocoaSession.m_dataTaskMapWithCredentials.contains([m_task taskIdentifier]));
215         cocoaSession.m_dataTaskMapWithCredentials.add([m_task taskIdentifier], this);
216         LOG(NetworkSession, "%llu Creating stateful NetworkDataTask with URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
217     } else {
218         m_task = [cocoaSession.m_statelessSession dataTaskWithRequest:nsRequest];
219         ASSERT(!cocoaSession.m_dataTaskMapWithoutState.contains([m_task taskIdentifier]));
220         cocoaSession.m_dataTaskMapWithoutState.add([m_task taskIdentifier], this);
221         LOG(NetworkSession, "%llu Creating stateless NetworkDataTask with URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
222     }
223
224     if (shouldPreconnectOnly == PreconnectOnly::Yes) {
225 #if ENABLE(SERVER_PRECONNECT)
226         m_task.get()._preconnect = true;
227 #else
228         ASSERT_NOT_REACHED();
229 #endif
230     }
231
232 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
233     if (shouldBlockCookies) {
234 #if !RELEASE_LOG_DISABLED
235         if (NetworkProcess::singleton().shouldLogCookieInformation())
236             RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkDataTaskCocoa::logCookieInformation: pageID = %llu, frameID = %llu, taskID = %lu: Blocking cookies for URL %s", this, pageID, frameID, (unsigned long)[m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
237 #else
238         LOG(NetworkSession, "%llu Blocking cookies for URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
239 #endif
240         applyCookieBlockingPolicy(shouldBlockCookies);
241     }
242 #endif
243
244     if (WebCore::ResourceRequest::resourcePrioritiesEnabled())
245         m_task.get().priority = toNSURLSessionTaskPriority(request.priority());
246
247     updateTaskWithFirstPartyForSameSiteCookies(m_task.get(), request);
248
249 #if HAVE(NW_ACTIVITY)
250     if (networkActivityTracker)
251         m_task.get()._nw_activity = networkActivityTracker.value().getPlatformObject();
252 #endif
253 }
254
255 NetworkDataTaskCocoa::~NetworkDataTaskCocoa()
256 {
257     if (!m_task)
258         return;
259
260     auto& cocoaSession = static_cast<NetworkSessionCocoa&>(m_session.get());
261     if (m_storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use) {
262         ASSERT(cocoaSession.m_dataTaskMapWithCredentials.get([m_task taskIdentifier]) == this);
263         cocoaSession.m_dataTaskMapWithCredentials.remove([m_task taskIdentifier]);
264     } else {
265         ASSERT(cocoaSession.m_dataTaskMapWithoutState.get([m_task taskIdentifier]) == this);
266         cocoaSession.m_dataTaskMapWithoutState.remove([m_task taskIdentifier]);
267     }
268 }
269
270 void NetworkDataTaskCocoa::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend)
271 {
272     if (m_client)
273         m_client->didSendData(totalBytesSent, totalBytesExpectedToSend);
274 }
275
276 void NetworkDataTaskCocoa::didReceiveChallenge(WebCore::AuthenticationChallenge&& challenge, ChallengeCompletionHandler&& completionHandler)
277 {
278     if (tryPasswordBasedAuthentication(challenge, completionHandler))
279         return;
280
281     if (m_client)
282         m_client->didReceiveChallenge(WTFMove(challenge), WTFMove(completionHandler));
283     else {
284         ASSERT_NOT_REACHED();
285         completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, { });
286     }
287 }
288
289 void NetworkDataTaskCocoa::didCompleteWithError(const WebCore::ResourceError& error, const WebCore::NetworkLoadMetrics& networkLoadMetrics)
290 {
291     if (m_client)
292         m_client->didCompleteWithError(error, networkLoadMetrics);
293 }
294
295 void NetworkDataTaskCocoa::didReceiveData(Ref<WebCore::SharedBuffer>&& data)
296 {
297     if (m_client)
298         m_client->didReceiveData(WTFMove(data));
299 }
300
301 void NetworkDataTaskCocoa::willPerformHTTPRedirection(WebCore::ResourceResponse&& redirectResponse, WebCore::ResourceRequest&& request, RedirectCompletionHandler&& completionHandler)
302 {
303     if (redirectResponse.httpStatusCode() == 307 || redirectResponse.httpStatusCode() == 308) {
304         ASSERT(m_lastHTTPMethod == request.httpMethod());
305         WebCore::FormData* body = m_firstRequest.httpBody();
306         if (body && !body->isEmpty() && !equalLettersIgnoringASCIICase(m_lastHTTPMethod, "get"))
307             request.setHTTPBody(body);
308         
309         String originalContentType = m_firstRequest.httpContentType();
310         if (!originalContentType.isEmpty())
311             request.setHTTPHeaderField(WebCore::HTTPHeaderName::ContentType, originalContentType);
312     }
313     
314     // Should not set Referer after a redirect from a secure resource to non-secure one.
315     if (m_shouldClearReferrerOnHTTPSToHTTPRedirect && !request.url().protocolIs("https") && WebCore::protocolIs(request.httpReferrer(), "https"))
316         request.clearHTTPReferrer();
317     
318     const auto& url = request.url();
319     m_user = url.user();
320     m_password = url.pass();
321     m_lastHTTPMethod = request.httpMethod();
322     request.removeCredentials();
323     
324     if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) {
325         // The network layer might carry over some headers from the original request that
326         // we want to strip here because the redirect is cross-origin.
327         request.clearHTTPAuthorization();
328         request.clearHTTPOrigin();
329 #if USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
330     } else {
331         // Only consider applying authentication credentials if this is actually a redirect and the redirect
332         // URL didn't include credentials of its own.
333         if (m_user.isEmpty() && m_password.isEmpty() && !redirectResponse.isNull()) {
334             auto credential = m_session->networkStorageSession().credentialStorage().get(m_partition, request.url());
335             if (!credential.isEmpty()) {
336                 m_initialCredential = credential;
337
338                 // FIXME: Support Digest authentication, and Proxy-Authorization.
339                 applyBasicAuthorizationHeader(request, m_initialCredential);
340             }
341         }
342 #endif
343     }
344
345     if (isTopLevelNavigation())
346         request.setFirstPartyForCookies(request.url());
347
348     bool shouldBlockCookies = false;
349 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
350     shouldBlockCookies = m_session->networkStorageSession().shouldBlockCookies(request, m_frameID, m_pageID);
351 #if !RELEASE_LOG_DISABLED
352     if (NetworkProcess::singleton().shouldLogCookieInformation())
353         RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkDataTaskCocoa::willPerformHTTPRedirection::logCookieInformation: pageID = %llu, frameID = %llu, taskID = %lu: %s cookies for redirect URL %s", this, m_pageID, m_frameID, (unsigned long)[m_task taskIdentifier], (shouldBlockCookies ? "Blocking" : "Not blocking"), request.url().string().utf8().data());
354 #else
355     LOG(NetworkSession, "%llu %s cookies for redirect URL %s", [m_task taskIdentifier], (shouldBlockCookies ? "Blocking" : "Not blocking"), request.url().string().utf8().data());
356 #endif
357 #endif
358
359     if (shouldBlockCookies || (m_session->sessionID().isEphemeral() && isThirdPartyRequest(request)))
360         request.setExistingHTTPReferrerToOriginString();
361
362 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
363     // Always apply the policy since blocking may need to be turned on or off in a redirect.
364     applyCookieBlockingPolicy(shouldBlockCookies);
365
366     if (!shouldBlockCookies) {
367 #if !RELEASE_LOG_DISABLED
368         if (NetworkProcess::singleton().shouldLogCookieInformation())
369             RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkDataTaskCocoa::willPerformHTTPRedirection::logCookieInformation: pageID = %llu, frameID = %llu, taskID = %lu: Not partitioning cookies for redirect URL %s", this, m_pageID, m_frameID, (unsigned long)[m_task taskIdentifier], request.url().string().utf8().data());
370 #else
371         LOG(NetworkSession, "%llu Not partitioning cookies for redirect URL %s", [m_task taskIdentifier], request.url().string().utf8().data());
372 #endif
373     }
374 #endif
375
376     updateTaskWithFirstPartyForSameSiteCookies(m_task.get(), request);
377
378     if (m_client)
379         m_client->willPerformHTTPRedirection(WTFMove(redirectResponse), WTFMove(request), WTFMove(completionHandler));
380     else {
381         ASSERT_NOT_REACHED();
382         completionHandler({ });
383     }
384 }
385
386 void NetworkDataTaskCocoa::setPendingDownloadLocation(const WTF::String& filename, SandboxExtension::Handle&& sandboxExtensionHandle, bool allowOverwrite)
387 {
388     NetworkDataTask::setPendingDownloadLocation(filename, { }, allowOverwrite);
389
390     ASSERT(!m_sandboxExtension);
391     m_sandboxExtension = SandboxExtension::create(WTFMove(sandboxExtensionHandle));
392     if (m_sandboxExtension)
393         m_sandboxExtension->consume();
394
395     m_task.get()._pathToDownloadTaskFile = m_pendingDownloadLocation;
396
397     if (allowOverwrite && WebCore::FileSystem::fileExists(m_pendingDownloadLocation))
398         WebCore::FileSystem::deleteFile(filename);
399 }
400
401 bool NetworkDataTaskCocoa::tryPasswordBasedAuthentication(const WebCore::AuthenticationChallenge& challenge, ChallengeCompletionHandler& completionHandler)
402 {
403     if (!challenge.protectionSpace().isPasswordBased())
404         return false;
405     
406     if (!m_user.isNull() && !m_password.isNull()) {
407         auto persistence = m_storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use ? WebCore::CredentialPersistenceForSession : WebCore::CredentialPersistenceNone;
408         completionHandler(AuthenticationChallengeDisposition::UseCredential, WebCore::Credential(m_user, m_password, persistence));
409         m_user = String();
410         m_password = String();
411         return true;
412     }
413
414 #if USE(CREDENTIAL_STORAGE_WITH_NETWORK_SESSION)
415     if (m_storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use) {
416         if (!m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
417             // The stored credential wasn't accepted, stop using it.
418             // There is a race condition here, since a different credential might have already been stored by another ResourceHandle,
419             // but the observable effect should be very minor, if any.
420             m_session->networkStorageSession().credentialStorage().remove(m_partition, challenge.protectionSpace());
421         }
422
423         if (!challenge.previousFailureCount()) {
424             auto credential = m_session->networkStorageSession().credentialStorage().get(m_partition, challenge.protectionSpace());
425             if (!credential.isEmpty() && credential != m_initialCredential) {
426                 ASSERT(credential.persistence() == WebCore::CredentialPersistenceNone);
427                 if (challenge.failureResponse().httpStatusCode() == 401) {
428                     // Store the credential back, possibly adding it as a default for this directory.
429                     m_session->networkStorageSession().credentialStorage().set(m_partition, credential, challenge.protectionSpace(), challenge.failureResponse().url());
430                 }
431                 completionHandler(AuthenticationChallengeDisposition::UseCredential, credential);
432                 return true;
433             }
434         }
435     }
436 #endif
437
438     if (!challenge.proposedCredential().isEmpty() && !challenge.previousFailureCount()) {
439         completionHandler(AuthenticationChallengeDisposition::UseCredential, challenge.proposedCredential());
440         return true;
441     }
442     
443     return false;
444 }
445
446 void NetworkDataTaskCocoa::transferSandboxExtensionToDownload(Download& download)
447 {
448     download.setSandboxExtension(WTFMove(m_sandboxExtension));
449 }
450
451 String NetworkDataTaskCocoa::suggestedFilename() const
452 {
453     if (!m_suggestedFilename.isEmpty())
454         return m_suggestedFilename;
455     return m_task.get().response.suggestedFilename;
456 }
457
458 void NetworkDataTaskCocoa::cancel()
459 {
460     [m_task cancel];
461 }
462
463 void NetworkDataTaskCocoa::resume()
464 {
465     if (m_scheduledFailureType != NoFailure)
466         m_failureTimer.startOneShot(0_s);
467     [m_task resume];
468 }
469
470 void NetworkDataTaskCocoa::suspend()
471 {
472     if (m_failureTimer.isActive())
473         m_failureTimer.stop();
474     [m_task suspend];
475 }
476
477 NetworkDataTask::State NetworkDataTaskCocoa::state() const
478 {
479     switch ([m_task state]) {
480     case NSURLSessionTaskStateRunning:
481         return State::Running;
482     case NSURLSessionTaskStateSuspended:
483         return State::Suspended;
484     case NSURLSessionTaskStateCanceling:
485         return State::Canceling;
486     case NSURLSessionTaskStateCompleted:
487         return State::Completed;
488     }
489
490     ASSERT_NOT_REACHED();
491     return State::Completed;
492 }
493
494 WebCore::Credential serverTrustCredential(const WebCore::AuthenticationChallenge& challenge)
495 {
496     return WebCore::Credential([NSURLCredential credentialForTrust:challenge.nsURLAuthenticationChallenge().protectionSpace.serverTrust]);
497 }
498
499 bool NetworkDataTaskCocoa::isAlwaysOnLoggingAllowed() const
500 {
501     if (NetworkProcess::singleton().sessionIsControlledByAutomation(m_session->sessionID()))
502         return true;
503
504     return m_session->sessionID().isAlwaysOnLoggingAllowed();
505 }
506
507 String NetworkDataTaskCocoa::description() const
508 {
509     return String([m_task description]);
510 }
511
512 }