123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- //
- // QNHttpRequest.m
- // QiniuSDK
- //
- // Created by yangsen on 2020/4/29.
- // Copyright © 2020 Qiniu. All rights reserved.
- //
- #import "QNDefine.h"
- #import "QNLogUtil.h"
- #import "QNAsyncRun.h"
- #import "QNDnsPrefetch.h"
- #import "QNUploadRequestState.h"
- #import "QNHttpRegionRequest.h"
- #import "QNConfiguration.h"
- #import "QNUploadOption.h"
- #import "NSURLRequest+QNRequest.h"
- #import "QNUploadRequestMetrics.h"
- #import "QNResponseInfo.h"
- @interface QNHttpRegionRequest()
- @property(nonatomic, strong)QNConfiguration *config;
- @property(nonatomic, strong)QNUploadOption *uploadOption;
- @property(nonatomic, strong)QNUploadRequestInfo *requestInfo;
- @property(nonatomic, strong)QNUploadRequestState *requestState;
- @property(nonatomic, strong)QNUploadRegionRequestMetrics *requestMetrics;
- @property(nonatomic, strong)QNHttpSingleRequest *singleRequest;
- @property(nonatomic, strong)id <QNUploadServer> currentServer;
- @property(nonatomic, strong)id <QNUploadRegion> region;
- @end
- @implementation QNHttpRegionRequest
- - (instancetype)initWithConfig:(QNConfiguration *)config
- uploadOption:(QNUploadOption *)uploadOption
- token:(QNUpToken *)token
- region:(id <QNUploadRegion>)region
- requestInfo:(QNUploadRequestInfo *)requestInfo
- requestState:(QNUploadRequestState *)requestState {
- if (self = [super init]) {
- _config = config;
- _uploadOption = uploadOption;
- _region = region;
- _requestInfo = requestInfo;
- _requestState = requestState;
- _singleRequest = [[QNHttpSingleRequest alloc] initWithConfig:config
- uploadOption:uploadOption
- token:token
- requestInfo:requestInfo
- requestState:requestState];
- }
- return self;
- }
- - (void)get:(NSString *)action
- headers:(NSDictionary *)headers
- shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
- complete:(QNRegionRequestCompleteHandler)complete{
-
- self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
- [self.requestMetrics start];
- [self performRequest:[self getNextServer:nil]
- action:action
- headers:headers
- method:@"GET"
- body:nil
- shouldRetry:shouldRetry
- progress:nil
- complete:complete];
- }
- - (void)post:(NSString *)action
- headers:(NSDictionary *)headers
- body:(NSData *)body
- shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRegionRequestCompleteHandler)complete{
-
- self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
- [self.requestMetrics start];
- [self performRequest:[self getNextServer:nil]
- action:action
- headers:headers
- method:@"POST"
- body:body
- shouldRetry:shouldRetry
- progress:progress
- complete:complete];
- }
- - (void)put:(NSString *)action
- headers:(NSDictionary *)headers
- body:(NSData *)body
- shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRegionRequestCompleteHandler)complete{
-
- self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
- [self.requestMetrics start];
- [self performRequest:[self getNextServer:nil]
- action:action
- headers:headers
- method:@"PUT"
- body:body
- shouldRetry:shouldRetry
- progress:progress
- complete:complete];
- }
- - (void)performRequest:(id <QNUploadServer>)server
- action:(NSString *)action
- headers:(NSDictionary *)headers
- method:(NSString *)method
- body:(NSData *)body
- shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRegionRequestCompleteHandler)complete{
-
- if (!server.host || server.host.length == 0) {
- QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"server error"];
- [self complete:responseInfo response:nil complete:complete];
- return;
- }
-
- NSString *serverHost = server.host;
- NSString *serverIP = server.ip;
-
- if (self.config.converter) {
- serverHost = self.config.converter(serverHost);
- serverIP = nil;
- }
-
- self.currentServer = server;
-
- NSString *scheme = self.config.useHttps ? @"https://" : @"http://";
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- NSString *urlString = [NSString stringWithFormat:@"%@%@%@", scheme, serverHost, action ?: @""];
- request.URL = [NSURL URLWithString:urlString];
- request.HTTPMethod = method;
- [request setAllHTTPHeaderFields:headers];
- [request setTimeoutInterval:self.config.timeoutInterval];
- request.HTTPBody = body;
-
- QNLogInfo(@"key:%@ url:%@", self.requestInfo.key, request.URL);
- QNLogInfo(@"key:%@ headers:%@", self.requestInfo.key, headers);
-
- kQNWeakSelf;
- [self.singleRequest request:request
- server:server
- shouldRetry:shouldRetry
- progress:progress
- complete:^(QNResponseInfo * _Nullable responseInfo, NSArray<QNUploadSingleRequestMetrics *> * _Nullable metrics, NSDictionary * _Nullable response) {
- kQNStrongSelf;
-
- [self.requestMetrics addMetricsList:metrics];
-
- BOOL hijacked = metrics.lastObject.isMaybeHijacked || metrics.lastObject.isForsureHijacked;
- BOOL isSafeDnsSource = kQNIsDnsSourceCustom(metrics.lastObject.syncDnsSource) || kQNIsDnsSourceDoh(metrics.lastObject.syncDnsSource) || kQNIsDnsSourceDnsPod(metrics.lastObject.syncDnsSource);
- BOOL hijackedAndNeedRetry = hijacked && isSafeDnsSource;
- if (hijackedAndNeedRetry) {
- [self.region updateIpListFormHost:server.host];
- }
-
- if ((shouldRetry(responseInfo, response)
- && self.config.allowBackupHost
- && responseInfo.couldRegionRetry) || hijackedAndNeedRetry) {
-
- id <QNUploadServer> newServer = [self getNextServer:responseInfo];
- if (newServer) {
- QNAsyncRunAfter(self.config.retryInterval, kQNBackgroundQueue, ^{
- [self performRequest:newServer
- action:action
- headers:headers
- method:method
- body:body
- shouldRetry:shouldRetry
- progress:progress
- complete:complete];
- });
- } else if (complete) {
- [self complete:responseInfo response:response complete:complete];
- }
- } else if (complete) {
- [self complete:responseInfo response:response complete:complete];
- }
- }];
- }
- - (void)complete:(QNResponseInfo *)responseInfo
- response:(NSDictionary *)response
- complete:(QNRegionRequestCompleteHandler)completionHandler {
- [self.requestMetrics end];
-
- if (completionHandler) {
- completionHandler(responseInfo, self.requestMetrics, response);
- }
- self.singleRequest = nil;
- }
- //MARK: --
- - (id <QNUploadServer>)getNextServer:(QNResponseInfo *)responseInfo{
- if (responseInfo.isTlsError) {
- self.requestState.isUseOldServer = YES;
- }
-
- return [self.region getNextServer:[self.requestState copy] responseInfo:responseInfo freezeServer:self.currentServer];
- }
- @end
|