PageRenderTime 126ms CodeModel.GetById 28ms RepoModel.GetById 7ms app.codeStats 11ms

/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m

https://bitbucket.org/af_1do/geolocation
Objective C | 855 lines | 675 code | 155 blank | 25 comment | 102 complexity | 95cc6368db5ad7e1d9c0670d569b8bed MD5 | raw file
  1. // AFURLConnectionOperation.m
  2. //
  3. // Copyright (c) 2011 Gowalla (http://gowalla.com/)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. #import "AFURLConnectionOperation.h"
  23. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  24. #import <UIKit/UIKit.h>
  25. #endif
  26. #if !__has_feature(objc_arc)
  27. #error AFNetworking must be built with ARC.
  28. // You can turn on ARC for only AFNetworking files by adding -fobjc-arc to the build phase for each of its files.
  29. #endif
  30. typedef enum {
  31. AFOperationPausedState = -1,
  32. AFOperationReadyState = 1,
  33. AFOperationExecutingState = 2,
  34. AFOperationFinishedState = 3,
  35. } _AFOperationState;
  36. typedef signed short AFOperationState;
  37. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  38. typedef UIBackgroundTaskIdentifier AFBackgroundTaskIdentifier;
  39. #else
  40. typedef id AFBackgroundTaskIdentifier;
  41. #endif
  42. static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock";
  43. NSString * const AFNetworkingErrorDomain = @"AFNetworkingErrorDomain";
  44. NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"AFNetworkingOperationFailingURLRequestErrorKey";
  45. NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"AFNetworkingOperationFailingURLResponseErrorKey";
  46. NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start";
  47. NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish";
  48. typedef void (^AFURLConnectionOperationProgressBlock)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected);
  49. typedef BOOL (^AFURLConnectionOperationAuthenticationAgainstProtectionSpaceBlock)(NSURLConnection *connection, NSURLProtectionSpace *protectionSpace);
  50. typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge);
  51. typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse);
  52. typedef NSURLRequest * (^AFURLConnectionOperationRedirectResponseBlock)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse);
  53. static inline NSString * AFKeyPathFromOperationState(AFOperationState state) {
  54. switch (state) {
  55. case AFOperationReadyState:
  56. return @"isReady";
  57. case AFOperationExecutingState:
  58. return @"isExecuting";
  59. case AFOperationFinishedState:
  60. return @"isFinished";
  61. case AFOperationPausedState:
  62. return @"isPaused";
  63. default:
  64. return @"state";
  65. }
  66. }
  67. static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) {
  68. switch (fromState) {
  69. case AFOperationReadyState:
  70. switch (toState) {
  71. case AFOperationPausedState:
  72. case AFOperationExecutingState:
  73. return YES;
  74. case AFOperationFinishedState:
  75. return isCancelled;
  76. default:
  77. return NO;
  78. }
  79. case AFOperationExecutingState:
  80. switch (toState) {
  81. case AFOperationPausedState:
  82. case AFOperationFinishedState:
  83. return YES;
  84. default:
  85. return NO;
  86. }
  87. case AFOperationFinishedState:
  88. return NO;
  89. case AFOperationPausedState:
  90. return toState == AFOperationReadyState;
  91. default:
  92. return YES;
  93. }
  94. }
  95. @interface AFURLConnectionOperation ()
  96. @property (readwrite, nonatomic, assign) AFOperationState state;
  97. @property (readwrite, nonatomic, assign, getter = isCancelled) BOOL cancelled;
  98. @property (readwrite, nonatomic, strong) NSRecursiveLock *lock;
  99. @property (readwrite, nonatomic, strong) NSURLConnection *connection;
  100. @property (readwrite, nonatomic, strong) NSURLRequest *request;
  101. @property (readwrite, nonatomic, strong) NSURLResponse *response;
  102. @property (readwrite, nonatomic, strong) NSError *error;
  103. @property (readwrite, nonatomic, strong) NSData *responseData;
  104. @property (readwrite, nonatomic, copy) NSString *responseString;
  105. @property (readwrite, nonatomic, assign) NSStringEncoding responseStringEncoding;
  106. @property (readwrite, nonatomic, assign) long long totalBytesRead;
  107. @property (readwrite, nonatomic, assign) AFBackgroundTaskIdentifier backgroundTaskIdentifier;
  108. @property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress;
  109. @property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress;
  110. @property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationAgainstProtectionSpaceBlock authenticationAgainstProtectionSpace;
  111. @property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge;
  112. @property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse;
  113. @property (readwrite, nonatomic, copy) AFURLConnectionOperationRedirectResponseBlock redirectResponse;
  114. - (void)operationDidStart;
  115. - (void)finish;
  116. - (void)cancelConnection;
  117. @end
  118. @implementation AFURLConnectionOperation
  119. @synthesize state = _state;
  120. @synthesize cancelled = _cancelled;
  121. @synthesize connection = _connection;
  122. @synthesize runLoopModes = _runLoopModes;
  123. @synthesize request = _request;
  124. @synthesize response = _response;
  125. @synthesize error = _error;
  126. @synthesize responseData = _responseData;
  127. @synthesize responseString = _responseString;
  128. @synthesize responseStringEncoding = _responseStringEncoding;
  129. @synthesize totalBytesRead = _totalBytesRead;
  130. @dynamic inputStream;
  131. @synthesize outputStream = _outputStream;
  132. @synthesize credential = _credential;
  133. #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_
  134. @synthesize SSLPinningMode = _SSLPinningMode;
  135. #endif
  136. @synthesize shouldUseCredentialStorage = _shouldUseCredentialStorage;
  137. @synthesize userInfo = _userInfo;
  138. @synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier;
  139. @synthesize uploadProgress = _uploadProgress;
  140. @synthesize downloadProgress = _downloadProgress;
  141. @synthesize authenticationAgainstProtectionSpace = _authenticationAgainstProtectionSpace;
  142. @synthesize authenticationChallenge = _authenticationChallenge;
  143. @synthesize cacheResponse = _cacheResponse;
  144. @synthesize redirectResponse = _redirectResponse;
  145. @synthesize lock = _lock;
  146. + (void) __attribute__((noreturn)) networkRequestThreadEntryPoint:(id)__unused object {
  147. do {
  148. @autoreleasepool {
  149. [[NSThread currentThread] setName:@"AFNetworking"];
  150. [[NSRunLoop currentRunLoop] run];
  151. }
  152. } while (YES);
  153. }
  154. + (NSThread *)networkRequestThread {
  155. static NSThread *_networkRequestThread = nil;
  156. static dispatch_once_t oncePredicate;
  157. dispatch_once(&oncePredicate, ^{
  158. _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
  159. [_networkRequestThread start];
  160. });
  161. return _networkRequestThread;
  162. }
  163. #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_
  164. + (NSArray *)pinnedCertificates {
  165. static NSArray *_pinnedCertificates = nil;
  166. static dispatch_once_t onceToken;
  167. dispatch_once(&onceToken, ^{
  168. NSBundle *bundle = [NSBundle bundleForClass:[self class]];
  169. NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
  170. NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]];
  171. for (NSString *path in paths) {
  172. NSData *certificateData = [NSData dataWithContentsOfFile:path];
  173. [certificates addObject:certificateData];
  174. }
  175. _pinnedCertificates = [[NSArray alloc] initWithArray:certificates];
  176. });
  177. return _pinnedCertificates;
  178. }
  179. + (NSArray *)pinnedPublicKeys {
  180. static NSArray *_pinnedPublicKeys = nil;
  181. static dispatch_once_t onceToken;
  182. dispatch_once(&onceToken, ^{
  183. NSArray *pinnedCertificates = [self pinnedCertificates];
  184. NSMutableArray *publicKeys = [NSMutableArray arrayWithCapacity:[pinnedCertificates count]];
  185. for (NSData *data in pinnedCertificates) {
  186. SecCertificateRef allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data);
  187. NSParameterAssert(allowedCertificate);
  188. SecCertificateRef allowedCertificates[] = {allowedCertificate};
  189. CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
  190. SecPolicyRef policy = SecPolicyCreateBasicX509();
  191. SecTrustRef allowedTrust = NULL;
  192. OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &allowedTrust);
  193. NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status);
  194. SecTrustResultType result = 0;
  195. status = SecTrustEvaluate(allowedTrust, &result);
  196. NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
  197. SecKeyRef allowedPublicKey = SecTrustCopyPublicKey(allowedTrust);
  198. NSParameterAssert(allowedPublicKey);
  199. [publicKeys addObject:(__bridge_transfer id)allowedPublicKey];
  200. CFRelease(allowedTrust);
  201. CFRelease(policy);
  202. CFRelease(certificates);
  203. CFRelease(allowedCertificate);
  204. }
  205. _pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys];
  206. });
  207. return _pinnedPublicKeys;
  208. }
  209. #endif
  210. - (id)initWithRequest:(NSURLRequest *)urlRequest {
  211. self = [super init];
  212. if (!self) {
  213. return nil;
  214. }
  215. self.lock = [[NSRecursiveLock alloc] init];
  216. self.lock.name = kAFNetworkingLockName;
  217. self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
  218. self.request = urlRequest;
  219. self.shouldUseCredentialStorage = YES;
  220. self.outputStream = [NSOutputStream outputStreamToMemory];
  221. self.state = AFOperationReadyState;
  222. // #ifdef included for backwards-compatibility
  223. #ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_
  224. self.allowsInvalidSSLCertificate = YES;
  225. #endif
  226. return self;
  227. }
  228. - (void)dealloc {
  229. if (_outputStream) {
  230. [_outputStream close];
  231. _outputStream = nil;
  232. }
  233. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  234. if (_backgroundTaskIdentifier) {
  235. [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
  236. _backgroundTaskIdentifier = UIBackgroundTaskInvalid;
  237. }
  238. #endif
  239. }
  240. - (NSString *)description {
  241. return [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response];
  242. }
  243. - (void)setCompletionBlock:(void (^)(void))block {
  244. [self.lock lock];
  245. if (!block) {
  246. [super setCompletionBlock:nil];
  247. } else {
  248. __weak __typeof(&*self)weakSelf = self;
  249. [super setCompletionBlock:^ {
  250. __strong __typeof(&*weakSelf)strongSelf = weakSelf;
  251. block();
  252. [strongSelf setCompletionBlock:nil];
  253. }];
  254. }
  255. [self.lock unlock];
  256. }
  257. - (NSInputStream *)inputStream {
  258. return self.request.HTTPBodyStream;
  259. }
  260. - (void)setInputStream:(NSInputStream *)inputStream {
  261. [self willChangeValueForKey:@"inputStream"];
  262. NSMutableURLRequest *mutableRequest = [self.request mutableCopy];
  263. mutableRequest.HTTPBodyStream = inputStream;
  264. self.request = mutableRequest;
  265. [self didChangeValueForKey:@"inputStream"];
  266. }
  267. - (void)setOutputStream:(NSOutputStream *)outputStream {
  268. if (outputStream == _outputStream) {
  269. return;
  270. }
  271. [self willChangeValueForKey:@"outputStream"];
  272. if (_outputStream) {
  273. [_outputStream close];
  274. }
  275. _outputStream = outputStream;
  276. [self didChangeValueForKey:@"outputStream"];
  277. }
  278. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  279. - (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
  280. [self.lock lock];
  281. if (!self.backgroundTaskIdentifier) {
  282. UIApplication *application = [UIApplication sharedApplication];
  283. __weak __typeof(&*self)weakSelf = self;
  284. self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
  285. __strong __typeof(&*weakSelf)strongSelf = weakSelf;
  286. if (handler) {
  287. handler();
  288. }
  289. if (strongSelf) {
  290. [strongSelf cancel];
  291. [application endBackgroundTask:strongSelf.backgroundTaskIdentifier];
  292. strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
  293. }
  294. }];
  295. }
  296. [self.lock unlock];
  297. }
  298. #endif
  299. - (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block {
  300. self.uploadProgress = block;
  301. }
  302. - (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block {
  303. self.downloadProgress = block;
  304. }
  305. - (void)setAuthenticationAgainstProtectionSpaceBlock:(BOOL (^)(NSURLConnection *, NSURLProtectionSpace *))block {
  306. self.authenticationAgainstProtectionSpace = block;
  307. }
  308. - (void)setAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block {
  309. self.authenticationChallenge = block;
  310. }
  311. - (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block {
  312. self.cacheResponse = block;
  313. }
  314. - (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block {
  315. self.redirectResponse = block;
  316. }
  317. - (void)setState:(AFOperationState)state {
  318. if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
  319. return;
  320. }
  321. [self.lock lock];
  322. NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
  323. NSString *newStateKey = AFKeyPathFromOperationState(state);
  324. [self willChangeValueForKey:newStateKey];
  325. [self willChangeValueForKey:oldStateKey];
  326. _state = state;
  327. [self didChangeValueForKey:oldStateKey];
  328. [self didChangeValueForKey:newStateKey];
  329. [self.lock unlock];
  330. }
  331. - (NSString *)responseString {
  332. [self.lock lock];
  333. if (!_responseString && self.response && self.responseData) {
  334. self.responseString = [[NSString alloc] initWithData:self.responseData encoding:self.responseStringEncoding];
  335. }
  336. [self.lock unlock];
  337. return _responseString;
  338. }
  339. - (NSStringEncoding)responseStringEncoding {
  340. [self.lock lock];
  341. if (!_responseStringEncoding && self.response) {
  342. NSStringEncoding stringEncoding = NSUTF8StringEncoding;
  343. if (self.response.textEncodingName) {
  344. CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName);
  345. if (IANAEncoding != kCFStringEncodingInvalidId) {
  346. stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding);
  347. }
  348. }
  349. self.responseStringEncoding = stringEncoding;
  350. }
  351. [self.lock unlock];
  352. return _responseStringEncoding;
  353. }
  354. - (void)pause {
  355. if ([self isPaused] || [self isFinished] || [self isCancelled]) {
  356. return;
  357. }
  358. [self.lock lock];
  359. if ([self isExecuting]) {
  360. [self.connection performSelector:@selector(cancel) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  361. dispatch_async(dispatch_get_main_queue(), ^{
  362. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  363. [notificationCenter postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
  364. });
  365. }
  366. self.state = AFOperationPausedState;
  367. [self.lock unlock];
  368. }
  369. - (BOOL)isPaused {
  370. return self.state == AFOperationPausedState;
  371. }
  372. - (void)resume {
  373. if (![self isPaused]) {
  374. return;
  375. }
  376. [self.lock lock];
  377. self.state = AFOperationReadyState;
  378. [self start];
  379. [self.lock unlock];
  380. }
  381. #pragma mark - NSOperation
  382. - (BOOL)isReady {
  383. return self.state == AFOperationReadyState && [super isReady];
  384. }
  385. - (BOOL)isExecuting {
  386. return self.state == AFOperationExecutingState;
  387. }
  388. - (BOOL)isFinished {
  389. return self.state == AFOperationFinishedState;
  390. }
  391. - (BOOL)isConcurrent {
  392. return YES;
  393. }
  394. - (void)start {
  395. [self.lock lock];
  396. if ([self isReady]) {
  397. self.state = AFOperationExecutingState;
  398. [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  399. }
  400. [self.lock unlock];
  401. }
  402. - (void)operationDidStart {
  403. [self.lock lock];
  404. if (! [self isCancelled]) {
  405. self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
  406. NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
  407. for (NSString *runLoopMode in self.runLoopModes) {
  408. [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
  409. [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
  410. }
  411. [self.connection start];
  412. }
  413. [self.lock unlock];
  414. dispatch_async(dispatch_get_main_queue(), ^{
  415. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
  416. });
  417. if ([self isCancelled]) {
  418. [self finish];
  419. }
  420. }
  421. - (void)finish {
  422. self.state = AFOperationFinishedState;
  423. dispatch_async(dispatch_get_main_queue(), ^{
  424. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
  425. });
  426. }
  427. - (void)cancel {
  428. [self.lock lock];
  429. if (![self isFinished] && ![self isCancelled]) {
  430. [self willChangeValueForKey:@"isCancelled"];
  431. _cancelled = YES;
  432. [super cancel];
  433. [self didChangeValueForKey:@"isCancelled"];
  434. // Cancel the connection on the thread it runs on to prevent race conditions
  435. [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  436. }
  437. [self.lock unlock];
  438. }
  439. - (void)cancelConnection {
  440. NSDictionary *userInfo = nil;
  441. if ([self.request URL]) {
  442. userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey];
  443. }
  444. self.error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
  445. if (self.connection) {
  446. [self.connection cancel];
  447. // Manually send this delegate message since `[self.connection cancel]` causes the connection to never send another message to its delegate
  448. [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.error];
  449. }
  450. }
  451. #pragma mark - NSURLConnectionDelegate
  452. #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_
  453. - (void)connection:(NSURLConnection *)connection
  454. willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
  455. {
  456. if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  457. SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
  458. SecPolicyRef policy = SecPolicyCreateBasicX509();
  459. CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
  460. NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:certificateCount];
  461. for (CFIndex i = 0; i < certificateCount; i++) {
  462. SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
  463. if (self.SSLPinningMode == AFSSLPinningModeCertificate) {
  464. [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
  465. } else if (self.SSLPinningMode == AFSSLPinningModePublicKey) {
  466. SecCertificateRef someCertificates[] = {certificate};
  467. CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL);
  468. SecTrustRef trust = NULL;
  469. OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust);
  470. NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status);
  471. SecTrustResultType result;
  472. status = SecTrustEvaluate(trust, &result);
  473. NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
  474. [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)];
  475. CFRelease(trust);
  476. CFRelease(certificates);
  477. }
  478. }
  479. CFRelease(policy);
  480. switch (self.SSLPinningMode) {
  481. case AFSSLPinningModePublicKey: {
  482. for (id publicKey in trustChain) {
  483. if ([[self.class pinnedPublicKeys] containsObject:publicKey]) {
  484. NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
  485. [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
  486. return;
  487. }
  488. }
  489. [[challenge sender] cancelAuthenticationChallenge:challenge];
  490. break;
  491. }
  492. case AFSSLPinningModeCertificate: {
  493. for (id serverCertificateData in trustChain) {
  494. if ([[self.class pinnedCertificates] containsObject:serverCertificateData]) {
  495. NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
  496. [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
  497. return;
  498. }
  499. }
  500. [[challenge sender] cancelAuthenticationChallenge:challenge];
  501. break;
  502. }
  503. case AFSSLPinningModeNone: {
  504. if (self.allowsInvalidSSLCertificate){
  505. NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
  506. [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
  507. } else {
  508. SecTrustResultType result = 0;
  509. OSStatus status = SecTrustEvaluate(serverTrust, &result);
  510. NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
  511. if (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed) {
  512. NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
  513. [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
  514. } else {
  515. [[challenge sender] cancelAuthenticationChallenge:challenge];
  516. }
  517. }
  518. break;
  519. }
  520. }
  521. }
  522. }
  523. #endif
  524. - (BOOL)connection:(NSURLConnection *)connection
  525. canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
  526. {
  527. if (self.allowsInvalidSSLCertificate &&
  528. [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  529. return YES;
  530. }
  531. if (self.authenticationAgainstProtectionSpace) {
  532. return self.authenticationAgainstProtectionSpace(connection, protectionSpace);
  533. } else if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
  534. return NO;
  535. } else {
  536. return YES;
  537. }
  538. }
  539. - (void)connection:(NSURLConnection *)connection
  540. didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
  541. {
  542. if (self.allowsInvalidSSLCertificate
  543. && [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  544. [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
  545. return;
  546. }
  547. if (self.authenticationChallenge) {
  548. self.authenticationChallenge(connection, challenge);
  549. } else {
  550. if ([challenge previousFailureCount] == 0) {
  551. NSURLCredential *credential = nil;
  552. NSString *user = [[self.request URL] user];
  553. NSString *password = [[self.request URL] password];
  554. if (user && password) {
  555. credential = [NSURLCredential credentialWithUser:user password:password persistence:NSURLCredentialPersistenceNone];
  556. } else if (user) {
  557. credential = [[[NSURLCredentialStorage sharedCredentialStorage] credentialsForProtectionSpace:[challenge protectionSpace]] objectForKey:user];
  558. } else {
  559. credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:[challenge protectionSpace]];
  560. }
  561. if (!credential) {
  562. credential = self.credential;
  563. }
  564. if (credential) {
  565. [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
  566. } else {
  567. [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
  568. }
  569. } else {
  570. [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
  571. }
  572. }
  573. }
  574. - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection {
  575. return self.shouldUseCredentialStorage;
  576. }
  577. - (NSInputStream *)connection:(NSURLConnection __unused *)connection
  578. needNewBodyStream:(NSURLRequest *)request
  579. {
  580. if ([request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
  581. return [request.HTTPBodyStream copy];
  582. }
  583. return nil;
  584. }
  585. - (NSURLRequest *)connection:(NSURLConnection *)connection
  586. willSendRequest:(NSURLRequest *)request
  587. redirectResponse:(NSURLResponse *)redirectResponse
  588. {
  589. if (self.redirectResponse) {
  590. return self.redirectResponse(connection, request, redirectResponse);
  591. } else {
  592. return request;
  593. }
  594. }
  595. - (void)connection:(NSURLConnection __unused *)connection
  596. didSendBodyData:(NSInteger)bytesWritten
  597. totalBytesWritten:(NSInteger)totalBytesWritten
  598. totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
  599. {
  600. if (self.uploadProgress) {
  601. dispatch_async(dispatch_get_main_queue(), ^{
  602. self.uploadProgress((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
  603. });
  604. }
  605. }
  606. - (void)connection:(NSURLConnection __unused *)connection
  607. didReceiveResponse:(NSURLResponse *)response
  608. {
  609. self.response = response;
  610. [self.outputStream open];
  611. }
  612. - (void)connection:(NSURLConnection __unused *)connection
  613. didReceiveData:(NSData *)data
  614. {
  615. NSUInteger length = [data length];
  616. if ([self.outputStream hasSpaceAvailable]) {
  617. const uint8_t *dataBuffer = (uint8_t *) [data bytes];
  618. [self.outputStream write:&dataBuffer[0] maxLength:length];
  619. }
  620. dispatch_async(dispatch_get_main_queue(), ^{
  621. self.totalBytesRead += length;
  622. if (self.downloadProgress) {
  623. self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength);
  624. }
  625. });
  626. }
  627. - (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
  628. self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
  629. [self.outputStream close];
  630. [self finish];
  631. self.connection = nil;
  632. }
  633. - (void)connection:(NSURLConnection __unused *)connection
  634. didFailWithError:(NSError *)error
  635. {
  636. self.error = error;
  637. [self.outputStream close];
  638. [self finish];
  639. self.connection = nil;
  640. }
  641. - (NSCachedURLResponse *)connection:(NSURLConnection *)connection
  642. willCacheResponse:(NSCachedURLResponse *)cachedResponse
  643. {
  644. if (self.cacheResponse) {
  645. return self.cacheResponse(connection, cachedResponse);
  646. } else {
  647. if ([self isCancelled]) {
  648. return nil;
  649. }
  650. return cachedResponse;
  651. }
  652. }
  653. #pragma mark - NSCoding
  654. - (id)initWithCoder:(NSCoder *)aDecoder {
  655. NSURLRequest *request = [aDecoder decodeObjectForKey:@"request"];
  656. self = [self initWithRequest:request];
  657. if (!self) {
  658. return nil;
  659. }
  660. self.state = (AFOperationState)[aDecoder decodeIntegerForKey:@"state"];
  661. self.cancelled = [aDecoder decodeBoolForKey:@"isCancelled"];
  662. self.response = [aDecoder decodeObjectForKey:@"response"];
  663. self.error = [aDecoder decodeObjectForKey:@"error"];
  664. self.responseData = [aDecoder decodeObjectForKey:@"responseData"];
  665. self.totalBytesRead = [[aDecoder decodeObjectForKey:@"totalBytesRead"] longLongValue];
  666. self.allowsInvalidSSLCertificate = [[aDecoder decodeObjectForKey:@"allowsInvalidSSLCertificate"] boolValue];
  667. return self;
  668. }
  669. - (void)encodeWithCoder:(NSCoder *)aCoder {
  670. [self pause];
  671. [aCoder encodeObject:self.request forKey:@"request"];
  672. switch (self.state) {
  673. case AFOperationExecutingState:
  674. case AFOperationPausedState:
  675. [aCoder encodeInteger:AFOperationReadyState forKey:@"state"];
  676. break;
  677. default:
  678. [aCoder encodeInteger:self.state forKey:@"state"];
  679. break;
  680. }
  681. [aCoder encodeBool:[self isCancelled] forKey:@"isCancelled"];
  682. [aCoder encodeObject:self.response forKey:@"response"];
  683. [aCoder encodeObject:self.error forKey:@"error"];
  684. [aCoder encodeObject:self.responseData forKey:@"responseData"];
  685. [aCoder encodeObject:[NSNumber numberWithLongLong:self.totalBytesRead] forKey:@"totalBytesRead"];
  686. [aCoder encodeObject:[NSNumber numberWithBool:self.allowsInvalidSSLCertificate] forKey:@"allowsInvalidSSLCertificate"];
  687. }
  688. #pragma mark - NSCopying
  689. - (id)copyWithZone:(NSZone *)zone {
  690. AFURLConnectionOperation *operation = [(AFURLConnectionOperation *)[[self class] allocWithZone:zone] initWithRequest:self.request];
  691. operation.uploadProgress = self.uploadProgress;
  692. operation.downloadProgress = self.downloadProgress;
  693. operation.authenticationAgainstProtectionSpace = self.authenticationAgainstProtectionSpace;
  694. operation.authenticationChallenge = self.authenticationChallenge;
  695. operation.cacheResponse = self.cacheResponse;
  696. operation.redirectResponse = self.redirectResponse;
  697. operation.allowsInvalidSSLCertificate = self.allowsInvalidSSLCertificate;
  698. return operation;
  699. }
  700. @end