12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274 |
- // AFURLSessionManager.m
- // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- #import "AFURLSessionManager.h"
- #import <objc/runtime.h>
- static dispatch_queue_t url_session_manager_processing_queue() {
- static dispatch_queue_t af_url_session_manager_processing_queue;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT);
- });
- return af_url_session_manager_processing_queue;
- }
- static dispatch_group_t url_session_manager_completion_group() {
- static dispatch_group_t af_url_session_manager_completion_group;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- af_url_session_manager_completion_group = dispatch_group_create();
- });
- return af_url_session_manager_completion_group;
- }
- NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume";
- NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete";
- NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend";
- NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";
- NSString * const AFURLSessionDownloadTaskDidMoveFileSuccessfullyNotification = @"com.alamofire.networking.session.download.file-manager-succeed";
- NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";
- NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";
- NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";
- NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";
- NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";
- NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";
- NSString * const AFNetworkingTaskDidCompleteSessionTaskMetrics = @"com.alamofire.networking.complete.sessiontaskmetrics";
- static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";
- typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
- typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
- typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request);
- typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
- typedef id (^AFURLSessionTaskAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, void (^completionHandler)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential));
- typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session);
- typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task);
- typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
- typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error);
- #if AF_CAN_INCLUDE_SESSION_TASK_METRICS
- typedef void (^AFURLSessionTaskDidFinishCollectingMetricsBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLSessionTaskMetrics * metrics) AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10));
- #endif
- typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response);
- typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask);
- typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data);
- typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse);
- typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
- typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
- typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);
- typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
- typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
- #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;
- @property (nonatomic, strong) NSProgress *downloadProgress;
- @property (nonatomic, copy) NSURL *downloadFileURL;
- #if AF_CAN_INCLUDE_SESSION_TASK_METRICS
- @property (nonatomic, strong) NSURLSessionTaskMetrics *sessionTaskMetrics AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10));
- #endif
- @property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
- @property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
- @property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
- @property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
- @end
- @implementation AFURLSessionManagerTaskDelegate
- - (instancetype)initWithTask:(NSURLSessionTask *)task {
- self = [super init];
- if (!self) {
- return nil;
- }
-
- _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(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;
- }
- - (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 isEqual:self.downloadProgress]) {
- if (self.downloadProgressBlock) {
- self.downloadProgressBlock(object);
- }
- }
- else if ([object isEqual:self.uploadProgress]) {
- if (self.uploadProgressBlock) {
- self.uploadProgressBlock(object);
- }
- }
- }
- static const void * const AuthenticationChallengeErrorKey = &AuthenticationChallengeErrorKey;
- #pragma mark - NSURLSessionTaskDelegate
- - (void)URLSession:(__unused NSURLSession *)session
- task:(NSURLSessionTask *)task
- didCompleteWithError:(NSError *)error
- {
- error = objc_getAssociatedObject(task, AuthenticationChallengeErrorKey) ?: error;
- __strong AFURLSessionManager *manager = self.manager;
- __block id responseObject = nil;
- NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
- userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
- //Performance Improvement from #2672
- NSData *data = nil;
- if (self.mutableData) {
- data = [self.mutableData copy];
- //We no longer need the reference, so nil it out to gain back some memory.
- self.mutableData = nil;
- }
- #if AF_CAN_USE_AT_AVAILABLE && AF_CAN_INCLUDE_SESSION_TASK_METRICS
- if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, *)) {
- if (self.sessionTaskMetrics) {
- userInfo[AFNetworkingTaskDidCompleteSessionTaskMetrics] = self.sessionTaskMetrics;
- }
- }
- #endif
- if (self.downloadFileURL) {
- userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
- } else if (data) {
- userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
- }
- if (error) {
- userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
- dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
- if (self.completionHandler) {
- self.completionHandler(task.response, responseObject, error);
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
- });
- });
- } else {
- dispatch_async(url_session_manager_processing_queue(), ^{
- NSError *serializationError = nil;
- responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
- if (self.downloadFileURL) {
- responseObject = self.downloadFileURL;
- }
- if (responseObject) {
- userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
- }
- if (serializationError) {
- userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
- }
- dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
- if (self.completionHandler) {
- self.completionHandler(task.response, responseObject, serializationError);
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
- });
- });
- });
- }
- }
- #if AF_CAN_INCLUDE_SESSION_TASK_METRICS
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10)) {
- self.sessionTaskMetrics = metrics;
- }
- #endif
- #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];
- }
- - (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
- {
- self.downloadFileURL = nil;
- if (self.downloadTaskDidFinishDownloading) {
- self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
- if (self.downloadFileURL) {
- NSError *fileManagerError = nil;
- if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
- [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
- } else {
- [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidMoveFileSuccessfullyNotification object:downloadTask userInfo:nil];
- }
- }
- }
- }
- @end
- #pragma mark -
- /**
- * A workaround for issues related to key-value observing the `state` of an `NSURLSessionTask`.
- *
- * See:
- * - https://github.com/AFNetworking/AFNetworking/issues/1477
- * - https://github.com/AFNetworking/AFNetworking/issues/2638
- * - https://github.com/AFNetworking/AFNetworking/pull/2702
- */
- static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
- Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
- Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
- method_exchangeImplementations(originalMethod, swizzledMethod);
- }
- static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
- return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method));
- }
- static NSString * const AFNSURLSessionTaskDidResumeNotification = @"com.alamofire.networking.nsurlsessiontask.resume";
- static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofire.networking.nsurlsessiontask.suspend";
- @interface _AFURLSessionTaskSwizzling : NSObject
- @end
- @implementation _AFURLSessionTaskSwizzling
- + (void)load {
- /**
- WARNING: Trouble Ahead
- https://github.com/AFNetworking/AFNetworking/pull/2702
- */
- if (NSClassFromString(@"NSURLSessionTask")) {
- /**
- iOS 7 and iOS 8 differ in NSURLSessionTask implementation, which makes the next bit of code a bit tricky.
- Many Unit Tests have been built to validate as much of this behavior has possible.
- Here is what we know:
- - NSURLSessionTasks are implemented with class clusters, meaning the class you request from the API isn't actually the type of class you will get back.
- - Simply referencing `[NSURLSessionTask class]` will not work. You need to ask an `NSURLSession` to actually create an object, and grab the class from there.
- - On iOS 7, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `__NSCFURLSessionTask`.
- - On iOS 8, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `NSURLSessionTask`.
- - On iOS 7, `__NSCFLocalSessionTask` and `__NSCFURLSessionTask` are the only two classes that have their own implementations of `resume` and `suspend`, and `__NSCFLocalSessionTask` DOES NOT CALL SUPER. This means both classes need to be swizzled.
- - On iOS 8, `NSURLSessionTask` is the only class that implements `resume` and `suspend`. This means this is the only class that needs to be swizzled.
- - Because `NSURLSessionTask` is not involved in the class hierarchy for every version of iOS, its easier to add the swizzled methods to a dummy class and manage them there.
-
- Some Assumptions:
- - No implementations of `resume` or `suspend` call super. If this were to change in a future version of iOS, we'd need to handle it.
- - No background task classes override `resume` or `suspend`
-
- The current solution:
- 1) Grab an instance of `__NSCFLocalDataTask` by asking an instance of `NSURLSession` for a data task.
- 2) Grab a pointer to the original implementation of `af_resume`
- 3) Check to see if the current class has an implementation of resume. If so, continue to step 4.
- 4) Grab the super class of the current class.
- 5) Grab a pointer for the current class to the current implementation of `resume`.
- 6) Grab a pointer for the super class to the current implementation of `resume`.
- 7) If the current class implementation of `resume` is not equal to the super class implementation of `resume` AND the current implementation of `resume` is not equal to the original implementation of `af_resume`, THEN swizzle the methods
- 8) Set the current class to the super class, and repeat steps 3-8
- */
- NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
- NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wnonnull"
- NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
- #pragma clang diagnostic pop
- IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
- Class currentClass = [localDataTask class];
-
- while (class_getInstanceMethod(currentClass, @selector(resume))) {
- Class superClass = [currentClass superclass];
- IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
- IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
- if (classResumeIMP != superclassResumeIMP &&
- originalAFResumeIMP != classResumeIMP) {
- [self swizzleResumeAndSuspendMethodForClass:currentClass];
- }
- currentClass = [currentClass superclass];
- }
-
- [localDataTask cancel];
- [session finishTasksAndInvalidate];
- }
- }
- + (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
- Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
- Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
- if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
- af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
- }
- if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
- af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
- }
- }
- - (NSURLSessionTaskState)state {
- NSAssert(NO, @"State method should never be called in the actual dummy class");
- return NSURLSessionTaskStateCanceling;
- }
- - (void)af_resume {
- NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
- NSURLSessionTaskState state = [self state];
- [self af_resume];
-
- if (state != NSURLSessionTaskStateRunning) {
- [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
- }
- }
- - (void)af_suspend {
- NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
- NSURLSessionTaskState state = [self state];
- [self af_suspend];
-
- if (state != NSURLSessionTaskStateSuspended) {
- [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
- }
- }
- @end
- #pragma mark -
- @interface AFURLSessionManager ()
- @property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
- @property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
- @property (readwrite, nonatomic, strong) NSURLSession *session;
- @property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
- @property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
- @property (readwrite, nonatomic, strong) NSLock *lock;
- @property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
- @property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
- @property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession AF_API_UNAVAILABLE(macos);
- @property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
- @property (readwrite, nonatomic, copy) AFURLSessionTaskAuthenticationChallengeBlock authenticationChallengeHandler;
- @property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
- @property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
- @property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
- #if AF_CAN_INCLUDE_SESSION_TASK_METRICS
- @property (readwrite, nonatomic, copy) AFURLSessionTaskDidFinishCollectingMetricsBlock taskDidFinishCollectingMetrics AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10));
- #endif
- @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
- @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
- @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
- @property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
- @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
- @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
- @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;
- @end
- @implementation AFURLSessionManager
- - (instancetype)init {
- return [self initWithSessionConfiguration:nil];
- }
- - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
- self = [super init];
- if (!self) {
- return nil;
- }
- if (!configuration) {
- configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
- }
- self.sessionConfiguration = configuration;
- self.operationQueue = [[NSOperationQueue alloc] init];
- self.operationQueue.maxConcurrentOperationCount = 1;
- self.responseSerializer = [AFJSONResponseSerializer serializer];
- self.securityPolicy = [AFSecurityPolicy defaultPolicy];
- #if !TARGET_OS_WATCH
- self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
- #endif
- self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
- self.lock = [[NSLock alloc] init];
- self.lock.name = AFURLSessionManagerLockName;
- [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
- for (NSURLSessionDataTask *task in dataTasks) {
- [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
- }
- for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
- [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
- }
- for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
- [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
- }
- }];
- return self;
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- #pragma mark -
- - (NSURLSession *)session {
-
- @synchronized (self) {
- if (!_session) {
- _session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
- }
- }
- return _session;
- }
- #pragma mark -
- - (NSString *)taskDescriptionForSessionTasks {
- return [NSString stringWithFormat:@"%p", self];
- }
- - (void)taskDidResume:(NSNotification *)notification {
- NSURLSessionTask *task = notification.object;
- if ([task respondsToSelector:@selector(taskDescription)]) {
- if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
- });
- }
- }
- }
- - (void)taskDidSuspend:(NSNotification *)notification {
- NSURLSessionTask *task = notification.object;
- if ([task respondsToSelector:@selector(taskDescription)]) {
- if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
- });
- }
- }
- }
- #pragma mark -
- - (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
- NSParameterAssert(task);
- AFURLSessionManagerTaskDelegate *delegate = nil;
- [self.lock lock];
- delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
- [self.lock unlock];
- return delegate;
- }
- - (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
- forTask:(NSURLSessionTask *)task
- {
- NSParameterAssert(task);
- NSParameterAssert(delegate);
- [self.lock lock];
- self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
- [self addNotificationObserverForTask:task];
- [self.lock unlock];
- }
- - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
- uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
- downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
- completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
- {
- AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
- delegate.manager = self;
- delegate.completionHandler = completionHandler;
- dataTask.taskDescription = self.taskDescriptionForSessionTasks;
- [self setDelegate:delegate forTask:dataTask];
- delegate.uploadProgressBlock = uploadProgressBlock;
- delegate.downloadProgressBlock = downloadProgressBlock;
- }
- - (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
- progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
- completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
- {
- AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask];
- delegate.manager = self;
- delegate.completionHandler = completionHandler;
- uploadTask.taskDescription = self.taskDescriptionForSessionTasks;
- [self setDelegate:delegate forTask:uploadTask];
- delegate.uploadProgressBlock = uploadProgressBlock;
- }
- - (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
- progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
- destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
- completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
- {
- AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
- delegate.manager = self;
- delegate.completionHandler = completionHandler;
- if (destination) {
- delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
- return destination(location, task.response);
- };
- }
- downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
- [self setDelegate:delegate forTask:downloadTask];
- delegate.downloadProgressBlock = downloadProgressBlock;
- }
- - (void)removeDelegateForTask:(NSURLSessionTask *)task {
- NSParameterAssert(task);
- [self.lock lock];
- [self removeNotificationObserverForTask:task];
- [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
- [self.lock unlock];
- }
- #pragma mark -
- - (NSArray *)tasksForKeyPath:(NSString *)keyPath {
- __block NSArray *tasks = nil;
- dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
- [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
- if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
- tasks = dataTasks;
- } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
- tasks = uploadTasks;
- } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
- tasks = downloadTasks;
- } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
- tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
- }
- dispatch_semaphore_signal(semaphore);
- }];
- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
- return tasks;
- }
- - (NSArray *)tasks {
- return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
- }
- - (NSArray *)dataTasks {
- return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
- }
- - (NSArray *)uploadTasks {
- return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
- }
- - (NSArray *)downloadTasks {
- return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
- }
- #pragma mark -
- - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks resetSession:(BOOL)resetSession {
- if (cancelPendingTasks) {
- [self.session invalidateAndCancel];
- } else {
- [self.session finishTasksAndInvalidate];
- }
- if (resetSession) {
- self.session = nil;
- }
- }
- #pragma mark -
- - (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerializer {
- NSParameterAssert(responseSerializer);
- _responseSerializer = responseSerializer;
- }
- #pragma mark -
- - (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
- }
- - (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
- [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
- }
- #pragma mark -
- - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
- uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
- downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
- completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
- NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
- [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
- return dataTask;
- }
- #pragma mark -
- - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
- fromFile:(NSURL *)fileURL
- progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
- completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
- {
- NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
-
- if (uploadTask) {
- [self addDelegateForUploadTask:uploadTask
- progress:uploadProgressBlock
- completionHandler:completionHandler];
- }
- return uploadTask;
- }
- - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
- fromData:(NSData *)bodyData
- progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
- completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
- {
- NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
-
- [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
- return uploadTask;
- }
- - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
- progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
- completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
- {
- NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithStreamedRequest:request];
- [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
- return uploadTask;
- }
- #pragma mark -
- - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
- progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
- destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
- completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
- {
- NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
-
- [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
- return downloadTask;
- }
- - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
- progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
- destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
- completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
- {
- NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithResumeData:resumeData];
- [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
- return downloadTask;
- }
- #pragma mark -
- - (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task {
- return [[self delegateForTask:task] uploadProgress];
- }
- - (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task {
- return [[self delegateForTask:task] downloadProgress];
- }
- #pragma mark -
- - (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block {
- self.sessionDidBecomeInvalid = block;
- }
- - (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block {
- self.sessionDidReceiveAuthenticationChallenge = block;
- }
- #if !TARGET_OS_OSX
- - (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block {
- self.didFinishEventsForBackgroundURLSession = block;
- }
- #endif
- #pragma mark -
- - (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block {
- self.taskNeedNewBodyStream = block;
- }
- - (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block {
- self.taskWillPerformHTTPRedirection = block;
- }
- - (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block {
- self.taskDidSendBodyData = block;
- }
- - (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block {
- self.taskDidComplete = block;
- }
- #if AF_CAN_INCLUDE_SESSION_TASK_METRICS
- - (void)setTaskDidFinishCollectingMetricsBlock:(void (^)(NSURLSession * _Nonnull, NSURLSessionTask * _Nonnull, NSURLSessionTaskMetrics * _Nullable))block AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10)) {
- self.taskDidFinishCollectingMetrics = block;
- }
- #endif
- #pragma mark -
- - (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block {
- self.dataTaskDidReceiveResponse = block;
- }
- - (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block {
- self.dataTaskDidBecomeDownloadTask = block;
- }
- - (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block {
- self.dataTaskDidReceiveData = block;
- }
- - (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block {
- self.dataTaskWillCacheResponse = block;
- }
- #pragma mark -
- - (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block {
- self.downloadTaskDidFinishDownloading = block;
- }
- - (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block {
- self.downloadTaskDidWriteData = block;
- }
- - (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block {
- self.downloadTaskDidResume = block;
- }
- #pragma mark - NSObject
- - (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue];
- }
- - (BOOL)respondsToSelector:(SEL)selector {
- if (selector == @selector(URLSession:didReceiveChallenge:completionHandler:)) {
- return self.sessionDidReceiveAuthenticationChallenge != nil;
- } else if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
- return self.taskWillPerformHTTPRedirection != nil;
- } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
- return self.dataTaskDidReceiveResponse != nil;
- } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
- return self.dataTaskWillCacheResponse != nil;
- }
- #if !TARGET_OS_OSX
- else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
- return self.didFinishEventsForBackgroundURLSession != nil;
- }
- #endif
- return [[self class] instancesRespondToSelector:selector];
- }
- #pragma mark - NSURLSessionDelegate
- - (void)URLSession:(NSURLSession *)session
- didBecomeInvalidWithError:(NSError *)error
- {
- if (self.sessionDidBecomeInvalid) {
- self.sessionDidBecomeInvalid(session, error);
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
- }
- - (void)URLSession:(NSURLSession *)session
- didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
- completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
- {
- NSAssert(self.sessionDidReceiveAuthenticationChallenge != nil, @"`respondsToSelector:` implementation forces `URLSession:didReceiveChallenge:completionHandler:` to be called only if `self.sessionDidReceiveAuthenticationChallenge` is not nil");
- NSURLCredential *credential = nil;
- NSURLSessionAuthChallengeDisposition disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
- if (completionHandler) {
- completionHandler(disposition, credential);
- }
- }
- #pragma mark - NSURLSessionTaskDelegate
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- willPerformHTTPRedirection:(NSHTTPURLResponse *)response
- newRequest:(NSURLRequest *)request
- completionHandler:(void (^)(NSURLRequest *))completionHandler
- {
- NSURLRequest *redirectRequest = request;
- if (self.taskWillPerformHTTPRedirection) {
- redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
- }
- if (completionHandler) {
- completionHandler(redirectRequest);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
- completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
- {
- BOOL evaluateServerTrust = NO;
- NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
- NSURLCredential *credential = nil;
- if (self.authenticationChallengeHandler) {
- id result = self.authenticationChallengeHandler(session, task, challenge, completionHandler);
- if (result == nil) {
- return;
- } else if ([result isKindOfClass:NSError.class]) {
- objc_setAssociatedObject(task, AuthenticationChallengeErrorKey, result, OBJC_ASSOCIATION_RETAIN);
- disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
- } else if ([result isKindOfClass:NSURLCredential.class]) {
- credential = result;
- disposition = NSURLSessionAuthChallengeUseCredential;
- } else if ([result isKindOfClass:NSNumber.class]) {
- disposition = [result integerValue];
- NSAssert(disposition == NSURLSessionAuthChallengePerformDefaultHandling || disposition == NSURLSessionAuthChallengeCancelAuthenticationChallenge || disposition == NSURLSessionAuthChallengeRejectProtectionSpace, @"");
- evaluateServerTrust = disposition == NSURLSessionAuthChallengePerformDefaultHandling && [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
- } else {
- @throw [NSException exceptionWithName:@"Invalid Return Value" reason:@"The return value from the authentication challenge handler must be nil, an NSError, an NSURLCredential or an NSNumber." userInfo:nil];
- }
- } else {
- evaluateServerTrust = [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
- }
- if (evaluateServerTrust) {
- if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
- disposition = NSURLSessionAuthChallengeUseCredential;
- credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
- } else {
- objc_setAssociatedObject(task, AuthenticationChallengeErrorKey,
- [self serverTrustErrorForServerTrust:challenge.protectionSpace.serverTrust url:task.currentRequest.URL],
- OBJC_ASSOCIATION_RETAIN);
- disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
- }
- }
- if (completionHandler) {
- completionHandler(disposition, credential);
- }
- }
- - (nonnull NSError *)serverTrustErrorForServerTrust:(nullable SecTrustRef)serverTrust url:(nullable NSURL *)url
- {
- NSBundle *CFNetworkBundle = [NSBundle bundleWithIdentifier:@"com.apple.CFNetwork"];
- NSString *defaultValue = @"The certificate for this server is invalid. You might be connecting to a server that is pretending to be “%@” which could put your confidential information at risk.";
- NSString *descriptionFormat = NSLocalizedStringWithDefaultValue(@"Err-1202.w", nil, CFNetworkBundle, defaultValue, @"") ?: defaultValue;
- NSString *localizedDescription = [descriptionFormat componentsSeparatedByString:@"%@"].count <= 2 ? [NSString localizedStringWithFormat:descriptionFormat, url.host] : descriptionFormat;
- NSMutableDictionary *userInfo = [@{
- NSLocalizedDescriptionKey: localizedDescription
- } mutableCopy];
- if (serverTrust) {
- userInfo[NSURLErrorFailingURLPeerTrustErrorKey] = (__bridge id)serverTrust;
- }
- if (url) {
- userInfo[NSURLErrorFailingURLErrorKey] = url;
- if (url.absoluteString) {
- userInfo[NSURLErrorFailingURLStringErrorKey] = url.absoluteString;
- }
- }
- return [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorServerCertificateUntrusted userInfo:userInfo];
- }
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
- {
- NSInputStream *inputStream = nil;
- if (self.taskNeedNewBodyStream) {
- inputStream = self.taskNeedNewBodyStream(session, task);
- } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
- inputStream = [task.originalRequest.HTTPBodyStream copy];
- }
- if (completionHandler) {
- completionHandler(inputStream);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- didSendBodyData:(int64_t)bytesSent
- totalBytesSent:(int64_t)totalBytesSent
- totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
- {
- int64_t totalUnitCount = totalBytesExpectedToSend;
- if (totalUnitCount == NSURLSessionTransferSizeUnknown) {
- NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
- if (contentLength) {
- 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);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- didCompleteWithError:(NSError *)error
- {
- AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
- // delegate may be nil when completing a task in the background
- if (delegate) {
- [delegate URLSession:session task:task didCompleteWithError:error];
- [self removeDelegateForTask:task];
- }
- if (self.taskDidComplete) {
- self.taskDidComplete(session, task, error);
- }
- }
- #if AF_CAN_INCLUDE_SESSION_TASK_METRICS
- - (void)URLSession:(NSURLSession *)session
- task:(NSURLSessionTask *)task
- didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10))
- {
- AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
- // Metrics may fire after URLSession:task:didCompleteWithError: is called, delegate may be nil
- if (delegate) {
- [delegate URLSession:session task:task didFinishCollectingMetrics:metrics];
- }
- if (self.taskDidFinishCollectingMetrics) {
- self.taskDidFinishCollectingMetrics(session, task, metrics);
- }
- }
- #endif
- #pragma mark - NSURLSessionDataDelegate
- - (void)URLSession:(NSURLSession *)session
- dataTask:(NSURLSessionDataTask *)dataTask
- didReceiveResponse:(NSURLResponse *)response
- completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
- {
- NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
- if (self.dataTaskDidReceiveResponse) {
- disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
- }
- if (completionHandler) {
- completionHandler(disposition);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- dataTask:(NSURLSessionDataTask *)dataTask
- didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
- {
- AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
- if (delegate) {
- [self removeDelegateForTask:dataTask];
- [self setDelegate:delegate forTask:downloadTask];
- }
- if (self.dataTaskDidBecomeDownloadTask) {
- self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- dataTask:(NSURLSessionDataTask *)dataTask
- didReceiveData:(NSData *)data
- {
- AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
- [delegate URLSession:session dataTask:dataTask didReceiveData:data];
- if (self.dataTaskDidReceiveData) {
- self.dataTaskDidReceiveData(session, dataTask, data);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- dataTask:(NSURLSessionDataTask *)dataTask
- willCacheResponse:(NSCachedURLResponse *)proposedResponse
- completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
- {
- NSCachedURLResponse *cachedResponse = proposedResponse;
- if (self.dataTaskWillCacheResponse) {
- cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse);
- }
- if (completionHandler) {
- completionHandler(cachedResponse);
- }
- }
- #if !TARGET_OS_OSX
- - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
- if (self.didFinishEventsForBackgroundURLSession) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.didFinishEventsForBackgroundURLSession(session);
- });
- }
- }
- #endif
- #pragma mark - NSURLSessionDownloadDelegate
- - (void)URLSession:(NSURLSession *)session
- downloadTask:(NSURLSessionDownloadTask *)downloadTask
- didFinishDownloadingToURL:(NSURL *)location
- {
- AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
- if (self.downloadTaskDidFinishDownloading) {
- NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
- if (fileURL) {
- delegate.downloadFileURL = fileURL;
- NSError *error = nil;
-
- if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) {
- [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
- } else {
- [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidMoveFileSuccessfullyNotification object:downloadTask userInfo:nil];
- }
- return;
- }
- }
- if (delegate) {
- [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
- }
- }
- - (void)URLSession:(NSURLSession *)session
- downloadTask:(NSURLSessionDownloadTask *)downloadTask
- didWriteData:(int64_t)bytesWritten
- 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);
- }
- }
- - (void)URLSession:(NSURLSession *)session
- downloadTask:(NSURLSessionDownloadTask *)downloadTask
- 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);
- }
- }
- #pragma mark - NSSecureCoding
- + (BOOL)supportsSecureCoding {
- return YES;
- }
- - (instancetype)initWithCoder:(NSCoder *)decoder {
- NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
- self = [self initWithSessionConfiguration:configuration];
- if (!self) {
- return nil;
- }
- return self;
- }
- - (void)encodeWithCoder:(NSCoder *)coder {
- [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
- }
- #pragma mark - NSCopying
- - (instancetype)copyWithZone:(NSZone *)zone {
- return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
- }
- @end
|