Stop using setDefersLoading from WebCore
[WebKit-https.git] / Source / WebCore / platform / network / cocoa / WebCoreNSURLSession.mm
1 /*
2  * Copyright (C) 2016 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "WebCoreNSURLSession.h"
28
29 #import "CachedResourceRequest.h"
30 #import "PlatformMediaResourceLoader.h"
31 #import "SubresourceLoader.h"
32 #import <wtf/BlockPtr.h>
33 #import <wtf/CompletionHandler.h>
34
35 using namespace WebCore;
36
37 #pragma mark - Private declarations
38
39 NS_ASSUME_NONNULL_BEGIN
40
41 @interface WebCoreNSURLSession ()
42 @property (readonly) PlatformMediaResourceLoader& loader;
43 @property (readwrite, retain) id<NSURLSessionTaskDelegate> delegate;
44 - (void)taskCompleted:(WebCoreNSURLSessionDataTask *)task;
45 - (void)addDelegateOperation:(Function<void()>&&)operation;
46 - (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveCORSAccessCheckResult:(BOOL)result;
47 - (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveResponseFromOrigin:(Ref<WebCore::SecurityOrigin>&&)origin;
48 @end
49
50 @interface WebCoreNSURLSessionDataTask ()
51 - (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier request:(NSURLRequest *)request;
52 - (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier URL:(NSURL *)url;
53 - (void)_restart;
54 - (void)_cancel;
55 - (void)_finish;
56 @property (assign) WebCoreNSURLSession * _Nullable session;
57
58 - (void)resource:(PlatformMediaResource&)resource sentBytes:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent;
59 - (void)resource:(PlatformMediaResource&)resource receivedResponse:(const ResourceResponse&)response completionHandler:(CompletionHandler<void(ShouldContinue)>&&)completionHandler;
60 - (BOOL)resource:(PlatformMediaResource&)resource shouldCacheResponse:(const ResourceResponse&)response;
61 - (void)resource:(PlatformMediaResource&)resource receivedData:(const char*)data length:(int)length;
62 - (void)resource:(PlatformMediaResource&)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&&)request completionHandler:(CompletionHandler<void(ResourceRequest&&)>&&)completionHandler;
63 - (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error;
64 - (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error;
65 - (void)resourceFinished:(PlatformMediaResource&)resource;
66 @end
67
68 NS_ASSUME_NONNULL_END
69
70 #pragma mark - WebCoreNSURLSession
71
72 @implementation WebCoreNSURLSession
73 - (id)initWithResourceLoader:(PlatformMediaResourceLoader&)loader delegate:(id<NSURLSessionTaskDelegate>)inDelegate delegateQueue:(NSOperationQueue*)inQueue
74 {
75     self = [super init];
76     if (!self)
77         return nil;
78
79     ASSERT(_corsResults == WebCoreNSURLSessionCORSAccessCheckResults::Unknown);
80     ASSERT(!_invalidated);
81
82     _loader = &loader;
83     self.delegate = inDelegate;
84     _queue = inQueue ? inQueue : [NSOperationQueue mainQueue];
85     _internalQueue = adoptOSObject(dispatch_queue_create("WebCoreNSURLSession _internalQueue", DISPATCH_QUEUE_SERIAL));
86
87     return self;
88 }
89
90 - (void)dealloc
91 {
92     {
93         Locker<Lock> locker(_dataTasksLock);
94         for (auto& task : _dataTasks)
95             ((__bridge WebCoreNSURLSessionDataTask *)task.get()).session = nil;
96     }
97
98     callOnMainThread([loader = WTFMove(_loader)] {
99     });
100     [super dealloc];
101 }
102
103 - (id)copyWithZone:(NSZone *)zone
104 {
105     UNUSED_PARAM(zone);
106     return [self retain];
107 }
108
109 #pragma mark - Internal Methods
110
111 - (void)taskCompleted:(WebCoreNSURLSessionDataTask *)task
112 {
113     task.session = nil;
114
115     {
116         Locker<Lock> locker(_dataTasksLock);
117
118         ASSERT(_dataTasks.contains((__bridge CFTypeRef)task));
119         _dataTasks.remove((__bridge CFTypeRef)task);
120         if (!_dataTasks.isEmpty() || !_invalidated)
121             return;
122     }
123
124     RetainPtr<WebCoreNSURLSession> strongSelf { self };
125     [self addDelegateOperation:[strongSelf] {
126         if ([strongSelf.get().delegate respondsToSelector:@selector(URLSession:didBecomeInvalidWithError:)])
127             [strongSelf.get().delegate URLSession:(NSURLSession *)strongSelf.get() didBecomeInvalidWithError:nil];
128     }];
129 }
130
131 - (void)addDelegateOperation:(Function<void()>&&)function
132 {
133     RetainPtr<WebCoreNSURLSession> strongSelf { self };
134     RetainPtr<NSBlockOperation> operation = [NSBlockOperation blockOperationWithBlock:makeBlockPtr(WTFMove(function)).get()];
135     dispatch_async(_internalQueue.get(), [strongSelf, operation] {
136         [strongSelf.get().delegateQueue addOperation:operation.get()];
137         [operation waitUntilFinished];
138     });
139 }
140
141 - (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveCORSAccessCheckResult:(BOOL)result
142 {
143     UNUSED_PARAM(task);
144     if (!result)
145         _corsResults = WebCoreNSURLSessionCORSAccessCheckResults::Fail;
146     else if (_corsResults != WebCoreNSURLSessionCORSAccessCheckResults::Fail)
147         _corsResults = WebCoreNSURLSessionCORSAccessCheckResults::Pass;
148 }
149
150 - (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveResponseFromOrigin:(Ref<WebCore::SecurityOrigin>&&)origin
151 {
152     UNUSED_PARAM(task);
153     _origins.add(WTFMove(origin));
154 }
155
156 #pragma mark - NSURLSession API
157 @dynamic delegate;
158 - (__nullable id<NSURLSessionDelegate>)delegate
159 {
160     return _delegate.get();
161 }
162
163 - (void)setDelegate:(id<NSURLSessionDelegate>)delegate
164 {
165     _delegate = delegate;
166 }
167
168 @dynamic delegateQueue;
169 - (NSOperationQueue *)delegateQueue
170 {
171     return _queue.get();
172 }
173
174 @dynamic configuration;
175 - (NSURLSessionConfiguration *)configuration
176 {
177     return nil;
178 }
179
180 - (NSString *)sessionDescription
181 {
182     return _sessionDescription.get();
183 }
184
185 - (void)setSessionDescription:(NSString *)sessionDescription
186 {
187     _sessionDescription = adoptNS([sessionDescription copy]);
188 }
189
190 @dynamic loader;
191 - (PlatformMediaResourceLoader&)loader
192 {
193     return *_loader;
194 }
195
196 @dynamic didPassCORSAccessChecks;
197 - (BOOL)didPassCORSAccessChecks
198 {
199     return _corsResults == WebCoreNSURLSessionCORSAccessCheckResults::Pass;
200 }
201
202 - (BOOL)wouldTaintOrigin:(const WebCore::SecurityOrigin &)origin
203 {
204     for (auto& responseOrigin : _origins) {
205         if (!origin.canAccess(*responseOrigin))
206             return true;
207     }
208     return false;
209 }
210
211 - (void)finishTasksAndInvalidate
212 {
213     _invalidated = YES;
214     {
215         Locker<Lock> locker(_dataTasksLock);
216         if (!_dataTasks.isEmpty())
217             return;
218     }
219
220     RetainPtr<WebCoreNSURLSession> strongSelf { self };
221     [self addDelegateOperation:[strongSelf] {
222         if ([strongSelf.get().delegate respondsToSelector:@selector(URLSession:didBecomeInvalidWithError:)])
223             [strongSelf.get().delegate URLSession:(NSURLSession *)strongSelf.get() didBecomeInvalidWithError:nil];
224     }];
225 }
226
227 - (void)invalidateAndCancel
228 {
229     Vector<RetainPtr<CFTypeRef>> tasksCopy;
230     {
231         Locker<Lock> locker(_dataTasksLock);
232         tasksCopy = copyToVector(_dataTasks);
233     }
234
235     for (auto& task : tasksCopy)
236         [(__bridge WebCoreNSURLSessionDataTask *)task.get() cancel];
237
238     [self finishTasksAndInvalidate];
239 }
240
241 - (void)resetWithCompletionHandler:(void (^)(void))completionHandler
242 {
243     // FIXME: This cannot currently be implemented. We cannot guarantee that the next connection will happen on a new socket.
244     [self addDelegateOperation:[completionHandler = BlockPtr<void()>(completionHandler)] {
245         completionHandler();
246     }];
247 }
248
249 - (void)flushWithCompletionHandler:(void (^)(void))completionHandler
250 {
251     // FIXME: This cannot currently be implemented. We cannot guarantee that the next connection will happen on a new socket.
252     [self addDelegateOperation:[completionHandler = BlockPtr<void()>(completionHandler)] {
253         completionHandler();
254     }];
255 }
256
257 - (void)getTasksWithCompletionHandler:(void (^)(NSArray<NSURLSessionDataTask *> *dataTasks, NSArray<NSURLSessionUploadTask *> *uploadTasks, NSArray<NSURLSessionDownloadTask *> *downloadTasks))completionHandler
258 {
259     NSMutableArray *array = nullptr;
260     {
261         Locker<Lock> locker(_dataTasksLock);
262         array = [NSMutableArray arrayWithCapacity:_dataTasks.size()];
263         for (auto& task : _dataTasks)
264             [array addObject:(__bridge WebCoreNSURLSessionDataTask *)task.get()];
265     }
266     [self addDelegateOperation:^{
267         completionHandler(array, nil, nil);
268     }];
269 }
270
271 - (void)getAllTasksWithCompletionHandler:(void (^)(NSArray<__kindof NSURLSessionTask *> *tasks))completionHandler
272 {
273     NSMutableArray *array = nullptr;
274     {
275         Locker<Lock> locker(_dataTasksLock);
276         array = [NSMutableArray arrayWithCapacity:_dataTasks.size()];
277         for (auto& task : _dataTasks)
278             [array addObject:(__bridge WebCoreNSURLSessionDataTask *)task.get()];
279     }
280     [self addDelegateOperation:^{
281         completionHandler(array);
282     }];
283 }
284
285 - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
286 {
287     if (_invalidated)
288         return nil;
289
290     WebCoreNSURLSessionDataTask *task = [[WebCoreNSURLSessionDataTask alloc] initWithSession:self identifier:_nextTaskIdentifier++ request:request];
291     {
292         Locker<Lock> locker(_dataTasksLock);
293         _dataTasks.add((__bridge CFTypeRef)task);
294     }
295     return (NSURLSessionDataTask *)[task autorelease];
296 }
297
298 - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url
299 {
300     if (_invalidated)
301         return nil;
302
303     WebCoreNSURLSessionDataTask *task = [[WebCoreNSURLSessionDataTask alloc] initWithSession:self identifier:_nextTaskIdentifier++ URL:url];
304     {
305         Locker<Lock> locker(_dataTasksLock);
306         _dataTasks.add((__bridge CFTypeRef)task);
307     }
308     return (NSURLSessionDataTask *)[task autorelease];
309 }
310
311 - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL
312 {
313     UNUSED_PARAM(request);
314     UNUSED_PARAM(fileURL);
315     return nil;
316 }
317
318 - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData
319 {
320     UNUSED_PARAM(request);
321     UNUSED_PARAM(bodyData);
322     return nil;
323 }
324
325 - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
326 {
327     UNUSED_PARAM(request);
328     return nil;
329 }
330
331 - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
332 {
333     UNUSED_PARAM(request);
334     return nil;
335 }
336
337 - (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url
338 {
339     UNUSED_PARAM(url);
340     return nil;
341 }
342
343 - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
344 {
345     UNUSED_PARAM(resumeData);
346     return nil;
347 }
348
349 - (NSURLSessionStreamTask *)streamTaskWithHostName:(NSString *)hostname port:(NSInteger)port
350 {
351     UNUSED_PARAM(hostname);
352     UNUSED_PARAM(port);
353     return nil;
354 }
355
356 - (NSURLSessionStreamTask *)streamTaskWithNetService:(NSNetService *)service
357 {
358     UNUSED_PARAM(service);
359     return nil;
360 }
361
362 - (BOOL)isKindOfClass:(Class)aClass
363 {
364     if (aClass == [NSURLSession class])
365         return YES;
366     return [super isKindOfClass:aClass];
367 }
368 @end
369
370 #pragma mark - WebCoreNSURLSessionDataTaskClient
371
372 namespace WebCore {
373
374 class WebCoreNSURLSessionDataTaskClient : public PlatformMediaResourceClient {
375     WTF_MAKE_FAST_ALLOCATED;
376 public:
377     WebCoreNSURLSessionDataTaskClient(WebCoreNSURLSessionDataTask *task)
378         : m_task(task)
379     {
380     }
381
382     void clearTask();
383
384     void responseReceived(PlatformMediaResource&, const ResourceResponse&, CompletionHandler<void(ShouldContinue)>&&) override;
385     void redirectReceived(PlatformMediaResource&, ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&) override;
386     bool shouldCacheResponse(PlatformMediaResource&, const ResourceResponse&) override;
387     void dataSent(PlatformMediaResource&, unsigned long long, unsigned long long) override;
388     void dataReceived(PlatformMediaResource&, const char* /* data */, int /* length */) override;
389     void accessControlCheckFailed(PlatformMediaResource&, const ResourceError&) override;
390     void loadFailed(PlatformMediaResource&, const ResourceError&) override;
391     void loadFinished(PlatformMediaResource&) override;
392
393 private:
394     Lock m_taskLock;
395     WebCoreNSURLSessionDataTask *m_task;
396 };
397
398 void WebCoreNSURLSessionDataTaskClient::clearTask()
399 {
400     LockHolder locker(m_taskLock);
401     m_task = nullptr;
402 }
403
404 void WebCoreNSURLSessionDataTaskClient::dataSent(PlatformMediaResource& resource, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
405 {
406     LockHolder locker(m_taskLock);
407     if (!m_task)
408         return;
409
410     [m_task resource:resource sentBytes:bytesSent totalBytesToBeSent:totalBytesToBeSent];
411 }
412
413 void WebCoreNSURLSessionDataTaskClient::responseReceived(PlatformMediaResource& resource, const ResourceResponse& response, CompletionHandler<void(ShouldContinue)>&& completionHandler)
414 {
415     LockHolder locker(m_taskLock);
416     if (!m_task)
417         return completionHandler(ShouldContinue::No);
418
419     [m_task resource:resource receivedResponse:response completionHandler:WTFMove(completionHandler)];
420 }
421
422 bool WebCoreNSURLSessionDataTaskClient::shouldCacheResponse(PlatformMediaResource& resource, const ResourceResponse& response)
423 {
424     LockHolder locker(m_taskLock);
425     if (!m_task)
426         return false;
427
428     return [m_task resource:resource shouldCacheResponse:response];
429 }
430
431 void WebCoreNSURLSessionDataTaskClient::dataReceived(PlatformMediaResource& resource, const char* data, int length)
432 {
433     LockHolder locker(m_taskLock);
434     if (!m_task)
435         return;
436
437     [m_task resource:resource receivedData:data length:length];
438 }
439
440 void WebCoreNSURLSessionDataTaskClient::redirectReceived(PlatformMediaResource& resource, ResourceRequest&& request, const ResourceResponse& response, CompletionHandler<void(ResourceRequest&&)>&& completionHandler)
441 {
442     LockHolder locker(m_taskLock);
443     if (!m_task)
444         return;
445
446     [m_task resource:resource receivedRedirect:response request:WTFMove(request) completionHandler: [completionHandler = WTFMove(completionHandler)] (auto&& request) mutable {
447         callOnMainThread([request = request.isolatedCopy(), completionHandler = WTFMove(completionHandler)] () mutable {
448             completionHandler(WTFMove(request));
449         });
450     }];
451 }
452
453 void WebCoreNSURLSessionDataTaskClient::accessControlCheckFailed(PlatformMediaResource& resource, const ResourceError& error)
454 {
455     LockHolder locker(m_taskLock);
456     if (!m_task)
457         return;
458
459     [m_task resource:resource accessControlCheckFailedWithError:error];
460 }
461
462 void WebCoreNSURLSessionDataTaskClient::loadFailed(PlatformMediaResource& resource, const ResourceError& error)
463 {
464     LockHolder locker(m_taskLock);
465     if (!m_task)
466         return;
467
468     [m_task resource:resource loadFailedWithError:error];
469 }
470
471 void WebCoreNSURLSessionDataTaskClient::loadFinished(PlatformMediaResource& resource)
472 {
473     LockHolder locker(m_taskLock);
474     if (!m_task)
475         return;
476
477     [m_task resourceFinished:resource];
478 }
479
480 }
481
482 #pragma mark - WebCoreNSURLSessionDataTask
483
484 @implementation WebCoreNSURLSessionDataTask
485 - (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier URL:(NSURL *)url
486 {
487     self.taskIdentifier = identifier;
488     self.session = session;
489     self.state = NSURLSessionTaskStateSuspended;
490     self.priority = NSURLSessionTaskPriorityDefault;
491     self.originalRequest = self.currentRequest = [NSURLRequest requestWithURL:url];
492
493     return self;
494 }
495
496 - (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier request:(NSURLRequest *)request
497 {
498     self.taskIdentifier = identifier;
499     self.session = session;
500     self.state = NSURLSessionTaskStateSuspended;
501     self.priority = NSURLSessionTaskPriorityDefault;
502     self.originalRequest = self.currentRequest = request;
503
504     return self;
505 }
506
507 - (id)copyWithZone:(NSZone *)zone
508 {
509     UNUSED_PARAM(zone);
510     return [self retain];
511 }
512
513 #pragma mark - Internal methods
514
515 - (void)_restart
516 {
517     ASSERT(isMainThread());
518
519     if (!self.session)
520         return;
521
522     [self _cancel];
523
524     _resource = self.session.loader.requestResource(self.originalRequest, PlatformMediaResourceLoader::LoadOption::DisallowCaching);
525     if (_resource)
526         _resource->setClient(std::make_unique<WebCoreNSURLSessionDataTaskClient>(self));
527 }
528
529 - (void)_cancel
530 {
531     ASSERT(isMainThread());
532     if (_resource) {
533         _resource->stop();
534         _resource->setClient(nullptr);
535         _resource = nil;
536     }
537 }
538
539 - (void)_finish
540 {
541     ASSERT(isMainThread());
542     if (_resource)
543         [self resourceFinished:*_resource];
544 }
545
546 #pragma mark - NSURLSession API
547 @synthesize session=_session;
548 @synthesize taskIdentifier=_taskIdentifier;
549 @synthesize originalRequest=_originalRequest;
550 @synthesize currentRequest=_currentRequest;
551 @synthesize countOfBytesReceived=_countOfBytesReceived;
552 @synthesize countOfBytesSent=_countOfBytesSent;
553 @synthesize countOfBytesExpectedToSend=_countOfBytesExpectedToSend;
554 @synthesize countOfBytesExpectedToReceive=_countOfBytesExpectedToReceive;
555 @synthesize state=_state;
556 @synthesize error=_error;
557 @synthesize taskDescription=_taskDescription;
558 @synthesize priority=_priority;
559
560 - (NSURLResponse *)response
561 {
562     return _response.get();
563 }
564
565 - (void)cancel
566 {
567     self.state = NSURLSessionTaskStateCanceling;
568     callOnMainThread([protectedSelf = RetainPtr<WebCoreNSURLSessionDataTask>(self)] {
569         [protectedSelf _cancel];
570         [protectedSelf _finish];
571     });
572 }
573
574 - (void)suspend
575 {
576     callOnMainThread([protectedSelf = RetainPtr<WebCoreNSURLSessionDataTask>(self)] {
577         // NSURLSessionDataTasks must start over after suspending, so while
578         // we could defer loading at this point, instead cancel and restart
579         // upon resume so as to adhere to NSURLSessionDataTask semantics.
580         [protectedSelf _cancel];
581         protectedSelf.get().state = NSURLSessionTaskStateSuspended;
582     });
583 }
584
585 - (void)resume
586 {
587     callOnMainThread([protectedSelf = RetainPtr<WebCoreNSURLSessionDataTask>(self)] {
588         if (protectedSelf.get().state != NSURLSessionTaskStateSuspended)
589             return;
590
591         [protectedSelf _restart];
592         protectedSelf.get().state = NSURLSessionTaskStateRunning;
593     });
594 }
595
596 - (void)dealloc
597 {
598     [_originalRequest release];
599     [_currentRequest release];
600     [_error release];
601     [_taskDescription release];
602
603     if (!isMainThread() && _resource) {
604         if (auto* client = _resource->client())
605             static_cast<WebCoreNSURLSessionDataTaskClient*>(client)->clearTask();
606         callOnMainThread([resource = WTFMove(_resource)] { });
607     }
608
609     [super dealloc];
610 }
611
612 #pragma mark - NSURLSession SPI
613
614 - (NSDictionary *)_timingData
615 {
616     // FIXME: return a dictionary sourced from ResourceHandle::getConnectionTimingData().
617     return @{ };
618 }
619
620 #pragma mark - PlatformMediaResourceClient callbacks
621
622 - (void)resource:(PlatformMediaResource&)resource sentBytes:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent
623 {
624     ASSERT_UNUSED(resource, &resource == _resource);
625     UNUSED_PARAM(bytesSent);
626     UNUSED_PARAM(totalBytesToBeSent);
627     // No-op.
628 }
629
630 - (void)resource:(PlatformMediaResource&)resource receivedResponse:(const ResourceResponse&)response completionHandler:(CompletionHandler<void(ShouldContinue)>&&)completionHandler
631 {
632     ASSERT(response.source() == ResourceResponse::Source::Network || response.source() == ResourceResponse::Source::DiskCache || response.source() == ResourceResponse::Source::DiskCacheAfterValidation || response.source() == ResourceResponse::Source::ServiceWorker);
633     ASSERT_UNUSED(resource, &resource == _resource);
634     ASSERT(isMainThread());
635     [self.session task:self didReceiveResponseFromOrigin:SecurityOrigin::create(response.url())];
636     [self.session task:self didReceiveCORSAccessCheckResult:resource.didPassAccessControlCheck()];
637     self.countOfBytesExpectedToReceive = response.expectedContentLength();
638     RetainPtr<NSURLResponse> strongResponse { response.nsURLResponse() };
639     RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
640     [self.session addDelegateOperation:[strongSelf, strongResponse, completionHandler = WTFMove(completionHandler)] () mutable {
641         strongSelf->_response = strongResponse.get();
642
643         id<NSURLSessionDataDelegate> dataDelegate = (id<NSURLSessionDataDelegate>)strongSelf.get().session.delegate;
644         if (![dataDelegate respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) {
645             callOnMainThread([strongSelf, completionHandler = WTFMove(completionHandler)] () mutable {
646                 completionHandler(ShouldContinue::Yes);
647             });
648             return;
649         }
650
651         [dataDelegate URLSession:(NSURLSession *)strongSelf.get().session dataTask:(NSURLSessionDataTask *)strongSelf.get() didReceiveResponse:strongResponse.get() completionHandler:makeBlockPtr([strongSelf, completionHandler = WTFMove(completionHandler)] (NSURLSessionResponseDisposition disposition) mutable {
652             callOnMainThread([strongSelf, disposition, completionHandler = WTFMove(completionHandler)] () mutable {
653                 if (disposition == NSURLSessionResponseCancel)
654                     completionHandler(ShouldContinue::No);
655                 else {
656                     ASSERT(disposition == NSURLSessionResponseAllow);
657                     completionHandler(ShouldContinue::Yes);
658                 }
659             });
660         }).get()];
661     }];
662 }
663
664 - (BOOL)resource:(PlatformMediaResource&)resource shouldCacheResponse:(const ResourceResponse&)response
665 {
666     ASSERT_UNUSED(resource, &resource == _resource);
667
668     ASSERT(isMainThread());
669
670     // FIXME: remove if <rdar://problem/20001985> is ever resolved.
671     return response.httpHeaderField(HTTPHeaderName::ContentRange).isEmpty();
672 }
673
674 - (void)resource:(PlatformMediaResource&)resource receivedData:(const char*)data length:(int)length
675 {
676     ASSERT_UNUSED(resource, &resource == _resource);
677     RetainPtr<NSData> nsData = adoptNS([[NSData alloc] initWithBytes:data length:length]);
678     RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
679     [self.session addDelegateOperation:[strongSelf, length, nsData] {
680         strongSelf.get().countOfBytesReceived += length;
681         id<NSURLSessionDataDelegate> dataDelegate = (id<NSURLSessionDataDelegate>)strongSelf.get().session.delegate;
682         if ([dataDelegate respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)])
683             [dataDelegate URLSession:(NSURLSession *)strongSelf.get().session dataTask:(NSURLSessionDataTask *)strongSelf.get() didReceiveData:nsData.get()];
684     }];
685 }
686
687 - (void)resource:(PlatformMediaResource&)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&&)request completionHandler:(CompletionHandler<void(ResourceRequest&&)>&&)completionHandler
688 {
689     ASSERT_UNUSED(resource, &resource == _resource);
690     [self.session addDelegateOperation:[strongSelf = retainPtr(self), response = retainPtr(response.nsURLResponse()), request = request.isolatedCopy(), completionHandler = WTFMove(completionHandler)] () mutable {
691         if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
692             ASSERT_NOT_REACHED();
693             callOnMainThread([request = WTFMove(request), completionHandler = WTFMove(completionHandler)] () mutable {
694                 completionHandler(WTFMove(request));
695             });
696             return;
697         }
698         
699         id<NSURLSessionDataDelegate> dataDelegate = (id<NSURLSessionDataDelegate>)strongSelf.get().session.delegate;
700         if ([dataDelegate respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)]) {
701             auto completionHandlerBlock = makeBlockPtr([completionHandler = WTFMove(completionHandler)](NSURLRequest *newRequest) mutable {
702                 if (!isMainThread()) {
703                     callOnMainThread([request = ResourceRequest { newRequest }, completionHandler = WTFMove(completionHandler)] () mutable {
704                         completionHandler(WTFMove(request));
705                     });
706                     return;
707                 }
708                 completionHandler(newRequest);
709             });
710             [dataDelegate URLSession:(NSURLSession *)strongSelf.get().session task:(NSURLSessionTask *)strongSelf.get() willPerformHTTPRedirection:(NSHTTPURLResponse *)response.get() newRequest:request.nsURLRequest(HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody) completionHandler:completionHandlerBlock.get()];
711         } else {
712             callOnMainThread([request = WTFMove(request), completionHandler = WTFMove(completionHandler)] () mutable {
713                 completionHandler(WTFMove(request));
714             });
715         }
716     }];
717 }
718
719 - (void)_resource:(PlatformMediaResource&)resource loadFinishedWithError:(NSError *)error
720 {
721     ASSERT_UNUSED(resource, &resource == _resource);
722     if (self.state == NSURLSessionTaskStateCompleted)
723         return;
724     self.state = NSURLSessionTaskStateCompleted;
725
726     RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
727     RetainPtr<WebCoreNSURLSession> strongSession { self.session };
728     RetainPtr<NSError> strongError { error };
729     [self.session addDelegateOperation:[strongSelf, strongSession, strongError] {
730         id<NSURLSessionTaskDelegate> delegate = (id<NSURLSessionTaskDelegate>)strongSession.get().delegate;
731         if ([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)])
732             [delegate URLSession:(NSURLSession *)strongSession.get() task:(NSURLSessionDataTask *)strongSelf.get() didCompleteWithError:strongError.get()];
733
734         callOnMainThread([strongSelf, strongSession] {
735             [strongSession taskCompleted:strongSelf.get()];
736         });
737     }];
738 }
739
740 - (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error
741 {
742     [self _resource:resource loadFinishedWithError:error.nsError()];
743 }
744
745 - (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error
746 {
747     [self _resource:resource loadFinishedWithError:error.nsError()];
748 }
749
750 - (void)resourceFinished:(PlatformMediaResource&)resource
751 {
752     [self _resource:resource loadFinishedWithError:nil];
753 }
754 @end