QNResponseInfo.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. //
  2. // QNResponseInfo.m
  3. // QiniuSDK
  4. //
  5. // Created by bailong on 14/10/2.
  6. // Copyright (c) 2014年 Qiniu. All rights reserved.
  7. //
  8. #import "QNErrorCode.h"
  9. #import "QNResponseInfo.h"
  10. #import "QNUserAgent.h"
  11. #import "QNUtils.h"
  12. static NSString *kQNErrorDomain = @"qiniu.com";
  13. @interface QNResponseInfo ()
  14. @property (assign) int statusCode;
  15. @property (nonatomic, copy) NSString *message;
  16. @property (nonatomic, copy) NSString *reqId;
  17. @property (nonatomic, copy) NSString *xlog;
  18. @property (nonatomic, copy) NSString *xvia;
  19. @property (nonatomic, copy) NSError *error;
  20. @property (nonatomic, copy) NSString *host;
  21. @property (nonatomic, copy) NSString *id;
  22. @property (assign) UInt64 timeStamp;
  23. @end
  24. @implementation QNResponseInfo
  25. + (instancetype)successResponse{
  26. QNResponseInfo *responseInfo = [[QNResponseInfo alloc] init];
  27. responseInfo.statusCode = 200;
  28. responseInfo.message = @"inter:ok";
  29. responseInfo.xlog = @"inter:xlog";
  30. responseInfo.reqId = @"inter:reqid";
  31. return responseInfo;
  32. }
  33. + (instancetype)cancelResponse {
  34. return [QNResponseInfo errorResponseInfo:kQNRequestCancelled
  35. errorDesc:@"cancelled by user"];
  36. }
  37. + (instancetype)responseInfoWithNetworkError:(NSString *)desc{
  38. return [QNResponseInfo errorResponseInfo:kQNNetworkError
  39. errorDesc:desc];
  40. }
  41. + (instancetype)responseInfoWithInvalidArgument:(NSString *)desc{
  42. return [QNResponseInfo errorResponseInfo:kQNInvalidArgument
  43. errorDesc:desc];
  44. }
  45. + (instancetype)responseInfoWithInvalidToken:(NSString *)desc {
  46. return [QNResponseInfo errorResponseInfo:kQNInvalidToken
  47. errorDesc:desc];
  48. }
  49. + (instancetype)responseInfoWithFileError:(NSError *)error {
  50. return [QNResponseInfo errorResponseInfo:kQNFileError
  51. errorDesc:nil
  52. error:error];
  53. }
  54. + (instancetype)responseInfoOfZeroData:(NSString *)path {
  55. NSString *desc;
  56. if (path == nil) {
  57. desc = @"data size is 0";
  58. } else {
  59. desc = [[NSString alloc] initWithFormat:@"file %@ size is 0", path];
  60. }
  61. return [QNResponseInfo errorResponseInfo:kQNZeroDataSize
  62. errorDesc:desc];
  63. }
  64. + (instancetype)responseInfoWithLocalIOError:(NSString *)desc{
  65. return [QNResponseInfo errorResponseInfo:kQNLocalIOError
  66. errorDesc:desc];
  67. }
  68. + (instancetype)responseInfoWithMaliciousResponseError:(NSString *)desc{
  69. return [QNResponseInfo errorResponseInfo:kQNMaliciousResponseError
  70. errorDesc:desc];
  71. }
  72. + (instancetype)responseInfoWithNoUsableHostError:(NSString *)desc{
  73. return [QNResponseInfo errorResponseInfo:kQNSDKInteriorError
  74. errorDesc:desc];
  75. }
  76. + (instancetype)responseInfoWithSDKInteriorError:(NSString *)desc{
  77. return [QNResponseInfo errorResponseInfo:kQNSDKInteriorError
  78. errorDesc:desc];
  79. }
  80. + (instancetype)responseInfoWithUnexpectedSysCallError:(NSString *)desc{
  81. return [QNResponseInfo errorResponseInfo:kQNUnexpectedSysCallError
  82. errorDesc:desc];
  83. }
  84. + (instancetype)errorResponseInfo:(int)errorType
  85. errorDesc:(NSString *)errorDesc{
  86. return [self errorResponseInfo:errorType errorDesc:errorDesc error:nil];
  87. }
  88. + (instancetype)errorResponseInfo:(int)errorType
  89. errorDesc:(NSString *)errorDesc
  90. error:(NSError *)error{
  91. QNResponseInfo *response = [[QNResponseInfo alloc] init];
  92. response.statusCode = errorType;
  93. response.message = errorDesc;
  94. if (error) {
  95. response.error = error;
  96. } else {
  97. NSError *error = [[NSError alloc] initWithDomain:kQNErrorDomain
  98. code:errorType
  99. userInfo:@{ @"error" : response.message ?: @"error" }];
  100. response.error = error;
  101. }
  102. return response;
  103. }
  104. - (instancetype)initWithResponseInfoHost:(NSString *)host
  105. response:(NSHTTPURLResponse *)response
  106. body:(NSData *)body
  107. error:(NSError *)error {
  108. self = [super init];
  109. if (self) {
  110. _host = host;
  111. _timeStamp = [[NSDate date] timeIntervalSince1970];
  112. if (response) {
  113. int statusCode = (int)[response statusCode];
  114. NSDictionary *headers = [response allHeaderFields];
  115. _responseHeader = [headers copy];
  116. _statusCode = statusCode;
  117. _reqId = headers[@"x-reqid"];
  118. _xlog = headers[@"x-log"];
  119. _xvia = headers[@"x-via"] ?: headers[@"x-px"] ?: headers[@"fw-via"];
  120. if (_statusCode == 200 && _reqId == nil && _xlog == nil) {
  121. _statusCode = kQNMaliciousResponseError;
  122. _message = @"this is a malicious response";
  123. _responseDictionary = nil;
  124. _error = [[NSError alloc] initWithDomain:kQNErrorDomain code:_statusCode userInfo:@{@"error" : _message}];
  125. } else if (error) {
  126. _error = error;
  127. _statusCode = (int)error.code;
  128. _message = [NSString stringWithFormat:@"%@", error];
  129. _responseDictionary = nil;
  130. } else {
  131. NSMutableDictionary *errorUserInfo = [@{@"errorHost" : host ?: @""} mutableCopy];
  132. if (!body) {
  133. _message = @"no response data";
  134. _error = nil;
  135. _responseDictionary = nil;
  136. } else {
  137. NSError *tmp = nil;
  138. NSDictionary *responseInfo = nil;
  139. responseInfo = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
  140. if (tmp){
  141. _message = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
  142. _error = nil;
  143. _responseDictionary = nil;
  144. } else if (statusCode >= 200 && statusCode < 300) {
  145. _error = nil;
  146. _message = @"ok";
  147. _responseDictionary = responseInfo;
  148. } else {
  149. NSString *errorString = responseInfo[@"error"];
  150. if (errorString) {
  151. [errorUserInfo setDictionary:@{@"error" : errorString}];
  152. _message = errorString;
  153. _error = [[NSError alloc] initWithDomain:kQNErrorDomain code:statusCode userInfo:errorUserInfo];
  154. } else {
  155. _message = errorString;
  156. _error = nil;
  157. }
  158. _responseDictionary = responseInfo;
  159. }
  160. }
  161. }
  162. } else if (error) {
  163. _error = error;
  164. _statusCode = (int)error.code;
  165. _message = [NSString stringWithFormat:@"%@", error];
  166. _responseDictionary = nil;
  167. } else {
  168. _statusCode = kQNUnexpectedSysCallError;
  169. _message = @"no response";
  170. }
  171. }
  172. return self;
  173. }
  174. - (BOOL)isCancelled {
  175. return _statusCode == kQNRequestCancelled || _statusCode == -999;
  176. }
  177. - (BOOL)isTlsError{
  178. if (_statusCode == NSURLErrorServerCertificateHasBadDate
  179. || _statusCode == NSURLErrorClientCertificateRejected
  180. || _statusCode == NSURLErrorClientCertificateRequired) {
  181. return true;
  182. } else {
  183. return false;
  184. }
  185. }
  186. - (BOOL)isQiniu {
  187. // reqId is nill means the server is not qiniu
  188. return ![self isNotQiniu];
  189. }
  190. - (BOOL)isNotQiniu {
  191. // reqId is nill means the server is not qiniu
  192. return (_statusCode == kQNMaliciousResponseError) || (_statusCode > 0 && _reqId == nil && _xlog == nil);
  193. }
  194. - (BOOL)isOK {
  195. return (_statusCode >= 200 && _statusCode < 300) && _error == nil && (_reqId != nil || _xlog != nil);
  196. }
  197. - (BOOL)couldRetry {
  198. if (![self isQiniu]) {
  199. return YES;
  200. }
  201. if ([self isCtxExpiedError]) {
  202. return YES;
  203. }
  204. if (self.isCancelled
  205. || _statusCode == 100
  206. || (_statusCode > 300 && _statusCode < 400)
  207. || (_statusCode > 400 && _statusCode < 500 && _statusCode != 406)
  208. || _statusCode == 501 || _statusCode == 573
  209. || _statusCode == 608 || _statusCode == 612 || _statusCode == 614 || _statusCode == 616
  210. || _statusCode == 619 || _statusCode == 630 || _statusCode == 631 || _statusCode == 640
  211. || (_statusCode != kQNLocalIOError && _statusCode != kQNUnexpectedSysCallError && _statusCode < -1 && _statusCode > -1000)) {
  212. return NO;
  213. } else {
  214. return YES;
  215. }
  216. }
  217. - (BOOL)couldRegionRetry{
  218. if (![self isQiniu]) {
  219. return YES;
  220. }
  221. if (self.isCancelled
  222. || _statusCode == 100
  223. || (_statusCode > 300 && _statusCode < 500 && _statusCode != 406)
  224. || _statusCode == 501 || _statusCode == 573 || _statusCode == 579
  225. || _statusCode == 608 || _statusCode == 612 || _statusCode == 614 || _statusCode == 616
  226. || _statusCode == 619 || _statusCode == 630 || _statusCode == 631 || _statusCode == 640
  227. || _statusCode == 701
  228. || (_statusCode != kQNLocalIOError && _statusCode != kQNUnexpectedSysCallError && _statusCode < -1 && _statusCode > -1000)) {
  229. return NO;
  230. } else {
  231. return YES;
  232. }
  233. }
  234. - (BOOL)couldHostRetry{
  235. if (![self isQiniu]) {
  236. return YES;
  237. }
  238. if (self.isCancelled
  239. || _statusCode == 100
  240. || (_statusCode > 300 && _statusCode < 500 && _statusCode != 406)
  241. || _statusCode == 501 || _statusCode == 502 || _statusCode == 503
  242. || _statusCode == 571 || _statusCode == 573 || _statusCode == 579 || _statusCode == 599
  243. || _statusCode == 608 || _statusCode == 612 || _statusCode == 614 || _statusCode == 616
  244. || _statusCode == 619 || _statusCode == 630 || _statusCode == 631 || _statusCode == 640
  245. || _statusCode == 701
  246. || (_statusCode != kQNLocalIOError && _statusCode != kQNUnexpectedSysCallError && _statusCode < -1 && _statusCode > -1000)) {
  247. return NO;
  248. } else {
  249. return YES;
  250. }
  251. }
  252. - (BOOL)canConnectToHost{
  253. if (_statusCode > 99 || self.isCancelled) {
  254. return true;
  255. } else {
  256. return false;
  257. }
  258. }
  259. - (BOOL)isHostUnavailable{
  260. // 基本不可恢复,注:会影响下次请求,范围太大可能会造成大量的timeout
  261. if (_statusCode == 502 || _statusCode == 503 || _statusCode == 504 || _statusCode == 599) {
  262. return true;
  263. } else {
  264. return false;
  265. }
  266. }
  267. - (BOOL)isCtxExpiedError {
  268. return _statusCode == 701 || (_statusCode == 612 && [_message containsString:@"no such uploadId"]);
  269. }
  270. - (BOOL)isConnectionBroken {
  271. return _statusCode == kQNNetworkError || _statusCode == NSURLErrorNotConnectedToInternet;
  272. }
  273. - (NSString *)description {
  274. return [NSString stringWithFormat:@"<%@= id: %@, ver: %@, status: %d, requestId: %@, xlog: %@, xvia: %@, host: %@ time: %llu error: %@>", NSStringFromClass([self class]), _id, [QNUtils sdkVersion], _statusCode, _reqId, _xlog, _xvia, _host, _timeStamp, _error];
  275. }
  276. @end