old mode 100755
new mode 100644
| | |
| | | |
| | | static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3; |
| | | |
| | | static void * AFTaskStateChangedContext = &AFTaskStateChangedContext; |
| | | |
| | | typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error); |
| | | typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential); |
| | | |
| | |
| | | #pragma mark - |
| | | |
| | | @interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate> |
| | | - (instancetype)initWithTask:(NSURLSessionTask *)task; |
| | | @property (nonatomic, weak) AFURLSessionManager *manager; |
| | | @property (nonatomic, strong) NSMutableData *mutableData; |
| | | @property (nonatomic, strong) NSProgress *uploadProgress; |
| | |
| | | |
| | | @implementation AFURLSessionManagerTaskDelegate |
| | | |
| | | - (instancetype)init { |
| | | - (instancetype)initWithTask:(NSURLSessionTask *)task { |
| | | self = [super init]; |
| | | if (!self) { |
| | | return nil; |
| | | } |
| | | |
| | | self.mutableData = [NSMutableData data]; |
| | | self.uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; |
| | | self.uploadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown; |
| | | |
| | | self.downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; |
| | | self.downloadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown; |
| | | |
| | | _mutableData = [NSMutableData data]; |
| | | _uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; |
| | | _downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; |
| | | |
| | | __weak __typeof__(task) weakTask = task; |
| | | for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ]) |
| | | { |
| | | progress.totalUnitCount = NSURLSessionTransferSizeUnknown; |
| | | progress.cancellable = YES; |
| | | progress.cancellationHandler = ^{ |
| | | [weakTask cancel]; |
| | | }; |
| | | progress.pausable = YES; |
| | | progress.pausingHandler = ^{ |
| | | [weakTask suspend]; |
| | | }; |
| | | #if AF_CAN_USE_AT_AVAILABLE |
| | | if (@available(iOS 9, macOS 10.11, *)) |
| | | #else |
| | | if ([progress respondsToSelector:@selector(setResumingHandler:)]) |
| | | #endif |
| | | { |
| | | progress.resumingHandler = ^{ |
| | | [weakTask resume]; |
| | | }; |
| | | } |
| | | |
| | | [progress addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | } |
| | | return self; |
| | | } |
| | | |
| | | #pragma mark - NSProgress Tracking |
| | | |
| | | - (void)setupProgressForTask:(NSURLSessionTask *)task { |
| | | __weak __typeof__(task) weakTask = task; |
| | | |
| | | self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend; |
| | | self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive; |
| | | [self.uploadProgress setCancellable:YES]; |
| | | [self.uploadProgress setCancellationHandler:^{ |
| | | __typeof__(weakTask) strongTask = weakTask; |
| | | [strongTask cancel]; |
| | | }]; |
| | | [self.uploadProgress setPausable:YES]; |
| | | [self.uploadProgress setPausingHandler:^{ |
| | | __typeof__(weakTask) strongTask = weakTask; |
| | | [strongTask suspend]; |
| | | }]; |
| | | if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) { |
| | | [self.uploadProgress setResumingHandler:^{ |
| | | __typeof__(weakTask) strongTask = weakTask; |
| | | [strongTask resume]; |
| | | }]; |
| | | } |
| | | |
| | | [self.downloadProgress setCancellable:YES]; |
| | | [self.downloadProgress setCancellationHandler:^{ |
| | | __typeof__(weakTask) strongTask = weakTask; |
| | | [strongTask cancel]; |
| | | }]; |
| | | [self.downloadProgress setPausable:YES]; |
| | | [self.downloadProgress setPausingHandler:^{ |
| | | __typeof__(weakTask) strongTask = weakTask; |
| | | [strongTask suspend]; |
| | | }]; |
| | | |
| | | if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) { |
| | | [self.downloadProgress setResumingHandler:^{ |
| | | __typeof__(weakTask) strongTask = weakTask; |
| | | [strongTask resume]; |
| | | }]; |
| | | } |
| | | |
| | | [task addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | [task addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | |
| | | [task addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(countOfBytesSent)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | [task addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | |
| | | [self.downloadProgress addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | [self.uploadProgress addObserver:self |
| | | forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) |
| | | options:NSKeyValueObservingOptionNew |
| | | context:NULL]; |
| | | } |
| | | |
| | | - (void)cleanUpProgressForTask:(NSURLSessionTask *)task { |
| | | [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))]; |
| | | [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]; |
| | | [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))]; |
| | | [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]; |
| | | - (void)dealloc { |
| | | [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))]; |
| | | [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))]; |
| | | } |
| | | |
| | | #pragma mark - NSProgress Tracking |
| | | |
| | | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { |
| | | if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) { |
| | | if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) { |
| | | self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue]; |
| | | } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) { |
| | | self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue]; |
| | | } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) { |
| | | self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue]; |
| | | } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) { |
| | | self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue]; |
| | | } |
| | | } |
| | | else if ([object isEqual:self.downloadProgress]) { |
| | | if ([object isEqual:self.downloadProgress]) { |
| | | if (self.downloadProgressBlock) { |
| | | self.downloadProgressBlock(object); |
| | | } |
| | |
| | | task:(NSURLSessionTask *)task |
| | | didCompleteWithError:(NSError *)error |
| | | { |
| | | #pragma clang diagnostic push |
| | | #pragma clang diagnostic ignored "-Wgnu" |
| | | __strong AFURLSessionManager *manager = self.manager; |
| | | |
| | | __block id responseObject = nil; |
| | |
| | | }); |
| | | }); |
| | | } |
| | | #pragma clang diagnostic pop |
| | | } |
| | | |
| | | #pragma mark - NSURLSessionDataTaskDelegate |
| | | #pragma mark - NSURLSessionDataDelegate |
| | | |
| | | - (void)URLSession:(__unused NSURLSession *)session |
| | | dataTask:(__unused NSURLSessionDataTask *)dataTask |
| | | didReceiveData:(NSData *)data |
| | | { |
| | | self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive; |
| | | self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived; |
| | | |
| | | [self.mutableData appendData:data]; |
| | | } |
| | | |
| | | #pragma mark - NSURLSessionDownloadTaskDelegate |
| | | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task |
| | | didSendBodyData:(int64_t)bytesSent |
| | | totalBytesSent:(int64_t)totalBytesSent |
| | | totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{ |
| | | |
| | | self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend; |
| | | self.uploadProgress.completedUnitCount = task.countOfBytesSent; |
| | | } |
| | | |
| | | #pragma mark - NSURLSessionDownloadDelegate |
| | | |
| | | - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask |
| | | didWriteData:(int64_t)bytesWritten |
| | | totalBytesWritten:(int64_t)totalBytesWritten |
| | | totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ |
| | | |
| | | self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite; |
| | | self.downloadProgress.completedUnitCount = totalBytesWritten; |
| | | } |
| | | |
| | | - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask |
| | | didResumeAtOffset:(int64_t)fileOffset |
| | | expectedTotalBytes:(int64_t)expectedTotalBytes{ |
| | | |
| | | self.downloadProgress.totalUnitCount = expectedTotalBytes; |
| | | self.downloadProgress.completedUnitCount = fileOffset; |
| | | } |
| | | |
| | | - (void)URLSession:(NSURLSession *)session |
| | | downloadTask:(NSURLSessionDownloadTask *)downloadTask |
| | | didFinishDownloadingToURL:(NSURL *)location |
| | | { |
| | | NSError *fileManagerError = nil; |
| | | self.downloadFileURL = nil; |
| | | |
| | | if (self.downloadTaskDidFinishDownloading) { |
| | | self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); |
| | | if (self.downloadFileURL) { |
| | | [[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]; |
| | | NSError *fileManagerError = nil; |
| | | |
| | | if (fileManagerError) { |
| | | if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) { |
| | | [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo]; |
| | | } |
| | | } |
| | |
| | | @property (readwrite, nonatomic, strong) NSLock *lock; |
| | | @property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid; |
| | | @property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge; |
| | | @property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession; |
| | | @property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession AF_API_UNAVAILABLE(macos); |
| | | @property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection; |
| | | @property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge; |
| | | @property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream; |
| | |
| | | |
| | | [self.lock lock]; |
| | | self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate; |
| | | [delegate setupProgressForTask:task]; |
| | | [self addNotificationObserverForTask:task]; |
| | | [self.lock unlock]; |
| | | } |
| | |
| | | downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock |
| | | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler |
| | | { |
| | | AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; |
| | | AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask]; |
| | | delegate.manager = self; |
| | | delegate.completionHandler = completionHandler; |
| | | |
| | |
| | | progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock |
| | | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler |
| | | { |
| | | AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; |
| | | AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask]; |
| | | delegate.manager = self; |
| | | delegate.completionHandler = completionHandler; |
| | | |
| | |
| | | destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination |
| | | completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler |
| | | { |
| | | AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; |
| | | AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask]; |
| | | delegate.manager = self; |
| | | delegate.completionHandler = completionHandler; |
| | | |
| | |
| | | - (void)removeDelegateForTask:(NSURLSessionTask *)task { |
| | | NSParameterAssert(task); |
| | | |
| | | AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; |
| | | [self.lock lock]; |
| | | [delegate cleanUpProgressForTask:task]; |
| | | [self removeNotificationObserverForTask:task]; |
| | | [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)]; |
| | | [self.lock unlock]; |
| | |
| | | #pragma mark - |
| | | |
| | | - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks { |
| | | dispatch_async(dispatch_get_main_queue(), ^{ |
| | | if (cancelPendingTasks) { |
| | | [self.session invalidateAndCancel]; |
| | | } else { |
| | | [self.session finishTasksAndInvalidate]; |
| | | } |
| | | }); |
| | | if (cancelPendingTasks) { |
| | | [self.session invalidateAndCancel]; |
| | | } else { |
| | | [self.session finishTasksAndInvalidate]; |
| | | } |
| | | } |
| | | |
| | | #pragma mark - |
| | |
| | | __block NSURLSessionUploadTask *uploadTask = nil; |
| | | url_session_manager_create_task_safely(^{ |
| | | uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; |
| | | }); |
| | | |
| | | if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) { |
| | | for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) { |
| | | uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; |
| | | |
| | | // uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113) |
| | | if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) { |
| | | for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) { |
| | | uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | if (uploadTask) { |
| | | [self addDelegateForUploadTask:uploadTask |
| | | progress:uploadProgressBlock |
| | | completionHandler:completionHandler]; |
| | | } |
| | | |
| | | [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; |
| | | |
| | | return uploadTask; |
| | | } |
| | |
| | | self.sessionDidReceiveAuthenticationChallenge = block; |
| | | } |
| | | |
| | | #if !TARGET_OS_OSX |
| | | - (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block { |
| | | self.didFinishEventsForBackgroundURLSession = block; |
| | | } |
| | | #endif |
| | | |
| | | #pragma mark - |
| | | |
| | |
| | | return self.dataTaskDidReceiveResponse != nil; |
| | | } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) { |
| | | return self.dataTaskWillCacheResponse != nil; |
| | | } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) { |
| | | } |
| | | #if !TARGET_OS_OSX |
| | | else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) { |
| | | return self.didFinishEventsForBackgroundURLSession != nil; |
| | | } |
| | | #endif |
| | | |
| | | return [[self class] instancesRespondToSelector:selector]; |
| | | } |
| | |
| | | totalUnitCount = (int64_t) [contentLength longLongValue]; |
| | | } |
| | | } |
| | | |
| | | AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; |
| | | |
| | | if (delegate) { |
| | | [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend]; |
| | | } |
| | | |
| | | if (self.taskDidSendBodyData) { |
| | | self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount); |
| | |
| | | } |
| | | } |
| | | |
| | | #if !TARGET_OS_OSX |
| | | - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { |
| | | if (self.didFinishEventsForBackgroundURLSession) { |
| | | dispatch_async(dispatch_get_main_queue(), ^{ |
| | |
| | | }); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | #pragma mark - NSURLSessionDownloadDelegate |
| | | |
| | |
| | | if (fileURL) { |
| | | delegate.downloadFileURL = fileURL; |
| | | NSError *error = nil; |
| | | [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]; |
| | | if (error) { |
| | | |
| | | if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) { |
| | | [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo]; |
| | | } |
| | | |
| | |
| | | totalBytesWritten:(int64_t)totalBytesWritten |
| | | totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite |
| | | { |
| | | |
| | | AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; |
| | | |
| | | if (delegate) { |
| | | [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite]; |
| | | } |
| | | |
| | | if (self.downloadTaskDidWriteData) { |
| | | self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); |
| | | } |
| | |
| | | didResumeAtOffset:(int64_t)fileOffset |
| | | expectedTotalBytes:(int64_t)expectedTotalBytes |
| | | { |
| | | |
| | | AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; |
| | | |
| | | if (delegate) { |
| | | [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes]; |
| | | } |
| | | |
| | | if (self.downloadTaskDidResume) { |
| | | self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes); |
| | | } |