QNHttpRegionRequest.m 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. //
  2. // QNHttpRequest.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2020/4/29.
  6. // Copyright © 2020 Qiniu. All rights reserved.
  7. //
  8. #import "QNDefine.h"
  9. #import "QNLogUtil.h"
  10. #import "QNAsyncRun.h"
  11. #import "QNDnsPrefetch.h"
  12. #import "QNUploadRequestState.h"
  13. #import "QNHttpRegionRequest.h"
  14. #import "QNConfiguration.h"
  15. #import "QNUploadOption.h"
  16. #import "NSURLRequest+QNRequest.h"
  17. #import "QNUploadRequestMetrics.h"
  18. #import "QNResponseInfo.h"
  19. @interface QNHttpRegionRequest()
  20. @property(nonatomic, strong)QNConfiguration *config;
  21. @property(nonatomic, strong)QNUploadOption *uploadOption;
  22. @property(nonatomic, strong)QNUploadRequestInfo *requestInfo;
  23. @property(nonatomic, strong)QNUploadRequestState *requestState;
  24. @property(nonatomic, strong)QNUploadRegionRequestMetrics *requestMetrics;
  25. @property(nonatomic, strong)QNHttpSingleRequest *singleRequest;
  26. @property(nonatomic, strong)id <QNUploadServer> currentServer;
  27. @property(nonatomic, strong)id <QNUploadRegion> region;
  28. @end
  29. @implementation QNHttpRegionRequest
  30. - (instancetype)initWithConfig:(QNConfiguration *)config
  31. uploadOption:(QNUploadOption *)uploadOption
  32. token:(QNUpToken *)token
  33. region:(id <QNUploadRegion>)region
  34. requestInfo:(QNUploadRequestInfo *)requestInfo
  35. requestState:(QNUploadRequestState *)requestState {
  36. if (self = [super init]) {
  37. _config = config;
  38. _uploadOption = uploadOption;
  39. _region = region;
  40. _requestInfo = requestInfo;
  41. _requestState = requestState;
  42. _singleRequest = [[QNHttpSingleRequest alloc] initWithConfig:config
  43. uploadOption:uploadOption
  44. token:token
  45. requestInfo:requestInfo
  46. requestState:requestState];
  47. }
  48. return self;
  49. }
  50. - (void)get:(NSString *)action
  51. headers:(NSDictionary *)headers
  52. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  53. complete:(QNRegionRequestCompleteHandler)complete{
  54. self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
  55. [self.requestMetrics start];
  56. [self performRequest:[self getNextServer:nil]
  57. action:action
  58. headers:headers
  59. method:@"GET"
  60. body:nil
  61. shouldRetry:shouldRetry
  62. progress:nil
  63. complete:complete];
  64. }
  65. - (void)post:(NSString *)action
  66. headers:(NSDictionary *)headers
  67. body:(NSData *)body
  68. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  69. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  70. complete:(QNRegionRequestCompleteHandler)complete{
  71. self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
  72. [self.requestMetrics start];
  73. [self performRequest:[self getNextServer:nil]
  74. action:action
  75. headers:headers
  76. method:@"POST"
  77. body:body
  78. shouldRetry:shouldRetry
  79. progress:progress
  80. complete:complete];
  81. }
  82. - (void)put:(NSString *)action
  83. headers:(NSDictionary *)headers
  84. body:(NSData *)body
  85. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  86. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  87. complete:(QNRegionRequestCompleteHandler)complete{
  88. self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
  89. [self.requestMetrics start];
  90. [self performRequest:[self getNextServer:nil]
  91. action:action
  92. headers:headers
  93. method:@"PUT"
  94. body:body
  95. shouldRetry:shouldRetry
  96. progress:progress
  97. complete:complete];
  98. }
  99. - (void)performRequest:(id <QNUploadServer>)server
  100. action:(NSString *)action
  101. headers:(NSDictionary *)headers
  102. method:(NSString *)method
  103. body:(NSData *)body
  104. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  105. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  106. complete:(QNRegionRequestCompleteHandler)complete{
  107. if (!server.host || server.host.length == 0) {
  108. QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"server error"];
  109. [self complete:responseInfo response:nil complete:complete];
  110. return;
  111. }
  112. NSString *serverHost = server.host;
  113. NSString *serverIP = server.ip;
  114. if (self.config.converter) {
  115. serverHost = self.config.converter(serverHost);
  116. serverIP = nil;
  117. }
  118. self.currentServer = server;
  119. NSString *scheme = self.config.useHttps ? @"https://" : @"http://";
  120. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  121. NSString *urlString = [NSString stringWithFormat:@"%@%@%@", scheme, serverHost, action ?: @""];
  122. request.URL = [NSURL URLWithString:urlString];
  123. request.HTTPMethod = method;
  124. [request setAllHTTPHeaderFields:headers];
  125. [request setTimeoutInterval:self.config.timeoutInterval];
  126. request.HTTPBody = body;
  127. QNLogInfo(@"key:%@ url:%@", self.requestInfo.key, request.URL);
  128. QNLogInfo(@"key:%@ headers:%@", self.requestInfo.key, headers);
  129. kQNWeakSelf;
  130. [self.singleRequest request:request
  131. server:server
  132. shouldRetry:shouldRetry
  133. progress:progress
  134. complete:^(QNResponseInfo * _Nullable responseInfo, NSArray<QNUploadSingleRequestMetrics *> * _Nullable metrics, NSDictionary * _Nullable response) {
  135. kQNStrongSelf;
  136. [self.requestMetrics addMetricsList:metrics];
  137. BOOL hijacked = metrics.lastObject.isMaybeHijacked || metrics.lastObject.isForsureHijacked;
  138. BOOL isSafeDnsSource = kQNIsDnsSourceCustom(metrics.lastObject.syncDnsSource) || kQNIsDnsSourceDoh(metrics.lastObject.syncDnsSource) || kQNIsDnsSourceDnsPod(metrics.lastObject.syncDnsSource);
  139. BOOL hijackedAndNeedRetry = hijacked && isSafeDnsSource;
  140. if (hijackedAndNeedRetry) {
  141. [self.region updateIpListFormHost:server.host];
  142. }
  143. if ((shouldRetry(responseInfo, response)
  144. && self.config.allowBackupHost
  145. && responseInfo.couldRegionRetry) || hijackedAndNeedRetry) {
  146. id <QNUploadServer> newServer = [self getNextServer:responseInfo];
  147. if (newServer) {
  148. QNAsyncRunAfter(self.config.retryInterval, kQNBackgroundQueue, ^{
  149. [self performRequest:newServer
  150. action:action
  151. headers:headers
  152. method:method
  153. body:body
  154. shouldRetry:shouldRetry
  155. progress:progress
  156. complete:complete];
  157. });
  158. } else if (complete) {
  159. [self complete:responseInfo response:response complete:complete];
  160. }
  161. } else if (complete) {
  162. [self complete:responseInfo response:response complete:complete];
  163. }
  164. }];
  165. }
  166. - (void)complete:(QNResponseInfo *)responseInfo
  167. response:(NSDictionary *)response
  168. complete:(QNRegionRequestCompleteHandler)completionHandler {
  169. [self.requestMetrics end];
  170. if (completionHandler) {
  171. completionHandler(responseInfo, self.requestMetrics, response);
  172. }
  173. self.singleRequest = nil;
  174. }
  175. //MARK: --
  176. - (id <QNUploadServer>)getNextServer:(QNResponseInfo *)responseInfo{
  177. if (responseInfo.isTlsError) {
  178. self.requestState.isUseOldServer = YES;
  179. }
  180. return [self.region getNextServer:[self.requestState copy] responseInfo:responseInfo freezeServer:self.currentServer];
  181. }
  182. @end