123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- //
- // QNRequestTransaction.m
- // QiniuSDK
- //
- // Created by yangsen on 2020/4/30.
- // Copyright © 2020 Qiniu. All rights reserved.
- //
- #import "QNRequestTransaction.h"
- #import "QNDefine.h"
- #import "QNUtils.h"
- #import "QNCrc32.h"
- #import "NSData+QNMD5.h"
- #import "QNUrlSafeBase64.h"
- #import "QNUpToken.h"
- #import "QNConfiguration.h"
- #import "QNUploadOption.h"
- #import "QNZoneInfo.h"
- #import "QNUserAgent.h"
- #import "QNResponseInfo.h"
- #import "QNUploadRequestState.h"
- #import "QNUploadRequestMetrics.h"
- #import "QNUploadDomainRegion.h"
- #import "QNHttpRegionRequest.h"
- @interface QNRequestTransaction()
- @property(nonatomic, strong)QNConfiguration *config;
- @property(nonatomic, strong)QNUploadOption *uploadOption;
- @property(nonatomic, copy)NSString *key;
- @property(nonatomic, strong)QNUpToken *token;
- @property(nonatomic, strong)QNUploadRequestInfo *requestInfo;
- @property(nonatomic, strong)QNUploadRequestState *requestState;
- @property(nonatomic, strong)QNHttpRegionRequest *regionRequest;
- @end
- @implementation QNRequestTransaction
- - (instancetype)initWithHosts:(NSArray <NSString *> *)hosts
- regionId:(NSString * _Nullable)regionId
- token:(QNUpToken *)token{
- return [self initWithConfig:[QNConfiguration defaultConfiguration]
- uploadOption:[QNUploadOption defaultOptions]
- hosts:hosts
- regionId:regionId
- key:nil
- token:token];
- }
- - (instancetype)initWithConfig:(QNConfiguration *)config
- uploadOption:(QNUploadOption *)uploadOption
- hosts:(NSArray <NSString *> *)hosts
- regionId:(NSString * _Nullable)regionId
- key:(NSString * _Nullable)key
- token:(nonnull QNUpToken *)token{
-
- QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] init];
- [region setupRegionData:[QNZoneInfo zoneInfoWithMainHosts:hosts regionId:regionId]];
- return [self initWithConfig:config
- uploadOption:uploadOption
- targetRegion:region
- currentRegion:region
- key:key
- token:token];
- }
- - (instancetype)initWithConfig:(QNConfiguration *)config
- uploadOption:(QNUploadOption *)uploadOption
- targetRegion:(id <QNUploadRegion>)targetRegion
- currentRegion:(id <QNUploadRegion>)currentRegion
- key:(NSString *)key
- token:(QNUpToken *)token{
- if (self = [super init]) {
- _config = config;
- _uploadOption = uploadOption;
- _requestState = [[QNUploadRequestState alloc] init];
- _key = key;
- _token = token;
- _requestInfo = [[QNUploadRequestInfo alloc] init];
- _requestInfo.targetRegionId = targetRegion.zoneInfo.regionId;
- _requestInfo.currentRegionId = currentRegion.zoneInfo.regionId;
- _requestInfo.bucket = token.bucket;
- _requestInfo.key = key;
- _regionRequest = [[QNHttpRegionRequest alloc] initWithConfig:config
- uploadOption:uploadOption
- token:token
- region:currentRegion
- requestInfo:_requestInfo
- requestState:_requestState];
- }
- return self;
- }
- //MARK: -- uc query
- - (void)queryUploadHosts:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeUCQuery;
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)!responseInfo.isOK;
- };
-
- NSDictionary *header = @{@"User-Agent" : [kQNUserAgent getUserAgent:self.token.token]};
- NSString *action = [NSString stringWithFormat:@"/v4/query?ak=%@&bucket=%@&sdk_name=%@&sdk_version=%@", self.token.access, self.token.bucket, [QNUtils sdkLanguage], [QNUtils sdkVersion]];
- [self.regionRequest get:action
- headers:header
- shouldRetry:shouldRetry
- complete:complete];
- }
- //MARK: -- upload form
- - (void)uploadFormData:(NSData *)data
- fileName:(NSString *)fileName
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRequestTransactionCompleteHandler)complete{
- self.requestInfo.requestType = QNUploadRequestTypeForm;
-
- NSMutableDictionary *param = [NSMutableDictionary dictionary];
- if (self.uploadOption.params) {
- [param addEntriesFromDictionary:self.uploadOption.params];
- }
- if (self.uploadOption.metaDataParam) {
- [param addEntriesFromDictionary:self.uploadOption.metaDataParam];
- }
- if (self.key && self.key.length > 0) {
- param[@"key"] = self.key;
- }
- param[@"token"] = self.token.token ?: @"";
- if (self.uploadOption.checkCrc) {
- param[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:data]];
- }
-
- NSString *boundary = @"werghnvt54wef654rjuhgb56trtg34tweuyrgf";
- NSString *disposition = @"Content-Disposition: form-data";
-
- NSMutableData *body = [NSMutableData data];
- @try {
- for (NSString *paramsKey in param) {
- NSString *pair = [NSString stringWithFormat:@"--%@\r\n%@; name=\"%@\"\r\n\r\n", boundary, disposition, paramsKey];
- [body appendData:[pair dataUsingEncoding:NSUTF8StringEncoding]];
- id value = [param objectForKey:paramsKey];
- if ([value isKindOfClass:[NSString class]]) {
- [body appendData:[value dataUsingEncoding:NSUTF8StringEncoding]];
- } else if ([value isKindOfClass:[NSData class]]) {
- [body appendData:value];
- }
- [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
- }
-
- fileName = [QNUtils formEscape:fileName];
-
- NSString *filePair = [NSString stringWithFormat:@"--%@\r\n%@; name=\"%@\"; filename=\"%@\"\nContent-Type:%@\r\n\r\n", boundary, disposition, @"file", fileName, self.uploadOption.mimeType];
- [body appendData:[filePair dataUsingEncoding:NSUTF8StringEncoding]];
-
- [body appendData:data];
- [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
- } @catch (NSException *exception) {
- if (complete) {
- QNResponseInfo *info = [QNResponseInfo responseInfoWithLocalIOError:[NSString stringWithFormat:@"%@", exception]];
- QNUploadRegionRequestMetrics *metrics = [QNUploadRegionRequestMetrics emptyMetrics];
- complete(info, metrics, nil);
- }
- return;
- }
-
-
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Content-Type"] = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
- header[@"Content-Length"] = [NSString stringWithFormat:@"%lu", (unsigned long)body.length];
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)!responseInfo.isOK;
- };
-
- [self.regionRequest post:nil
- headers:header
- body:body
- shouldRetry:shouldRetry
- progress:progress
- complete:complete];
- }
- //MARK: -- 分块上传
- - (void)makeBlock:(long long)blockOffset
- blockSize:(long long)blockSize
- firstChunkData:(NSData *)firstChunkData
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeMkblk;
- self.requestInfo.fileOffset = @(blockOffset);
-
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/octet-stream";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *action = [NSString stringWithFormat:@"/mkblk/%u", (unsigned int)blockSize];
-
- NSString *chunkCrc = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:firstChunkData]];
-
- kQNWeakSelf;
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- kQNStrongSelf;
-
- NSString *ctx = response[@"ctx"];
- NSString *crcServer = [NSString stringWithFormat:@"%@", response[@"crc32"]];
- return (BOOL)(responseInfo.isOK == false || (responseInfo.isOK && (!ctx || (self.uploadOption.checkCrc && ![chunkCrc isEqualToString:crcServer]))));
- };
-
- [self.regionRequest post:action
- headers:header
- body:firstChunkData
- shouldRetry:shouldRetry
- progress:progress
- complete:complete];
- }
- - (void)uploadChunk:(NSString *)blockContext
- blockOffset:(long long)blockOffset
- chunkData:(NSData *)chunkData
- chunkOffset:(long long)chunkOffset
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeBput;
- self.requestInfo.fileOffset = @(blockOffset + chunkOffset);
-
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/octet-stream";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *action = [NSString stringWithFormat:@"/bput/%@/%lld", blockContext, chunkOffset];
-
- NSString *chunkCrc = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:chunkData]];
-
- kQNWeakSelf;
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- kQNStrongSelf;
-
- NSString *ctx = response[@"ctx"];
- NSString *crcServer = [NSString stringWithFormat:@"%@", response[@"crc32"]];
- return (BOOL)(responseInfo.isOK == false || (responseInfo.isOK && (!ctx || (self.uploadOption.checkCrc && ![chunkCrc isEqualToString:crcServer]))));
- };
-
- [self.regionRequest post:action
- headers:header
- body:chunkData
- shouldRetry:shouldRetry
- progress:progress
- complete:complete];
- }
- - (void)makeFile:(long long)fileSize
- fileName:(NSString *)fileName
- blockContexts:(NSArray <NSString *> *)blockContexts
- complete:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeMkfile;
-
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/octet-stream";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *mimeType = [[NSString alloc] initWithFormat:@"/mimeType/%@", [QNUrlSafeBase64 encodeString:self.uploadOption.mimeType]];
- __block NSString *action = [[NSString alloc] initWithFormat:@"/mkfile/%lld%@", fileSize, mimeType];
- if (self.key != nil) {
- NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [QNUrlSafeBase64 encodeString:self.key]];
- action = [NSString stringWithFormat:@"%@%@", action, keyStr];
- }
- [self.uploadOption.params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
- action = [NSString stringWithFormat:@"%@/%@/%@", action, key, [QNUrlSafeBase64 encodeString:obj]];
- }];
-
- [self.uploadOption.metaDataParam enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
- action = [NSString stringWithFormat:@"%@/%@/%@", action, key, [QNUrlSafeBase64 encodeString:obj]];
- }];
- //添加路径
- NSString *fname = [[NSString alloc] initWithFormat:@"/fname/%@", [QNUrlSafeBase64 encodeString:fileName]];
- action = [NSString stringWithFormat:@"%@%@", action, fname];
- NSMutableData *body = [NSMutableData data];
- NSString *bodyString = [blockContexts componentsJoinedByString:@","];
- [body appendData:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)(!responseInfo.isOK);
- };
-
- [self.regionRequest post:action
- headers:header
- body:body
- shouldRetry:shouldRetry
- progress:nil
- complete:complete];
- }
- - (void)initPart:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeInitParts;
-
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/octet-stream";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
- NSString *buckets = [[NSString alloc] initWithFormat:@"/buckets/%@", self.token.bucket];
- NSString *objects = [[NSString alloc] initWithFormat:@"/objects/%@", [self resumeV2EncodeKey:self.key]];;
- NSString *action = [[NSString alloc] initWithFormat:@"%@%@/uploads", buckets, objects];
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)(!responseInfo.isOK);
- };
-
- [self.regionRequest post:action
- headers:header
- body:nil
- shouldRetry:shouldRetry
- progress:nil
- complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- complete(responseInfo, metrics, response);
- }];
- }
- - (void)uploadPart:(NSString *)uploadId
- partIndex:(NSInteger)partIndex
- partData:(NSData *)partData
- progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
- complete:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeUploadPart;
-
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/octet-stream";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
- if (self.uploadOption.checkCrc) {
- NSString *md5 = [[partData qn_md5] lowercaseString];
- if (md5) {
- header[@"Content-MD5"] = md5;
- }
- }
- NSString *buckets = [[NSString alloc] initWithFormat:@"/buckets/%@", self.token.bucket];
- NSString *objects = [[NSString alloc] initWithFormat:@"/objects/%@", [self resumeV2EncodeKey:self.key]];;
- NSString *uploads = [[NSString alloc] initWithFormat:@"/uploads/%@", uploadId];
- NSString *partNumber = [[NSString alloc] initWithFormat:@"/%ld", (long)partIndex];
- NSString *action = [[NSString alloc] initWithFormat:@"%@%@%@%@", buckets, objects, uploads, partNumber];
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- NSString *etag = [NSString stringWithFormat:@"%@", response[@"etag"]];
- NSString *serverMD5 = [NSString stringWithFormat:@"%@", response[@"md5"]];
- return (BOOL)(!responseInfo.isOK || !etag || !serverMD5);
- };
-
- [self.regionRequest put:action
- headers:header
- body:partData
- shouldRetry:shouldRetry
- progress:progress
- complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- complete(responseInfo, metrics, response);
- }];
- }
- - (void)completeParts:(NSString *)fileName
- uploadId:(NSString *)uploadId
- partInfoArray:(NSArray <NSDictionary *> *)partInfoArray
- complete:(QNRequestTransactionCompleteHandler)complete{
-
- self.requestInfo.requestType = QNUploadRequestTypeCompletePart;
-
- if (!partInfoArray || partInfoArray.count == 0) {
- QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithInvalidArgument:@"partInfoArray"];
- if (complete) {
- complete(responseInfo, nil, responseInfo.responseDictionary);
- }
- return;
- }
-
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/json";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *buckets = [[NSString alloc] initWithFormat:@"/buckets/%@", self.token.bucket];
- NSString *objects = [[NSString alloc] initWithFormat:@"/objects/%@", [self resumeV2EncodeKey:self.key]];
- NSString *uploads = [[NSString alloc] initWithFormat:@"/uploads/%@", uploadId];
-
- NSString *action = [[NSString alloc] initWithFormat:@"%@%@%@", buckets, objects, uploads];
- NSMutableDictionary *bodyDictionary = [NSMutableDictionary dictionary];
- if (partInfoArray) {
- bodyDictionary[@"parts"] = partInfoArray;
- }
- if (fileName) {
- bodyDictionary[@"fname"] = fileName;
- }
- if (self.uploadOption.mimeType) {
- bodyDictionary[@"mimeType"] = self.uploadOption.mimeType;
- }
- if (self.uploadOption.params) {
- bodyDictionary[@"customVars"] = self.uploadOption.params;
- }
- if (self.uploadOption.metaDataParam) {
- bodyDictionary[@"metaData"] = self.uploadOption.metaDataParam;
- }
-
- NSError *error = nil;
- NSData *body = [NSJSONSerialization dataWithJSONObject:bodyDictionary
- options:NSJSONWritingPrettyPrinted
- error:&error];
- if (error) {
- QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithLocalIOError:error.description];
- if (complete) {
- complete(responseInfo, nil, responseInfo.responseDictionary);
- }
- return;
- }
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)(!responseInfo.isOK);
- };
-
- [self.regionRequest post:action
- headers:header
- body:body
- shouldRetry:shouldRetry
- progress:nil
- complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- complete(responseInfo, metrics, response);
- }];
- }
- - (void)reportLog:(NSData *)logData
- logClientId:(NSString *)logClientId
- complete:(QNRequestTransactionCompleteHandler)complete {
-
- self.requestInfo.requestType = QNUploadRequestTypeUpLog;
- NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"Authorization"] = token;
- header[@"Content-Type"] = @"application/json";
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *action = @"/log/4?compressed=gzip";
-
- if (logClientId) {
- header[@"X-Log-Client-Id"] = logClientId;
- }
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)(!responseInfo.isOK);
- };
-
- [self.regionRequest post:action
- headers:header
- body:logData
- shouldRetry:shouldRetry
- progress:nil
- complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- complete(responseInfo, metrics, response);
- }];
- }
- - (void)serverConfig:(QNRequestTransactionCompleteHandler)complete {
-
- self.requestInfo.requestType = QNUploadRequestTypeServerConfig;
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *action = [NSString stringWithFormat:@"/v1/sdk/config?sdk_name=%@&sdk_version=%@", [QNUtils sdkLanguage], [QNUtils sdkVersion]];
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)(!responseInfo.isOK);
- };
-
- [self.regionRequest post:action
- headers:header
- body:nil
- shouldRetry:shouldRetry
- progress:nil
- complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- complete(responseInfo, metrics, response);
- }];
- }
- - (void)serverUserConfig:(QNRequestTransactionCompleteHandler)complete {
-
- self.requestInfo.requestType = QNUploadRequestTypeServerUserConfig;
- NSMutableDictionary *header = [NSMutableDictionary dictionary];
- header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
-
- NSString *action = [NSString stringWithFormat:@"/v1/sdk/config/user?ak=%@&sdk_name=%@&sdk_version=%@", self.token.access, [QNUtils sdkLanguage], [QNUtils sdkVersion]];
-
- BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
- return (BOOL)(!responseInfo.isOK);
- };
-
- [self.regionRequest post:action
- headers:header
- body:nil
- shouldRetry:shouldRetry
- progress:nil
- complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- complete(responseInfo, metrics, response);
- }];
- }
- - (NSString *)resumeV2EncodeKey:(NSString *)key{
- NSString *encodeKey = nil;
- if (!self.key) {
- encodeKey = @"~";
- } else if (self.key.length == 0) {
- encodeKey = @"";
- } else {
- encodeKey = [QNUrlSafeBase64 encodeString:self.key];
- }
- return encodeKey;
- }
- @end
|