YTKNetworkPrivate.m 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. //
  2. // YTKNetworkPrivate.m
  3. //
  4. // Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. #import <CommonCrypto/CommonDigest.h>
  24. #import "YTKNetworkPrivate.h"
  25. #if __has_include(<AFNetworking/AFURLRequestSerialization.h>)
  26. #import <AFNetworking/AFURLRequestSerialization.h>
  27. #else
  28. #import <AFNetworking/AFURLRequestSerialization.h>
  29. #endif
  30. void YTKLog(NSString *format, ...) {
  31. #ifdef DEBUG
  32. if (![YTKNetworkConfig sharedConfig].debugLogEnabled) {
  33. return;
  34. }
  35. va_list argptr;
  36. va_start(argptr, format);
  37. NSLogv(format, argptr);
  38. va_end(argptr);
  39. #endif
  40. }
  41. @implementation YTKNetworkUtils
  42. + (BOOL)validateJSON:(id)json withValidator:(id)jsonValidator {
  43. if ([json isKindOfClass:[NSDictionary class]] &&
  44. [jsonValidator isKindOfClass:[NSDictionary class]]) {
  45. NSDictionary * dict = json;
  46. NSDictionary * validator = jsonValidator;
  47. BOOL result = YES;
  48. NSEnumerator * enumerator = [validator keyEnumerator];
  49. NSString * key;
  50. while ((key = [enumerator nextObject]) != nil) {
  51. id value = dict[key];
  52. id format = validator[key];
  53. if ([value isKindOfClass:[NSDictionary class]]
  54. || [value isKindOfClass:[NSArray class]]) {
  55. result = [self validateJSON:value withValidator:format];
  56. if (!result) {
  57. break;
  58. }
  59. } else {
  60. if ([value isKindOfClass:format] == NO &&
  61. [value isKindOfClass:[NSNull class]] == NO) {
  62. result = NO;
  63. break;
  64. }
  65. }
  66. }
  67. return result;
  68. } else if ([json isKindOfClass:[NSArray class]] &&
  69. [jsonValidator isKindOfClass:[NSArray class]]) {
  70. NSArray * validatorArray = (NSArray *)jsonValidator;
  71. if (validatorArray.count > 0) {
  72. NSArray * array = json;
  73. NSDictionary * validator = jsonValidator[0];
  74. for (id item in array) {
  75. BOOL result = [self validateJSON:item withValidator:validator];
  76. if (!result) {
  77. return NO;
  78. }
  79. }
  80. }
  81. return YES;
  82. } else if ([json isKindOfClass:jsonValidator]) {
  83. return YES;
  84. } else {
  85. return NO;
  86. }
  87. }
  88. + (void)addDoNotBackupAttribute:(NSString *)path {
  89. NSURL *url = [NSURL fileURLWithPath:path];
  90. NSError *error = nil;
  91. [url setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
  92. if (error) {
  93. YTKLog(@"error to set do not backup attribute, error = %@", error);
  94. }
  95. }
  96. + (NSString *)md5StringFromString:(NSString *)string {
  97. NSParameterAssert(string != nil && [string length] > 0);
  98. const char *value = [string UTF8String];
  99. unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
  100. CC_MD5(value, (CC_LONG)strlen(value), outputBuffer);
  101. NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  102. for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
  103. [outputString appendFormat:@"%02x", outputBuffer[count]];
  104. }
  105. return outputString;
  106. }
  107. + (NSString *)appVersionString {
  108. return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
  109. }
  110. + (NSStringEncoding)stringEncodingWithRequest:(YTKBaseRequest *)request {
  111. // From AFNetworking 2.6.3
  112. NSStringEncoding stringEncoding = NSUTF8StringEncoding;
  113. NSString *encodingName = [request.response.textEncodingName copy];
  114. if (encodingName) {
  115. CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName);
  116. if (encoding != kCFStringEncodingInvalidId) {
  117. stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);
  118. }
  119. }
  120. return stringEncoding;
  121. }
  122. + (BOOL)validateResumeData:(NSData *)data {
  123. // From http://stackoverflow.com/a/22137510/3562486
  124. if (!data || [data length] < 1) return NO;
  125. NSError *error;
  126. NSDictionary *resumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
  127. if (!resumeDictionary || error) return NO;
  128. // Before iOS 9 & Mac OS X 10.11
  129. #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < 90000)\
  130. || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED < 101100)
  131. NSString *localFilePath = [resumeDictionary objectForKey:@"NSURLSessionResumeInfoLocalPath"];
  132. if ([localFilePath length] < 1) return NO;
  133. return [[NSFileManager defaultManager] fileExistsAtPath:localFilePath];
  134. #endif
  135. // After iOS 9 we can not actually detects if the cache file exists. This plist file has a somehow
  136. // complicated structure. Besides, the plist structure is different between iOS 9 and iOS 10.
  137. // We can only assume that the plist being successfully parsed means the resume data is valid.
  138. return YES;
  139. }
  140. @end
  141. @implementation YTKBaseRequest (RequestAccessory)
  142. - (void)toggleAccessoriesWillStartCallBack {
  143. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  144. if ([accessory respondsToSelector:@selector(requestWillStart:)]) {
  145. [accessory requestWillStart:self];
  146. }
  147. }
  148. }
  149. - (void)toggleAccessoriesWillStopCallBack {
  150. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  151. if ([accessory respondsToSelector:@selector(requestWillStop:)]) {
  152. [accessory requestWillStop:self];
  153. }
  154. }
  155. }
  156. - (void)toggleAccessoriesDidStopCallBack {
  157. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  158. if ([accessory respondsToSelector:@selector(requestDidStop:)]) {
  159. [accessory requestDidStop:self];
  160. }
  161. }
  162. }
  163. @end
  164. @implementation YTKBatchRequest (RequestAccessory)
  165. - (void)toggleAccessoriesWillStartCallBack {
  166. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  167. if ([accessory respondsToSelector:@selector(requestWillStart:)]) {
  168. [accessory requestWillStart:self];
  169. }
  170. }
  171. }
  172. - (void)toggleAccessoriesWillStopCallBack {
  173. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  174. if ([accessory respondsToSelector:@selector(requestWillStop:)]) {
  175. [accessory requestWillStop:self];
  176. }
  177. }
  178. }
  179. - (void)toggleAccessoriesDidStopCallBack {
  180. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  181. if ([accessory respondsToSelector:@selector(requestDidStop:)]) {
  182. [accessory requestDidStop:self];
  183. }
  184. }
  185. }
  186. @end
  187. @implementation YTKChainRequest (RequestAccessory)
  188. - (void)toggleAccessoriesWillStartCallBack {
  189. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  190. if ([accessory respondsToSelector:@selector(requestWillStart:)]) {
  191. [accessory requestWillStart:self];
  192. }
  193. }
  194. }
  195. - (void)toggleAccessoriesWillStopCallBack {
  196. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  197. if ([accessory respondsToSelector:@selector(requestWillStop:)]) {
  198. [accessory requestWillStop:self];
  199. }
  200. }
  201. }
  202. - (void)toggleAccessoriesDidStopCallBack {
  203. for (id<YTKRequestAccessory> accessory in self.requestAccessories) {
  204. if ([accessory respondsToSelector:@selector(requestDidStop:)]) {
  205. [accessory requestDidStop:self];
  206. }
  207. }
  208. }
  209. @end