|
|
@@ -22,33 +22,6 @@
|
|
|
#import "AFURLSessionManager.h"
|
|
|
#import <objc/runtime.h>
|
|
|
|
|
|
-#ifndef NSFoundationVersionNumber_iOS_8_0
|
|
|
-#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11
|
|
|
-#else
|
|
|
-#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0
|
|
|
-#endif
|
|
|
-
|
|
|
-static dispatch_queue_t url_session_manager_creation_queue() {
|
|
|
- static dispatch_queue_t af_url_session_manager_creation_queue;
|
|
|
- static dispatch_once_t onceToken;
|
|
|
- dispatch_once(&onceToken, ^{
|
|
|
- af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL);
|
|
|
- });
|
|
|
-
|
|
|
- return af_url_session_manager_creation_queue;
|
|
|
-}
|
|
|
-
|
|
|
-static void url_session_manager_create_task_safely(dispatch_block_t block) {
|
|
|
- if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
|
|
|
- // Fix of bug
|
|
|
- // Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
|
|
|
- // Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
|
|
|
- dispatch_sync(url_session_manager_creation_queue(), block);
|
|
|
- } else {
|
|
|
- block();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static dispatch_queue_t url_session_manager_processing_queue() {
|
|
|
static dispatch_queue_t af_url_session_manager_processing_queue;
|
|
|
static dispatch_once_t onceToken;
|
|
|
@@ -73,6 +46,7 @@ NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.network
|
|
|
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";
|
|
|
@@ -80,21 +54,24 @@ NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamof
|
|
|
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";
|
|
|
|
|
|
-static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
|
|
|
-
|
|
|
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);
|
|
|
@@ -108,7 +85,6 @@ typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
|
|
|
|
|
|
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
|
|
|
|
|
|
-
|
|
|
#pragma mark -
|
|
|
|
|
|
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
|
|
|
@@ -118,6 +94,9 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
|
|
|
@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;
|
|
|
@@ -149,7 +128,7 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
|
|
|
[weakTask suspend];
|
|
|
};
|
|
|
#if AF_CAN_USE_AT_AVAILABLE
|
|
|
- if (@available(iOS 9, macOS 10.11, *))
|
|
|
+ if (@available(macOS 10.11, *))
|
|
|
#else
|
|
|
if ([progress respondsToSelector:@selector(setResumingHandler:)])
|
|
|
#endif
|
|
|
@@ -187,17 +166,20 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+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;
|
|
|
|
|
|
- __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
|
|
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
|
|
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
|
|
|
|
|
|
//Performance Improvement from #2672
|
|
|
@@ -208,6 +190,14 @@ didCompleteWithError:(NSError *)error
|
|
|
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) {
|
|
|
@@ -256,6 +246,14 @@ didCompleteWithError:(NSError *)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)) {
|
|
|
+ self.sessionTaskMetrics = metrics;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
#pragma mark - NSURLSessionDataDelegate
|
|
|
|
|
|
- (void)URLSession:(__unused NSURLSession *)session
|
|
|
@@ -309,6 +307,8 @@ didFinishDownloadingToURL:(NSURL *)location
|
|
|
|
|
|
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];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -380,7 +380,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
8) Set the current class to the super class, and repeat steps 3-8
|
|
|
*/
|
|
|
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
|
|
- NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
|
|
|
+ NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
|
|
|
#pragma GCC diagnostic push
|
|
|
#pragma GCC diagnostic ignored "-Wnonnull"
|
|
|
NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
|
|
|
@@ -456,10 +456,13 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
@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) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
|
|
|
+@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;
|
|
|
@@ -490,8 +493,6 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
self.operationQueue = [[NSOperationQueue alloc] init];
|
|
|
self.operationQueue.maxConcurrentOperationCount = 1;
|
|
|
|
|
|
- self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
|
|
|
-
|
|
|
self.responseSerializer = [AFJSONResponseSerializer serializer];
|
|
|
|
|
|
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
|
|
|
@@ -528,6 +529,19 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
|
|
|
#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];
|
|
|
}
|
|
|
@@ -683,12 +697,15 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
-- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {
|
|
|
+- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks resetSession:(BOOL)resetSession {
|
|
|
if (cancelPendingTasks) {
|
|
|
[self.session invalidateAndCancel];
|
|
|
} else {
|
|
|
[self.session finishTasksAndInvalidate];
|
|
|
}
|
|
|
+ if (resetSession) {
|
|
|
+ self.session = nil;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
@@ -713,20 +730,11 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
#pragma mark -
|
|
|
|
|
|
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
|
|
- completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
|
|
-{
|
|
|
- return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
|
|
|
-}
|
|
|
-
|
|
|
-- (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 {
|
|
|
|
|
|
- __block NSURLSessionDataTask *dataTask = nil;
|
|
|
- url_session_manager_create_task_safely(^{
|
|
|
- dataTask = [self.session dataTaskWithRequest:request];
|
|
|
- });
|
|
|
+ NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
|
|
|
|
|
|
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
|
|
|
|
|
|
@@ -740,17 +748,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
|
|
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
|
|
{
|
|
|
- __block NSURLSessionUploadTask *uploadTask = nil;
|
|
|
- url_session_manager_create_task_safely(^{
|
|
|
- uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
|
|
|
-
|
|
|
- // uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113)
|
|
|
- if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
|
|
|
- for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
|
|
|
- uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
+ NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
|
|
|
|
|
|
if (uploadTask) {
|
|
|
[self addDelegateForUploadTask:uploadTask
|
|
|
@@ -766,11 +764,8 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
|
|
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
|
|
{
|
|
|
- __block NSURLSessionUploadTask *uploadTask = nil;
|
|
|
- url_session_manager_create_task_safely(^{
|
|
|
- uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
|
|
|
- });
|
|
|
-
|
|
|
+ NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
|
|
|
+
|
|
|
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
|
|
|
|
|
|
return uploadTask;
|
|
|
@@ -780,10 +775,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
|
|
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
|
|
{
|
|
|
- __block NSURLSessionUploadTask *uploadTask = nil;
|
|
|
- url_session_manager_create_task_safely(^{
|
|
|
- uploadTask = [self.session uploadTaskWithStreamedRequest:request];
|
|
|
- });
|
|
|
+ NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithStreamedRequest:request];
|
|
|
|
|
|
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
|
|
|
|
|
|
@@ -797,11 +789,8 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
|
|
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
|
|
|
{
|
|
|
- __block NSURLSessionDownloadTask *downloadTask = nil;
|
|
|
- url_session_manager_create_task_safely(^{
|
|
|
- downloadTask = [self.session downloadTaskWithRequest:request];
|
|
|
- });
|
|
|
-
|
|
|
+ NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
|
|
|
+
|
|
|
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
|
|
|
|
|
|
return downloadTask;
|
|
|
@@ -812,10 +801,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
|
|
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
|
|
|
{
|
|
|
- __block NSURLSessionDownloadTask *downloadTask = nil;
|
|
|
- url_session_manager_create_task_safely(^{
|
|
|
- downloadTask = [self.session downloadTaskWithResumeData:resumeData];
|
|
|
- });
|
|
|
+ NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithResumeData:resumeData];
|
|
|
|
|
|
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
|
|
|
|
|
|
@@ -857,10 +843,6 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
self.taskWillPerformHTTPRedirection = block;
|
|
|
}
|
|
|
|
|
|
-- (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block {
|
|
|
- self.taskDidReceiveAuthenticationChallenge = block;
|
|
|
-}
|
|
|
-
|
|
|
- (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block {
|
|
|
self.taskDidSendBodyData = block;
|
|
|
}
|
|
|
@@ -869,6 +851,12 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
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 {
|
|
|
@@ -908,7 +896,9 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|
|
}
|
|
|
|
|
|
- (BOOL)respondsToSelector:(SEL)selector {
|
|
|
- if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
|
|
|
+ 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;
|
|
|
@@ -940,27 +930,10 @@ didBecomeInvalidWithError:(NSError *)error
|
|
|
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
|
|
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
|
|
|
{
|
|
|
- NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
|
|
|
- __block NSURLCredential *credential = nil;
|
|
|
+ NSAssert(self.sessionDidReceiveAuthenticationChallenge != nil, @"`respondsToSelector:` implementation forces `URLSession:didReceiveChallenge:completionHandler:` to be called only if `self.sessionDidReceiveAuthenticationChallenge` is not nil");
|
|
|
|
|
|
- if (self.sessionDidReceiveAuthenticationChallenge) {
|
|
|
- disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
|
|
|
- } else {
|
|
|
- if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
|
|
- if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
|
|
|
- credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
|
|
- if (credential) {
|
|
|
- disposition = NSURLSessionAuthChallengeUseCredential;
|
|
|
- } else {
|
|
|
- disposition = NSURLSessionAuthChallengePerformDefaultHandling;
|
|
|
- }
|
|
|
- } else {
|
|
|
- disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
|
|
|
- }
|
|
|
- } else {
|
|
|
- disposition = NSURLSessionAuthChallengePerformDefaultHandling;
|
|
|
- }
|
|
|
- }
|
|
|
+ NSURLCredential *credential = nil;
|
|
|
+ NSURLSessionAuthChallengeDisposition disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
|
|
|
|
|
|
if (completionHandler) {
|
|
|
completionHandler(disposition, credential);
|
|
|
@@ -991,21 +964,40 @@ willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
|
|
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
|
|
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
|
|
|
{
|
|
|
+ BOOL evaluateServerTrust = NO;
|
|
|
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
|
|
|
- __block NSURLCredential *credential = nil;
|
|
|
+ NSURLCredential *credential = nil;
|
|
|
|
|
|
- if (self.taskDidReceiveAuthenticationChallenge) {
|
|
|
- disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
|
|
|
+ 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 {
|
|
|
- if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
|
|
- if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
|
|
|
- disposition = NSURLSessionAuthChallengeUseCredential;
|
|
|
- credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
|
|
- } else {
|
|
|
- disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
|
|
|
- }
|
|
|
+ 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 {
|
|
|
- disposition = NSURLSessionAuthChallengePerformDefaultHandling;
|
|
|
+ objc_setAssociatedObject(task, AuthenticationChallengeErrorKey,
|
|
|
+ [self serverTrustErrorForServerTrust:challenge.protectionSpace.serverTrust url:task.currentRequest.URL],
|
|
|
+ OBJC_ASSOCIATION_RETAIN);
|
|
|
+ disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1014,6 +1006,31 @@ didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+- (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
|
|
|
@@ -1039,9 +1056,9 @@ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
|
|
|
{
|
|
|
|
|
|
int64_t totalUnitCount = totalBytesExpectedToSend;
|
|
|
- if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
|
|
|
+ if (totalUnitCount == NSURLSessionTransferSizeUnknown) {
|
|
|
NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
|
|
|
- if(contentLength) {
|
|
|
+ if (contentLength) {
|
|
|
totalUnitCount = (int64_t) [contentLength longLongValue];
|
|
|
}
|
|
|
}
|
|
|
@@ -1075,6 +1092,23 @@ didCompleteWithError:(NSError *)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
|
|
|
@@ -1162,6 +1196,8 @@ didFinishDownloadingToURL:(NSURL *)location
|
|
|
|
|
|
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;
|