AFURLSessionManager.m 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. // AFURLSessionManager.m
  2. // Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. #import "AFURLSessionManager.h"
  22. #import <objc/runtime.h>
  23. #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
  24. static dispatch_queue_t url_session_manager_creation_queue() {
  25. static dispatch_queue_t af_url_session_manager_creation_queue;
  26. static dispatch_once_t onceToken;
  27. dispatch_once(&onceToken, ^{
  28. af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL);
  29. });
  30. return af_url_session_manager_creation_queue;
  31. }
  32. static dispatch_queue_t url_session_manager_processing_queue() {
  33. static dispatch_queue_t af_url_session_manager_processing_queue;
  34. static dispatch_once_t onceToken;
  35. dispatch_once(&onceToken, ^{
  36. af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT);
  37. });
  38. return af_url_session_manager_processing_queue;
  39. }
  40. static dispatch_group_t url_session_manager_completion_group() {
  41. static dispatch_group_t af_url_session_manager_completion_group;
  42. static dispatch_once_t onceToken;
  43. dispatch_once(&onceToken, ^{
  44. af_url_session_manager_completion_group = dispatch_group_create();
  45. });
  46. return af_url_session_manager_completion_group;
  47. }
  48. NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume";
  49. NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete";
  50. NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend";
  51. NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";
  52. NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";
  53. NSString * const AFNetworkingTaskDidStartNotification = @"com.alamofire.networking.task.resume"; // Deprecated
  54. NSString * const AFNetworkingTaskDidFinishNotification = @"com.alamofire.networking.task.complete"; // Deprecated
  55. NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";
  56. NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";
  57. NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";
  58. NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";
  59. NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";
  60. NSString * const AFNetworkingTaskDidFinishSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse"; // Deprecated
  61. NSString * const AFNetworkingTaskDidFinishResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer"; // Deprecated
  62. NSString * const AFNetworkingTaskDidFinishResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata"; // Deprecated
  63. NSString * const AFNetworkingTaskDidFinishErrorKey = @"com.alamofire.networking.task.complete.error"; // Deprecated
  64. NSString * const AFNetworkingTaskDidFinishAssetPathKey = @"com.alamofire.networking.task.complete.assetpath"; // Deprecated
  65. static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";
  66. static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
  67. static void * AFTaskStateChangedContext = &AFTaskStateChangedContext;
  68. typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
  69. typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
  70. typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request);
  71. typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
  72. typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session);
  73. typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task);
  74. typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
  75. typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error);
  76. typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response);
  77. typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask);
  78. typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data);
  79. typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse);
  80. typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
  81. typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
  82. typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);
  83. typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
  84. #pragma mark -
  85. @interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
  86. @property (nonatomic, weak) AFURLSessionManager *manager;
  87. @property (nonatomic, strong) NSMutableData *mutableData;
  88. @property (nonatomic, strong) NSProgress *progress;
  89. @property (nonatomic, copy) NSURL *downloadFileURL;
  90. @property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
  91. @property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
  92. @end
  93. @implementation AFURLSessionManagerTaskDelegate
  94. - (instancetype)init {
  95. self = [super init];
  96. if (!self) {
  97. return nil;
  98. }
  99. self.mutableData = [NSMutableData data];
  100. self.progress = [NSProgress progressWithTotalUnitCount:0];
  101. return self;
  102. }
  103. #pragma mark - NSURLSessionTaskDelegate
  104. - (void)URLSession:(__unused NSURLSession *)session
  105. task:(__unused NSURLSessionTask *)task
  106. didSendBodyData:(__unused int64_t)bytesSent
  107. totalBytesSent:(int64_t)totalBytesSent
  108. totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
  109. {
  110. self.progress.totalUnitCount = totalBytesExpectedToSend;
  111. self.progress.completedUnitCount = totalBytesSent;
  112. }
  113. - (void)URLSession:(__unused NSURLSession *)session
  114. task:(NSURLSessionTask *)task
  115. didCompleteWithError:(NSError *)error
  116. {
  117. #pragma clang diagnostic push
  118. #pragma clang diagnostic ignored "-Wgnu"
  119. __strong AFURLSessionManager *manager = self.manager;
  120. __block id responseObject = nil;
  121. __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  122. userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
  123. //Performance Improvement from #2672
  124. NSData *data = nil;
  125. if (self.mutableData) {
  126. data = [self.mutableData copy];
  127. //We no longer need the reference, so nil it out to gain back some memory.
  128. self.mutableData = nil;
  129. }
  130. if (self.downloadFileURL) {
  131. userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
  132. } else if (data) {
  133. userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
  134. }
  135. if (error) {
  136. userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
  137. dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
  138. if (self.completionHandler) {
  139. self.completionHandler(task.response, responseObject, error);
  140. }
  141. dispatch_async(dispatch_get_main_queue(), ^{
  142. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
  143. });
  144. });
  145. } else {
  146. dispatch_async(url_session_manager_processing_queue(), ^{
  147. NSError *serializationError = nil;
  148. responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
  149. if (self.downloadFileURL) {
  150. responseObject = self.downloadFileURL;
  151. }
  152. if (responseObject) {
  153. userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
  154. }
  155. if (serializationError) {
  156. userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
  157. }
  158. dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
  159. if (self.completionHandler) {
  160. self.completionHandler(task.response, responseObject, serializationError);
  161. }
  162. dispatch_async(dispatch_get_main_queue(), ^{
  163. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
  164. });
  165. });
  166. });
  167. }
  168. #pragma clang diagnostic pop
  169. }
  170. #pragma mark - NSURLSessionDataTaskDelegate
  171. - (void)URLSession:(__unused NSURLSession *)session
  172. dataTask:(__unused NSURLSessionDataTask *)dataTask
  173. didReceiveData:(NSData *)data
  174. {
  175. [self.mutableData appendData:data];
  176. }
  177. #pragma mark - NSURLSessionDownloadTaskDelegate
  178. - (void)URLSession:(NSURLSession *)session
  179. downloadTask:(NSURLSessionDownloadTask *)downloadTask
  180. didFinishDownloadingToURL:(NSURL *)location
  181. {
  182. NSError *fileManagerError = nil;
  183. self.downloadFileURL = nil;
  184. if (self.downloadTaskDidFinishDownloading) {
  185. self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
  186. if (self.downloadFileURL) {
  187. [[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError];
  188. if (fileManagerError) {
  189. [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
  190. }
  191. }
  192. }
  193. }
  194. - (void)URLSession:(__unused NSURLSession *)session
  195. downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask
  196. didWriteData:(__unused int64_t)bytesWritten
  197. totalBytesWritten:(int64_t)totalBytesWritten
  198. totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
  199. {
  200. self.progress.totalUnitCount = totalBytesExpectedToWrite;
  201. self.progress.completedUnitCount = totalBytesWritten;
  202. }
  203. - (void)URLSession:(__unused NSURLSession *)session
  204. downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask
  205. didResumeAtOffset:(int64_t)fileOffset
  206. expectedTotalBytes:(int64_t)expectedTotalBytes {
  207. self.progress.totalUnitCount = expectedTotalBytes;
  208. self.progress.completedUnitCount = fileOffset;
  209. }
  210. @end
  211. #pragma mark -
  212. /**
  213. * A workaround for issues related to key-value observing the `state` of an `NSURLSessionTask`.
  214. *
  215. * See:
  216. * - https://github.com/AFNetworking/AFNetworking/issues/1477
  217. * - https://github.com/AFNetworking/AFNetworking/issues/2638
  218. * - https://github.com/AFNetworking/AFNetworking/pull/2702
  219. */
  220. static inline void af_swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector) {
  221. Method originalMethod = class_getInstanceMethod(class, originalSelector);
  222. Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
  223. method_exchangeImplementations(originalMethod, swizzledMethod);
  224. }
  225. static inline BOOL af_addMethod(Class class, SEL selector, Method method) {
  226. return class_addMethod(class, selector, method_getImplementation(method), method_getTypeEncoding(method));
  227. }
  228. static NSString * const AFNSURLSessionTaskDidResumeNotification = @"com.alamofire.networking.nsurlsessiontask.resume";
  229. static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofire.networking.nsurlsessiontask.suspend";
  230. @interface _AFURLSessionTaskSwizzling : NSObject
  231. @end
  232. @implementation _AFURLSessionTaskSwizzling
  233. + (void)load {
  234. /**
  235. WARNING: Trouble Ahead
  236. https://github.com/AFNetworking/AFNetworking/pull/2702
  237. */
  238. if (NSClassFromString(@"NSURLSessionTask")) {
  239. /**
  240. iOS 7 and iOS 8 differ in NSURLSessionTask implementation, which makes the next bit of code a bit tricky.
  241. Many Unit Tests have been built to validate as much of this behavior has possible.
  242. Here is what we know:
  243. - 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.
  244. - Simply referencing `[NSURLSessionTask class]` will not work. You need to ask an `NSURLSession` to actually create an object, and grab the class from there.
  245. - On iOS 7, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `__NSCFURLSessionTask`.
  246. - On iOS 8, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `NSURLSessionTask`.
  247. - 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.
  248. - 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.
  249. - 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.
  250. Some Assumptions:
  251. - 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.
  252. - No background task classes override `resume` or `suspend`
  253. The current solution:
  254. 1) Grab an instance of `__NSCFLocalDataTask` by asking an instance of `NSURLSession` for a data task.
  255. 2) Grab a pointer to the original implementation of `af_resume`
  256. 3) Check to see if the current class has an implementation of resume. If so, continue to step 4.
  257. 4) Grab the super class of the current class.
  258. 5) Grab a pointer for the current class to the current implementation of `resume`.
  259. 6) Grab a pointer for the super class to the current implementation of `resume`.
  260. 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
  261. 8) Set the current class to the super class, and repeat steps 3-8
  262. */
  263. #pragma GCC diagnostic push
  264. #pragma GCC diagnostic ignored "-Wnonnull"
  265. NSURLSessionDataTask *localDataTask = [[NSURLSession sessionWithConfiguration:nil] dataTaskWithURL:nil];
  266. #pragma clang diagnostic pop
  267. IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
  268. Class currentClass = [localDataTask class];
  269. while (class_getInstanceMethod(currentClass, @selector(resume))) {
  270. Class superClass = [currentClass superclass];
  271. IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
  272. IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
  273. if (classResumeIMP != superclassResumeIMP &&
  274. originalAFResumeIMP != classResumeIMP) {
  275. [self swizzleResumeAndSuspendMethodForClass:currentClass];
  276. }
  277. currentClass = [currentClass superclass];
  278. }
  279. [localDataTask cancel];
  280. }
  281. }
  282. + (void)swizzleResumeAndSuspendMethodForClass:(Class)class {
  283. Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
  284. Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
  285. if (af_addMethod(class, @selector(af_resume), afResumeMethod)) {
  286. af_swizzleSelector(class, @selector(resume), @selector(af_resume));
  287. }
  288. if (af_addMethod(class, @selector(af_suspend), afSuspendMethod)) {
  289. af_swizzleSelector(class, @selector(suspend), @selector(af_suspend));
  290. }
  291. }
  292. - (NSURLSessionTaskState)state {
  293. NSAssert(NO, @"State method should never be called in the actual dummy class");
  294. return NSURLSessionTaskStateCanceling;
  295. }
  296. - (void)af_resume {
  297. NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
  298. NSURLSessionTaskState state = [self state];
  299. [self af_resume];
  300. if (state != NSURLSessionTaskStateRunning) {
  301. [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
  302. }
  303. }
  304. - (void)af_suspend {
  305. NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
  306. NSURLSessionTaskState state = [self state];
  307. [self af_suspend];
  308. if (state != NSURLSessionTaskStateSuspended) {
  309. [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
  310. }
  311. }
  312. @end
  313. #pragma mark -
  314. @interface AFURLSessionManager ()
  315. @property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
  316. @property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
  317. @property (readwrite, nonatomic, strong) NSURLSession *session;
  318. @property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
  319. @property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
  320. @property (readwrite, nonatomic, strong) NSLock *lock;
  321. @property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
  322. @property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
  323. @property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
  324. @property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
  325. @property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
  326. @property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
  327. @property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
  328. @property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
  329. @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
  330. @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
  331. @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
  332. @property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
  333. @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
  334. @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
  335. @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;
  336. @end
  337. @implementation AFURLSessionManager
  338. - (instancetype)init {
  339. return [self initWithSessionConfiguration:nil];
  340. }
  341. - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
  342. self = [super init];
  343. if (!self) {
  344. return nil;
  345. }
  346. if (!configuration) {
  347. configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
  348. }
  349. self.sessionConfiguration = configuration;
  350. self.operationQueue = [[NSOperationQueue alloc] init];
  351. self.operationQueue.maxConcurrentOperationCount = 1;
  352. self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
  353. self.responseSerializer = [AFJSONResponseSerializer serializer];
  354. self.securityPolicy = [AFSecurityPolicy defaultPolicy];
  355. #if !TARGET_OS_WATCH
  356. self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
  357. #endif
  358. self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
  359. self.lock = [[NSLock alloc] init];
  360. self.lock.name = AFURLSessionManagerLockName;
  361. [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
  362. for (NSURLSessionDataTask *task in dataTasks) {
  363. [self addDelegateForDataTask:task completionHandler:nil];
  364. }
  365. for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
  366. [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
  367. }
  368. for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
  369. [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
  370. }
  371. }];
  372. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:nil];
  373. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:nil];
  374. return self;
  375. }
  376. - (void)dealloc {
  377. [[NSNotificationCenter defaultCenter] removeObserver:self];
  378. }
  379. #pragma mark -
  380. - (NSString *)taskDescriptionForSessionTasks {
  381. return [NSString stringWithFormat:@"%p", self];
  382. }
  383. - (void)taskDidResume:(NSNotification *)notification {
  384. NSURLSessionTask *task = notification.object;
  385. if ([task respondsToSelector:@selector(taskDescription)]) {
  386. if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
  387. dispatch_async(dispatch_get_main_queue(), ^{
  388. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
  389. });
  390. }
  391. }
  392. }
  393. - (void)taskDidSuspend:(NSNotification *)notification {
  394. NSURLSessionTask *task = notification.object;
  395. if ([task respondsToSelector:@selector(taskDescription)]) {
  396. if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
  397. dispatch_async(dispatch_get_main_queue(), ^{
  398. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
  399. });
  400. }
  401. }
  402. }
  403. #pragma mark -
  404. - (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
  405. NSParameterAssert(task);
  406. AFURLSessionManagerTaskDelegate *delegate = nil;
  407. [self.lock lock];
  408. delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
  409. [self.lock unlock];
  410. return delegate;
  411. }
  412. - (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
  413. forTask:(NSURLSessionTask *)task
  414. {
  415. NSParameterAssert(task);
  416. NSParameterAssert(delegate);
  417. [self.lock lock];
  418. self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
  419. [self.lock unlock];
  420. }
  421. - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
  422. completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
  423. {
  424. AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
  425. delegate.manager = self;
  426. delegate.completionHandler = completionHandler;
  427. dataTask.taskDescription = self.taskDescriptionForSessionTasks;
  428. [self setDelegate:delegate forTask:dataTask];
  429. }
  430. - (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
  431. progress:(NSProgress * __autoreleasing *)progress
  432. completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
  433. {
  434. AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
  435. delegate.manager = self;
  436. delegate.completionHandler = completionHandler;
  437. int64_t totalUnitCount = uploadTask.countOfBytesExpectedToSend;
  438. if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
  439. NSString *contentLength = [uploadTask.originalRequest valueForHTTPHeaderField:@"Content-Length"];
  440. if(contentLength) {
  441. totalUnitCount = (int64_t)[contentLength longLongValue];
  442. }
  443. }
  444. if (delegate.progress) {
  445. delegate.progress.totalUnitCount = totalUnitCount;
  446. } else {
  447. delegate.progress = [NSProgress progressWithTotalUnitCount:totalUnitCount];
  448. }
  449. delegate.progress.pausingHandler = ^{
  450. [uploadTask suspend];
  451. };
  452. delegate.progress.cancellationHandler = ^{
  453. [uploadTask cancel];
  454. };
  455. if (progress) {
  456. *progress = delegate.progress;
  457. }
  458. uploadTask.taskDescription = self.taskDescriptionForSessionTasks;
  459. [self setDelegate:delegate forTask:uploadTask];
  460. }
  461. - (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
  462. progress:(NSProgress * __autoreleasing *)progress
  463. destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
  464. completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
  465. {
  466. AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
  467. delegate.manager = self;
  468. delegate.completionHandler = completionHandler;
  469. if (destination) {
  470. delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
  471. return destination(location, task.response);
  472. };
  473. }
  474. if (progress) {
  475. *progress = delegate.progress;
  476. }
  477. downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
  478. [self setDelegate:delegate forTask:downloadTask];
  479. }
  480. - (void)removeDelegateForTask:(NSURLSessionTask *)task {
  481. NSParameterAssert(task);
  482. [self.lock lock];
  483. [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
  484. [self.lock unlock];
  485. }
  486. - (void)removeAllDelegates {
  487. [self.lock lock];
  488. [self.mutableTaskDelegatesKeyedByTaskIdentifier removeAllObjects];
  489. [self.lock unlock];
  490. }
  491. #pragma mark -
  492. - (NSArray *)tasksForKeyPath:(NSString *)keyPath {
  493. __block NSArray *tasks = nil;
  494. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  495. [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
  496. if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
  497. tasks = dataTasks;
  498. } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
  499. tasks = uploadTasks;
  500. } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
  501. tasks = downloadTasks;
  502. } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
  503. tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
  504. }
  505. dispatch_semaphore_signal(semaphore);
  506. }];
  507. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  508. return tasks;
  509. }
  510. - (NSArray *)tasks {
  511. return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
  512. }
  513. - (NSArray *)dataTasks {
  514. return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
  515. }
  516. - (NSArray *)uploadTasks {
  517. return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
  518. }
  519. - (NSArray *)downloadTasks {
  520. return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
  521. }
  522. #pragma mark -
  523. - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {
  524. dispatch_async(dispatch_get_main_queue(), ^{
  525. if (cancelPendingTasks) {
  526. [self.session invalidateAndCancel];
  527. } else {
  528. [self.session finishTasksAndInvalidate];
  529. }
  530. });
  531. }
  532. #pragma mark -
  533. - (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerializer {
  534. NSParameterAssert(responseSerializer);
  535. _responseSerializer = responseSerializer;
  536. }
  537. #pragma mark -
  538. - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
  539. completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
  540. {
  541. __block NSURLSessionDataTask *dataTask = nil;
  542. dispatch_sync(url_session_manager_creation_queue(), ^{
  543. dataTask = [self.session dataTaskWithRequest:request];
  544. });
  545. [self addDelegateForDataTask:dataTask completionHandler:completionHandler];
  546. return dataTask;
  547. }
  548. #pragma mark -
  549. - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
  550. fromFile:(NSURL *)fileURL
  551. progress:(NSProgress * __autoreleasing *)progress
  552. completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
  553. {
  554. __block NSURLSessionUploadTask *uploadTask = nil;
  555. dispatch_sync(url_session_manager_creation_queue(), ^{
  556. uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
  557. });
  558. if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
  559. for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
  560. uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
  561. }
  562. }
  563. [self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
  564. return uploadTask;
  565. }
  566. - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
  567. fromData:(NSData *)bodyData
  568. progress:(NSProgress * __autoreleasing *)progress
  569. completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
  570. {
  571. __block NSURLSessionUploadTask *uploadTask = nil;
  572. dispatch_sync(url_session_manager_creation_queue(), ^{
  573. uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
  574. });
  575. [self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
  576. return uploadTask;
  577. }
  578. - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
  579. progress:(NSProgress * __autoreleasing *)progress
  580. completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
  581. {
  582. __block NSURLSessionUploadTask *uploadTask = nil;
  583. dispatch_sync(url_session_manager_creation_queue(), ^{
  584. uploadTask = [self.session uploadTaskWithStreamedRequest:request];
  585. });
  586. [self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
  587. return uploadTask;
  588. }
  589. #pragma mark -
  590. - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
  591. progress:(NSProgress * __autoreleasing *)progress
  592. destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
  593. completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
  594. {
  595. __block NSURLSessionDownloadTask *downloadTask = nil;
  596. dispatch_sync(url_session_manager_creation_queue(), ^{
  597. downloadTask = [self.session downloadTaskWithRequest:request];
  598. });
  599. [self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler];
  600. return downloadTask;
  601. }
  602. - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
  603. progress:(NSProgress * __autoreleasing *)progress
  604. destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
  605. completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
  606. {
  607. __block NSURLSessionDownloadTask *downloadTask = nil;
  608. dispatch_sync(url_session_manager_creation_queue(), ^{
  609. downloadTask = [self.session downloadTaskWithResumeData:resumeData];
  610. });
  611. [self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler];
  612. return downloadTask;
  613. }
  614. #pragma mark -
  615. - (NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask {
  616. return [[self delegateForTask:uploadTask] progress];
  617. }
  618. - (NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask {
  619. return [[self delegateForTask:downloadTask] progress];
  620. }
  621. #pragma mark -
  622. - (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block {
  623. self.sessionDidBecomeInvalid = block;
  624. }
  625. - (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block {
  626. self.sessionDidReceiveAuthenticationChallenge = block;
  627. }
  628. - (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block {
  629. self.didFinishEventsForBackgroundURLSession = block;
  630. }
  631. #pragma mark -
  632. - (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block {
  633. self.taskNeedNewBodyStream = block;
  634. }
  635. - (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block {
  636. self.taskWillPerformHTTPRedirection = block;
  637. }
  638. - (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block {
  639. self.taskDidReceiveAuthenticationChallenge = block;
  640. }
  641. - (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block {
  642. self.taskDidSendBodyData = block;
  643. }
  644. - (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block {
  645. self.taskDidComplete = block;
  646. }
  647. #pragma mark -
  648. - (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block {
  649. self.dataTaskDidReceiveResponse = block;
  650. }
  651. - (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block {
  652. self.dataTaskDidBecomeDownloadTask = block;
  653. }
  654. - (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block {
  655. self.dataTaskDidReceiveData = block;
  656. }
  657. - (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block {
  658. self.dataTaskWillCacheResponse = block;
  659. }
  660. #pragma mark -
  661. - (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block {
  662. self.downloadTaskDidFinishDownloading = block;
  663. }
  664. - (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block {
  665. self.downloadTaskDidWriteData = block;
  666. }
  667. - (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block {
  668. self.downloadTaskDidResume = block;
  669. }
  670. #pragma mark - NSObject
  671. - (NSString *)description {
  672. return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue];
  673. }
  674. - (BOOL)respondsToSelector:(SEL)selector {
  675. if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
  676. return self.taskWillPerformHTTPRedirection != nil;
  677. } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
  678. return self.dataTaskDidReceiveResponse != nil;
  679. } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
  680. return self.dataTaskWillCacheResponse != nil;
  681. } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
  682. return self.didFinishEventsForBackgroundURLSession != nil;
  683. }
  684. return [[self class] instancesRespondToSelector:selector];
  685. }
  686. #pragma mark - NSURLSessionDelegate
  687. - (void)URLSession:(NSURLSession *)session
  688. didBecomeInvalidWithError:(NSError *)error
  689. {
  690. if (self.sessionDidBecomeInvalid) {
  691. self.sessionDidBecomeInvalid(session, error);
  692. }
  693. [self removeAllDelegates];
  694. [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
  695. }
  696. - (void)URLSession:(NSURLSession *)session
  697. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  698. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
  699. {
  700. NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  701. __block NSURLCredential *credential = nil;
  702. if (self.sessionDidReceiveAuthenticationChallenge) {
  703. disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
  704. } else {
  705. if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  706. if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
  707. credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
  708. if (credential) {
  709. disposition = NSURLSessionAuthChallengeUseCredential;
  710. } else {
  711. disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  712. }
  713. } else {
  714. disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
  715. }
  716. } else {
  717. disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  718. }
  719. }
  720. if (completionHandler) {
  721. completionHandler(disposition, credential);
  722. }
  723. }
  724. #pragma mark - NSURLSessionTaskDelegate
  725. - (void)URLSession:(NSURLSession *)session
  726. task:(NSURLSessionTask *)task
  727. willPerformHTTPRedirection:(NSHTTPURLResponse *)response
  728. newRequest:(NSURLRequest *)request
  729. completionHandler:(void (^)(NSURLRequest *))completionHandler
  730. {
  731. NSURLRequest *redirectRequest = request;
  732. if (self.taskWillPerformHTTPRedirection) {
  733. redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
  734. }
  735. if (completionHandler) {
  736. completionHandler(redirectRequest);
  737. }
  738. }
  739. - (void)URLSession:(NSURLSession *)session
  740. task:(NSURLSessionTask *)task
  741. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  742. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
  743. {
  744. NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  745. __block NSURLCredential *credential = nil;
  746. if (self.taskDidReceiveAuthenticationChallenge) {
  747. disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
  748. } else {
  749. if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  750. if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
  751. disposition = NSURLSessionAuthChallengeUseCredential;
  752. credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
  753. } else {
  754. disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
  755. }
  756. } else {
  757. disposition = NSURLSessionAuthChallengePerformDefaultHandling;
  758. }
  759. }
  760. if (completionHandler) {
  761. completionHandler(disposition, credential);
  762. }
  763. }
  764. - (void)URLSession:(NSURLSession *)session
  765. task:(NSURLSessionTask *)task
  766. needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
  767. {
  768. NSInputStream *inputStream = nil;
  769. if (self.taskNeedNewBodyStream) {
  770. inputStream = self.taskNeedNewBodyStream(session, task);
  771. } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
  772. inputStream = [task.originalRequest.HTTPBodyStream copy];
  773. }
  774. if (completionHandler) {
  775. completionHandler(inputStream);
  776. }
  777. }
  778. - (void)URLSession:(NSURLSession *)session
  779. task:(NSURLSessionTask *)task
  780. didSendBodyData:(int64_t)bytesSent
  781. totalBytesSent:(int64_t)totalBytesSent
  782. totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
  783. {
  784. int64_t totalUnitCount = totalBytesExpectedToSend;
  785. if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
  786. NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
  787. if(contentLength) {
  788. totalUnitCount = (int64_t) [contentLength longLongValue];
  789. }
  790. }
  791. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
  792. [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalUnitCount];
  793. if (self.taskDidSendBodyData) {
  794. self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
  795. }
  796. }
  797. - (void)URLSession:(NSURLSession *)session
  798. task:(NSURLSessionTask *)task
  799. didCompleteWithError:(NSError *)error
  800. {
  801. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
  802. // delegate may be nil when completing a task in the background
  803. if (delegate) {
  804. [delegate URLSession:session task:task didCompleteWithError:error];
  805. [self removeDelegateForTask:task];
  806. }
  807. if (self.taskDidComplete) {
  808. self.taskDidComplete(session, task, error);
  809. }
  810. }
  811. #pragma mark - NSURLSessionDataDelegate
  812. - (void)URLSession:(NSURLSession *)session
  813. dataTask:(NSURLSessionDataTask *)dataTask
  814. didReceiveResponse:(NSURLResponse *)response
  815. completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
  816. {
  817. NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
  818. if (self.dataTaskDidReceiveResponse) {
  819. disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
  820. }
  821. if (completionHandler) {
  822. completionHandler(disposition);
  823. }
  824. }
  825. - (void)URLSession:(NSURLSession *)session
  826. dataTask:(NSURLSessionDataTask *)dataTask
  827. didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
  828. {
  829. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
  830. if (delegate) {
  831. [self removeDelegateForTask:dataTask];
  832. [self setDelegate:delegate forTask:downloadTask];
  833. }
  834. if (self.dataTaskDidBecomeDownloadTask) {
  835. self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
  836. }
  837. }
  838. - (void)URLSession:(NSURLSession *)session
  839. dataTask:(NSURLSessionDataTask *)dataTask
  840. didReceiveData:(NSData *)data
  841. {
  842. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
  843. [delegate URLSession:session dataTask:dataTask didReceiveData:data];
  844. if (self.dataTaskDidReceiveData) {
  845. self.dataTaskDidReceiveData(session, dataTask, data);
  846. }
  847. }
  848. - (void)URLSession:(NSURLSession *)session
  849. dataTask:(NSURLSessionDataTask *)dataTask
  850. willCacheResponse:(NSCachedURLResponse *)proposedResponse
  851. completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
  852. {
  853. NSCachedURLResponse *cachedResponse = proposedResponse;
  854. if (self.dataTaskWillCacheResponse) {
  855. cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse);
  856. }
  857. if (completionHandler) {
  858. completionHandler(cachedResponse);
  859. }
  860. }
  861. - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
  862. if (self.didFinishEventsForBackgroundURLSession) {
  863. dispatch_async(dispatch_get_main_queue(), ^{
  864. self.didFinishEventsForBackgroundURLSession(session);
  865. });
  866. }
  867. }
  868. #pragma mark - NSURLSessionDownloadDelegate
  869. - (void)URLSession:(NSURLSession *)session
  870. downloadTask:(NSURLSessionDownloadTask *)downloadTask
  871. didFinishDownloadingToURL:(NSURL *)location
  872. {
  873. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
  874. if (self.downloadTaskDidFinishDownloading) {
  875. NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
  876. if (fileURL) {
  877. delegate.downloadFileURL = fileURL;
  878. NSError *error = nil;
  879. [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error];
  880. if (error) {
  881. [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
  882. }
  883. return;
  884. }
  885. }
  886. if (delegate) {
  887. [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
  888. }
  889. }
  890. - (void)URLSession:(NSURLSession *)session
  891. downloadTask:(NSURLSessionDownloadTask *)downloadTask
  892. didWriteData:(int64_t)bytesWritten
  893. totalBytesWritten:(int64_t)totalBytesWritten
  894. totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
  895. {
  896. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
  897. [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
  898. if (self.downloadTaskDidWriteData) {
  899. self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
  900. }
  901. }
  902. - (void)URLSession:(NSURLSession *)session
  903. downloadTask:(NSURLSessionDownloadTask *)downloadTask
  904. didResumeAtOffset:(int64_t)fileOffset
  905. expectedTotalBytes:(int64_t)expectedTotalBytes
  906. {
  907. AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
  908. [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];
  909. if (self.downloadTaskDidResume) {
  910. self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);
  911. }
  912. }
  913. #pragma mark - NSSecureCoding
  914. + (BOOL)supportsSecureCoding {
  915. return YES;
  916. }
  917. - (id)initWithCoder:(NSCoder *)decoder {
  918. NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
  919. self = [self initWithSessionConfiguration:configuration];
  920. if (!self) {
  921. return nil;
  922. }
  923. return self;
  924. }
  925. - (void)encodeWithCoder:(NSCoder *)coder {
  926. [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
  927. }
  928. #pragma mark - NSCopying
  929. - (id)copyWithZone:(NSZone *)zone {
  930. return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
  931. }
  932. @end
  933. #endif