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