PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m

https://gitlab.com/lisit1003/test
Objective C | 793 lines | 627 code | 143 blank | 23 comment | 86 complexity | 7b7668d898c2068fb841e52dd875ceec MD5 | raw file
  1. // AFURLConnectionOperation.m
  2. //
  3. // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.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 NS_ENUM(NSInteger, AFOperationState) {
  31. AFOperationPausedState = -1,
  32. AFOperationReadyState = 1,
  33. AFOperationExecutingState = 2,
  34. AFOperationFinishedState = 3,
  35. };
  36. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  37. typedef UIBackgroundTaskIdentifier AFBackgroundTaskIdentifier;
  38. #else
  39. typedef id AFBackgroundTaskIdentifier;
  40. #endif
  41. static dispatch_group_t url_request_operation_completion_group() {
  42. static dispatch_group_t af_url_request_operation_completion_group;
  43. static dispatch_once_t onceToken;
  44. dispatch_once(&onceToken, ^{
  45. af_url_request_operation_completion_group = dispatch_group_create();
  46. });
  47. return af_url_request_operation_completion_group;
  48. }
  49. static dispatch_queue_t url_request_operation_completion_queue() {
  50. static dispatch_queue_t af_url_request_operation_completion_queue;
  51. static dispatch_once_t onceToken;
  52. dispatch_once(&onceToken, ^{
  53. af_url_request_operation_completion_queue = dispatch_queue_create("com.alamofire.networking.operation.queue", DISPATCH_QUEUE_CONCURRENT );
  54. });
  55. return af_url_request_operation_completion_queue;
  56. }
  57. static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock";
  58. NSString * const AFNetworkingErrorDomain = @"AFNetworkingErrorDomain";
  59. NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"AFNetworkingOperationFailingURLRequestErrorKey";
  60. NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"AFNetworkingOperationFailingURLResponseErrorKey";
  61. NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start";
  62. NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish";
  63. typedef void (^AFURLConnectionOperationProgressBlock)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected);
  64. typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge);
  65. typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse);
  66. typedef NSURLRequest * (^AFURLConnectionOperationRedirectResponseBlock)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse);
  67. static inline NSString * AFKeyPathFromOperationState(AFOperationState state) {
  68. switch (state) {
  69. case AFOperationReadyState:
  70. return @"isReady";
  71. case AFOperationExecutingState:
  72. return @"isExecuting";
  73. case AFOperationFinishedState:
  74. return @"isFinished";
  75. case AFOperationPausedState:
  76. return @"isPaused";
  77. default: {
  78. #pragma clang diagnostic push
  79. #pragma clang diagnostic ignored "-Wunreachable-code"
  80. return @"state";
  81. #pragma clang diagnostic pop
  82. }
  83. }
  84. }
  85. static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) {
  86. switch (fromState) {
  87. case AFOperationReadyState:
  88. switch (toState) {
  89. case AFOperationPausedState:
  90. case AFOperationExecutingState:
  91. return YES;
  92. case AFOperationFinishedState:
  93. return isCancelled;
  94. default:
  95. return NO;
  96. }
  97. case AFOperationExecutingState:
  98. switch (toState) {
  99. case AFOperationPausedState:
  100. case AFOperationFinishedState:
  101. return YES;
  102. default:
  103. return NO;
  104. }
  105. case AFOperationFinishedState:
  106. return NO;
  107. case AFOperationPausedState:
  108. return toState == AFOperationReadyState;
  109. default: {
  110. #pragma clang diagnostic push
  111. #pragma clang diagnostic ignored "-Wunreachable-code"
  112. switch (toState) {
  113. case AFOperationPausedState:
  114. case AFOperationReadyState:
  115. case AFOperationExecutingState:
  116. case AFOperationFinishedState:
  117. return YES;
  118. default:
  119. return NO;
  120. }
  121. }
  122. #pragma clang diagnostic pop
  123. }
  124. }
  125. @interface AFURLConnectionOperation ()
  126. @property (readwrite, nonatomic, assign) AFOperationState state;
  127. @property (readwrite, nonatomic, strong) NSRecursiveLock *lock;
  128. @property (readwrite, nonatomic, strong) NSURLConnection *connection;
  129. @property (readwrite, nonatomic, strong) NSURLRequest *request;
  130. @property (readwrite, nonatomic, strong) NSURLResponse *response;
  131. @property (readwrite, nonatomic, strong) NSError *error;
  132. @property (readwrite, nonatomic, strong) NSData *responseData;
  133. @property (readwrite, nonatomic, copy) NSString *responseString;
  134. @property (readwrite, nonatomic, assign) NSStringEncoding responseStringEncoding;
  135. @property (readwrite, nonatomic, assign) long long totalBytesRead;
  136. @property (readwrite, nonatomic, assign) AFBackgroundTaskIdentifier backgroundTaskIdentifier;
  137. @property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress;
  138. @property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress;
  139. @property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge;
  140. @property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse;
  141. @property (readwrite, nonatomic, copy) AFURLConnectionOperationRedirectResponseBlock redirectResponse;
  142. - (void)operationDidStart;
  143. - (void)finish;
  144. - (void)cancelConnection;
  145. @end
  146. @implementation AFURLConnectionOperation
  147. @synthesize outputStream = _outputStream;
  148. + (void)networkRequestThreadEntryPoint:(id)__unused object {
  149. @autoreleasepool {
  150. [[NSThread currentThread] setName:@"AFNetworking"];
  151. NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
  152. [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
  153. [runLoop run];
  154. }
  155. }
  156. + (NSThread *)networkRequestThread {
  157. static NSThread *_networkRequestThread = nil;
  158. static dispatch_once_t oncePredicate;
  159. dispatch_once(&oncePredicate, ^{
  160. _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
  161. [_networkRequestThread start];
  162. });
  163. return _networkRequestThread;
  164. }
  165. - (instancetype)initWithRequest:(NSURLRequest *)urlRequest {
  166. NSParameterAssert(urlRequest);
  167. self = [super init];
  168. if (!self) {
  169. return nil;
  170. }
  171. _state = AFOperationReadyState;
  172. self.lock = [[NSRecursiveLock alloc] init];
  173. self.lock.name = kAFNetworkingLockName;
  174. self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
  175. self.request = urlRequest;
  176. self.shouldUseCredentialStorage = YES;
  177. self.securityPolicy = [AFSecurityPolicy defaultPolicy];
  178. return self;
  179. }
  180. - (void)dealloc {
  181. if (_outputStream) {
  182. [_outputStream close];
  183. _outputStream = nil;
  184. }
  185. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  186. if (_backgroundTaskIdentifier) {
  187. [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
  188. _backgroundTaskIdentifier = UIBackgroundTaskInvalid;
  189. }
  190. #endif
  191. }
  192. #pragma mark -
  193. - (void)setResponseData:(NSData *)responseData {
  194. [self.lock lock];
  195. if (!responseData) {
  196. _responseData = nil;
  197. } else {
  198. _responseData = [NSData dataWithBytes:responseData.bytes length:responseData.length];
  199. }
  200. [self.lock unlock];
  201. }
  202. - (NSString *)responseString {
  203. [self.lock lock];
  204. if (!_responseString && self.response && self.responseData) {
  205. self.responseString = [[NSString alloc] initWithData:self.responseData encoding:self.responseStringEncoding];
  206. }
  207. [self.lock unlock];
  208. return _responseString;
  209. }
  210. - (NSStringEncoding)responseStringEncoding {
  211. [self.lock lock];
  212. if (!_responseStringEncoding && self.response) {
  213. NSStringEncoding stringEncoding = NSUTF8StringEncoding;
  214. if (self.response.textEncodingName) {
  215. CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName);
  216. if (IANAEncoding != kCFStringEncodingInvalidId) {
  217. stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding);
  218. }
  219. }
  220. self.responseStringEncoding = stringEncoding;
  221. }
  222. [self.lock unlock];
  223. return _responseStringEncoding;
  224. }
  225. - (NSInputStream *)inputStream {
  226. return self.request.HTTPBodyStream;
  227. }
  228. - (void)setInputStream:(NSInputStream *)inputStream {
  229. NSMutableURLRequest *mutableRequest = [self.request mutableCopy];
  230. mutableRequest.HTTPBodyStream = inputStream;
  231. self.request = mutableRequest;
  232. }
  233. - (NSOutputStream *)outputStream {
  234. if (!_outputStream) {
  235. self.outputStream = [NSOutputStream outputStreamToMemory];
  236. }
  237. return _outputStream;
  238. }
  239. - (void)setOutputStream:(NSOutputStream *)outputStream {
  240. [self.lock lock];
  241. if (outputStream != _outputStream) {
  242. if (_outputStream) {
  243. [_outputStream close];
  244. }
  245. _outputStream = outputStream;
  246. }
  247. [self.lock unlock];
  248. }
  249. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  250. - (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
  251. [self.lock lock];
  252. if (!self.backgroundTaskIdentifier) {
  253. UIApplication *application = [UIApplication sharedApplication];
  254. __weak __typeof(self)weakSelf = self;
  255. self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
  256. __strong __typeof(weakSelf)strongSelf = weakSelf;
  257. if (handler) {
  258. handler();
  259. }
  260. if (strongSelf) {
  261. [strongSelf cancel];
  262. [application endBackgroundTask:strongSelf.backgroundTaskIdentifier];
  263. strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
  264. }
  265. }];
  266. }
  267. [self.lock unlock];
  268. }
  269. #endif
  270. #pragma mark -
  271. - (void)setState:(AFOperationState)state {
  272. if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
  273. return;
  274. }
  275. [self.lock lock];
  276. NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
  277. NSString *newStateKey = AFKeyPathFromOperationState(state);
  278. [self willChangeValueForKey:newStateKey];
  279. [self willChangeValueForKey:oldStateKey];
  280. _state = state;
  281. [self didChangeValueForKey:oldStateKey];
  282. [self didChangeValueForKey:newStateKey];
  283. [self.lock unlock];
  284. }
  285. - (void)pause {
  286. if ([self isPaused] || [self isFinished] || [self isCancelled]) {
  287. return;
  288. }
  289. [self.lock lock];
  290. if ([self isExecuting]) {
  291. [self performSelector:@selector(operationDidPause) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  292. dispatch_async(dispatch_get_main_queue(), ^{
  293. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  294. [notificationCenter postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
  295. });
  296. }
  297. self.state = AFOperationPausedState;
  298. [self.lock unlock];
  299. }
  300. - (void)operationDidPause {
  301. [self.lock lock];
  302. [self.connection cancel];
  303. [self.lock unlock];
  304. }
  305. - (BOOL)isPaused {
  306. return self.state == AFOperationPausedState;
  307. }
  308. - (void)resume {
  309. if (![self isPaused]) {
  310. return;
  311. }
  312. [self.lock lock];
  313. self.state = AFOperationReadyState;
  314. [self start];
  315. [self.lock unlock];
  316. }
  317. #pragma mark -
  318. - (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block {
  319. self.uploadProgress = block;
  320. }
  321. - (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block {
  322. self.downloadProgress = block;
  323. }
  324. - (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block {
  325. self.authenticationChallenge = block;
  326. }
  327. - (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block {
  328. self.cacheResponse = block;
  329. }
  330. - (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block {
  331. self.redirectResponse = block;
  332. }
  333. #pragma mark - NSOperation
  334. - (void)setCompletionBlock:(void (^)(void))block {
  335. [self.lock lock];
  336. if (!block) {
  337. [super setCompletionBlock:nil];
  338. } else {
  339. __weak __typeof(self)weakSelf = self;
  340. [super setCompletionBlock:^ {
  341. __strong __typeof(weakSelf)strongSelf = weakSelf;
  342. #pragma clang diagnostic push
  343. #pragma clang diagnostic ignored "-Wgnu"
  344. dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
  345. dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
  346. #pragma clang diagnostic pop
  347. dispatch_group_async(group, queue, ^{
  348. block();
  349. });
  350. dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
  351. [strongSelf setCompletionBlock:nil];
  352. });
  353. }];
  354. }
  355. [self.lock unlock];
  356. }
  357. - (BOOL)isReady {
  358. return self.state == AFOperationReadyState && [super isReady];
  359. }
  360. - (BOOL)isExecuting {
  361. return self.state == AFOperationExecutingState;
  362. }
  363. - (BOOL)isFinished {
  364. return self.state == AFOperationFinishedState;
  365. }
  366. - (BOOL)isConcurrent {
  367. return YES;
  368. }
  369. - (void)start {
  370. [self.lock lock];
  371. if ([self isCancelled]) {
  372. [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  373. } else if ([self isReady]) {
  374. self.state = AFOperationExecutingState;
  375. [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  376. }
  377. [self.lock unlock];
  378. }
  379. - (void)operationDidStart {
  380. [self.lock lock];
  381. if (![self isCancelled]) {
  382. self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
  383. NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
  384. for (NSString *runLoopMode in self.runLoopModes) {
  385. [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
  386. [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
  387. }
  388. [self.connection start];
  389. }
  390. [self.lock unlock];
  391. dispatch_async(dispatch_get_main_queue(), ^{
  392. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
  393. });
  394. }
  395. - (void)finish {
  396. [self.lock lock];
  397. self.state = AFOperationFinishedState;
  398. [self.lock unlock];
  399. dispatch_async(dispatch_get_main_queue(), ^{
  400. [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
  401. });
  402. }
  403. - (void)cancel {
  404. [self.lock lock];
  405. if (![self isFinished] && ![self isCancelled]) {
  406. [super cancel];
  407. if ([self isExecuting]) {
  408. [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
  409. }
  410. }
  411. [self.lock unlock];
  412. }
  413. - (void)cancelConnection {
  414. NSDictionary *userInfo = nil;
  415. if ([self.request URL]) {
  416. userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey];
  417. }
  418. NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
  419. if (![self isFinished]) {
  420. if (self.connection) {
  421. [self.connection cancel];
  422. [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:error];
  423. } else {
  424. // Accomodate race condition where `self.connection` has not yet been set before cancellation
  425. self.error = error;
  426. [self finish];
  427. }
  428. }
  429. }
  430. #pragma mark -
  431. + (NSArray *)batchOfRequestOperations:(NSArray *)operations
  432. progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
  433. completionBlock:(void (^)(NSArray *operations))completionBlock
  434. {
  435. if (!operations || [operations count] == 0) {
  436. return @[[NSBlockOperation blockOperationWithBlock:^{
  437. dispatch_async(dispatch_get_main_queue(), ^{
  438. if (completionBlock) {
  439. completionBlock(@[]);
  440. }
  441. });
  442. }]];
  443. }
  444. __block dispatch_group_t group = dispatch_group_create();
  445. NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{
  446. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  447. if (completionBlock) {
  448. completionBlock(operations);
  449. }
  450. });
  451. }];
  452. for (AFURLConnectionOperation *operation in operations) {
  453. operation.completionGroup = group;
  454. void (^originalCompletionBlock)(void) = [operation.completionBlock copy];
  455. __weak __typeof(operation)weakOperation = operation;
  456. operation.completionBlock = ^{
  457. __strong __typeof(weakOperation)strongOperation = weakOperation;
  458. #pragma clang diagnostic push
  459. #pragma clang diagnostic ignored "-Wgnu"
  460. dispatch_queue_t queue = strongOperation.completionQueue ?: dispatch_get_main_queue();
  461. #pragma clang diagnostic pop
  462. dispatch_group_async(group, queue, ^{
  463. if (originalCompletionBlock) {
  464. originalCompletionBlock();
  465. }
  466. NSUInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) {
  467. return [op isFinished];
  468. }] count];
  469. if (progressBlock) {
  470. progressBlock(numberOfFinishedOperations, [operations count]);
  471. }
  472. dispatch_group_leave(group);
  473. });
  474. };
  475. dispatch_group_enter(group);
  476. [batchedOperation addDependency:operation];
  477. }
  478. return [operations arrayByAddingObject:batchedOperation];
  479. }
  480. #pragma mark - NSObject
  481. - (NSString *)description {
  482. return [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response];
  483. }
  484. #pragma mark - NSURLConnectionDelegate
  485. - (void)connection:(NSURLConnection *)connection
  486. willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
  487. {
  488. if (self.authenticationChallenge) {
  489. self.authenticationChallenge(connection, challenge);
  490. return;
  491. }
  492. if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  493. if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
  494. NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
  495. [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
  496. } else {
  497. [[challenge sender] cancelAuthenticationChallenge:challenge];
  498. }
  499. } else {
  500. if ([challenge previousFailureCount] == 0) {
  501. if (self.credential) {
  502. [[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge];
  503. } else {
  504. [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
  505. }
  506. } else {
  507. [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
  508. }
  509. }
  510. }
  511. - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection {
  512. return self.shouldUseCredentialStorage;
  513. }
  514. - (NSURLRequest *)connection:(NSURLConnection *)connection
  515. willSendRequest:(NSURLRequest *)request
  516. redirectResponse:(NSURLResponse *)redirectResponse
  517. {
  518. if (self.redirectResponse) {
  519. return self.redirectResponse(connection, request, redirectResponse);
  520. } else {
  521. return request;
  522. }
  523. }
  524. - (void)connection:(NSURLConnection __unused *)connection
  525. didSendBodyData:(NSInteger)bytesWritten
  526. totalBytesWritten:(NSInteger)totalBytesWritten
  527. totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
  528. {
  529. if (self.uploadProgress) {
  530. dispatch_async(dispatch_get_main_queue(), ^{
  531. self.uploadProgress((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
  532. });
  533. }
  534. }
  535. - (void)connection:(NSURLConnection __unused *)connection
  536. didReceiveResponse:(NSURLResponse *)response
  537. {
  538. self.response = response;
  539. [self.outputStream open];
  540. }
  541. - (void)connection:(NSURLConnection __unused *)connection
  542. didReceiveData:(NSData *)data
  543. {
  544. NSUInteger length = [data length];
  545. while (YES) {
  546. NSInteger totalNumberOfBytesWritten = 0;
  547. if ([self.outputStream hasSpaceAvailable]) {
  548. const uint8_t *dataBuffer = (uint8_t *)[data bytes];
  549. NSInteger numberOfBytesWritten = 0;
  550. while (totalNumberOfBytesWritten < (NSInteger)length) {
  551. numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
  552. if (numberOfBytesWritten == -1) {
  553. break;
  554. }
  555. totalNumberOfBytesWritten += numberOfBytesWritten;
  556. }
  557. break;
  558. }
  559. if (self.outputStream.streamError) {
  560. [self.connection cancel];
  561. [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError];
  562. return;
  563. }
  564. }
  565. dispatch_async(dispatch_get_main_queue(), ^{
  566. self.totalBytesRead += (long long)length;
  567. if (self.downloadProgress) {
  568. self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength);
  569. }
  570. });
  571. }
  572. - (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
  573. self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
  574. [self.outputStream close];
  575. if (self.responseData) {
  576. self.outputStream = nil;
  577. }
  578. self.connection = nil;
  579. [self finish];
  580. }
  581. - (void)connection:(NSURLConnection __unused *)connection
  582. didFailWithError:(NSError *)error
  583. {
  584. self.error = error;
  585. [self.outputStream close];
  586. if (self.responseData) {
  587. self.outputStream = nil;
  588. }
  589. self.connection = nil;
  590. [self finish];
  591. }
  592. - (NSCachedURLResponse *)connection:(NSURLConnection *)connection
  593. willCacheResponse:(NSCachedURLResponse *)cachedResponse
  594. {
  595. if (self.cacheResponse) {
  596. return self.cacheResponse(connection, cachedResponse);
  597. } else {
  598. if ([self isCancelled]) {
  599. return nil;
  600. }
  601. return cachedResponse;
  602. }
  603. }
  604. #pragma mark - NSecureCoding
  605. + (BOOL)supportsSecureCoding {
  606. return YES;
  607. }
  608. - (id)initWithCoder:(NSCoder *)decoder {
  609. NSURLRequest *request = [decoder decodeObjectOfClass:[NSURLRequest class] forKey:NSStringFromSelector(@selector(request))];
  610. self = [self initWithRequest:request];
  611. if (!self) {
  612. return nil;
  613. }
  614. self.state = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(state))] integerValue];
  615. self.response = [decoder decodeObjectOfClass:[NSHTTPURLResponse class] forKey:NSStringFromSelector(@selector(response))];
  616. self.error = [decoder decodeObjectOfClass:[NSError class] forKey:NSStringFromSelector(@selector(error))];
  617. self.responseData = [decoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(responseData))];
  618. self.totalBytesRead = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(totalBytesRead))] longLongValue];
  619. return self;
  620. }
  621. - (void)encodeWithCoder:(NSCoder *)coder {
  622. [self pause];
  623. [coder encodeObject:self.request forKey:NSStringFromSelector(@selector(request))];
  624. switch (self.state) {
  625. case AFOperationExecutingState:
  626. case AFOperationPausedState:
  627. [coder encodeInteger:AFOperationReadyState forKey:NSStringFromSelector(@selector(state))];
  628. break;
  629. default:
  630. [coder encodeInteger:self.state forKey:NSStringFromSelector(@selector(state))];
  631. break;
  632. }
  633. [coder encodeObject:self.response forKey:NSStringFromSelector(@selector(response))];
  634. [coder encodeObject:self.error forKey:NSStringFromSelector(@selector(error))];
  635. [coder encodeObject:self.responseData forKey:NSStringFromSelector(@selector(responseData))];
  636. [coder encodeInt64:self.totalBytesRead forKey:NSStringFromSelector(@selector(totalBytesRead))];
  637. }
  638. #pragma mark - NSCopying
  639. - (id)copyWithZone:(NSZone *)zone {
  640. AFURLConnectionOperation *operation = [(AFURLConnectionOperation *)[[self class] allocWithZone:zone] initWithRequest:self.request];
  641. operation.uploadProgress = self.uploadProgress;
  642. operation.downloadProgress = self.downloadProgress;
  643. operation.authenticationChallenge = self.authenticationChallenge;
  644. operation.cacheResponse = self.cacheResponse;
  645. operation.redirectResponse = self.redirectResponse;
  646. operation.completionQueue = self.completionQueue;
  647. operation.completionGroup = self.completionGroup;
  648. return operation;
  649. }
  650. @end