PageRenderTime 91ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Pods/AFNetworking/AFNetworking/AFHTTPClient.m

https://bitbucket.org/af_1do/geolocation
Objective C | 1270 lines | 985 code | 254 blank | 31 comment | 124 complexity | 1e57708a12c681927ffa06628925e660 MD5 | raw file
  1. // AFHTTPClient.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 <Foundation/Foundation.h>
  23. #import "AFHTTPClient.h"
  24. #import "AFHTTPRequestOperation.h"
  25. #import <Availability.h>
  26. #ifdef _SYSTEMCONFIGURATION_H
  27. #import <netinet/in.h>
  28. #import <netinet6/in6.h>
  29. #import <arpa/inet.h>
  30. #import <ifaddrs.h>
  31. #import <netdb.h>
  32. #endif
  33. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  34. #import <UIKit/UIKit.h>
  35. #endif
  36. #ifdef _SYSTEMCONFIGURATION_H
  37. NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
  38. NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";
  39. typedef SCNetworkReachabilityRef AFNetworkReachabilityRef;
  40. typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
  41. #else
  42. typedef id AFNetworkReachabilityRef;
  43. #endif
  44. typedef void (^AFCompletionBlock)(void);
  45. static NSString * AFBase64EncodedStringFromString(NSString *string) {
  46. NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
  47. NSUInteger length = [data length];
  48. NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
  49. uint8_t *input = (uint8_t *)[data bytes];
  50. uint8_t *output = (uint8_t *)[mutableData mutableBytes];
  51. for (NSUInteger i = 0; i < length; i += 3) {
  52. NSUInteger value = 0;
  53. for (NSUInteger j = i; j < (i + 3); j++) {
  54. value <<= 8;
  55. if (j < length) {
  56. value |= (0xFF & input[j]);
  57. }
  58. }
  59. static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  60. NSUInteger idx = (i / 3) * 4;
  61. output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F];
  62. output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F];
  63. output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '=';
  64. output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '=';
  65. }
  66. return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding];
  67. }
  68. static NSString * AFPercentEscapedQueryStringPairMemberFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
  69. static NSString * const kAFCharactersToBeEscaped = @":/?&=;+!@#$()~',*";
  70. static NSString * const kAFCharactersToLeaveUnescaped = @"[].";
  71. return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescaped, (__bridge CFStringRef)kAFCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding));
  72. }
  73. #pragma mark -
  74. @interface AFQueryStringPair : NSObject
  75. @property (readwrite, nonatomic, strong) id field;
  76. @property (readwrite, nonatomic, strong) id value;
  77. - (id)initWithField:(id)field value:(id)value;
  78. - (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding;
  79. @end
  80. @implementation AFQueryStringPair
  81. @synthesize field = _field;
  82. @synthesize value = _value;
  83. - (id)initWithField:(id)field value:(id)value {
  84. self = [super init];
  85. if (!self) {
  86. return nil;
  87. }
  88. self.field = field;
  89. self.value = value;
  90. return self;
  91. }
  92. - (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding {
  93. if (!self.value || [self.value isEqual:[NSNull null]]) {
  94. return AFPercentEscapedQueryStringPairMemberFromStringWithEncoding([self.field description], stringEncoding);
  95. } else {
  96. return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedQueryStringPairMemberFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringPairMemberFromStringWithEncoding([self.value description], stringEncoding)];
  97. }
  98. }
  99. @end
  100. #pragma mark -
  101. extern NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary);
  102. extern NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value);
  103. NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) {
  104. NSMutableArray *mutablePairs = [NSMutableArray array];
  105. for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
  106. [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]];
  107. }
  108. return [mutablePairs componentsJoinedByString:@"&"];
  109. }
  110. NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
  111. return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
  112. }
  113. NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
  114. NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
  115. if ([value isKindOfClass:[NSDictionary class]]) {
  116. NSDictionary *dictionary = value;
  117. // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
  118. NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(caseInsensitiveCompare:)];
  119. for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
  120. id nestedValue = dictionary[nestedKey];
  121. if (nestedValue) {
  122. [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
  123. }
  124. }
  125. } else if ([value isKindOfClass:[NSArray class]]) {
  126. NSArray *array = value;
  127. for (id nestedValue in array) {
  128. [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
  129. }
  130. } else if ([value isKindOfClass:[NSSet class]]) {
  131. NSSet *set = value;
  132. for (id obj in set) {
  133. [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
  134. }
  135. } else {
  136. [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
  137. }
  138. return mutableQueryStringComponents;
  139. }
  140. @interface AFStreamingMultipartFormData : NSObject <AFMultipartFormData>
  141. - (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest
  142. stringEncoding:(NSStringEncoding)encoding;
  143. - (NSMutableURLRequest *)requestByFinalizingMultipartFormData;
  144. @end
  145. #pragma mark -
  146. @interface AFHTTPClient ()
  147. @property (readwrite, nonatomic, strong) NSURL *baseURL;
  148. @property (readwrite, nonatomic, strong) NSMutableArray *registeredHTTPOperationClassNames;
  149. @property (readwrite, nonatomic, strong) NSMutableDictionary *defaultHeaders;
  150. @property (readwrite, nonatomic, strong) NSURLCredential *defaultCredential;
  151. @property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
  152. #ifdef _SYSTEMCONFIGURATION_H
  153. @property (readwrite, nonatomic, assign) AFNetworkReachabilityRef networkReachability;
  154. @property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
  155. @property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
  156. #endif
  157. #ifdef _SYSTEMCONFIGURATION_H
  158. - (void)startMonitoringNetworkReachability;
  159. - (void)stopMonitoringNetworkReachability;
  160. #endif
  161. @end
  162. @implementation AFHTTPClient
  163. @synthesize baseURL = _baseURL;
  164. @synthesize stringEncoding = _stringEncoding;
  165. @synthesize parameterEncoding = _parameterEncoding;
  166. @synthesize registeredHTTPOperationClassNames = _registeredHTTPOperationClassNames;
  167. @synthesize defaultHeaders = _defaultHeaders;
  168. @synthesize defaultCredential = _defaultCredential;
  169. @synthesize operationQueue = _operationQueue;
  170. #ifdef _SYSTEMCONFIGURATION_H
  171. @synthesize networkReachability = _networkReachability;
  172. @synthesize networkReachabilityStatus = _networkReachabilityStatus;
  173. @synthesize networkReachabilityStatusBlock = _networkReachabilityStatusBlock;
  174. #endif
  175. + (instancetype)clientWithBaseURL:(NSURL *)url {
  176. return [[self alloc] initWithBaseURL:url];
  177. }
  178. - (id)initWithBaseURL:(NSURL *)url {
  179. NSParameterAssert(url);
  180. self = [super init];
  181. if (!self) {
  182. return nil;
  183. }
  184. // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
  185. if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
  186. url = [url URLByAppendingPathComponent:@""];
  187. }
  188. self.baseURL = url;
  189. self.stringEncoding = NSUTF8StringEncoding;
  190. self.parameterEncoding = AFFormURLParameterEncoding;
  191. self.registeredHTTPOperationClassNames = [NSMutableArray array];
  192. self.defaultHeaders = [NSMutableDictionary dictionary];
  193. // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
  194. NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
  195. [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  196. float q = 1.0f - (idx * 0.1f);
  197. [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
  198. *stop = q <= 0.5f;
  199. }];
  200. [self setDefaultHeader:@"Accept-Language" value:[acceptLanguagesComponents componentsJoinedByString:@", "]];
  201. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  202. // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
  203. [self setDefaultHeader:@"User-Agent" value:[NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleIdentifierKey], (__bridge id)CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), kCFBundleVersionKey) ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0f)]];
  204. #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
  205. [self setDefaultHeader:@"User-Agent" value:[NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]];
  206. #endif
  207. #ifdef _SYSTEMCONFIGURATION_H
  208. self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
  209. [self startMonitoringNetworkReachability];
  210. #endif
  211. self.operationQueue = [[NSOperationQueue alloc] init];
  212. [self.operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
  213. // #ifdef included for backwards-compatibility
  214. #ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_
  215. self.allowsInvalidSSLCertificate = YES;
  216. #endif
  217. return self;
  218. }
  219. - (void)dealloc {
  220. #ifdef _SYSTEMCONFIGURATION_H
  221. [self stopMonitoringNetworkReachability];
  222. #endif
  223. }
  224. - (NSString *)description {
  225. return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, defaultHeaders: %@, registeredOperationClasses: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.defaultHeaders, self.registeredHTTPOperationClassNames, self.operationQueue];
  226. }
  227. #pragma mark -
  228. #ifdef _SYSTEMCONFIGURATION_H
  229. static BOOL AFURLHostIsIPAddress(NSURL *url) {
  230. struct sockaddr_in sa_in;
  231. struct sockaddr_in6 sa_in6;
  232. return [url host] && (inet_pton(AF_INET, [[url host] UTF8String], &sa_in) == 1 || inet_pton(AF_INET6, [[url host] UTF8String], &sa_in6) == 1);
  233. }
  234. static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
  235. BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
  236. BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
  237. BOOL isNetworkReachable = (isReachable && !needsConnection);
  238. AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
  239. if (isNetworkReachable == NO) {
  240. status = AFNetworkReachabilityStatusNotReachable;
  241. }
  242. #if TARGET_OS_IPHONE
  243. else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
  244. status = AFNetworkReachabilityStatusReachableViaWWAN;
  245. }
  246. #endif
  247. else {
  248. status = AFNetworkReachabilityStatusReachableViaWiFi;
  249. }
  250. return status;
  251. }
  252. static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
  253. AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
  254. AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info;
  255. if (block) {
  256. block(status);
  257. }
  258. dispatch_async(dispatch_get_main_queue(), ^{
  259. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  260. [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:status] forKey:AFNetworkingReachabilityNotificationStatusItem]];
  261. });
  262. }
  263. static const void * AFNetworkReachabilityRetainCallback(const void *info) {
  264. return (__bridge_retained const void *)([(__bridge AFNetworkReachabilityStatusBlock)info copy]);
  265. }
  266. static void AFNetworkReachabilityReleaseCallback(const void *info) {
  267. if (info) {
  268. CFRelease(info);
  269. }
  270. }
  271. - (void)startMonitoringNetworkReachability {
  272. [self stopMonitoringNetworkReachability];
  273. if (!self.baseURL) {
  274. return;
  275. }
  276. self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]);
  277. if (!self.networkReachability) {
  278. return;
  279. }
  280. __weak __typeof(&*self)weakSelf = self;
  281. AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
  282. __strong __typeof(&*weakSelf)strongSelf = weakSelf;
  283. if (!strongSelf) {
  284. return;
  285. }
  286. strongSelf.networkReachabilityStatus = status;
  287. if (strongSelf.networkReachabilityStatusBlock) {
  288. strongSelf.networkReachabilityStatusBlock(status);
  289. }
  290. };
  291. SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
  292. SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
  293. SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
  294. /* Network reachability monitoring does not establish a baseline for IP addresses as it does for hostnames, so if the base URL host is an IP address, the initial reachability callback is manually triggered.
  295. */
  296. if (AFURLHostIsIPAddress(self.baseURL)) {
  297. SCNetworkReachabilityFlags flags;
  298. SCNetworkReachabilityGetFlags(self.networkReachability, &flags);
  299. dispatch_async(dispatch_get_main_queue(), ^{
  300. AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
  301. callback(status);
  302. });
  303. }
  304. }
  305. - (void)stopMonitoringNetworkReachability {
  306. if (_networkReachability) {
  307. SCNetworkReachabilityUnscheduleFromRunLoop(_networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
  308. CFRelease(_networkReachability);
  309. _networkReachability = NULL;
  310. }
  311. }
  312. - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
  313. self.networkReachabilityStatusBlock = block;
  314. }
  315. #endif
  316. #pragma mark -
  317. - (BOOL)registerHTTPOperationClass:(Class)operationClass {
  318. if (![operationClass isSubclassOfClass:[AFHTTPRequestOperation class]]) {
  319. return NO;
  320. }
  321. NSString *className = NSStringFromClass(operationClass);
  322. [self.registeredHTTPOperationClassNames removeObject:className];
  323. [self.registeredHTTPOperationClassNames insertObject:className atIndex:0];
  324. return YES;
  325. }
  326. - (void)unregisterHTTPOperationClass:(Class)operationClass {
  327. NSString *className = NSStringFromClass(operationClass);
  328. [self.registeredHTTPOperationClassNames removeObject:className];
  329. }
  330. #pragma mark -
  331. - (NSString *)defaultValueForHeader:(NSString *)header {
  332. return [self.defaultHeaders valueForKey:header];
  333. }
  334. - (void)setDefaultHeader:(NSString *)header value:(NSString *)value {
  335. [self.defaultHeaders setValue:value forKey:header];
  336. }
  337. - (void)setAuthorizationHeaderWithUsername:(NSString *)username password:(NSString *)password {
  338. NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password];
  339. [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)]];
  340. }
  341. - (void)setAuthorizationHeaderWithToken:(NSString *)token {
  342. [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Token token=\"%@\"", token]];
  343. }
  344. - (void)clearAuthorizationHeader {
  345. [self.defaultHeaders removeObjectForKey:@"Authorization"];
  346. }
  347. #pragma mark -
  348. - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
  349. path:(NSString *)path
  350. parameters:(NSDictionary *)parameters
  351. {
  352. NSParameterAssert(method);
  353. if (!path) {
  354. path = @"";
  355. }
  356. NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL];
  357. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
  358. [request setHTTPMethod:method];
  359. [request setAllHTTPHeaderFields:self.defaultHeaders];
  360. if (parameters) {
  361. if ([method isEqualToString:@"GET"] || [method isEqualToString:@"HEAD"] || [method isEqualToString:@"DELETE"]) {
  362. url = [NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:[path rangeOfString:@"?"].location == NSNotFound ? @"?%@" : @"&%@", AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding)]];
  363. [request setURL:url];
  364. } else {
  365. NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding));
  366. NSError *error = nil;
  367. switch (self.parameterEncoding) {
  368. case AFFormURLParameterEncoding:;
  369. [request setValue:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] forHTTPHeaderField:@"Content-Type"];
  370. [request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]];
  371. break;
  372. case AFJSONParameterEncoding:;
  373. [request setValue:[NSString stringWithFormat:@"application/json; charset=%@", charset] forHTTPHeaderField:@"Content-Type"];
  374. [request setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:0 error:&error]];
  375. break;
  376. case AFPropertyListParameterEncoding:;
  377. [request setValue:[NSString stringWithFormat:@"application/x-plist; charset=%@", charset] forHTTPHeaderField:@"Content-Type"];
  378. [request setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]];
  379. break;
  380. }
  381. if (error) {
  382. NSLog(@"%@ %@: %@", [self class], NSStringFromSelector(_cmd), error);
  383. }
  384. }
  385. }
  386. return request;
  387. }
  388. - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
  389. path:(NSString *)path
  390. parameters:(NSDictionary *)parameters
  391. constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
  392. {
  393. NSParameterAssert(method);
  394. NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]);
  395. NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil];
  396. __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding];
  397. if (parameters) {
  398. for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
  399. NSData *data = nil;
  400. if ([pair.value isKindOfClass:[NSData class]]) {
  401. data = pair.value;
  402. } else if ([pair.value isEqual:[NSNull null]]) {
  403. data = [NSData data];
  404. } else {
  405. data = [[pair.value description] dataUsingEncoding:self.stringEncoding];
  406. }
  407. if (data) {
  408. [formData appendPartWithFormData:data name:[pair.field description]];
  409. }
  410. }
  411. }
  412. if (block) {
  413. block(formData);
  414. }
  415. return [formData requestByFinalizingMultipartFormData];
  416. }
  417. - (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest
  418. success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
  419. failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
  420. {
  421. AFHTTPRequestOperation *operation = nil;
  422. for (NSString *className in self.registeredHTTPOperationClassNames) {
  423. Class operationClass = NSClassFromString(className);
  424. if (operationClass && [operationClass canProcessRequest:urlRequest]) {
  425. operation = [(AFHTTPRequestOperation *)[operationClass alloc] initWithRequest:urlRequest];
  426. break;
  427. }
  428. }
  429. if (!operation) {
  430. operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
  431. }
  432. [operation setCompletionBlockWithSuccess:success failure:failure];
  433. operation.credential = self.defaultCredential;
  434. #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_
  435. operation.SSLPinningMode = self.defaultSSLPinningMode;
  436. #endif
  437. operation.allowsInvalidSSLCertificate = self.allowsInvalidSSLCertificate;
  438. return operation;
  439. }
  440. #pragma mark -
  441. - (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation {
  442. [self.operationQueue addOperation:operation];
  443. }
  444. - (void)cancelAllHTTPOperationsWithMethod:(NSString *)method
  445. path:(NSString *)path
  446. {
  447. NSString *pathToBeMatched = [[[self requestWithMethod:(method ?: @"GET") path:path parameters:nil] URL] path];
  448. for (NSOperation *operation in [self.operationQueue operations]) {
  449. if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) {
  450. continue;
  451. }
  452. BOOL hasMatchingMethod = !method || [method isEqualToString:[[(AFHTTPRequestOperation *)operation request] HTTPMethod]];
  453. BOOL hasMatchingPath = [[[[(AFHTTPRequestOperation *)operation request] URL] path] isEqual:pathToBeMatched];
  454. if (hasMatchingMethod && hasMatchingPath) {
  455. [operation cancel];
  456. }
  457. }
  458. }
  459. - (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests
  460. progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
  461. completionBlock:(void (^)(NSArray *operations))completionBlock
  462. {
  463. NSMutableArray *mutableOperations = [NSMutableArray array];
  464. for (NSURLRequest *request in urlRequests) {
  465. AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:nil failure:nil];
  466. [mutableOperations addObject:operation];
  467. }
  468. [self enqueueBatchOfHTTPRequestOperations:mutableOperations progressBlock:progressBlock completionBlock:completionBlock];
  469. }
  470. - (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations
  471. progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
  472. completionBlock:(void (^)(NSArray *operations))completionBlock
  473. {
  474. __block dispatch_group_t dispatchGroup = dispatch_group_create();
  475. NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{
  476. dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
  477. if (completionBlock) {
  478. completionBlock(operations);
  479. }
  480. });
  481. #if !OS_OBJECT_USE_OBJC
  482. dispatch_release(dispatchGroup);
  483. #endif
  484. }];
  485. for (AFHTTPRequestOperation *operation in operations) {
  486. AFCompletionBlock originalCompletionBlock = [operation.completionBlock copy];
  487. __weak __typeof(&*operation)weakOperation = operation;
  488. operation.completionBlock = ^{
  489. __strong __typeof(&*weakOperation)strongOperation = weakOperation;
  490. dispatch_queue_t queue = strongOperation.successCallbackQueue ?: dispatch_get_main_queue();
  491. dispatch_group_async(dispatchGroup, queue, ^{
  492. if (originalCompletionBlock) {
  493. originalCompletionBlock();
  494. }
  495. NSInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) {
  496. return [op isFinished];
  497. }] count];
  498. if (progressBlock) {
  499. progressBlock(numberOfFinishedOperations, [operations count]);
  500. }
  501. dispatch_group_leave(dispatchGroup);
  502. });
  503. };
  504. dispatch_group_enter(dispatchGroup);
  505. [batchedOperation addDependency:operation];
  506. }
  507. [self.operationQueue addOperations:operations waitUntilFinished:NO];
  508. [self.operationQueue addOperation:batchedOperation];
  509. }
  510. #pragma mark -
  511. - (void)getPath:(NSString *)path
  512. parameters:(NSDictionary *)parameters
  513. success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
  514. failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
  515. {
  516. NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
  517. AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
  518. [self enqueueHTTPRequestOperation:operation];
  519. }
  520. - (void)postPath:(NSString *)path
  521. parameters:(NSDictionary *)parameters
  522. success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
  523. failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
  524. {
  525. NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters];
  526. AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
  527. [self enqueueHTTPRequestOperation:operation];
  528. }
  529. - (void)putPath:(NSString *)path
  530. parameters:(NSDictionary *)parameters
  531. success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
  532. failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
  533. {
  534. NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters];
  535. AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
  536. [self enqueueHTTPRequestOperation:operation];
  537. }
  538. - (void)deletePath:(NSString *)path
  539. parameters:(NSDictionary *)parameters
  540. success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
  541. failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
  542. {
  543. NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters];
  544. AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
  545. [self enqueueHTTPRequestOperation:operation];
  546. }
  547. - (void)patchPath:(NSString *)path
  548. parameters:(NSDictionary *)parameters
  549. success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
  550. failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
  551. {
  552. NSURLRequest *request = [self requestWithMethod:@"PATCH" path:path parameters:parameters];
  553. AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
  554. [self enqueueHTTPRequestOperation:operation];
  555. }
  556. #pragma mark - NSCoding
  557. - (id)initWithCoder:(NSCoder *)aDecoder {
  558. NSURL *baseURL = [aDecoder decodeObjectForKey:@"baseURL"];
  559. self = [self initWithBaseURL:baseURL];
  560. if (!self) {
  561. return nil;
  562. }
  563. self.stringEncoding = [aDecoder decodeIntegerForKey:@"stringEncoding"];
  564. self.parameterEncoding = [aDecoder decodeIntegerForKey:@"parameterEncoding"];
  565. self.registeredHTTPOperationClassNames = [aDecoder decodeObjectForKey:@"registeredHTTPOperationClassNames"];
  566. self.defaultHeaders = [aDecoder decodeObjectForKey:@"defaultHeaders"];
  567. return self;
  568. }
  569. - (void)encodeWithCoder:(NSCoder *)aCoder {
  570. [aCoder encodeObject:self.baseURL forKey:@"baseURL"];
  571. [aCoder encodeInteger:(NSInteger)self.stringEncoding forKey:@"stringEncoding"];
  572. [aCoder encodeInteger:self.parameterEncoding forKey:@"parameterEncoding"];
  573. [aCoder encodeObject:self.registeredHTTPOperationClassNames forKey:@"registeredHTTPOperationClassNames"];
  574. [aCoder encodeObject:self.defaultHeaders forKey:@"defaultHeaders"];
  575. }
  576. #pragma mark - NSCopying
  577. - (id)copyWithZone:(NSZone *)zone {
  578. AFHTTPClient *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL];
  579. HTTPClient.stringEncoding = self.stringEncoding;
  580. HTTPClient.parameterEncoding = self.parameterEncoding;
  581. HTTPClient.registeredHTTPOperationClassNames = [self.registeredHTTPOperationClassNames copyWithZone:zone];
  582. HTTPClient.defaultHeaders = [self.defaultHeaders copyWithZone:zone];
  583. #ifdef _SYSTEMCONFIGURATION_H
  584. HTTPClient.networkReachabilityStatusBlock = self.networkReachabilityStatusBlock;
  585. #endif
  586. return HTTPClient;
  587. }
  588. @end
  589. #pragma mark -
  590. static NSString * const kAFMultipartFormBoundary = @"Boundary+0xAbCdEfGbOuNdArY";
  591. static NSString * const kAFMultipartFormCRLF = @"\r\n";
  592. static NSInteger const kAFStreamToStreamBufferSize = 1024 * 1024; //1 meg default
  593. static inline NSString * AFMultipartFormInitialBoundary() {
  594. return [NSString stringWithFormat:@"--%@%@", kAFMultipartFormBoundary, kAFMultipartFormCRLF];
  595. }
  596. static inline NSString * AFMultipartFormEncapsulationBoundary() {
  597. return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, kAFMultipartFormBoundary, kAFMultipartFormCRLF];
  598. }
  599. static inline NSString * AFMultipartFormFinalBoundary() {
  600. return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, kAFMultipartFormBoundary, kAFMultipartFormCRLF];
  601. }
  602. static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
  603. #ifdef __UTTYPE__
  604. NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
  605. NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
  606. if (!contentType) {
  607. return @"application/octet-stream";
  608. } else {
  609. return contentType;
  610. }
  611. #else
  612. return @"application/octet-stream";
  613. #endif
  614. }
  615. NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16;
  616. NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
  617. @interface AFHTTPBodyPart : NSObject
  618. @property (nonatomic, assign) NSStringEncoding stringEncoding;
  619. @property (nonatomic, strong) NSDictionary *headers;
  620. @property (nonatomic, strong) id body;
  621. @property (nonatomic, assign) unsigned long long bodyContentLength;
  622. @property (nonatomic, strong) NSInputStream *inputStream;
  623. @property (nonatomic, assign) BOOL hasInitialBoundary;
  624. @property (nonatomic, assign) BOOL hasFinalBoundary;
  625. @property (nonatomic, readonly, getter = hasBytesAvailable) BOOL bytesAvailable;
  626. @property (nonatomic, readonly) unsigned long long contentLength;
  627. - (NSInteger)read:(uint8_t *)buffer
  628. maxLength:(NSUInteger)length;
  629. @end
  630. @interface AFMultipartBodyStreamProvider : NSObject
  631. @property (nonatomic, assign) NSUInteger bufferLength;
  632. @property (nonatomic, assign) NSTimeInterval delay;
  633. @property (nonatomic, strong) NSInputStream *inputStream;
  634. @property (nonatomic, readonly) unsigned long long contentLength;
  635. @property (nonatomic, readonly, getter = isEmpty) BOOL empty;
  636. - (id)initWithStringEncoding:(NSStringEncoding)encoding;
  637. - (void)setInitialAndFinalBoundaries;
  638. - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart;
  639. @end
  640. #pragma mark -
  641. @interface AFStreamingMultipartFormData ()
  642. @property (readwrite, nonatomic, copy) NSMutableURLRequest *request;
  643. @property (readwrite, nonatomic, strong) AFMultipartBodyStreamProvider *bodyStream;
  644. @property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
  645. @end
  646. @implementation AFStreamingMultipartFormData
  647. @synthesize request = _request;
  648. @synthesize bodyStream = _bodyStream;
  649. @synthesize stringEncoding = _stringEncoding;
  650. - (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest
  651. stringEncoding:(NSStringEncoding)encoding
  652. {
  653. self = [super init];
  654. if (!self) {
  655. return nil;
  656. }
  657. self.request = urlRequest;
  658. self.stringEncoding = encoding;
  659. self.bodyStream = [[AFMultipartBodyStreamProvider alloc] initWithStringEncoding:encoding];
  660. return self;
  661. }
  662. - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
  663. name:(NSString *)name
  664. error:(NSError * __autoreleasing *)error
  665. {
  666. NSParameterAssert(fileURL);
  667. NSParameterAssert(name);
  668. NSString *fileName = [fileURL lastPathComponent];
  669. NSString *mimeType = AFContentTypeForPathExtension([fileURL pathExtension]);
  670. return [self appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error];
  671. }
  672. - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
  673. name:(NSString *)name
  674. fileName:(NSString *)fileName
  675. mimeType:(NSString *)mimeType
  676. error:(NSError * __autoreleasing *)error
  677. {
  678. NSParameterAssert(fileURL);
  679. NSParameterAssert(name);
  680. NSParameterAssert(fileName);
  681. NSParameterAssert(mimeType);
  682. if (![fileURL isFileURL]) {
  683. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil) forKey:NSLocalizedFailureReasonErrorKey];
  684. if (error != NULL) {
  685. *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo];
  686. }
  687. return NO;
  688. } else if ([fileURL checkResourceIsReachableAndReturnError:error] == NO) {
  689. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"File URL not reachable.", @"AFNetworking", nil) forKey:NSLocalizedFailureReasonErrorKey];
  690. if (error != NULL) {
  691. *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo];
  692. }
  693. return NO;
  694. }
  695. NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
  696. [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
  697. [mutableHeaders setValue:mimeType forKey:@"Content-Type"];
  698. AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
  699. bodyPart.stringEncoding = self.stringEncoding;
  700. bodyPart.headers = mutableHeaders;
  701. bodyPart.body = fileURL;
  702. NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:nil];
  703. bodyPart.bodyContentLength = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue];
  704. [self.bodyStream appendHTTPBodyPart:bodyPart];
  705. return YES;
  706. }
  707. - (void)appendPartWithInputStream:(NSInputStream *)inputStream
  708. name:(NSString *)name
  709. fileName:(NSString *)fileName
  710. length:(unsigned long long)length
  711. mimeType:(NSString *)mimeType
  712. {
  713. NSParameterAssert(name);
  714. NSParameterAssert(fileName);
  715. NSParameterAssert(mimeType);
  716. NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
  717. [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
  718. [mutableHeaders setValue:mimeType forKey:@"Content-Type"];
  719. AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
  720. bodyPart.stringEncoding = self.stringEncoding;
  721. bodyPart.headers = mutableHeaders;
  722. bodyPart.body = inputStream;
  723. bodyPart.bodyContentLength = length;
  724. [self.bodyStream appendHTTPBodyPart:bodyPart];
  725. }
  726. - (void)appendPartWithFileData:(NSData *)data
  727. name:(NSString *)name
  728. fileName:(NSString *)fileName
  729. mimeType:(NSString *)mimeType
  730. {
  731. NSParameterAssert(name);
  732. NSParameterAssert(fileName);
  733. NSParameterAssert(mimeType);
  734. NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
  735. [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
  736. [mutableHeaders setValue:mimeType forKey:@"Content-Type"];
  737. [self appendPartWithHeaders:mutableHeaders body:data];
  738. }
  739. - (void)appendPartWithFormData:(NSData *)data
  740. name:(NSString *)name
  741. {
  742. NSParameterAssert(name);
  743. NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
  744. [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"];
  745. [self appendPartWithHeaders:mutableHeaders body:data];
  746. }
  747. - (void)appendPartWithHeaders:(NSDictionary *)headers
  748. body:(NSData *)body
  749. {
  750. NSParameterAssert(body);
  751. AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
  752. bodyPart.stringEncoding = self.stringEncoding;
  753. bodyPart.headers = headers;
  754. bodyPart.bodyContentLength = [body length];
  755. bodyPart.body = body;
  756. [self.bodyStream appendHTTPBodyPart:bodyPart];
  757. }
  758. - (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
  759. delay:(NSTimeInterval)delay
  760. {
  761. self.bodyStream.bufferLength = numberOfBytes;
  762. self.bodyStream.delay = delay;
  763. }
  764. - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
  765. if ([self.bodyStream isEmpty]) {
  766. return self.request;
  767. }
  768. // Reset the initial and final boundaries to ensure correct Content-Length
  769. [self.bodyStream setInitialAndFinalBoundaries];
  770. [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", kAFMultipartFormBoundary] forHTTPHeaderField:@"Content-Type"];
  771. [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];
  772. [self.request setHTTPBodyStream:self.bodyStream.inputStream];
  773. return self.request;
  774. }
  775. @end
  776. #pragma mark -
  777. @interface AFMultipartBodyStreamProvider () <NSCopying, NSStreamDelegate>
  778. @property (nonatomic, assign) NSStringEncoding stringEncoding;
  779. @property (nonatomic, strong) NSMutableArray *HTTPBodyParts;
  780. @property (nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator;
  781. @property (nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart;
  782. @property (nonatomic, strong) NSOutputStream *outputStream;
  783. @property (nonatomic, strong) NSMutableData *buffer;
  784. @end
  785. static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
  786. @implementation AFMultipartBodyStreamProvider {
  787. @private
  788. // Workaround for stream delegates being weakly referenced, but otherwise unowned
  789. __strong id _self;
  790. }
  791. @synthesize stringEncoding = _stringEncoding;
  792. @synthesize HTTPBodyParts = _HTTPBodyParts;
  793. @synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator;
  794. @synthesize currentHTTPBodyPart = _currentHTTPBodyPart;
  795. @synthesize inputStream = _inputStream;
  796. @synthesize outputStream = _outputStream;
  797. @synthesize buffer = _buffer;
  798. @synthesize bufferLength = _numberOfBytesInPacket;
  799. @synthesize delay = _delay;
  800. - (id)initWithStringEncoding:(NSStringEncoding)encoding {
  801. self = [super init];
  802. if (!self) {
  803. return nil;
  804. }
  805. self.stringEncoding = encoding;
  806. self.HTTPBodyParts = [NSMutableArray array];
  807. self.bufferLength = NSIntegerMax;
  808. self.buffer = [[NSMutableData alloc] init];
  809. self.bufferLength = AFMultipartBodyStreamProviderDefaultBufferLength;
  810. return self;
  811. }
  812. - (void)dealloc {
  813. _outputStream.delegate = nil;
  814. }
  815. - (void)setInitialAndFinalBoundaries {
  816. if ([self.HTTPBodyParts count] > 0) {
  817. for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
  818. bodyPart.hasInitialBoundary = NO;
  819. bodyPart.hasFinalBoundary = NO;
  820. }
  821. [[self.HTTPBodyParts objectAtIndex:0] setHasInitialBoundary:YES];
  822. [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES];
  823. }
  824. }
  825. - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart {
  826. [self.HTTPBodyParts addObject:bodyPart];
  827. }
  828. - (NSInputStream *)inputStream {
  829. if (_inputStream == nil) {
  830. CFReadStreamRef readStream;
  831. CFWriteStreamRef writeStream;
  832. CFStreamCreateBoundPair(NULL, &readStream, &writeStream, self.bufferLength);
  833. _inputStream = CFBridgingRelease(readStream);
  834. _outputStream = CFBridgingRelease(writeStream);
  835. _outputStream.delegate = self;
  836. if ([NSThread isMainThread]) {
  837. [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  838. } else {
  839. dispatch_sync(dispatch_get_main_queue(), ^{
  840. [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  841. });
  842. }
  843. [_outputStream open];
  844. _self = self;
  845. }
  846. return _inputStream;
  847. }
  848. - (BOOL)isEmpty {
  849. return [self.HTTPBodyParts count] == 0;
  850. }
  851. #pragma mark - NSStreamDelegate
  852. - (void)stream:(NSStream *)stream
  853. handleEvent:(NSStreamEvent)eventCode
  854. {
  855. if (eventCode & NSStreamEventHasSpaceAvailable) {
  856. [self handleOutputStreamSpaceAvailable];
  857. }
  858. }
  859. - (void)handleOutputStreamSpaceAvailable {
  860. while ([_outputStream hasSpaceAvailable]) {
  861. if ([_buffer length] > 0) {
  862. NSInteger numberOfBytesWritten = [_outputStream write:[_buffer bytes] maxLength:[_buffer length]];
  863. if (numberOfBytesWritten < 0) {
  864. [self close];
  865. return;
  866. }
  867. [_buffer replaceBytesInRange:NSMakeRange(0, numberOfBytesWritten) withBytes:NULL length:0];
  868. } else {
  869. if (!self.currentHTTPBodyPart) {
  870. if (!self.HTTPBodyPartEnumerator) {
  871. self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
  872. }
  873. self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject];
  874. }
  875. if (!self.currentHTTPBodyPart) {
  876. [self close];
  877. return;
  878. }
  879. [_buffer setLength:self.bufferLength];
  880. NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:[_buffer mutableBytes] maxLength:[_buffer length]];
  881. if (numberOfBytesRead < 0) {
  882. [self close];
  883. return;
  884. }
  885. [_buffer setLength:numberOfBytesRead];
  886. if (numberOfBytesRead == 0) {
  887. self.currentHTTPBodyPart = nil;
  888. }
  889. if (self.delay > 0.0f) {
  890. [NSThread sleepForTimeInterval:self.delay];
  891. }
  892. }
  893. }
  894. }
  895. - (void)close {
  896. [_outputStream close];
  897. _outputStream.delegate = nil;
  898. _self = nil;
  899. }
  900. - (unsigned long long)contentLength {
  901. unsigned long long length = 0;
  902. for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
  903. length += [bodyPart contentLength];
  904. }
  905. return length;
  906. }
  907. #pragma mark - NSCopying
  908. - (id)copyWithZone:(NSZone *)zone {
  909. AFMultipartBodyStreamProvider *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
  910. for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
  911. [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]];
  912. }
  913. [bodyStreamCopy setInitialAndFinalBoundaries];
  914. return bodyStreamCopy;
  915. }
  916. @end
  917. #pragma mark -
  918. typedef enum {
  919. AFInitialPhase = 0,
  920. AFEncapsulationBoundaryPhase = 1,
  921. AFHeaderPhase = 2,
  922. AFBodyPhase = 3,
  923. AFFinalBoundaryPhase = 4,
  924. AFCompletedPhase = 5,
  925. } AFHTTPBodyPartReadPhase;
  926. @interface AFHTTPBodyPart () <NSCopying> {
  927. AFHTTPBodyPartReadPhase _phase;
  928. NSInputStream *_inputStream;
  929. unsigned long long _phaseReadOffset;
  930. }
  931. - (BOOL)transitionToNextPhase;
  932. - (NSInteger)readData:(NSData *)data
  933. intoBuffer:(uint8_t *)buffer
  934. maxLength:(NSUInteger)length;
  935. @end
  936. @implementation AFHTTPBodyPart
  937. @synthesize stringEncoding = _stringEncoding;
  938. @synthesize headers = _headers;
  939. @synthesize body = _body;
  940. @synthesize bodyContentLength = _bodyContentLength;
  941. @synthesize hasInitialBoundary = _hasInitialBoundary;
  942. @synthesize hasFinalBoundary = _hasFinalBoundary;
  943. - (id)init {
  944. self = [super init];
  945. if (!self) {
  946. return nil;
  947. }
  948. [self transitionToNextPhase];
  949. return self;
  950. }
  951. - (void)dealloc {
  952. if (_inputStream) {
  953. [_inputStream close];
  954. _inputStream = nil;
  955. }
  956. }
  957. - (NSInputStream *)inputStream {
  958. if (!_inputStream) {
  959. if ([self.body isKindOfClass:[NSData class]]) {
  960. _inputStream = [NSInputStream inputStreamWithData:self.body];
  961. } else if ([self.body isKindOfClass:[NSURL class]]) {
  962. _inputStream = [NSInputStream inputStreamWithURL:self.body];
  963. } else if ([self.body isKindOfClass:[NSInputStream class]]) {
  964. _inputStream = self.body;
  965. }
  966. }
  967. return _inputStream;
  968. }
  969. - (NSString *)stringForHeaders {
  970. NSMutableString *headerString = [NSMutableString string];
  971. for (NSString *field in [self.headers allKeys]) {
  972. [headerString appendString:[NSString stringWithFormat:@"%@: %@%@", field, [self.headers valueForKey:field], kAFMultipartFormCRLF]];
  973. }
  974. [headerString appendString:kAFMultipartFormCRLF];
  975. return [NSString stringWithString:headerString];
  976. }
  977. - (unsigned long long)contentLength {
  978. unsigned long long length = 0;
  979. NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary() : AFMultipartFormEncapsulationBoundary()) dataUsingEncoding:self.stringEncoding];
  980. length += [encapsulationBoundaryData length];
  981. NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding];
  982. length += [headersData length];
  983. length += _bodyContentLength;
  984. NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary() dataUsingEncoding:self.stringEncoding] : [NSData data]);
  985. length += [closingBoundaryData length];
  986. return length;
  987. }
  988. - (BOOL)hasBytesAvailable {
  989. // Allows `read:maxLength:` to be called again if `AFMultipartFormFinalBoundary` doesn't fit into the available buffer
  990. if (_phase == AFFinalBoundaryPhase) {
  991. return YES;
  992. }
  993. #pragma clang diagnostic push
  994. #pragma clang diagnostic ignored "-Wcovered-switch-default"
  995. switch (self.inputStream.streamStatus) {
  996. case NSStreamStatusNotOpen:
  997. case NSStreamStatusOpening:
  998. case NSStreamStatusOpen:
  999. case NSStreamStatusReading:
  1000. case NSStreamStatusWriting:
  1001. return YES;
  1002. case NSStreamStatusAtEnd:
  1003. case NSStreamStatusClosed:
  1004. case NSStreamStatusError:
  1005. default:
  1006. return NO;
  1007. }
  1008. #pragma clang diagnostic pop
  1009. }
  1010. - (NSInteger)read:(uint8_t *)buffer
  1011. maxLength:(NSUInteger)length
  1012. {
  1013. NSInteger bytesRead = 0;
  1014. if (_phase == AFEncapsulationBoundaryPhase) {
  1015. NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary() : AFMultipartFormEncapsulationBoundary()) dataUsingEncoding:self.stringEncoding];
  1016. bytesRead += [self readData:encapsulationBoundaryData intoBuf