add .gitignore
This commit is contained in:
33
msext/QiniuSDK/Http/QNHttpDelegate.h
Executable file
33
msext/QiniuSDK/Http/QNHttpDelegate.h
Executable file
@@ -0,0 +1,33 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class QNResponseInfo;
|
||||
|
||||
typedef void (^QNInternalProgressBlock)(long long totalBytesWritten, long long totalBytesExpectedToWrite);
|
||||
typedef void (^QNCompleteBlock)(QNResponseInfo *info, NSDictionary *resp);
|
||||
typedef BOOL (^QNCancelBlock)(void);
|
||||
|
||||
/**
|
||||
* Http 客户端接口
|
||||
*/
|
||||
@protocol QNHttpDelegate <NSObject>
|
||||
|
||||
- (void)multipartPost:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withParams:(NSDictionary *)params
|
||||
withFileName:(NSString *)key
|
||||
withMimeType:(NSString *)mime
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access;
|
||||
|
||||
- (void)post:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withParams:(NSDictionary *)params
|
||||
withHeaders:(NSDictionary *)headers
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access;
|
||||
|
||||
@end
|
||||
206
msext/QiniuSDK/Http/QNResponseInfo.h
Executable file
206
msext/QiniuSDK/Http/QNResponseInfo.h
Executable file
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// QNResponseInfo.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/2.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* 中途取消的状态码
|
||||
*/
|
||||
extern const int kQNRequestCancelled;
|
||||
|
||||
/**
|
||||
* 网络错误状态码
|
||||
*/
|
||||
extern const int kQNNetworkError;
|
||||
|
||||
/**
|
||||
* 错误参数状态码
|
||||
*/
|
||||
extern const int kQNInvalidArgument;
|
||||
|
||||
/**
|
||||
* 0 字节文件或数据
|
||||
*/
|
||||
extern const int kQNZeroDataSize;
|
||||
|
||||
/**
|
||||
* 错误token状态码
|
||||
*/
|
||||
extern const int kQNInvalidToken;
|
||||
|
||||
/**
|
||||
* 读取文件错误状态码
|
||||
*/
|
||||
extern const int kQNFileError;
|
||||
|
||||
/**
|
||||
* 上传完成后返回的状态信息
|
||||
*/
|
||||
@interface QNResponseInfo : NSObject
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
@property (readonly) int statusCode;
|
||||
|
||||
/**
|
||||
* 七牛服务器生成的请求ID,用来跟踪请求信息,如果使用过程中出现问题,请反馈此ID
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *reqId;
|
||||
|
||||
/**
|
||||
* 七牛服务器内部跟踪记录
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *xlog;
|
||||
|
||||
/**
|
||||
* cdn服务器内部跟踪记录
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *xvia;
|
||||
|
||||
/**
|
||||
* 错误信息,出错时请反馈此记录
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSError *error;
|
||||
|
||||
/**
|
||||
* 服务器域名
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *host;
|
||||
|
||||
/**
|
||||
* 请求消耗的时间,单位 秒
|
||||
*/
|
||||
@property (nonatomic, readonly) double duration;
|
||||
|
||||
/**
|
||||
* 服务器IP
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *serverIp;
|
||||
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *id;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
@property (readonly) UInt64 timeStamp;
|
||||
|
||||
/**
|
||||
* 网络类型
|
||||
*/
|
||||
//@property (nonatomic, readonly) NSString *networkType;
|
||||
|
||||
/**
|
||||
* 是否取消
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isCancelled) BOOL canceled;
|
||||
|
||||
/**
|
||||
* 成功的请求
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isOK) BOOL ok;
|
||||
|
||||
/**
|
||||
* 是否网络错误
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isConnectionBroken) BOOL broken;
|
||||
|
||||
/**
|
||||
* 是否需要重试,内部使用
|
||||
*/
|
||||
@property (nonatomic, readonly) BOOL couldRetry;
|
||||
|
||||
/**
|
||||
* 是否需要换备用server,内部使用
|
||||
*/
|
||||
@property (nonatomic, readonly) BOOL needSwitchServer;
|
||||
|
||||
/**
|
||||
* 是否为 七牛响应
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isNotQiniu) BOOL notQiniu;
|
||||
|
||||
/**
|
||||
* 工厂函数,内部使用
|
||||
*
|
||||
* @return 取消的实例
|
||||
*/
|
||||
+ (instancetype)cancel;
|
||||
|
||||
/**
|
||||
* 工厂函数,内部使用
|
||||
*
|
||||
* @param desc 错误参数描述
|
||||
*
|
||||
* @return 错误参数实例
|
||||
*/
|
||||
+ (instancetype)responseInfoWithInvalidArgument:(NSString *)desc;
|
||||
|
||||
/**
|
||||
* 工厂函数,内部使用
|
||||
*
|
||||
* @param desc 错误token描述
|
||||
*
|
||||
* @return 错误token实例
|
||||
*/
|
||||
+ (instancetype)responseInfoWithInvalidToken:(NSString *)desc;
|
||||
|
||||
/**
|
||||
* 工厂函数,内部使用
|
||||
*
|
||||
* @param error 错误信息
|
||||
* @param host 服务器域名
|
||||
* @param duration 请求完成时间,单位秒
|
||||
*
|
||||
* @return 网络错误实例
|
||||
*/
|
||||
+ (instancetype)responseInfoWithNetError:(NSError *)error
|
||||
host:(NSString *)host
|
||||
duration:(double)duration;
|
||||
|
||||
/**
|
||||
* 工厂函数,内部使用
|
||||
*
|
||||
* @param error 错误信息
|
||||
*
|
||||
* @return 文件错误实例
|
||||
*/
|
||||
+ (instancetype)responseInfoWithFileError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* 工厂函数,内部使用
|
||||
*
|
||||
* @return 文件错误实例
|
||||
*/
|
||||
+ (instancetype)responseInfoOfZeroData:(NSString *)path;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param status 状态码
|
||||
* @param reqId 七牛服务器请求id
|
||||
* @param xlog 七牛服务器记录
|
||||
* @param body 服务器返回内容
|
||||
* @param host 服务器域名
|
||||
* @param duration 请求完成时间,单位秒
|
||||
*
|
||||
* @return 实例
|
||||
*/
|
||||
- (instancetype)init:(int)status
|
||||
withReqId:(NSString *)reqId
|
||||
withXLog:(NSString *)xlog
|
||||
withXVia:(NSString *)xvia
|
||||
withHost:(NSString *)host
|
||||
withIp:(NSString *)ip
|
||||
withDuration:(double)duration
|
||||
withBody:(NSData *)body;
|
||||
|
||||
@end
|
||||
210
msext/QiniuSDK/Http/QNResponseInfo.m
Executable file
210
msext/QiniuSDK/Http/QNResponseInfo.m
Executable file
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// QNResponseInfo.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/2.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNUserAgent.h"
|
||||
#import "QNVersion.h"
|
||||
|
||||
const int kQNZeroDataSize = -6;
|
||||
const int kQNInvalidToken = -5;
|
||||
const int kQNFileError = -4;
|
||||
const int kQNInvalidArgument = -3;
|
||||
const int kQNRequestCancelled = -2;
|
||||
const int kQNNetworkError = -1;
|
||||
|
||||
/**
|
||||
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/index.html#//apple_ref/doc/constant_group/URL_Loading_System_Error_Codes
|
||||
|
||||
NSURLErrorUnknown = -1,
|
||||
NSURLErrorCancelled = -999,
|
||||
NSURLErrorBadURL = -1000,
|
||||
NSURLErrorTimedOut = -1001,
|
||||
NSURLErrorUnsupportedURL = -1002,
|
||||
NSURLErrorCannotFindHost = -1003,
|
||||
NSURLErrorCannotConnectToHost = -1004,
|
||||
NSURLErrorDataLengthExceedsMaximum = -1103,
|
||||
NSURLErrorNetworkConnectionLost = -1005,
|
||||
NSURLErrorDNSLookupFailed = -1006,
|
||||
NSURLErrorHTTPTooManyRedirects = -1007,
|
||||
NSURLErrorResourceUnavailable = -1008,
|
||||
NSURLErrorNotConnectedToInternet = -1009,
|
||||
NSURLErrorRedirectToNonExistentLocation = -1010,
|
||||
NSURLErrorBadServerResponse = -1011,
|
||||
NSURLErrorUserCancelledAuthentication = -1012,
|
||||
NSURLErrorUserAuthenticationRequired = -1013,
|
||||
NSURLErrorZeroByteResource = -1014,
|
||||
NSURLErrorCannotDecodeRawData = -1015,
|
||||
NSURLErrorCannotDecodeContentData = -1016,
|
||||
NSURLErrorCannotParseResponse = -1017,
|
||||
NSURLErrorInternationalRoamingOff = -1018,
|
||||
NSURLErrorCallIsActive = -1019,
|
||||
NSURLErrorDataNotAllowed = -1020,
|
||||
NSURLErrorRequestBodyStreamExhausted = -1021,
|
||||
NSURLErrorFileDoesNotExist = -1100,
|
||||
NSURLErrorFileIsDirectory = -1101,
|
||||
NSURLErrorNoPermissionsToReadFile = -1102,
|
||||
NSURLErrorSecureConnectionFailed = -1200,
|
||||
NSURLErrorServerCertificateHasBadDate = -1201,
|
||||
NSURLErrorServerCertificateUntrusted = -1202,
|
||||
NSURLErrorServerCertificateHasUnknownRoot = -1203,
|
||||
NSURLErrorServerCertificateNotYetValid = -1204,
|
||||
NSURLErrorClientCertificateRejected = -1205,
|
||||
NSURLErrorClientCertificateRequired = -1206,
|
||||
NSURLErrorCannotLoadFromNetwork = -2000,
|
||||
NSURLErrorCannotCreateFile = -3000,
|
||||
NSURLErrorCannotOpenFile = -3001,
|
||||
NSURLErrorCannotCloseFile = -3002,
|
||||
NSURLErrorCannotWriteToFile = -3003,
|
||||
NSURLErrorCannotRemoveFile = -3004,
|
||||
NSURLErrorCannotMoveFile = -3005,
|
||||
NSURLErrorDownloadDecodingFailedMidStream = -3006,
|
||||
NSURLErrorDownloadDecodingFailedToComplete = -3007
|
||||
*/
|
||||
|
||||
static QNResponseInfo *cancelledInfo = nil;
|
||||
|
||||
static NSString *domain = @"qiniu.com";
|
||||
|
||||
@implementation QNResponseInfo
|
||||
|
||||
+ (instancetype)cancel {
|
||||
return [[QNResponseInfo alloc] initWithCancelled];
|
||||
}
|
||||
|
||||
+ (instancetype)responseInfoWithInvalidArgument:(NSString *)text {
|
||||
return [[QNResponseInfo alloc] initWithStatus:kQNInvalidArgument errorDescription:text];
|
||||
}
|
||||
|
||||
+ (instancetype)responseInfoWithInvalidToken:(NSString *)text {
|
||||
return [[QNResponseInfo alloc] initWithStatus:kQNInvalidToken errorDescription:text];
|
||||
}
|
||||
|
||||
+ (instancetype)responseInfoWithNetError:(NSError *)error host:(NSString *)host duration:(double)duration {
|
||||
int code = kQNNetworkError;
|
||||
if (error != nil) {
|
||||
code = (int)error.code;
|
||||
}
|
||||
return [[QNResponseInfo alloc] initWithStatus:code error:error host:host duration:duration];
|
||||
}
|
||||
|
||||
+ (instancetype)responseInfoWithFileError:(NSError *)error {
|
||||
return [[QNResponseInfo alloc] initWithStatus:kQNFileError error:error];
|
||||
}
|
||||
|
||||
+ (instancetype)responseInfoOfZeroData:(NSString *)path {
|
||||
NSString *desc;
|
||||
if (path == nil) {
|
||||
desc = @"data size is 0";
|
||||
} else {
|
||||
desc = [[NSString alloc] initWithFormat:@"file %@ size is 0", path];
|
||||
}
|
||||
return [[QNResponseInfo alloc] initWithStatus:kQNZeroDataSize errorDescription:desc];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCancelled {
|
||||
return [self initWithStatus:kQNRequestCancelled errorDescription:@"cancelled by user"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithStatus:(int)status
|
||||
error:(NSError *)error {
|
||||
return [self initWithStatus:status error:error host:nil duration:0];
|
||||
}
|
||||
|
||||
- (instancetype)initWithStatus:(int)status
|
||||
error:(NSError *)error
|
||||
host:(NSString *)host
|
||||
duration:(double)duration {
|
||||
if (self = [super init]) {
|
||||
_statusCode = status;
|
||||
_error = error;
|
||||
_host = host;
|
||||
_duration = duration;
|
||||
_id = [QNUserAgent sharedInstance].id;
|
||||
_timeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithStatus:(int)status
|
||||
errorDescription:(NSString *)text {
|
||||
NSError *error = [[NSError alloc] initWithDomain:domain code:status userInfo:@{ @"error" : text }];
|
||||
return [self initWithStatus:status error:error];
|
||||
}
|
||||
|
||||
- (instancetype)init:(int)status
|
||||
withReqId:(NSString *)reqId
|
||||
withXLog:(NSString *)xlog
|
||||
withXVia:(NSString *)xvia
|
||||
withHost:(NSString *)host
|
||||
withIp:(NSString *)ip
|
||||
withDuration:(double)duration
|
||||
withBody:(NSData *)body {
|
||||
if (self = [super init]) {
|
||||
_statusCode = status;
|
||||
_reqId = [reqId copy];
|
||||
_xlog = [xlog copy];
|
||||
_xvia = [xvia copy];
|
||||
_host = [host copy];
|
||||
_duration = duration;
|
||||
_serverIp = ip;
|
||||
_id = [QNUserAgent sharedInstance].id;
|
||||
_timeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
if (status != 200) {
|
||||
if (body == nil) {
|
||||
_error = [[NSError alloc] initWithDomain:domain code:_statusCode userInfo:nil];
|
||||
} else {
|
||||
NSError *tmp;
|
||||
NSDictionary *uInfo = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
|
||||
if (tmp != nil) {
|
||||
// 出现错误时,如果信息是非UTF8编码会失败,返回nil
|
||||
NSString *str = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
|
||||
if (str == nil) {
|
||||
str = @"";
|
||||
}
|
||||
uInfo = @{ @"error" : str };
|
||||
}
|
||||
_error = [[NSError alloc] initWithDomain:domain code:_statusCode userInfo:uInfo];
|
||||
}
|
||||
} else if (body == nil || body.length == 0) {
|
||||
NSDictionary *uInfo = @{ @"error" : @"no response json" };
|
||||
_error = [[NSError alloc] initWithDomain:domain code:_statusCode userInfo:uInfo];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@= id: %@, ver: %@, status: %d, requestId: %@, xlog: %@, xvia: %@, host: %@ ip: %@ duration: %f s time: %llu error: %@>", NSStringFromClass([self class]), _id, kQiniuVersion, _statusCode, _reqId, _xlog, _xvia, _host, _serverIp, _duration, _timeStamp, _error];
|
||||
}
|
||||
|
||||
- (BOOL)isCancelled {
|
||||
return _statusCode == kQNRequestCancelled || _statusCode == -999;
|
||||
}
|
||||
|
||||
- (BOOL)isNotQiniu {
|
||||
return (_statusCode >= 200 && _statusCode < 500) && _reqId == nil;
|
||||
}
|
||||
|
||||
- (BOOL)isOK {
|
||||
return _statusCode == 200 && _error == nil && _reqId != nil;
|
||||
}
|
||||
|
||||
- (BOOL)isConnectionBroken {
|
||||
// reqId is nill means the server is not qiniu
|
||||
return _statusCode == kQNNetworkError || (_statusCode < -1000 && _statusCode != -1003);
|
||||
}
|
||||
|
||||
- (BOOL)needSwitchServer {
|
||||
return _statusCode == kQNNetworkError || (_statusCode < -1000 && _statusCode != -1003) || (_statusCode / 100 == 5 && _statusCode != 579);
|
||||
}
|
||||
|
||||
- (BOOL)couldRetry {
|
||||
return (_statusCode >= 500 && _statusCode < 600 && _statusCode != 579) || _statusCode == kQNNetworkError || _statusCode == 996 || _statusCode == 406 || (_statusCode == 200 && _error != nil) || _statusCode < -1000 || self.isNotQiniu;
|
||||
}
|
||||
|
||||
@end
|
||||
40
msext/QiniuSDK/Http/QNSessionManager.h
Executable file
40
msext/QiniuSDK/Http/QNSessionManager.h
Executable file
@@ -0,0 +1,40 @@
|
||||
#import "QNHttpDelegate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "QNConfiguration.h"
|
||||
|
||||
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
|
||||
|
||||
@interface QNSessionManager : NSObject <QNHttpDelegate>
|
||||
|
||||
- (instancetype)initWithProxy:(NSDictionary *)proxyDict
|
||||
timeout:(UInt32)timeout
|
||||
urlConverter:(QNUrlConvert)converter
|
||||
dns:(QNDnsManager *)dns;
|
||||
|
||||
- (void)multipartPost:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withParams:(NSDictionary *)params
|
||||
withFileName:(NSString *)key
|
||||
withMimeType:(NSString *)mime
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access;
|
||||
|
||||
- (void)post:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withParams:(NSDictionary *)params
|
||||
withHeaders:(NSDictionary *)headers
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access;
|
||||
|
||||
- (void)get:(NSString *)url
|
||||
withHeaders:(NSDictionary *)headers
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
333
msext/QiniuSDK/Http/QNSessionManager.m
Executable file
333
msext/QiniuSDK/Http/QNSessionManager.m
Executable file
@@ -0,0 +1,333 @@
|
||||
//
|
||||
// QNHttpManager.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/1.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AFNetworking.h"
|
||||
|
||||
#import "HappyDNS.h"
|
||||
#import "QNAsyncRun.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNSessionManager.h"
|
||||
#include "QNSystem.h"
|
||||
#import "QNUserAgent.h"
|
||||
|
||||
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
|
||||
|
||||
@interface QNProgessDelegate : NSObject
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
|
||||
@property (nonatomic, strong) QNInternalProgressBlock progressBlock;
|
||||
@property (nonatomic, strong) NSProgress *progress;
|
||||
@property (nonatomic, strong) NSURLSessionUploadTask *task;
|
||||
@property (nonatomic, strong) QNCancelBlock cancelBlock;
|
||||
- (instancetype)initWithProgress:(QNInternalProgressBlock)progressBlock;
|
||||
@end
|
||||
|
||||
static NSURL *buildUrl(NSString *host, NSNumber *port, NSString *path) {
|
||||
port = port == nil ? [NSNumber numberWithInt:80] : port;
|
||||
NSString *p = [[NSString alloc] initWithFormat:@"http://%@:%@%@", host, port, path];
|
||||
return [[NSURL alloc] initWithString:p];
|
||||
}
|
||||
|
||||
static BOOL needRetry(NSHTTPURLResponse *httpResponse, NSError *error) {
|
||||
if (error != nil) {
|
||||
return error.code < -1000;
|
||||
}
|
||||
if (httpResponse == nil) {
|
||||
return YES;
|
||||
}
|
||||
int status = (int)httpResponse.statusCode;
|
||||
return status >= 500 && status < 600 && status != 579;
|
||||
}
|
||||
|
||||
@implementation QNProgessDelegate
|
||||
- (instancetype)initWithProgress:(QNInternalProgressBlock)progressBlock {
|
||||
if (self = [super init]) {
|
||||
_progressBlock = progressBlock;
|
||||
_progress = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)valueChange:(NSProgress *)uploadProgress {
|
||||
_progressBlock(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
|
||||
if (_cancelBlock && _cancelBlock()) {
|
||||
[_task cancel];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
|
||||
{
|
||||
if (context == nil || object == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSProgress *progress = (NSProgress *)object;
|
||||
|
||||
void *p = (__bridge void *)(self);
|
||||
if (p == context) {
|
||||
_progressBlock(progress.completedUnitCount, progress.totalUnitCount);
|
||||
if (_cancelBlock && _cancelBlock()) {
|
||||
[_task cancel];
|
||||
}
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface QNSessionManager ()
|
||||
@property (nonatomic) AFHTTPSessionManager *httpManager;
|
||||
@property UInt32 timeout;
|
||||
@property (nonatomic, strong) QNUrlConvert converter;
|
||||
@property bool noProxy;
|
||||
@property (nonatomic) QNDnsManager *dns;
|
||||
@end
|
||||
|
||||
@implementation QNSessionManager
|
||||
|
||||
- (instancetype)initWithProxy:(NSDictionary *)proxyDict
|
||||
timeout:(UInt32)timeout
|
||||
urlConverter:(QNUrlConvert)converter
|
||||
dns:(QNDnsManager *)dns {
|
||||
if (self = [super init]) {
|
||||
if (proxyDict != nil) {
|
||||
_noProxy = NO;
|
||||
} else {
|
||||
_noProxy = YES;
|
||||
}
|
||||
|
||||
_httpManager = [QNSessionManager httpManagerWithProxy:proxyDict];
|
||||
|
||||
_timeout = timeout;
|
||||
_converter = converter;
|
||||
_dns = dns;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (AFHTTPSessionManager *)httpManagerWithProxy:(NSDictionary *)proxyDict {
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
if (proxyDict != nil) {
|
||||
configuration.connectionProxyDictionary = proxyDict;
|
||||
}
|
||||
|
||||
AFHTTPSessionManager *httpManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
|
||||
httpManager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
||||
return httpManager;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithProxy:nil timeout:60 urlConverter:nil dns:nil];
|
||||
}
|
||||
|
||||
+ (QNResponseInfo *)buildResponseInfo:(NSHTTPURLResponse *)response
|
||||
withError:(NSError *)error
|
||||
withDuration:(double)duration
|
||||
withResponse:(NSData *)body
|
||||
withHost:(NSString *)host
|
||||
withIp:(NSString *)ip {
|
||||
QNResponseInfo *info;
|
||||
|
||||
if (response) {
|
||||
int status = (int)[response statusCode];
|
||||
NSDictionary *headers = [response allHeaderFields];
|
||||
NSString *reqId = headers[@"X-Reqid"];
|
||||
NSString *xlog = headers[@"X-Log"];
|
||||
NSString *xvia = headers[@"X-Via"];
|
||||
if (xvia == nil) {
|
||||
xvia = headers[@"X-Px"];
|
||||
}
|
||||
if (xvia == nil) {
|
||||
xvia = headers[@"Fw-Via"];
|
||||
}
|
||||
info = [[QNResponseInfo alloc] init:status withReqId:reqId withXLog:xlog withXVia:xvia withHost:host withIp:ip withDuration:duration withBody:body];
|
||||
} else {
|
||||
info = [QNResponseInfo responseInfoWithNetError:error host:host duration:duration];
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
- (void)sendRequest:(NSMutableURLRequest *)request
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access {
|
||||
__block NSDate *startTime = [NSDate date];
|
||||
NSString *domain = request.URL.host;
|
||||
NSString *u = request.URL.absoluteString;
|
||||
NSURL *url = request.URL;
|
||||
NSArray *ips = nil;
|
||||
if (_converter != nil) {
|
||||
url = [[NSURL alloc] initWithString:_converter(u)];
|
||||
request.URL = url;
|
||||
domain = url.host;
|
||||
} else if (_noProxy && _dns != nil && [url.scheme isEqualToString:@"http"]) {
|
||||
if (isIpV6FullySupported() || ![QNIP isV6]) {
|
||||
ips = [_dns queryWithDomain:[[QNDomain alloc] init:domain hostsFirst:NO hasCname:YES maxTtl:1000]];
|
||||
double duration = [[NSDate date] timeIntervalSinceDate:startTime];
|
||||
|
||||
if (ips == nil || ips.count == 0) {
|
||||
NSError *error = [[NSError alloc] initWithDomain:domain code:-1003 userInfo:@{ @"error" : @"unkonwn host" }];
|
||||
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithNetError:error host:domain duration:duration];
|
||||
NSLog(@"failure %@", info);
|
||||
|
||||
completeBlock(info, nil);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
[self sendRequest2:request withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:cancelBlock withIpArray:ips withIndex:0 withDomain:domain withRetryTimes:3 withStartTime:startTime withAccess:access];
|
||||
}
|
||||
|
||||
- (void)sendRequest2:(NSMutableURLRequest *)request
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withIpArray:(NSArray *)ips
|
||||
withIndex:(int)index
|
||||
withDomain:(NSString *)domain
|
||||
withRetryTimes:(int)times
|
||||
withStartTime:(NSDate *)startTime
|
||||
withAccess:(NSString *)access {
|
||||
NSURL *url = request.URL;
|
||||
__block NSString *ip = nil;
|
||||
if (ips != nil) {
|
||||
ip = [ips objectAtIndex:(index % ips.count)];
|
||||
NSString *path = url.path;
|
||||
if (path == nil || [@"" isEqualToString:path]) {
|
||||
path = @"/";
|
||||
}
|
||||
url = buildUrl(ip, url.port, path);
|
||||
[request setValue:domain forHTTPHeaderField:@"Host"];
|
||||
}
|
||||
request.URL = url;
|
||||
[request setTimeoutInterval:_timeout];
|
||||
[request setValue:[[QNUserAgent sharedInstance] getUserAgent:access] forHTTPHeaderField:@"User-Agent"];
|
||||
[request setValue:nil forHTTPHeaderField:@"Accept-Language"];
|
||||
if (progressBlock == nil) {
|
||||
progressBlock = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
|
||||
};
|
||||
}
|
||||
QNInternalProgressBlock progressBlock2 = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
|
||||
progressBlock(totalBytesWritten, totalBytesExpectedToWrite);
|
||||
};
|
||||
__block QNProgessDelegate *delegate = [[QNProgessDelegate alloc] initWithProgress:progressBlock2];
|
||||
|
||||
NSURLSessionUploadTask *uploadTask = [_httpManager uploadTaskWithRequest:request fromData:nil progress:^(NSProgress *_Nonnull uploadProgress) {
|
||||
[delegate valueChange:uploadProgress];
|
||||
}
|
||||
completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
|
||||
NSData *data = responseObject;
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
double duration = [[NSDate date] timeIntervalSinceDate:startTime];
|
||||
QNResponseInfo *info;
|
||||
NSDictionary *resp = nil;
|
||||
if (_converter != nil && _noProxy && (index + 1 < ips.count || times > 0) && needRetry(httpResponse, error)) {
|
||||
[self sendRequest2:request withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:cancelBlock withIpArray:ips withIndex:index + 1 withDomain:domain withRetryTimes:times - 1 withStartTime:startTime withAccess:access];
|
||||
return;
|
||||
}
|
||||
if (error == nil) {
|
||||
info = [QNSessionManager buildResponseInfo:httpResponse withError:nil withDuration:duration withResponse:data withHost:domain withIp:ip];
|
||||
if (info.isOK) {
|
||||
NSError *tmp;
|
||||
resp = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&tmp];
|
||||
}
|
||||
} else {
|
||||
info = [QNSessionManager buildResponseInfo:httpResponse withError:error withDuration:duration withResponse:data withHost:domain withIp:ip];
|
||||
}
|
||||
completeBlock(info, resp);
|
||||
}];
|
||||
delegate.task = uploadTask;
|
||||
delegate.cancelBlock = cancelBlock;
|
||||
|
||||
[uploadTask resume];
|
||||
}
|
||||
|
||||
- (void)multipartPost:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withParams:(NSDictionary *)params
|
||||
withFileName:(NSString *)key
|
||||
withMimeType:(NSString *)mime
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access {
|
||||
NSMutableURLRequest *request = [_httpManager.requestSerializer multipartFormRequestWithMethod:@"POST"
|
||||
URLString:url
|
||||
parameters:params
|
||||
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
|
||||
[formData appendPartWithFileData:data name:@"file" fileName:key mimeType:mime];
|
||||
}
|
||||
error:nil];
|
||||
[self sendRequest:request withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:cancelBlock
|
||||
withAccess:access];
|
||||
}
|
||||
|
||||
- (void)post:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withParams:(NSDictionary *)params
|
||||
withHeaders:(NSDictionary *)headers
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock
|
||||
withCancelBlock:(QNCancelBlock)cancelBlock
|
||||
withAccess:(NSString *)access {
|
||||
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:url]];
|
||||
if (headers) {
|
||||
[request setAllHTTPHeaderFields:headers];
|
||||
}
|
||||
[request setHTTPMethod:@"POST"];
|
||||
if (params) {
|
||||
[request setValuesForKeysWithDictionary:params];
|
||||
}
|
||||
[request setHTTPBody:data];
|
||||
QNAsyncRun(^{
|
||||
[self sendRequest:request
|
||||
withCompleteBlock:completeBlock
|
||||
withProgressBlock:progressBlock
|
||||
withCancelBlock:cancelBlock
|
||||
withAccess:access];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)get:(NSString *)url
|
||||
withHeaders:(NSDictionary *)headers
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock {
|
||||
QNAsyncRun(^{
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
|
||||
|
||||
NSURL *URL = [NSURL URLWithString:url];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
|
||||
|
||||
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSData *s = [@"{}" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *resp = nil;
|
||||
QNResponseInfo *info;
|
||||
if (error == nil) {
|
||||
info = [QNSessionManager buildResponseInfo:httpResponse withError:nil withDuration:0 withResponse:s withHost:@"" withIp:@""];
|
||||
if (info.isOK) {
|
||||
resp = responseObject;
|
||||
}
|
||||
} else {
|
||||
info = [QNSessionManager buildResponseInfo:httpResponse withError:error withDuration:0 withResponse:s withHost:@"" withIp:@""];
|
||||
}
|
||||
|
||||
completeBlock(info, resp);
|
||||
}];
|
||||
[dataTask resume];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
37
msext/QiniuSDK/Http/QNUserAgent.h
Executable file
37
msext/QiniuSDK/Http/QNUserAgent.h
Executable file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// QNUserAgent.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14-9-29.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* UserAgent
|
||||
*
|
||||
*/
|
||||
|
||||
@interface QNUserAgent : NSObject
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *id;
|
||||
|
||||
/**
|
||||
* UserAgent 字串
|
||||
*/
|
||||
- (NSString *)description;
|
||||
|
||||
/**
|
||||
* UserAgent + AK 字串
|
||||
*/
|
||||
- (NSString *)getUserAgent:(NSString *)access;
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
+ (instancetype)sharedInstance;
|
||||
@end
|
||||
86
msext/QiniuSDK/Http/QNUserAgent.m
Executable file
86
msext/QiniuSDK/Http/QNUserAgent.m
Executable file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// QNUserAgent.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14-9-29.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#import <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#import "QNUserAgent.h"
|
||||
#import "QNVersion.h"
|
||||
|
||||
static NSString *qn_clientId(void) {
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
NSString *s = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
|
||||
if (s == nil) {
|
||||
s = @"simulator";
|
||||
}
|
||||
return s;
|
||||
#else
|
||||
long long now_timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
|
||||
int r = arc4random() % 1000;
|
||||
return [NSString stringWithFormat:@"%lld%u", now_timestamp, r];
|
||||
#endif
|
||||
}
|
||||
|
||||
static NSString *qn_userAgent(NSString *id, NSString *ak) {
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
return [NSString stringWithFormat:@"QiniuObject-C/%@ (%@; iOS %@; %@; %@)", kQiniuVersion, [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], id, ak];
|
||||
#else
|
||||
return [NSString stringWithFormat:@"QiniuObject-C/%@ (Mac OS X %@; %@; %@)", kQiniuVersion, [[NSProcessInfo processInfo] operatingSystemVersionString], id, ak];
|
||||
#endif
|
||||
}
|
||||
|
||||
@interface QNUserAgent ()
|
||||
@property (nonatomic) NSString *ua;
|
||||
@end
|
||||
|
||||
@implementation QNUserAgent
|
||||
|
||||
- (NSString *)description {
|
||||
return _ua;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_id = qn_clientId();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* UserAgent
|
||||
*/
|
||||
- (NSString *)getUserAgent:(NSString *)access {
|
||||
NSString *ak;
|
||||
if (access == nil || access.length == 0) {
|
||||
ak = @"-";
|
||||
} else {
|
||||
ak = access;
|
||||
}
|
||||
return qn_userAgent(_id, ak);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
+ (instancetype)sharedInstance {
|
||||
static QNUserAgent *sharedInstance = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user