diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..66c32d5 --- /dev/null +++ b/Podfile @@ -0,0 +1,8 @@ +source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git' + +platform :ios, '9.0' + +target 'msext' do + # 添加七牛云SDK + pod 'Qiniu', '~> 8.0' +end \ No newline at end of file diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..03f6997 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,20 @@ +PODS: + - HappyDNS (1.0.4) + - Qiniu (8.8.1): + - HappyDNS (~> 1.0.4) + +DEPENDENCIES: + - Qiniu (~> 8.0) + +SPEC REPOS: + https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git: + - HappyDNS + - Qiniu + +SPEC CHECKSUMS: + HappyDNS: aefbd28cdcda93cffac64013dfe3342a2f87ed0a + Qiniu: 37131e52fdf43fe70da0c89dd0df3c9ce25bb74b + +PODFILE CHECKSUM: 4aa3a53aaead366c96efe2b5f93ec0e4c4468bc0 + +COCOAPODS: 1.15.2 diff --git a/Pods/HappyDNS/HappyDNS/Common/QNDnsError.h b/Pods/HappyDNS/HappyDNS/Common/QNDnsError.h new file mode 100644 index 0000000..97e863f --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNDnsError.h @@ -0,0 +1,36 @@ +// +// QNDnsError.h +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +extern const int kQNDomainHijackingCode; +extern const int kQNDomainNotOwnCode; +extern const int kQNDomainSeverError; + +extern const int kQNDnsMethodErrorCode; +extern const int kQNDnsInvalidParamCode; +extern const int kQNDnsResponseBadTypeCode; +extern const int kQNDnsResponseBadClassCode; +extern const int kQNDnsResponseFormatCode; + +#define kQNDnsErrorDomain @"qiniu.dns" + +@interface QNDnsError : NSObject + ++ (NSError *)error:(int)code desc:(NSString *)desc; + +@end + +#define kQNDnsMethodError(description) [QNDnsError error:kQNDnsMethodErrorCode desc:description] +#define kQNDnsInvalidParamError(description) [QNDnsError error:kQNDnsInvalidParamCode desc:description] +#define kQNDnsResponseBadTypeError(description) [QNDnsError error:kQNDnsResponseBadTypeCode desc:description] +#define kQNDnsResponseBadClassError(description) [QNDnsError error:kQNDnsResponseBadClassCode desc:description] +#define kQNDnsResponseFormatError(description) [QNDnsError error:kQNDnsResponseFormatCode desc:description] + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Common/QNDnsError.m b/Pods/HappyDNS/HappyDNS/Common/QNDnsError.m new file mode 100644 index 0000000..d2c368f --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNDnsError.m @@ -0,0 +1,27 @@ +// +// QNDnsError.m +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import "QNDnsError.h" + +const int kQNDomainHijackingCode = -7001; +const int kQNDomainNotOwnCode = -7002; +const int kQNDomainSeverError = -7003; + +const int kQNDnsMethodErrorCode = -7010; + +const int kQNDnsInvalidParamCode = -7021; +const int kQNDnsResponseBadTypeCode = -7022; +const int kQNDnsResponseBadClassCode = -7023; +const int kQNDnsResponseFormatCode = -7024; + +@implementation QNDnsError + ++ (NSError *)error:(int)code desc:(NSString *)desc { + return [NSError errorWithDomain:kQNDnsErrorDomain code:code userInfo:@{@"user_info" : desc ?: @"nil"}]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNDnsManager.h b/Pods/HappyDNS/HappyDNS/Common/QNDnsManager.h new file mode 100644 index 0000000..90e2d5b --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNDnsManager.h @@ -0,0 +1,174 @@ +// +// QNDnsManager.h +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNRecord.h" + +@class QNNetworkInfo; +@class QNDomain; + +/** + * getaddrinfo 回调上层的函数 + * + * @param host 请求的域名 + * @return ip 列表 + */ +typedef NSArray * (^QNGetAddrInfoCallback)(NSString *host); + +/** + * ip status 回调上层的函数 + * + * @param ip 请求的IP + * @param code 错误码 + * @param ms 消耗时间 + */ +typedef void (^QNIpStatusCallback)(NSString *ip, int code, int ms); + +/** + * 外部 Record 排序接口 + */ +@protocol QNRecordSorter + +/** + * 排序方法 + * + * @param ips 传入的IP列表 + * + * @return 返回排序好的IP 列表 + */ +- (NSArray *)sort:(NSArray *)ips; +@end + +/** + * DNS请求客户端,集成了cache管理 + */ +@interface QNDnsManager : NSObject + +/// 查询失败时抛出错误信息回调 +@property(nonatomic, copy)void(^queryErrorHandler)(NSError *error, NSString *host); + +/** + * 解析域名 + * + * @param domain 域名 + * + * @return QNRecord列表 QNRecord.value即为host +*/ +- (NSArray *)queryRecords:(NSString *)domain; + +/** + * 解析域名,使用Domain对象进行详细约定 + * + * @param domain 配置了一些domain 参数的 domain 对象 + * + * @return IP 列表 + */ +- (NSArray *)queryRecordsWithDomain:(QNDomain *)domain; + +/** + * 通知网络发生变化 + * + * @param netInfo 网络信息 + */ +- (void)onNetworkChange:(QNNetworkInfo *)netInfo; + +/** + * Dns client 初始化 + * + * @param resolvers 解析服务器列表 + * @param netInfo 当前网络信息 + * + * @return DnsManager + */ +- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo; + +/** + * Dns client 初始化 + * + * @param resolvers 解析服务器列表 + * @param netInfo 当前网络信息 + * @param sorter 外部排序函数 + * + * @return DnsManager + */ +- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo sorter:(id)sorter; + +/** + * 内置 Hosts 解析 + * + * @param domain 域名 + * @param ipv4 对应IPv4 ip + * + * @return 当前Dnsmanager, 为了链式调用 + */ +- (instancetype)putHosts:(NSString *)domain ipv4:(NSString *)ipv4; + +/** + * 内置 Hosts 解析 + * + * @param domain 域名 + * @param ip 对应IP + * @param type ip 类别,kQNTypeA / kQNTypeAAAA + * @param provider 网络运营商 + * + * @return 当前Dnsmanager, 为了链式调用 + */ +- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip type:(int)type provider:(int)provider; + +/** + * 内置 Hosts 解析 + * + * @param domain 域名 + * @param record 对应 record 记录 + * @param provider 网络运营商 + * + * @return 当前Dnsmanager, 为了链式调用 + */ +- (instancetype)putHosts:(NSString *)domain record:(QNRecord *)record provider:(int)provider; + +/** + * 设置底层 getaddrinfo 使用的回调 + * + * @param block 回调的代码块 + */ ++ (void)setGetAddrInfoBlock:(QNGetAddrInfoCallback)block; + +/** + * 设置底层 getaddrinfo 回调使用的dnsmanager + * + * @param dns 回调用的dnsmanager + */ ++ (void)setDnsManagerForGetAddrInfo:(QNDnsManager *)dns; + +/** + * 设置底层 业务统计 如connect 回调使用的Callback + * + * @param block 回调返回该IP状态 + */ ++ (void)setIpStatusCallback:(QNIpStatusCallback)block; + +/** + * 根据时区判断是否要设置httpDns + */ ++ (BOOL)needHttpDns; + +@end + +/** + * DnsManager 的 URL 辅助类 + */ +@interface QNDnsManager (NSURL) + +/** + * 使用URL 进行请求 + * + * @param url 请求的Url + * + * @return 返回IP 替换过的url + */ +- (NSURL *)queryAndReplaceWithIP:(NSURL *)url; +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNDnsManager.m b/Pods/HappyDNS/HappyDNS/Common/QNDnsManager.m new file mode 100644 index 0000000..602289a --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNDnsManager.m @@ -0,0 +1,322 @@ +// +// QNDnsManager.m +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNDnsManager.h" +#import "QNDomain.h" +#import "QNHosts.h" +#import "QNIP.h" +#import "QNLruCache.h" +#import "QNNetworkInfo.h" +#import "QNRecord.h" +#import "QNResolverDelegate.h" + +#include "QNGetAddrInfo.h" + +@interface QNDnsManager () + +@property (nonatomic, strong) QNLruCache *cache; +@property (atomic) QNNetworkInfo *curNetwork; +@property (nonatomic) NSArray *resolvers; +@property (atomic) UInt32 resolverStatus; +@property (nonatomic, strong) QNHosts *hosts; +@property (nonatomic, strong) id sorter; +@end + +//static inline BOOL bits_isSet(UInt32 v, int index) { +// return (v & (1 << index)) != 0; +//} + +static inline UInt32 bits_set(UInt32 v, int bitIndex) { + return v |= (1 << bitIndex); +} + +static inline UInt32 bits_leadingZeros(UInt32 x) { + UInt32 y; + int n = 32; + y = x >> 16; + if (y != 0) { + n = n - 16; + x = y; + } + y = x >> 8; + if (y != 0) { + n = n - 8; + x = y; + } + y = x >> 4; + if (y != 0) { + n = n - 4; + x = y; + } + y = x >> 2; + if (y != 0) { + n = n - 2; + x = y; + } + y = x >> 1; + if (y != 0) { + return n - 2; + } + return n - x; +} + +static NSMutableArray *trimCname(NSArray *records) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + for (QNRecord *r in records) { + if (r.type == kQNTypeA || r.type == kQNTypeAAAA) { + [array addObject:r]; + } + } + return array; +} + +static NSArray *records2Ips(NSArray *records) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + for (QNRecord *r in records) { + if (r.value && r.value.length > 0) { + [array addObject:r.value]; + } + } + return [array copy]; +} + +static NSArray * filterInvalidRecords(NSArray *records) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + long long timestamp = [[NSDate date] timeIntervalSince1970]; + for (QNRecord *r in records) { + if (r.value && r.value.length > 0 && ![r expired:timestamp]) { + [array addObject:r]; + } + } + return [array copy]; +} + +@interface DummySorter : NSObject + +@end + +@implementation DummySorter + +//sorted already +- (NSArray *)sort:(NSArray *)ips { + return ips; +} + +@end + +@implementation QNDnsManager + +- (NSArray *)queryRecords:(NSString *)domain { + return [self queryRecordsWithDomain:[[QNDomain alloc] init:domain]]; +} + +- (NSArray *)queryRecordsWithDomain:(QNDomain *)domain{ + if (domain == nil) { + return nil; + } + if ([QNIP mayBeIpV4:domain.domain]) { + QNRecord *record = [[QNRecord alloc] init:domain.domain ttl:kQNRecordForeverTTL type:kQNTypeA source:QNRecordSourceUnknown]; + return [NSArray arrayWithObject:record]; + } + NSArray *records = [self queryInternalWithDomain:domain]; + return [_sorter sort:records]; +} + +- (NSArray *)queryInternalWithDomain:(QNDomain *)domain { + if (domain.hostsFirst) { + NSArray *result = [_hosts query:domain networkInfo:_curNetwork]; + result = filterInvalidRecords(result); + if (result.count > 0) { + return [result copy]; + } + } + + if ([_curNetwork isEqualToInfo:[QNNetworkInfo normal]] && [QNNetworkInfo isNetworkChanged]) { + @synchronized(_cache) { + [_cache removeAllObjects]; + } + _resolverStatus = 0; + } else { + @synchronized(_cache) { + NSArray *result = [_cache objectForKey:domain.domain]; + result = filterInvalidRecords(result); + if (result.count > 0) { + return [result copy]; + } + } + } + + NSArray *records = nil; + NSError *error = nil; + int firstOk = 32 - bits_leadingZeros(_resolverStatus); + for (int i = 0; i < _resolvers.count; i++) { + int pos = (firstOk + i) % _resolvers.count; + id resolver = [_resolvers objectAtIndex:pos]; + QNNetworkInfo *previousNetwork = _curNetwork; + NSString *previousIp = [QNNetworkInfo getIp]; + records = [resolver query:domain networkInfo:previousNetwork error:&error]; + if (error != nil) { + NSError *tmp = error; + error = nil; + if (tmp.code == kQNDomainNotOwnCode) { + continue; + } + + if (self.queryErrorHandler) { + self.queryErrorHandler(error, domain.domain); + } + } + + if (records == nil || records.count == 0) { + if (_curNetwork == previousNetwork && [previousIp isEqualToString:[QNNetworkInfo getIp]]) { + _resolverStatus = bits_set(_resolverStatus, pos); + } + } else { + NSMutableArray *result = trimCname(records); + if (_curNetwork == previousNetwork && [previousIp isEqualToString:[QNNetworkInfo getIp]]) { + @synchronized(_cache) { + [_cache setObject:[result copy] forKey:domain.domain]; + } + } + return [result copy]; + } + } + + if (!domain.hostsFirst) { + return [_hosts query:domain networkInfo:_curNetwork]; + } + + return nil; +} + +- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo { + return [self init:resolvers networkInfo:netInfo sorter:nil]; +} + +- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo sorter:(id)sorter { + if (self = [super init]) { + _cache = [[QNLruCache alloc] init:1024]; + _curNetwork = netInfo; + _resolvers = [[NSArray alloc] initWithArray:resolvers]; + _hosts = [[QNHosts alloc] init]; + if (sorter == nil) { + _sorter = [[DummySorter alloc] init]; + } else { + _sorter = sorter; + } + } + return self; +} + +- (void)onNetworkChange:(QNNetworkInfo *)netInfo { + @synchronized(_cache) { + [_cache removeAllObjects]; + } + _curNetwork = netInfo; +} + +- (instancetype)putHosts:(NSString *)domain ipv4:(NSString *)ipv4 { + return [self putHosts:domain ip:ipv4 type:kQNTypeA provider:kQNISP_GENERAL]; +} + +- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip type:(int)type provider:(int)provider { + return [self putHosts:domain record:[[QNRecord alloc] init:ip ttl:kQNRecordForeverTTL type:type source:QNRecordSourceCustom] provider:provider]; +} + +- (instancetype)putHosts:(NSString *)domain record:(QNRecord *)record provider:(int)provider { + QNRecord *recordNew = [[QNRecord alloc] init:record.value ttl:record.ttl type:record.type timeStamp:record.timeStamp server:record.server source:QNRecordSourceCustom]; + [_hosts put:domain record:recordNew provider:provider]; + return self; +} + +- (NSURL *)queryAndReplaceWithIP:(NSURL *)url { + NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:YES]; + if (!urlComponents) { + return nil; + } + + NSString *host = urlComponents.host; + NSArray *records = [self queryRecords:host]; + + NSURL *URL = nil; + if (records && records.firstObject) { + urlComponents.host = [QNIP ipHost:records.firstObject.value]; + } + + URL = urlComponents.URL; + return URL; +} + +static QNGetAddrInfoCallback getAddrInfoCallback = nil; +static qn_ips_ret *dns_callback_internal(const char *host) { + if (getAddrInfoCallback == nil) { + return NULL; + } + NSString *s = [[NSString alloc] initWithUTF8String:host]; + if (s == nil) { + return NULL; + } + NSArray *ips = getAddrInfoCallback(s); + if (ips == nil) { + return NULL; + } + qn_ips_ret *ret = calloc(sizeof(char *), ips.count + 1); + for (int i = 0; i < ips.count; i++) { + NSString *ip = ips[i]; + char *ip2 = strdup([ip cStringUsingEncoding:NSUTF8StringEncoding]); + ret->ips[i] = ip2; + } + return ret; +} +static qn_ips_ret *dns_callback(const char *host) { + qn_ips_ret *ret = dns_callback_internal(host); + if (ret == NULL) { + //only for compatible + qn_ips_ret *ret = calloc(sizeof(char *), 2); + ret->ips[0] = strdup(host); + } + return ret; +} + +static QNIpStatusCallback ipStatusCallback = nil; +static void ip_status_callback(const char *ip, int code, int time_ms) { + if (ipStatusCallback == nil) { + return; + } + NSString *s = [[NSString alloc] initWithUTF8String:ip]; + if (s == nil) { + return; + } + ipStatusCallback(s, code, time_ms); +} + ++ (void)setGetAddrInfoBlock:(QNGetAddrInfoCallback)block { + if ([QNIP isIpV6FullySupported] || ![QNIP isV6]) { + getAddrInfoCallback = block; + qn_set_dns_callback(dns_callback); + } +} + ++ (void)setDnsManagerForGetAddrInfo:(QNDnsManager *)dns { + [QNDnsManager setGetAddrInfoBlock:^NSArray *(NSString *host) { + NSArray *records = [dns queryRecords:host]; + return records2Ips(records); + }]; +} + ++ (void)setIpStatusCallback:(QNIpStatusCallback)block { + ipStatusCallback = block; + qn_set_ip_report_callback(ip_status_callback); +} + ++ (BOOL)needHttpDns { + NSTimeZone *timeZone = [NSTimeZone localTimeZone]; + NSString *tzName = [timeZone name]; + return [tzName isEqual:@"Asia/Shanghai"] || [tzName isEqual:@"Asia/Chongqing"] || [tzName isEqual:@"Asia/Harbin"] || [tzName isEqual:@"Asia/Urumqi"]; +} +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNDomain.h b/Pods/HappyDNS/HappyDNS/Common/QNDomain.h new file mode 100644 index 0000000..6218b14 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNDomain.h @@ -0,0 +1,27 @@ +// +// QNDomain.h +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +@interface QNDomain : NSObject +@property (nonatomic, strong, readonly) NSString *domain; + +// 用来判断劫持 +@property (nonatomic, readonly) BOOL hasCname; +// 用来判断劫持 +@property (nonatomic, readonly) int maxTtl; + +@property (nonatomic, readonly) BOOL hostsFirst; + +- (instancetype)init:(NSString *)domain; + +- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname; + +- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname maxTtl:(int)maxTtl; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNDomain.m b/Pods/HappyDNS/HappyDNS/Common/QNDomain.m new file mode 100644 index 0000000..56d138d --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNDomain.m @@ -0,0 +1,30 @@ +// +// QNDomain.m +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNDomain.h" + +@implementation QNDomain +- (instancetype)init:(NSString *)domain { + return [self init:domain hostsFirst:NO hasCname:NO maxTtl:0]; +} + +- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname { + return [self init:domain hostsFirst:hostsFirst hasCname:hasCname maxTtl:0]; +} + +- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname maxTtl:(int)maxTtl { + if (self = [super init]) { + _domain = domain; + _hasCname = hasCname; + _maxTtl = maxTtl; + _hostsFirst = hostsFirst; + } + return self; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNLruCache.h b/Pods/HappyDNS/HappyDNS/Common/QNLruCache.h new file mode 100644 index 0000000..e6c8785 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNLruCache.h @@ -0,0 +1,23 @@ +// +// QNLruCache.h +// HappyDNS +// +// Created by bailong on 16/7/5. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +@interface QNLruCache : NSObject + +- (instancetype)init:(NSUInteger)limit; + +- (void)removeAllObjects; + +- (void)removeObjectForKey:(NSString *)key; + +- (id)objectForKey:(NSString *)key; + +- (void)setObject:(id)obj forKey:(NSString *)key; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNLruCache.m b/Pods/HappyDNS/HappyDNS/Common/QNLruCache.m new file mode 100644 index 0000000..e318959 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNLruCache.m @@ -0,0 +1,90 @@ +// +// QNLruCache.m +// HappyDNS +// +// Created by bailong on 16/7/5. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNLruCache.h" + +@interface QNLruCache () + +@property (nonatomic, readonly) NSUInteger limit; + +@property (nonatomic, readonly) NSMutableDictionary* cache; + +@property (nonatomic, readonly) NSMutableArray* list; + +@end + +@interface _QNElement : NSObject +@property (nonatomic, readonly, strong) NSString* key; +@property (nonatomic, strong) id obj; +- (instancetype)initObject:(id)obj forKey:(NSString*)key; +@end + +@implementation _QNElement + +- (instancetype)initObject:(id)obj forKey:(NSString*)key { + if (self = [super init]) { + _key = key; + _obj = obj; + } + return self; +} + +@end + +@implementation QNLruCache + +- (instancetype)init:(NSUInteger)limit { + if (self = [super init]) { + _limit = limit; + _cache = [NSMutableDictionary new]; + _list = [NSMutableArray new]; + } + return self; +} + +- (void)removeAllObjects { + [_cache removeAllObjects]; + [_list removeAllObjects]; +} + +- (void)removeObjectForKey:(NSString*)key { + _QNElement* obj = [_cache objectForKey:key]; + if (obj == nil) { + return; + } + [_cache removeObjectForKey:key]; + [_list removeObjectIdenticalTo:obj]; +} + +- (id)objectForKey:(NSString*)key { + _QNElement* obj = [_cache objectForKey:key]; + if (obj != nil) { + [_list removeObjectIdenticalTo:obj]; + [_list insertObject:obj atIndex:0]; + } + return obj.obj; +} + +- (void)setObject:(id)obj forKey:(NSString*)key { + _QNElement* old = [_cache objectForKey:key]; + if (old) { + old.obj = obj; + [_list removeObjectIdenticalTo:old]; + [_list insertObject:old atIndex:0]; + return; + } else if (_list.count == _limit) { + old = [_list lastObject]; + [_list removeLastObject]; + [_cache removeObjectForKey:old.key]; + } + _QNElement* newElement = [[_QNElement alloc] initObject:obj forKey:key]; + [_cache setObject:newElement forKey:key]; + [_list insertObject:newElement atIndex:0]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.h b/Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.h new file mode 100644 index 0000000..a0e7153 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.h @@ -0,0 +1,42 @@ +// +// QNNetworkInfo.h +// HappyDNS +// +// Created by bailong on 15/6/25. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +extern const int kQNNO_NETWORK; +extern const int kQNWIFI; +extern const int kQNMOBILE; + +extern const int kQNISP_GENERAL; +extern const int kQNISP_CTC; +extern const int kQNISP_DIANXIN; +extern const int kQNISP_CNC; +extern const int kQNISP_LIANTONG; +extern const int kQNISP_CMCC; +extern const int kQNISP_YIDONG; +extern const int kQNISP_OTHER; + +@interface QNNetworkInfo : NSObject + +@property (nonatomic, readonly) int networkConnection; +@property (nonatomic, readonly) int provider; + +- (instancetype)init:(int)connecton provider:(int)provider; + +- (BOOL)isEqual:(id)other; +- (BOOL)isEqualToInfo:(QNNetworkInfo *)info; + ++ (instancetype)noNet; + ++ (instancetype)normal; + ++ (BOOL)isNetworkChanged; + ++ (NSString *)getIp; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.m b/Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.m new file mode 100644 index 0000000..84d928c --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.m @@ -0,0 +1,86 @@ +// +// QNNetworkInfo.m +// HappyDNS +// +// Created by bailong on 15/6/25. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import +#include +#include +#include +#include + +#import "QNIP.h" +#import "QNNetworkInfo.h" + +const int kQNNO_NETWORK = -1; +const int kQNWIFI = 1; +const int kQNMOBILE = 2; + +const int kQNISP_GENERAL = 0; +const int kQNISP_CTC = 1; +const int kQNISP_DIANXIN = kQNISP_CTC; +const int kQNISP_CNC = 2; +const int kQNISP_LIANTONG = kQNISP_CNC; +const int kQNISP_CMCC = 3; +const int kQNISP_YIDONG = kQNISP_CMCC; +const int kQNISP_OTHER = 999; + +#define IPLength 64 + +static char previousIp[IPLength] = {0}; +static NSString *lock = @""; + +@implementation QNNetworkInfo + +- (instancetype)init:(int)connecton provider:(int)provider { + if (self = [super init]) { + _networkConnection = connecton; + _provider = provider; + } + return self; +} + ++ (instancetype)noNet { + return [[QNNetworkInfo alloc] init:kQNNO_NETWORK provider:kQNISP_GENERAL]; +} + ++ (instancetype)normal { + return [[QNNetworkInfo alloc] init:kQNISP_GENERAL provider:kQNISP_GENERAL]; +} + +- (BOOL)isEqualToInfo:(QNNetworkInfo *)info { + if (self == info) + return YES; + return self.provider == info.provider && self.networkConnection == info.networkConnection; +} + +- (BOOL)isEqual:(id)other { + if (other == self) + return YES; + if (!other || ![other isKindOfClass:[self class]]) + return NO; + return [self isEqualToInfo:other]; +} + ++ (BOOL)isNetworkChanged { + @synchronized(lock) { + char local[IPLength] = {0}; + int err = qn_localIp(local, sizeof(local)); + if (err != 0) { + return YES; + } + if (memcmp(previousIp, local, sizeof(local)) != 0) { + memcpy(previousIp, local, sizeof(local)); + return YES; + } + return NO; + } +} + ++ (NSString *)getIp { + return [QNIP local]; +} +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNRecord.h b/Pods/HappyDNS/HappyDNS/Common/QNRecord.h new file mode 100644 index 0000000..4ebe36c --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNRecord.h @@ -0,0 +1,69 @@ +// +// QNRecord.h +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +/** + * A 记录 + */ +extern const int kQNTypeA; + +/** + * AAAA 记录 + */ +extern const int kQNTypeAAAA; + +/** + * Cname 记录 + */ +extern const int kQNTypeCname; + +/** + * Txt 记录 + */ +extern const int kQNTypeTXT; + +/** + * 永久有效的 ttl + */ +extern const int kQNRecordForeverTTL; + +typedef NS_ENUM(NSUInteger, QNRecordSource) { + QNRecordSourceUnknown, + QNRecordSourceCustom, + QNRecordSourceDnspodEnterprise, + QNRecordSourceSystem, + QNRecordSourceUdp, + QNRecordSourceDoh, +}; + + +@interface QNRecord : NSObject + +@property (nonatomic, copy, readonly) NSString *value; +@property (nonatomic, copy, readonly) NSString *server; +@property (nonatomic, readonly) int ttl; +@property (nonatomic, readonly) int type; +@property (nonatomic, readonly) long long timeStamp; +@property (nonatomic, readonly) QNRecordSource source; + +- (instancetype)init:(NSString *)value + ttl:(int)ttl + type:(int)type + source:(QNRecordSource)source; + +- (instancetype)init:(NSString *)value + ttl:(int)ttl + type:(int)type + timeStamp:(long long)timeStamp + server:(NSString *)server + source:(QNRecordSource)source; + +- (BOOL)expired:(long long)time; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNRecord.m b/Pods/HappyDNS/HappyDNS/Common/QNRecord.m new file mode 100644 index 0000000..b37b614 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNRecord.m @@ -0,0 +1,60 @@ +// +// QNRecord.m +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNRecord.h" + +const int kQNTypeA = 1; +const int kQNTypeAAAA = 28; +const int kQNTypeCname = 5; +const int kQNTypeTXT = 16; +const int kQNRecordForeverTTL = -1; + +@implementation QNRecord +- (instancetype)init:(NSString *)value + ttl:(int)ttl + type:(int)type + source:(QNRecordSource)source { + if (self = [super init]) { + _value = value; + _type = type; + _ttl = ttl; + _source = source; + _timeStamp = [[NSDate date] timeIntervalSince1970]; + } + return self; +} + +- (instancetype)init:(NSString *)value + ttl:(int)ttl + type:(int)type + timeStamp:(long long)timeStamp + server:(NSString *)server + source:(QNRecordSource)source { + if (self = [super init]) { + _value = value; + _type = type; + _ttl = ttl; + _server = server; + _source = source; + _timeStamp = timeStamp; + } + return self; +} + +- (BOOL)expired:(long long)time { + if (_ttl == kQNRecordForeverTTL) { + return false; + } + return time > _timeStamp + _ttl; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"value:%@, ttl:%d, timestamp:%lld, type:%d server:%@ source:%lu", _value, _ttl, _timeStamp, _type, _server, (unsigned long)_source]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Common/QNResolverDelegate.h b/Pods/HappyDNS/HappyDNS/Common/QNResolverDelegate.h new file mode 100644 index 0000000..0fff1cb --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Common/QNResolverDelegate.h @@ -0,0 +1,19 @@ +// +// QNResolverDelegate.h +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNDnsError.h" + +#define QN_DNS_DEFAULT_TIMEOUT 20 //seconds + +@class QNDomain; +@class QNNetworkInfo; +@protocol QNResolverDelegate + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError **)error; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsDefine.h b/Pods/HappyDNS/HappyDNS/Dns/QNDnsDefine.h new file mode 100644 index 0000000..32945f6 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsDefine.h @@ -0,0 +1,15 @@ +// +// QNDnsDefine.h +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import + +typedef NS_ENUM(NSInteger, QNDnsOpCode) { + QNDnsOpCodeQuery = 0, // 标准查询 + QNDnsOpCodeIQuery = 1, // 反向查询 + QNDnsOpCodeStatus = 2, // DNS状态请求 + QNDnsOpCodeUpdate = 5, // DNS域更新请求 +}; diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.h b/Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.h new file mode 100644 index 0000000..f6a1870 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.h @@ -0,0 +1,41 @@ +// +// QNDnsMessage.h +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDnsMessage : NSObject + +/** + * 16位的消息ID标示一次正常的交互,该ID由消息请求者设置,消息响应者回复请求时带上该ID。最大:0xFFFF,即:65536 + */ +@property(nonatomic, assign, readonly)int messageId; + +/** + * 请求类型,目前有三类值: + * 0 QUERY, 标准查询 + * 1 IQUERY, 反向查询 + * 2 STATUS, DNS状态请求 + * 5 UPDATE, DNS域更新请求 + */ +@property(nonatomic, assign, readonly)int opCode; + +/** + * 是否递归查询。如果该位被设置为1,则收到请求的域名服务器会递归查询域名, + * 注: 该位为1,域名服务器不一定会做递归查询,这取决于域名服务器是否支持递归查询。 + */ +@property(nonatomic, assign, readonly)int rd; + +/** + * 在响应消息中清除并设置。表示该DNS域名服务器是否支持递归查询。 + */ +@property(nonatomic, assign, readonly)int ra; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.m b/Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.m new file mode 100644 index 0000000..234e7a6 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.m @@ -0,0 +1,12 @@ +// +// QNDnsMessage.m +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import "QNDnsMessage.h" + +@implementation QNDnsMessage + +@end diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.h b/Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.h new file mode 100644 index 0000000..9338934 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.h @@ -0,0 +1,43 @@ +// +// DnsQuestion.h +// Doh +// +// Created by yangsen on 2021/7/16. +// + +#import "QNDnsDefine.h" +#import "QNDnsMessage.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDnsRequest : QNDnsMessage + +@property(nonatomic, assign, readonly)int recordType; +@property(nonatomic, copy, readonly)NSString *host; + +/// 构造函数 +/// @param messageId 请求 id +/// @param recordType 记录类型 +/// @param host 需要进行 Dns 解析的 host ++ (instancetype)request:(int)messageId + recordType:(int)recordType + host:(NSString *)host; + +/// 构造函数 +/// @param messageId 请求 id +/// @param opCode 请求类型 +/// @param rd 是否递归查询。如果该位被设置为1,则收到请求的域名服务器会递归查询域名 +/// 注: 该位为1,域名服务器不一定会做递归查询,这取决于域名服务器是否支持递归查询。 +/// @param recordType 记录类型 +/// @param host 需要进行 Dns 解析的 host ++ (instancetype)request:(int)messageId + opCode:(QNDnsOpCode)opCode + rd:(int)rd + recordType:(int)recordType + host:(NSString *)host; + +- (NSData *)toDnsQuestionData:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.m b/Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.m new file mode 100644 index 0000000..0ce1ff4 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.m @@ -0,0 +1,118 @@ +// +// DnsQuestion.m +// Doh +// +// Created by yangsen on 2021/7/16. +// + +#import "QNRecord.h" +#import "NSData+QNRW.h" +#import "QNDnsError.h" +#import "QNDnsRequest.h" + +@interface QNDnsRequest() + +@property(nonatomic, assign)int messageId; +@property(nonatomic, assign)QNDnsOpCode opCode; +@property(nonatomic, assign)int rd; +@property(nonatomic, assign)int recordType; +@property(nonatomic, copy)NSString *host; + +@end +@implementation QNDnsRequest +@synthesize messageId; +@synthesize opCode; +@synthesize rd; + ++ (instancetype)request:(int)messageId + recordType:(int)recordType + host:(NSString *)host { + return [self request:messageId opCode:QNDnsOpCodeQuery rd:1 recordType:recordType host:host]; +} + ++ (instancetype)request:(int)messageId + opCode:(QNDnsOpCode)opCode + rd:(int)rd + recordType:(int)recordType + host:(NSString *)host { + QNDnsRequest *request = [[QNDnsRequest alloc] init]; + request.messageId = messageId; + request.opCode = opCode; + request.rd = rd; + request.recordType = recordType; + request.host = host; + return request; +} + +- (NSData *)toDnsQuestionData:(NSError *__autoreleasing _Nullable *)error { + if (self.host == nil || self.host.length == 0) { + [self copyError:kQNDnsInvalidParamError(@"host can not empty") toErrorPoint:error]; + return nil; + } + + if (self.opCode != QNDnsOpCodeQuery && + self.opCode != QNDnsOpCodeIQuery && + self.opCode != QNDnsOpCodeStatus && + self.opCode != QNDnsOpCodeUpdate) { + [self copyError:kQNDnsInvalidParamError(@"opCode is not valid") toErrorPoint:error]; + return nil; + } + + if (self.rd != 0 && self.rd != 1) { + [self copyError:kQNDnsInvalidParamError(@"rd is not valid") toErrorPoint:error]; + return nil; + } + + if (self.recordType != kQNTypeA && + self.recordType != kQNTypeCname && + self.recordType != kQNTypeTXT && + self.recordType != kQNTypeAAAA) { + [self copyError:kQNDnsInvalidParamError(@"recordType is not valid") toErrorPoint:error]; + return nil; + } + + NSMutableData *data = [NSMutableData data]; + [data qn_appendBigEndianInt16:self.messageId]; // 16 bit id + // |00|01|02|03|04|05|06|07| + // |QR| OPCODE |AA|TC|RD| + [data qn_appendInt8:(self.opCode<<3) + self.rd]; + // |00|01|02|03|04|05|06|07| + // |RA|r1|r2|r3| RCODE | + [data qn_appendInt8:0x00]; + [data qn_appendInt8:0x00]; + [data qn_appendInt8:0x01]; // QDCOUNT (number of entries in the question section) + [data qn_appendInt8:0x00]; + [data qn_appendInt8:0x00]; // ANCOUNT + [data qn_appendInt8:0x00]; + [data qn_appendInt8:0x00]; // NSCOUNT + [data qn_appendInt8:0x00]; + [data qn_appendInt8:0x00]; // ARCOUNT + + NSArray *hostParts = [self.host componentsSeparatedByString:@"."]; + for (NSString *part in hostParts) { + if (part.length > 63) { + return nil; + } + [data qn_appendInt8:part.length]; + [data qn_appendString:part usingEncoding:NSUTF8StringEncoding]; + } + [data qn_appendInt8:0x00]; /* terminating zero */ + [data qn_appendInt8:0x00]; + [data qn_appendInt8:self.recordType]; + [data qn_appendInt8:0x00]; + [data qn_appendInt8:0x01]; /* IN - "the Internet" */ + + return data; +} + +- (void)copyError:(NSError *)error toErrorPoint:(NSError **)errorPoint { + if (errorPoint != nil) { + *errorPoint = error; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"messageId:%d opcode:%ld rd:%d ra:%d type:%ld", self.messageId, (long)self.opCode, self.rd, self.ra, (long)self.recordType]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.h b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.h new file mode 100644 index 0000000..ee69a31 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.h @@ -0,0 +1,33 @@ +// +// QNDnsResolver.h +// HappyDNS +// +// Created by yangsen on 2021/7/28. +// Copyright © 2021 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNDnsDefine.h" +#import "QNRecord.h" +#import "QNResolverDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNDnsResponse; +// 抽象对象,不能直接使用,使用其子类 +@interface QNDnsResolver : NSObject + +@property(nonatomic, assign, readonly)int recordType; +@property(nonatomic, assign, readonly)int timeout; +@property(nonatomic, copy, readonly)NSArray *servers; + + + +// 抽象方法,子类实现 +- (void)request:(NSString *)server + host:(NSString *)host + recordType:(int)recordType + complete:(void(^)(QNDnsResponse *response, NSError *error))complete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.m b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.m new file mode 100644 index 0000000..124313c --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.m @@ -0,0 +1,129 @@ +// +// QNDnsResolver.m +// HappyDNS +// +// Created by yangsen on 2021/7/28. +// Copyright © 2021 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNRecord.h" +#import "QNDomain.h" +#import "QNDnsError.h" +#import "QNDnsResponse.h" +#import "QNDnsResolver.h" + +@interface QNDnsResolver() + +@property(nonatomic, strong)dispatch_queue_t timerQueue; + +@end +@implementation QNDnsResolver ++ (dispatch_queue_t)timeoutQueue { + static dispatch_once_t onceToken; + static dispatch_queue_t timerQueue; + dispatch_once(&onceToken, ^{ + timerQueue = dispatch_queue_create("com.happyDns.timeoutQueue", DISPATCH_QUEUE_CONCURRENT); + }); + return timerQueue; +} + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error { + NSError *err = nil; + QNDnsResponse *response = [self lookupHost:domain.domain error:&err]; + if (err != nil) { + *error = err; + return @[]; + } + + NSMutableArray *records = [NSMutableArray array]; + for (QNRecord *record in response.answerArray) { + if (record.type == kQNTypeA || record.type == kQNTypeAAAA || record.type == kQNTypeCname) { + [records addObject:record]; + } + } + return [records copy]; +} + +- (QNDnsResponse *)lookupHost:(NSString *)host error:(NSError *__autoreleasing _Nullable *)error { + + // 异步转同步 + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + __block NSError *errorP = nil; + __block QNDnsResponse *dnsResponse = nil; + [self request:host recordType:self.recordType complete:^(QNDnsResponse *response, NSError *err) { + errorP = err; + dnsResponse = response; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, self.timeout * NSEC_PER_SEC)); + + if (error != NULL) { + *error = errorP; + } + + return dnsResponse; +} + +- (void)request:(NSString *)host + recordType:(int)recordType + complete:(void(^)(QNDnsResponse *response, NSError *error))complete { + if (complete == nil) { + return; + } + + if (self.servers == nil || self.servers.count == 0) { + complete(nil, kQNDnsInvalidParamError(@"server can not empty")); + return; + } + + NSLock *locker = [[NSLock alloc] init]; + __block BOOL hasCallBack = false; + __block BOOL completeCount = 0; + + // 超时处理 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), [QNDnsResolver timeoutQueue], ^{ + BOOL shouldCallBack = false; + [locker lock]; + if (!hasCallBack) { + shouldCallBack = true; + hasCallBack = true; + } + [locker unlock]; + + if (shouldCallBack) { + NSString *error = [NSString stringWithFormat:@"resolver timeout for server:%@ host:%@",[self.servers description], host]; + complete(nil, kQNDnsInvalidParamError(error)); + } + }); + + for (NSString *server in self.servers) { + [self request:server host:host recordType:recordType complete:^(QNDnsResponse *response, NSError *error) { + BOOL shouldCallBack = false; + + [locker lock]; + completeCount++; + if (completeCount == self.servers.count || (response != nil && response.rCode == 0 && !hasCallBack)) { + shouldCallBack = true; + hasCallBack = true; + } + [locker unlock]; + + if (shouldCallBack) { + complete(response, error); + } + }]; + } + +} + +- (void)request:(NSString *)server + host:(NSString *)host + recordType:(int)recordType + complete:(void(^)(QNDnsResponse *response, NSError *error))complete { + if (complete != nil) { + complete(nil, kQNDnsMethodError(@"use sub class of QNDnsResolver")); + } +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.h b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.h new file mode 100644 index 0000000..a44bdb8 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.h @@ -0,0 +1,46 @@ +// +// DnsRecord.h +// Doh +// +// Created by yangsen on 2021/7/16. +// + +#import "QNRecord.h" +#import "QNDnsRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDnsResponse : QNDnsMessage + +@property(nonatomic, assign, readonly)NSInteger timestamp; +@property(nonatomic, assign, readonly)QNRecordSource source; +@property(nonatomic, copy, readonly)NSString *server; +@property(nonatomic, strong, readonly)QNDnsRequest *request; +@property(nonatomic, strong, readonly)NSData *recordData; + + +/** + * 响应该消息的域名服务器是该域中的权威域名服务器。因为Answer Section中可能会有很多域名 + */ +@property(nonatomic, assign, readonly)int aa; + +/** + * 响应消息的类型: + * 0 成功的响应 + * 1 格式错误--域名服务器无法解析请求,因为请求消息格式错误 + * 2 服务器错误--域名服务器因为内部错误无法解析该请求 + * 3 名字错误-- 只在权威域名服务器的响应消息中有效,标示请求中请求的域不存在 + * 4 Not Implemented--域名服务器不支持请求的类型 + * 5 Refused -- 域名服务器因为策略的原因拒绝执行请求的操作。例如域名服务器不会为特定的请求者返回查询结果,或者域名服务器不会为特定的请求返回特定的数据 + */ +@property(nonatomic, assign, readonly)int rCode; + +@property(nonatomic, copy, readonly)NSArray *answerArray; +@property(nonatomic, copy, readonly)NSArray *authorityArray; +@property(nonatomic, copy, readonly)NSArray *additionalArray; + ++ (instancetype)dnsResponse:(NSString *)server source:(QNRecordSource)source request:(QNDnsRequest *)request dnsRecordData:(NSData *)recordData error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.m b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.m new file mode 100644 index 0000000..0e34852 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.m @@ -0,0 +1,350 @@ +// +// DnsRecord.m +// Doh +// +// Created by yangsen on 2021/7/16. +// +#import "QNRecord.h" +#import "QNDnsError.h" +#import "NSData+QNRW.h" +#import "QNDnsResponse.h" + + +/// DNS 记录中的名字可能是引用,需要到指定的 index 读取,所以需要跳过的长度不一定是 name 的长度 +@interface QNDnsRecordName : NSObject + +@property(nonatomic, assign)NSInteger skipLength; +@property(nonatomic, copy)NSString *name; + +@end +@implementation QNDnsRecordName +@end + + +@interface QNDnsRecordResource : NSObject + +@property(nonatomic, copy)NSString *name; +@property(nonatomic, assign)int count; +@property(nonatomic, assign)int from; +@property(nonatomic, assign)int length; +@property(nonatomic, strong)NSMutableArray *records; + +@end +@implementation QNDnsRecordResource ++ (instancetype)resource:(NSString *)name count:(int)count from:(int)from { + QNDnsRecordResource *resource = [[QNDnsRecordResource alloc] init]; + resource.name = name; + resource.count = count; + resource.from = from; + resource.length = 0; + resource.records = [NSMutableArray array]; + return resource; +} +@end + + +@interface QNDnsResponse() + +@property(nonatomic, assign)NSInteger timestamp; +@property(nonatomic, assign)QNRecordSource source; +@property(nonatomic, copy)NSString *server; +@property(nonatomic, strong)QNDnsRequest *request; +@property(nonatomic, strong)NSData *recordData; + +@property(nonatomic, assign)int messageId; +@property(nonatomic, assign)QNDnsOpCode opCode; +@property(nonatomic, assign)int aa; +@property(nonatomic, assign)int ra; +@property(nonatomic, assign)int rd; +@property(nonatomic, assign)int rCode; + +@property(nonatomic, copy)NSArray *answerArray; +@property(nonatomic, copy)NSArray *authorityArray; +@property(nonatomic, copy)NSArray *additionalArray; + +@end +@implementation QNDnsResponse +@synthesize messageId; +@synthesize opCode; +@synthesize aa; +@synthesize ra; +@synthesize rd; +@synthesize rCode; + ++ (instancetype)dnsResponse:(NSString *)server source:(QNRecordSource)source request:(QNDnsRequest *)request dnsRecordData:(NSData *)recordData error:(NSError *__autoreleasing _Nullable *)error { + QNDnsResponse *record = [[QNDnsResponse alloc] init]; + record.server = server; + record.source = source; + record.request = request; + record.recordData = recordData; + record.timestamp = [[NSDate date] timeIntervalSince1970]; + + NSError *err = nil; + [record parse:&err]; + if (error != nil) { + *error = err; + } + return record; +} + +- (void)parse:(NSError **)error { + + if (self.recordData.length < 12) { + [self copyError:kQNDnsResponseFormatError(@"response data too small") toErrorPoint:error]; + return; + } + + // Header + [self parseHeader:error]; + if (error != nil && *error != nil) { + return; + } + + // Question + int index = [self parseQuestion:error]; + if (error != nil && *error != nil) { + return; + } + + // Answer + QNDnsRecordResource *answer = [QNDnsRecordResource resource:@"answer" + count:[self.recordData qn_readBigEndianInt16:6] + from:index]; + [self parseResourceRecord:answer error:error]; + if (error != nil && *error != nil) { + return; + } + index += answer.length; + self.answerArray = [answer.records copy]; + + // Authority + QNDnsRecordResource *authority = [QNDnsRecordResource resource:@"authority" + count:[self.recordData qn_readBigEndianInt16:8] + from:index]; + [self parseResourceRecord:authority error:error]; + if (error != nil && *error != nil) { + return; + } + index += authority.length; + self.authorityArray = [authority.records copy]; + + // Additional + QNDnsRecordResource *additional = [QNDnsRecordResource resource:@"additional" + count:[self.recordData qn_readBigEndianInt16:10] + from:index]; + [self parseResourceRecord:additional error:error]; + if (error != nil && *error != nil) { + return; + } + self.additionalArray = [additional.records copy]; +} + +- (void)parseHeader:(NSError **)error { + self.messageId = [self.recordData qn_readBigEndianInt16:0]; + // question id 不匹配 + if (self.messageId != self.request.messageId) { + [self copyError:kQNDnsResponseFormatError(@"question id error") toErrorPoint:error]; + return; + } + + // |00|01|02|03|04|05|06|07| + // |QR| OPCODE |AA|TC|RD| + int field0 = [self.recordData qn_readInt8:2]; + int qr = [self.recordData qn_readInt8:2] & 0x80; + // 非 dns 响应数据 + if (qr == 0) { + [self copyError:kQNDnsResponseFormatError(@"not a response data") toErrorPoint:error]; + return; + } + + self.opCode = (field0 >> 3) & 0x07; + self.aa = (field0 >> 2) & 0x01; + self.rd = field0 & 0x01; + + // |00|01|02|03|04|05|06|07| + // |RA|r1|r2|r3| RCODE | + int field1 = [self.recordData qn_readInt8:3]; + self.ra = (field1 >> 7) & 0x1; + self.rCode = field1 & 0x0F; +} + +- (int)parseQuestion:(NSError **)error { + int index = 12; + int qdCount = [self.recordData qn_readBigEndianInt16:4]; + while (qdCount) { + QNDnsRecordName *recordName = [self getNameFrom:index]; + if (recordName == nil) { + [self copyError:kQNDnsResponseFormatError(@"read Question error") toErrorPoint:error]; + return -1; + } + + if (self.recordData.length < (index + recordName.skipLength + 4)) { + [self copyError:kQNDnsResponseFormatError(@"read Question error: out of range") toErrorPoint:error]; + return -1; + } + + index += recordName.skipLength + 4; + qdCount --; + } + return index; +} + +- (void)parseResourceRecord:(QNDnsRecordResource *)resource error:(NSError **)error { + int index = resource.from; + int count = resource.count; + while (count) { + QNDnsRecordName *recordName = [self getNameFrom:index]; + if (recordName == nil) { + NSString *errorDesc = [NSString stringWithFormat:@"read %@ error", resource.name]; + [self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error]; + return; + } + + index += recordName.skipLength; + if (self.recordData.length < (index + 2)) { + NSString *errorDesc = [NSString stringWithFormat:@"read %@ error: out of range", resource.name]; + [self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error]; + return; + } + + int type = [self.recordData qn_readBigEndianInt16:index]; + index += 2; + + if (self.recordData.length < (index + 2)) { + NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name]; + [self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error]; + return; + } + + int class = [self.recordData qn_readBigEndianInt16:index]; + index += 2; + + if (self.recordData.length < (index + 4)) { + NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name]; + [self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error]; + return; + } + + int ttl = [self.recordData qn_readBigEndianInt32:index]; + index += 4; + + if (self.recordData.length < (index + 2)) { + NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name]; + [self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error]; + return; + } + + int rdLength = [self.recordData qn_readBigEndianInt16:index]; + index += 2; + if (self.recordData.length < (index + rdLength)) { + NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name]; + [self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error]; + return; + } + + NSString *value = [self readData:type range:NSMakeRange(index, rdLength)]; + + if (class == 0x01 && (type == kQNTypeCname || type == self.request.recordType)) { + QNRecord *record = [[QNRecord alloc] init:[value copy] ttl:ttl type:type timeStamp:self.timestamp server:self.server source:self.source]; + [resource.records addObject:record]; + } + + index += rdLength; + count --; + } + resource.length = index - resource.from; +} + +- (QNDnsRecordName *)getNameFrom:(NSInteger)fromIndex { + + NSInteger partLength = 0; + NSInteger index = fromIndex; + NSMutableString *name = [NSMutableString string]; + QNDnsRecordName *recordName = [[QNDnsRecordName alloc] init]; + + int maxLoop = 128; + do { + if (index >= self.recordData.length) { + return nil; + } + + partLength = [self.recordData qn_readInt8:index]; + if ((partLength & 0xc0) == 0xc0) { + // name pointer + if((index + 1) >= self.recordData.length) { + return nil; + } + if (recordName.skipLength < 1) { + recordName.skipLength = index + 2 - fromIndex; + } + index = (partLength & 0x3f) << 8 | [self.recordData qn_readInt8:index + 1]; + continue; + } else if((partLength & 0xc0) > 0) { + return nil; + } else { + index++; + } + + if (partLength > 0) { + if (name.length > 0) { + [name appendString:@"."]; + } + + if (index + partLength > self.recordData.length) { + return nil; + } + + NSData *nameData = [self.recordData subdataWithRange:NSMakeRange(index, partLength)]; + [name appendString:[[NSString alloc] initWithData:nameData encoding:NSUTF8StringEncoding]]; + index += partLength; + } + + } while (partLength && --maxLoop); + + recordName.name = name; + if (recordName.skipLength < 1) { + recordName.skipLength = index - fromIndex; + } + return recordName; +} + +- (NSString *)readData:(int)recordType range:(NSRange)range { + + NSString *dataString = nil; + NSData *dataValue = [self.recordData subdataWithRange:range]; + if (recordType == kQNTypeA) { + if (dataValue.length == 4) { + dataString = [NSString stringWithFormat:@"%d.%d.%d.%d", [dataValue qn_readInt8:0], [dataValue qn_readInt8:1], [dataValue qn_readInt8:2], [dataValue qn_readInt8:3]]; + } + } else if (recordType == kQNTypeAAAA) { + if (dataValue.length == 16) { + NSMutableString *ipv6 = [NSMutableString string]; + for (int i=0; i<16; i+=2) { + [ipv6 appendFormat:@"%@%02x%02x",(i?@":":@""), [dataValue qn_readInt8:i], [dataValue qn_readInt8:i+1]]; + } + dataString = [ipv6 copy]; + } + } else if (recordType == kQNTypeCname) { + if (dataValue.length > 1) { + QNDnsRecordName *name = [self getNameFrom:range.location]; + dataString = [name.name copy]; + } + } else if (recordType == kQNTypeTXT) { + if (dataValue.length > 1) { + dataString = [[NSString alloc] initWithData:[dataValue subdataWithRange:NSMakeRange(1, dataValue.length - 1)] encoding:NSUTF8StringEncoding]; + } + } + return dataString; +} + +- (void)copyError:(NSError *)error toErrorPoint:(NSError **)errorPoint { + if (errorPoint != nil) { + *errorPoint = error; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"{messageId:%d, rd:%d, ra:%d, aa:%d, rCode:%d, server:%@, request:%@, answerArray:%@, authorityArray:%@, additionalArray:%@}", self.messageId, self.rd, self.ra, self.aa, self.rCode, self.server, self.request, self.answerArray, self.authorityArray, self.additionalArray]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h b/Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h new file mode 100644 index 0000000..e69bc3e --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h @@ -0,0 +1,47 @@ +// +// QNDnsServer.h +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import "QNDnsResolver.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDnsUdpResolver : QNDnsResolver + + +/// 构造函数 +/// @param serverIP 指定 dns local server1. eg:114.114.114.114 ++ (instancetype)resolverWithServerIP:(NSString *)serverIP; + +/// 构造函数 +/// @param serverIP 指定 dns local server1. eg:114.114.114.114 +/// @param recordType 记录类型 eg:kQNTypeA +/// @param timeout 超时时间 ++ (instancetype)resolverWithServerIP:(NSString *)serverIP + recordType:(int)recordType + timeout:(int)timeout; + +/// 构造函数 +/// @param serverIPs 指定多个 dns local server,同时进行 dns 解析,当第一个有效数据返回时结束,或均为解析到数据时结束. eg:@[@"8.8.8.8"] +/// @param recordType 记录类型 eg:kQNTypeA +/// @param timeout 超时时间 ++ (instancetype)resolverWithServerIPs:(NSArray *)serverIPs + recordType:(int)recordType + timeout:(int)timeout; + +/// 构造函数 +/// @param serverIPs 指定多个 dns local server,同时进行 dns 解析,当第一个有效数据返回时结束,或均为解析到数据时结束. eg:@[@"8.8.8.8"] +/// @param recordType 记录类型 eg:kQNTypeA +/// @param queue 多个 udp 包所在的 queue +/// @param timeout 超时时间 ++ (instancetype)resolverWithServerIPs:(NSArray *)serverIPs + recordType:(int)recordType + queue:(dispatch_queue_t _Nullable)queue + timeout:(int)timeout; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.m b/Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.m new file mode 100644 index 0000000..ec9101e --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.m @@ -0,0 +1,214 @@ +// +// QNDnsServer.m +// Doh +// +// Created by yangsen on 2021/7/20. +// + +#import "QNRecord.h" +#import "QNDomain.h" +#import "QNDnsError.h" +#import "QNDnsResponse.h" +#import "QNDnsUdpResolver.h" +#import "QNAsyncUdpSocket.h" + +@interface QNDnsFlow : NSObject + +@property(nonatomic, assign)long flowId; +@property(nonatomic, copy)NSString *server; +@property(nonatomic, strong)QNDnsRequest *dnsRequest; +@property(nonatomic, strong)QNAsyncUdpSocket *socket; +@property(nonatomic, copy)void(^complete)(QNDnsResponse *response, NSError *error); + +@end +@implementation QNDnsFlow +@end + +#define kDnsPort 53 +@interface QNDnsUdpResolver() + +@property(nonatomic, assign)int recordType; +@property(nonatomic, assign)int timeout; +@property(nonatomic, copy)NSArray *servers; +@property(nonatomic, strong)dispatch_queue_t queue; +@property(nonatomic, strong)NSMutableDictionary *flows; + +@end + +@implementation QNDnsUdpResolver +@synthesize recordType; +@synthesize timeout; +@synthesize servers; + ++ (instancetype)resolverWithServerIP:(NSString *)serverIP { + return [self resolverWithServerIP:serverIP recordType:kQNTypeA timeout:QN_DNS_DEFAULT_TIMEOUT]; +} + ++ (instancetype)resolverWithServerIP:(NSString *)serverIP + recordType:(int)recordType + timeout:(int)timeout { + return [self resolverWithServerIPs:serverIP ? @[serverIP] : @[] recordType:recordType timeout:timeout]; +} + ++ (instancetype)resolverWithServerIPs:(NSArray *)serverIPs + recordType:(int)recordType + timeout:(int)timeout { + return [self resolverWithServerIPs:serverIPs recordType:recordType queue:nil timeout:timeout]; +} + ++ (instancetype)resolverWithServerIPs:(NSArray *)servers + recordType:(int)recordType + queue:(dispatch_queue_t _Nullable)queue + timeout:(int)timeout { + + QNDnsUdpResolver *resolver = [[self alloc] init]; + resolver.recordType = recordType; + resolver.servers = [servers copy] ?: @[]; + resolver.timeout = timeout; + resolver.queue = queue; + return resolver; +} + ++ (dispatch_queue_t)defaultQueue { + static dispatch_once_t onceToken; + static dispatch_queue_t timerQueue; + dispatch_once(&onceToken, ^{ + timerQueue = dispatch_queue_create("com.qiniu.dns.udp.queue", DISPATCH_QUEUE_CONCURRENT); + }); + return timerQueue; +} + +- (dispatch_queue_t)queue { + if (_queue == nil) { + _queue = [QNDnsUdpResolver defaultQueue]; + } + return _queue; +} + +- (NSMutableDictionary *)flows { + if (_flows == nil) { + _flows = [NSMutableDictionary dictionary]; + } + return _flows; +} + +- (void)request:(NSString *)server + host:(NSString *)host + recordType:(int)recordType + complete:(void(^)(QNDnsResponse *response, NSError *error))complete { + if (complete == nil) { + return; + } + + int messageId = arc4random()%(0xFFFF); + QNDnsRequest *dnsRequest = [QNDnsRequest request:messageId recordType:recordType host:host]; + + NSError *error = nil; + NSData *requestData = [dnsRequest toDnsQuestionData:&error]; + if (error) { + complete(nil, error); + return; + } + + QNAsyncUdpSocket *socket = [[QNAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:self.queue]; + // 由系统决定端口号 + [socket bindToPort:0 error: &error]; + if (error) { + complete(nil, error); + return; + } + + [socket beginReceiving:&error]; + if (error) { + complete(nil, error); + return; + } + + QNDnsFlow *flow = [[QNDnsFlow alloc] init]; + flow.flowId = [socket hash]; + flow.server = server; + flow.dnsRequest = dnsRequest; + flow.socket = socket; + flow.complete = complete; + [self setFlow:flow withId:flow.flowId]; + + [socket sendData:requestData toHost:server port:kDnsPort withTimeout:self.timeout tag:flow.flowId]; +} + +- (void)udpSocketComplete:(QNAsyncUdpSocket *)sock data:(NSData *)data error:(NSError * _Nullable)error { + [sock close]; + + QNDnsFlow *flow = [self getFlowWithId:[sock hash]]; + if (!flow) { + return; + } + [self removeFlowWithId:flow.flowId]; + + if (error != nil) { + flow.complete(nil, error); + } else if (data != nil) { + NSError *err = nil; + QNDnsResponse *response = [QNDnsResponse dnsResponse:flow.server source:QNRecordSourceUdp request:flow.dnsRequest dnsRecordData:data error:&err]; + flow.complete(response, err); + } else { + flow.complete(nil, nil); + } +} + +//MARK: -- QNAsyncUdpSocketDelegate +- (void)udpSocket:(QNAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address { +} + +- (void)udpSocket:(QNAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error { + [self udpSocketComplete:sock data:nil error:error]; +} + +- (void)udpSocket:(QNAsyncUdpSocket *)sock didSendDataWithTag:(long)tag { +} + +- (void)udpSocket:(QNAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error { + [self udpSocketComplete:sock data:nil error:error]; +} + +- (void)udpSocket:(QNAsyncUdpSocket *)sock + didReceiveData:(NSData *)data + fromAddress:(NSData *)address +withFilterContext:(nullable id)filterContext { + [self udpSocketComplete:sock data:data error:nil]; +} + +- (void)udpSocketDidClose:(QNAsyncUdpSocket *)sock withError:(NSError * _Nullable)error { + [self udpSocketComplete:sock data:nil error:error]; +} + + +//MARK: flows +- (QNDnsFlow *)getFlowWithId:(long)flowId { + NSString *key = [NSString stringWithFormat:@"%ld", flowId]; + QNDnsFlow *flow = nil; + @synchronized (self) { + flow = self.flows[key]; + } + return flow; +} + +- (BOOL)setFlow:(QNDnsFlow *)flow withId:(long)flowId { + if (flow == nil) { + return false; + } + + NSString *key = [NSString stringWithFormat:@"%ld", flowId]; + @synchronized (self) { + self.flows[key] = flow; + } + return true; +} + +- (void)removeFlowWithId:(long)flowId { + NSString *key = [NSString stringWithFormat:@"%ld", flowId]; + @synchronized (self) { + [self.flows removeObjectForKey:key]; + } +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.h b/Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.h new file mode 100644 index 0000000..b78b1cf --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.h @@ -0,0 +1,38 @@ +// +// Doh.h +// Doh +// +// Created by yangsen on 2021/7/15. +// + +#import "QNDnsResolver.h" +#import "QNDnsDefine.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDohResolver : QNDnsResolver + +/// 构造函数 +/// @param server 指定 dns server url。 eg:https://dns.google/dns-query ++ (instancetype)resolverWithServer:(NSString *)server; + +/// 构造函数 +/// @param server 指定 dns server url。 eg:https://dns.google/dns-query +/// @param recordType 记录类型 eg:kQNTypeA +/// @param timeout 超时时间 ++ (instancetype)resolverWithServer:(NSString *)server + recordType:(int)recordType + timeout:(int)timeout; + +/// 构造函数 +/// @param servers 指定多个 dns server url,同时进行 dns 解析,当第一个有效数据返回时结束,或均为解析到数据时结束 +/// eg:https://dns.google/dns-query +/// @param recordType 记录类型 eg:kQNTypeA +/// @param timeout 超时时间 ++ (instancetype)resolverWithServers:(NSArray *)servers + recordType:(int)recordType + timeout:(int)timeout; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.m b/Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.m new file mode 100644 index 0000000..2355934 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.m @@ -0,0 +1,85 @@ +// +// Doh.m +// Doh +// +// Created by yangsen on 2021/7/15. +// +#import "QNDnsResponse.h" +#import "QNDohResolver.h" + +@interface QNDohResolver() + +@property(nonatomic, assign)int recordType; +@property(nonatomic, assign)int timeout; +@property(nonatomic, copy)NSArray *servers; + +@end +@implementation QNDohResolver +@synthesize recordType; +@synthesize timeout; +@synthesize servers; + ++ (instancetype)resolverWithServer:(NSString *)server { + return [self resolverWithServer:server recordType:kQNTypeA timeout:QN_DNS_DEFAULT_TIMEOUT]; +} + ++ (instancetype)resolverWithServer:(NSString *)server + recordType:(int)recordType + timeout:(int)timeout { + return [self resolverWithServers:server ? @[server] : @[] recordType:recordType timeout:timeout]; +} + ++ (instancetype)resolverWithServers:(NSArray *)servers + recordType:(int)recordType + timeout:(int)timeout { + QNDohResolver *resolver = [[self alloc] init]; + resolver.recordType = recordType; + resolver.servers = [servers copy] ?: @[]; + resolver.timeout = timeout; + return resolver; +} + +- (void)request:(NSString *)server + host:(NSString *)host + recordType:(int)recordType + complete:(void(^)(QNDnsResponse *response, NSError *error))complete { + if (complete == nil) { + return; + } + + if (host == nil || host.length == 0) { + complete(nil, kQNDnsInvalidParamError(@"host can not empty")); + return; + } + + int messageId = arc4random()%(0xFFFF); + QNDnsRequest *dnsRequest = [QNDnsRequest request:messageId recordType:recordType host:host]; + NSError *error = nil; + NSData *requestData = [dnsRequest toDnsQuestionData:&error]; + if (error) { + complete(nil, error); + return; + } + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:server]]; + request.HTTPMethod = @"POST"; + request.HTTPBody = requestData; + request.timeoutInterval = self.timeout; + [request addValue:@"application/dns-message" forHTTPHeaderField:@"Content-Type"]; + [request addValue:@"application/dns-message" forHTTPHeaderField:@"Accept"]; + + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (error) { + complete(nil, error); + } else if (data) { + QNDnsResponse *dnsResponse = [QNDnsResponse dnsResponse:server source:QNRecordSourceDoh request:dnsRequest dnsRecordData:data error:nil]; + complete(dnsResponse, nil); + } else { + complete(nil, nil); + } + }]; + [task resume]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/HappyDNS.h b/Pods/HappyDNS/HappyDNS/HappyDNS.h new file mode 100644 index 0000000..90ba0ed --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/HappyDNS.h @@ -0,0 +1,25 @@ +// +// HappyDNS.h +// HappyDNS +// +// Created by bailong on 15/6/24. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +#import "QNDnsError.h" +#import "QNDnsManager.h" +#import "QNDnspodEnterprise.h" +#import "QNDomain.h" +#import "QNDnsResolver.h" +#import "QNDnsUdpResolver.h" +#import "QNDohResolver.h" +#import "QNDnsDefine.h" +#import "QNHijackingDetectWrapper.h" +#import "QNIP.h" +#import "QNNetworkInfo.h" +#import "QNRecord.h" +#import "QNResolver.h" +#import "QNResolverDelegate.h" +#import "QNGetAddrInfo.h" diff --git a/Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h b/Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h new file mode 100644 index 0000000..0320bbc --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h @@ -0,0 +1,30 @@ +// +// QNDnspodEnterprise.h +// HappyDNS +// +// Created by bailong on 15/7/31. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNResolverDelegate.h" +#import + +extern const int kQN_ENCRYPT_FAILED; +extern const int kQN_DECRYPT_FAILED; + +@interface QNDnspodEnterprise : NSObject + +- (instancetype)initWithId:(NSString *)userId + key:(NSString *)key; + +- (instancetype)initWithId:(NSString *)userId + key:(NSString *)key + server:(NSString *)server; + +- (instancetype)initWithId:(NSString *)userId + key:(NSString *)key + server:(NSString *)server + timeout:(NSUInteger)time; + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error; +@end diff --git a/Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.m b/Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.m new file mode 100644 index 0000000..0516df7 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.m @@ -0,0 +1,141 @@ +// +// QNDnspodEnterprise.m +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNDnspodEnterprise.h" +#import + +#import "QNDes.h" +#import "QNDomain.h" +#import "QNHex.h" +#import "QNIP.h" +#import "QNRecord.h" + +const int kQN_ENCRYPT_FAILED = -10001; +const int kQN_DECRYPT_FAILED = -10002; + +@interface QNDnspodEnterprise () +@property (readonly, strong) NSString *server; +@property (nonatomic, strong) NSString *userId; +@property (nonatomic, strong) QNDes *des; +@property (nonatomic) NSUInteger timeout; + +@end + +@implementation QNDnspodEnterprise + +- (instancetype)initWithId:(NSString *)userId + key:(NSString *)key { + return [self initWithId:userId key:key server:@"119.29.29.98"]; +} + +- (instancetype)initWithId:(NSString *)userId + key:(NSString *)key + server:(NSString *)server { + return [self initWithId:userId key:key server:@"119.29.29.98" timeout:QN_DNS_DEFAULT_TIMEOUT]; +} + +- (instancetype)initWithId:(NSString *)userId + key:(NSString *)key + server:(NSString *)server + timeout:(NSUInteger)time { + if (self = [super init]) { + _server = server; + _userId = userId; + _des = [[QNDes alloc] init:[key dataUsingEncoding:NSUTF8StringEncoding]]; + _timeout = time; + } + return self; +} + +- (NSString *)encrypt:(NSString *)domain { + NSData *data = [_des encrypt:[domain dataUsingEncoding:NSUTF8StringEncoding]]; + if (data == nil) { + return nil; + } + NSString *str = [QNHex encodeHexData:data]; + return str; +} + +- (NSString *)decrypt:(NSData *)raw { + NSData *enc = [QNHex decodeHexString:[[NSString alloc] initWithData:raw + encoding:NSUTF8StringEncoding]]; + if (enc == nil) { + return nil; + } + NSData *data = [_des decrpyt:enc]; + if (data == nil) { + return nil; + } + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error { + NSString *encrypt = [self encrypt:domain.domain]; + if (encrypt == nil) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:domain.domain code:kQN_ENCRYPT_FAILED userInfo:nil]; + } + return nil; + } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + __block NSData *data = nil; + __block NSError *httpError = nil; + __block NSHTTPURLResponse *response = nil; + NSString *url = [NSString stringWithFormat:@"http://%@/d?ttl=1&dn=%@&id=%@", [QNIP ipHost:_server], encrypt, _userId]; + NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:_timeout]; + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable resp, NSError * _Nullable error) { + + data = data; + httpError = error; + response = (NSHTTPURLResponse *)resp; + dispatch_semaphore_signal(semaphore); + }]; + [task resume]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (httpError != nil) { + if (error != nil) { + *error = httpError; + } + return nil; + } + if (response.statusCode != 200) { + return nil; + } + + NSString *raw = [self decrypt:data]; + if (raw == nil) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:domain.domain code:kQN_DECRYPT_FAILED userInfo:nil]; + } + return nil; + } + NSArray *ip1 = [raw componentsSeparatedByString:@","]; + if (ip1.count != 2) { + return nil; + } + NSString *ttlStr = [ip1 objectAtIndex:1]; + int ttl = [ttlStr intValue]; + if (ttl <= 0) { + return nil; + } + NSString *ips = [ip1 objectAtIndex:0]; + NSArray *ipArray = [ips componentsSeparatedByString:@";"]; + NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:ipArray.count]; + for (int i = 0; i < ipArray.count; i++) { + QNRecord *record = [[QNRecord alloc] init:[ipArray objectAtIndex:i] ttl:ttl type:kQNTypeA source:QNRecordSourceDnspodEnterprise]; + [ret addObject:record]; + } + return ret; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h b/Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h new file mode 100644 index 0000000..95f8d87 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h @@ -0,0 +1,17 @@ +// +// QNHijackingDetectWrapper.h +// HappyDNS +// +// Created by bailong on 15/7/16. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +#import "QNResolverDelegate.h" + +@class QNResolver; +@interface QNHijackingDetectWrapper : NSObject +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error; +- (instancetype)initWithResolver:(QNResolver *)resolver; +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.m b/Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.m new file mode 100644 index 0000000..e915cc8 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.m @@ -0,0 +1,51 @@ +// +// QNHijackingDetectWrapper.m +// HappyDNS +// +// Created by bailong on 15/7/16. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNHijackingDetectWrapper.h" +#import "QNDomain.h" +#import "QNRecord.h" +#import "QNResolver.h" + +@interface QNHijackingDetectWrapper () +@property (nonatomic, readonly) QNResolver *resolver; +@end + +@implementation QNHijackingDetectWrapper + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error { + NSArray *result = [_resolver query:domain networkInfo:netInfo error:error]; + if (((!domain.hasCname) && domain.maxTtl == 0) || result == nil || result.count == 0) { + return result; + } + BOOL hasCname = NO; + BOOL outOfTtl = NO; + for (int i = 0; i < result.count; i++) { + QNRecord *record = [result objectAtIndex:i]; + if (record.type == kQNTypeCname) { + hasCname = YES; + } + if (domain.maxTtl > 0 && record.type == kQNTypeA && record.ttl > domain.maxTtl) { + outOfTtl = YES; + } + } + if ((domain.hasCname && !hasCname) || outOfTtl) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:domain.domain code:kQNDomainHijackingCode userInfo:nil]; + } + return nil; + } + return result; +} +- (instancetype)initWithResolver:(QNResolver *)resolver { + if (self = [super init]) { + _resolver = resolver; + } + return self; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNHosts.h b/Pods/HappyDNS/HappyDNS/Local/QNHosts.h new file mode 100644 index 0000000..84e4892 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNHosts.h @@ -0,0 +1,20 @@ +// +// QNHosts.h +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNRecord.h" +#import "QNResolverDelegate.h" +#import + +@interface QNHosts : NSObject + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo; + +- (void)put:(NSString *)domain record:(QNRecord *)record; +- (void)put:(NSString *)domain record:(QNRecord *)record provider:(int)provider; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNHosts.m b/Pods/HappyDNS/HappyDNS/Local/QNHosts.m new file mode 100644 index 0000000..dacc7bf --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNHosts.m @@ -0,0 +1,111 @@ +// +// QNHosts.m +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNHosts.h" +#import "QNDomain.h" +#import "QNNetworkInfo.h" + +@interface QNHostsValue : NSObject +@property (nonatomic, copy, readonly) QNRecord *record; +@property (readonly) int provider; +@end + +@implementation QNHostsValue + +- (instancetype)init:(QNRecord *)record provider:(int)provider { + if (self = [super init]) { + _record = record; + _provider = provider; + } + return self; +} + +@end + +static NSArray *filter(NSArray *input, int provider) { + NSMutableArray *normal = [[NSMutableArray alloc] initWithCapacity:input.count]; + NSMutableArray *special = [[NSMutableArray alloc] init]; + for (QNHostsValue *v in input) { + if (v.provider == kQNISP_GENERAL) { + [normal addObject:v]; + } else if (provider == v.provider) { + [special addObject:v]; + } + } + if (special.count != 0) { + return special; + } + return [normal copy]; +} + +@interface QNHosts () +@property (nonatomic) NSMutableDictionary *dict; +@end + +@implementation QNHosts +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo { + NSMutableArray *x; + @synchronized(_dict) { + x = [_dict objectForKey:domain.domain]; + } + + if (x == nil || x.count == 0) { + return nil; + } + + @synchronized (_dict) { + if (x.count >= 2) { + QNHostsValue *first = [x firstObject]; + [x removeObjectAtIndex:0]; + [x addObject:first]; + } + } + + NSArray *values = filter([x copy], netInfo.provider); + return [self toRecords:values]; +} + +- (NSArray *)toRecords:(NSArray *)values { + if (values == nil) { + return nil; + } + + NSMutableArray *records = [NSMutableArray array]; + for (QNHostsValue *value in values) { + if (value.record != nil && value.record.value != nil) { + [records addObject:value.record]; + } + } + return [records copy]; +} + + +- (void)put:(NSString *)domain record:(QNRecord *)record { + [self put:domain record:record provider:kQNISP_GENERAL]; +} + +- (void)put:(NSString *)domain record:(QNRecord *)record provider:(int)provider { + QNHostsValue *v = [[QNHostsValue alloc] init:record provider:provider]; + @synchronized(_dict) { + NSMutableArray *x = [_dict objectForKey:domain]; + if (x == nil) { + x = [[NSMutableArray alloc] init]; + } + [x addObject:v]; + [_dict setObject:x forKey:domain]; + } +} + +- (instancetype)init { + if (self = [super init]) { + _dict = [[NSMutableDictionary alloc] init]; + } + return self; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.h b/Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.h new file mode 100644 index 0000000..56778e6 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.h @@ -0,0 +1,16 @@ +// +// QNResolv.h +// HappyDNS +// +// Created by bailong on 16/5/28. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#ifndef QNResolv_h +#define QNResolv_h + +extern BOOL isV6(NSString *address); + +extern int setup_dns_server(void *res, NSString *dns_server, NSUInteger timeout); + +#endif /* QNResolv_h */ diff --git a/Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.m b/Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.m new file mode 100644 index 0000000..c7d8207 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.m @@ -0,0 +1,84 @@ +// +// QNResolvUtil.m +// HappyDNS +// +// Created by bailong on 16/5/28. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +#include +#include +#include + +#include +#include +#include +#include +#include + +#import "QNIP.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#import +#endif + +BOOL isV6(NSString *address) { + return strchr(address.UTF8String, ':') != NULL; +} + +int setup_dns_server(void *_res_state, NSString *dns_server, NSUInteger timeout) { + res_state res = (res_state)_res_state; + int r = res_ninit(res); + if (r != 0) { + return r; + } + res->retrans = (int)timeout; + res->retry = 1; + if (dns_server == nil) { + return 0; + } + res->options |= RES_IGNTC; + + union res_sockaddr_union server = {0}; + + struct addrinfo hints = {0}, *ai = NULL; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + int ret = getaddrinfo(dns_server.UTF8String, "53", &hints, &ai); + if (ret != 0) { + return ret; + } + int family = ai->ai_family; + + if (family == AF_INET6) { + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53); + server.sin6 = *((struct sockaddr_in6 *)ai->ai_addr); + } else { + server.sin = *((struct sockaddr_in *)ai->ai_addr); + } + + if (![QNIP isIpV6FullySupported] && family == AF_INET) { + if ([QNIP isV6]) { + freeaddrinfo(ai); + ai = NULL; + bzero(&hints, (size_t)0); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + char buf[64] = {0}; + qn_nat64(buf, sizeof(buf), (uint32_t)server.sin.sin_addr.s_addr); + int ret = getaddrinfo(buf, "53", &hints, &ai); + if (ret != 0) { + return -1; + } + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53); + server.sin6 = *((struct sockaddr_in6 *)ai->ai_addr); + } + } + + freeaddrinfo(ai); + res_setservers(res, &server, 1); + return 0; +} \ No newline at end of file diff --git a/Pods/HappyDNS/HappyDNS/Local/QNResolver.h b/Pods/HappyDNS/HappyDNS/Local/QNResolver.h new file mode 100644 index 0000000..90471ea --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNResolver.h @@ -0,0 +1,25 @@ +// +// QNResolver.h +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNResolverDelegate.h" +#import + +@interface QNResolver : NSObject +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error; + +// @deprecated typo +- (instancetype)initWithAddres:(NSString *)address DEPRECATED_ATTRIBUTE; + +- (instancetype)initWithAddress:(NSString *)address; + +- (instancetype)initWithAddress:(NSString *)address + timeout:(NSUInteger)time; + ++ (instancetype)systemResolver; ++ (NSString *)systemDnsServer; +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNResolver.m b/Pods/HappyDNS/HappyDNS/Local/QNResolver.m new file mode 100644 index 0000000..8dc7f90 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNResolver.m @@ -0,0 +1,153 @@ +// +// QNResolver.m +// HappyDNS +// +// Created by bailong on 15/6/23. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +#import "QNDomain.h" +#import "QNIP.h" +#import "QNRecord.h" +#import "QNResolver.h" + +#import "QNResolvUtil.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#import +#endif + +@interface QNResolver () +@property (nonatomic, readonly, strong) NSString *address; +@property (nonatomic, readonly) NSUInteger timeout; +@end + +static NSArray *query_ip_v4(res_state res, const char *host) { + u_char answer[2000]; + int len = res_nquery(res, host, ns_c_in, ns_t_a, answer, sizeof(answer)); + + ns_msg handle; + ns_initparse(answer, len, &handle); + + int count = ns_msg_count(handle, ns_s_an); + if (count <= 0) { + res_ndestroy(res); + return nil; + } + NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count]; + char buf[32]; + char cnameBuf[NS_MAXDNAME]; + memset(cnameBuf, 0, sizeof(cnameBuf)); + for (int i = 0; i < count; i++) { + ns_rr rr; + if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) { + res_ndestroy(res); + return nil; + } + int t = ns_rr_type(rr); + int ttl = ns_rr_ttl(rr); + NSString *val; + if (t == ns_t_a) { + const char *p = inet_ntop(AF_INET, ns_rr_rdata(rr), buf, sizeof(buf)); + val = [NSString stringWithUTF8String:p]; + } else if (t == ns_t_cname) { + int x = ns_name_uncompress(answer, &(answer[len]), ns_rr_rdata(rr), cnameBuf, sizeof(cnameBuf)); + if (x <= 0) { + continue; + } + val = [NSString stringWithUTF8String:cnameBuf]; + memset(cnameBuf, 0, sizeof(cnameBuf)); + } else { + continue; + } + QNRecord *record = [[QNRecord alloc] init:val ttl:ttl type:t source:QNRecordSourceSystem]; + [array addObject:record]; + } + res_ndestroy(res); + return array; +} + +@implementation QNResolver +- (instancetype)initWithAddres:(NSString *)address { + return [self initWithAddress:address]; +} + +- (instancetype)initWithAddress:(NSString *)address { + return [self initWithAddress:address timeout:QN_DNS_DEFAULT_TIMEOUT]; +} + +- (instancetype)initWithAddress:(NSString *)address + timeout:(NSUInteger)time { + if (self = [super init]) { + _address = address; + _timeout = time; + } + return self; +} + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error { + struct __res_state res; + + int r = setup_dns_server(&res, _address, _timeout); + if (r != 0) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:kQNDomainSeverError userInfo:nil]; + } + return nil; + } + + NSArray *ret = query_ip_v4(&res, [domain.domain cStringUsingEncoding:NSUTF8StringEncoding]); + if (ret != nil && ret.count != 0) { + return ret; + } + if (error != nil) { + *error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:NSURLErrorDNSLookupFailed userInfo:nil]; + } + return nil; +} + ++ (instancetype)systemResolver { + return [[QNResolver alloc] initWithAddress:nil]; +} + ++ (NSString *)systemDnsServer { + struct __res_state res; + int r = res_ninit(&res); + if (r != 0) { + return nil; + } + + union res_sockaddr_union server[MAXNS] = {0}; + r = res_getservers(&res, server, MAXNS); + res_ndestroy(&res); + if (r <= 0) { + return nil; + } + + int family = server[0].sin.sin_family; + char buf[64] = {0}; + const void *addr; + if (family == AF_INET6) { + addr = &server[0].sin6.sin6_addr; + } else { + addr = &server[0].sin.sin_addr; + } + const char *p = inet_ntop(family, addr, buf, sizeof(buf)); + if (p == NULL) { + return nil; + } + return [NSString stringWithUTF8String:p]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.h b/Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.h new file mode 100644 index 0000000..2e5df0e --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.h @@ -0,0 +1,23 @@ +// +// QNTxtResolver.h +// HappyDNS +// +// Created by bailong on 16/1/5. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNResolverDelegate.h" +#import + +@interface QNTxtResolver : NSObject +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error; + +/** + * 根据服务器地址进行初始化 + * + * @param address DNS 服务器地址,nil 表示系统的 + */ +- (instancetype)initWithAddress:(NSString *)address; + +- (instancetype)initWithAddress:(NSString *)address timeout:(NSUInteger)time; +@end diff --git a/Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.m b/Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.m new file mode 100644 index 0000000..7df3103 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.m @@ -0,0 +1,109 @@ +// +// QNTxtResolver.m +// HappyDNS +// +// Created by bailong on 16/1/5. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNTxtResolver.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#import "QNDomain.h" +#import "QNRecord.h" +#import "QNResolvUtil.h" +#import "QNResolver.h" + +@interface QNTxtResolver () +@property (nonatomic, readonly, strong) NSString *address; +@property (nonatomic, readonly) NSUInteger timeout; +@end + +static NSArray *query_ip(res_state res, const char *host) { + u_char answer[1500]; + int len = res_nquery(res, host, ns_c_in, ns_t_txt, answer, sizeof(answer)); + + ns_msg handle; + ns_initparse(answer, len, &handle); + + int count = ns_msg_count(handle, ns_s_an); + if (count != 1) { + res_ndestroy(res); + return nil; + } + + char txtbuf[256]; + memset(txtbuf, 0, sizeof(txtbuf)); + + ns_rr rr; + if (ns_parserr(&handle, ns_s_an, 0, &rr) != 0) { + res_ndestroy(res); + return nil; + } + int t = ns_rr_type(rr); + int ttl = ns_rr_ttl(rr); + int rdlen = ns_rr_rdlen(rr); + if (rdlen <= 1 + 7) { + res_ndestroy(res); + return nil; + } + NSString *val; + if (t == ns_t_txt) { + memcpy(txtbuf, ns_rr_rdata(rr) + 1, rdlen - 1); + val = [NSString stringWithUTF8String:txtbuf]; + } else { + res_ndestroy(res); + return nil; + } + NSArray *ipArray = [val componentsSeparatedByString:@","]; + NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:ipArray.count]; + for (int i = 0; i < ipArray.count; i++) { + QNRecord *record = [[QNRecord alloc] init:[ipArray objectAtIndex:i] ttl:ttl type:kQNTypeA source:QNRecordSourceSystem]; + [ret addObject:record]; + } + + res_ndestroy(res); + return ret; +} + +@implementation QNTxtResolver +- (instancetype)initWithAddress:(NSString *)address { + return [self initWithAddress:address timeout:QN_DNS_DEFAULT_TIMEOUT]; +} + +- (instancetype)initWithAddress:(NSString *)address timeout:(NSUInteger)time { + if (self = [super init]) { + _address = address; + _timeout = time; + } + return self; +} + +- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error { + struct __res_state res; + + int r = setup_dns_server(&res, _address, _timeout); + if (r != 0) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:kQNDomainSeverError userInfo:nil]; + } + return nil; + } + + NSArray *ret = query_ip(&res, [domain.domain cStringUsingEncoding:NSUTF8StringEncoding]); + if (ret == nil && error != nil) { + *error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:NSURLErrorDNSLookupFailed userInfo:nil]; + } + return ret; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/PrivacyInfo.xcprivacy b/Pods/HappyDNS/HappyDNS/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..86768b9 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTracking + + NSPrivacyAccessedAPITypes + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + + diff --git a/Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.h b/Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.h new file mode 100644 index 0000000..0314dbf --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.h @@ -0,0 +1,75 @@ +// +// NSMutableData+QNWriter.h +// Doh +// +// Created by yangsen on 2021/7/16. +// +#import + +@interface NSData (QNReader) + +//MARK: 读数据 +- (uint8_t)qn_readInt8:(NSInteger)from; + +- (uint16_t)qn_readLittleEndianInt16:(NSInteger)from; +- (uint32_t)qn_readLittleEndianInt32:(NSInteger)from; +- (uint64_t)qn_readLittleEndianInt64:(NSInteger)from; + +- (uint16_t)qn_readBigEndianInt16:(NSInteger)from; +- (uint32_t)qn_readBigEndianInt32:(NSInteger)from; +- (uint64_t)qn_readBigEndianInt64:(NSInteger)from; + +- (int8_t)qn_readSInt8:(NSInteger)from; +- (int16_t)qn_readLittleEndianSInt16:(NSInteger)from; +- (int32_t)qn_readLittleEndianSInt32:(NSInteger)from; +- (int64_t)qn_readLittleEndianSInt64:(NSInteger)from; + +- (int16_t)qn_readBigEndianSInt16:(NSInteger)from; +- (int32_t)qn_readBigEndianSInt32:(NSInteger)from; +- (int64_t)qn_readBigEndianSInt64:(NSInteger)from; + +- (float)qn_readFloat:(NSInteger)from; +- (double)qn_readDouble:(NSInteger)from; + +- (float)qn_readSwappedFloat:(NSInteger)from; +- (double)qn_readSwappedDouble:(NSInteger)from; + +- (NSString *)qn_readString:(NSRange)range usingEncoding:(NSStringEncoding)encoding; + +@end + + +@interface NSMutableData (QNWriter) + +//MARK: 写数据 +- (void)qn_appendInt8:(uint8_t)value; + +- (void)qn_appendLittleEndianInt16:(uint16_t)value; +- (void)qn_appendLittleEndianInt32:(uint32_t)value; +- (void)qn_appendLittleEndianInt64:(uint64_t)value; + +- (void)qn_appendBigEndianInt16:(uint16_t)value; +- (void)qn_appendBigEndianInt32:(uint32_t)value; +- (void)qn_appendBigEndianInt64:(uint64_t)value; + +- (void)qn_appendSInt8:(int8_t)value; + +- (void)qn_appendLittleEndianSInt16:(int16_t)value; +- (void)qn_appendLittleEndianSInt32:(int32_t)value; +- (void)qn_appendLittleEndianSInt64:(int64_t)value; + +- (void)qn_appendBigEndianSInt16:(int16_t)value; +- (void)qn_appendBigEndianSInt32:(int32_t)value; +- (void)qn_appendBigEndianSInt64:(int64_t)value; + +// These methods append floating point values depending on the architecture of your processor +// they're usually not appropriate for network transmission +- (void)qn_appendFloat:(float)value; +- (void)qn_appendDouble:(double)value; + +- (void)qn_appendSwappedFloat:(float)value; +- (void)qn_appendSwappedDouble:(double)value; + +- (void)qn_appendString:(NSString *)value usingEncoding:(NSStringEncoding)encoding; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.m b/Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.m new file mode 100644 index 0000000..53fc9e5 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.m @@ -0,0 +1,151 @@ +// +// NSMutableData+QNWriter.m +// Doh +// +// Created by yangsen on 2021/7/16. +// +#import "NSData+QNRW.h" + +@implementation NSData (QNReader) + +//MARK: 读数据 +- (uint8_t)qn_readInt8:(NSInteger)from { + uint8_t value = 0; + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; + return value; +} + +#define READ_METHOD(endian, size) \ +- (uint ## size ## _t)qn_read ## endian ## EndianInt ## size:(NSInteger)from { \ + uint ## size ## _t value = 0; \ + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; \ + value = CFSwapInt ## size ## HostTo ## endian(value); \ + return value; \ +} + +READ_METHOD(Little, 16) +READ_METHOD(Little, 32) +READ_METHOD(Little, 64) +READ_METHOD(Big, 16) +READ_METHOD(Big, 32) +READ_METHOD(Big, 64) + +#undef READ_METHOD + +- (int8_t)qn_readSInt8:(NSInteger)from { + int8_t value = 0; + [[self subdataWithRange:NSMakeRange(from, 8)] getBytes:&value length:sizeof(value)]; + return value; +} + +#define READ_METHOD(endian, size) \ +- (int ## size ## _t)qn_read ## endian ## EndianSInt ## size:(NSInteger)from { \ + int ## size ## _t value = 0; \ + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; \ + value = CFSwapInt ## size ## HostTo ## endian(value); \ + return value; \ +} + +READ_METHOD(Little, 16) +READ_METHOD(Little, 32) +READ_METHOD(Little, 64) +READ_METHOD(Big, 16) +READ_METHOD(Big, 32) +READ_METHOD(Big, 64) + +#undef READ_METHOD + + +- (float)qn_readFloat:(NSInteger)from { + float value = 0; + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; + return value; +} + +- (double)qn_readDouble:(NSInteger)from { + double value = 0; + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; + return value; +} + +- (float)qn_readSwappedFloat:(NSInteger)from { + CFSwappedFloat32 value; + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; + return CFConvertFloatSwappedToHost(value); +} + +- (double)qn_readSwappedDouble:(NSInteger)from { + CFSwappedFloat64 value; + [[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; + return CFConvertDoubleSwappedToHost(value); +} + +- (NSString *)qn_readString:(NSRange)range usingEncoding:(NSStringEncoding)encoding { + NSData *value = [self subdataWithRange:range]; + return [[NSString alloc] initWithData:value encoding:encoding]; +} + +@end + +@implementation NSMutableData (QNWriter) + +- (void)qn_appendInt8:(uint8_t)value { + [self appendBytes:&value length:sizeof(value)]; +} + +#define APPEND_METHOD(endian, size) \ +- (void)qn_append ## endian ## EndianInt ## size:(uint ## size ## _t)value { \ + value = CFSwapInt ## size ## HostTo ## endian(value); \ + [self appendBytes:&value length:sizeof(value)]; \ +} + +APPEND_METHOD(Little, 16) +APPEND_METHOD(Little, 32) +APPEND_METHOD(Little, 64) +APPEND_METHOD(Big, 16) +APPEND_METHOD(Big, 32) +APPEND_METHOD(Big, 64) + +#undef APPEND_METHOD + +- (void)qn_appendSInt8:(int8_t)value { + [self qn_appendInt8:*(int8_t *)&value]; +} + +#define APPEND_METHOD(endian, size) \ +- (void)qn_append ## endian ## EndianSInt ## size:(int ## size ## _t)value { \ + [self qn_append ## endian ## EndianInt ## size:*(uint ## size ## _t *)&value]; \ +} + +APPEND_METHOD(Little, 16) +APPEND_METHOD(Little, 32) +APPEND_METHOD(Little, 64) +APPEND_METHOD(Big, 16) +APPEND_METHOD(Big, 32) +APPEND_METHOD(Big, 64) + +#undef APPEND_METHOD + +- (void)qn_appendFloat:(float)value { + [self appendBytes:&value length:sizeof(value)]; +} + +- (void)qn_appendDouble:(double)value { + [self appendBytes:&value length:sizeof(value)]; +} + +- (void)qn_appendSwappedFloat:(float)value { + CFSwappedFloat32 v = CFConvertFloatHostToSwapped(value); + [self appendBytes:&v length:sizeof(value)]; +} + +- (void)qn_appendSwappedDouble:(double)value { + CFSwappedFloat64 v = CFConvertDoubleHostToSwapped(value); + [self appendBytes:&v length:sizeof(value)]; +} + +- (void)qn_appendString:(NSString *)value usingEncoding:(NSStringEncoding)encoding { + [self appendData:[value dataUsingEncoding:encoding]]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h b/Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h new file mode 100644 index 0000000..aee714a --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h @@ -0,0 +1,1024 @@ +// +// QNAsyncUdpSocket +// +// This class is in the public domain. +// Originally created by Robbie Hanson of Deusty LLC. +// Updated and maintained by Deusty LLC and the Apple development community. +// +// https://github.com/robbiehanson/CocoaAsyncSocket +// + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN +extern NSString *const QNAsyncUdpSocketException; +extern NSString *const QNAsyncUdpSocketErrorDomain; + +extern NSString *const QNAsyncUdpSocketQueueName; +extern NSString *const QNAsyncUdpSocketThreadName; + +typedef NS_ERROR_ENUM(QNAsyncUdpSocketErrorDomain, QNAsyncUdpSocketError) { + QNAsyncUdpSocketNoError = 0, // Never used + QNAsyncUdpSocketBadConfigError, // Invalid configuration + QNAsyncUdpSocketBadParamError, // Invalid parameter was passed + QNAsyncUdpSocketSendTimeoutError, // A send operation timed out + QNAsyncUdpSocketClosedError, // The socket was closed + QNAsyncUdpSocketOtherError, // Description provided in userInfo +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@class QNAsyncUdpSocket; + +@protocol QNAsyncUdpSocketDelegate +@optional + +/** + * By design, UDP is a connectionless protocol, and connecting is not needed. + * However, you may optionally choose to connect to a particular host for reasons + * outlined in the documentation for the various connect methods listed above. + * + * This method is called if one of the connect methods are invoked, and the connection is successful. +**/ +- (void)udpSocket:(QNAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address; + +/** + * By design, UDP is a connectionless protocol, and connecting is not needed. + * However, you may optionally choose to connect to a particular host for reasons + * outlined in the documentation for the various connect methods listed above. + * + * This method is called if one of the connect methods are invoked, and the connection fails. + * This may happen, for example, if a domain name is given for the host and the domain name is unable to be resolved. +**/ +- (void)udpSocket:(QNAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error; + +/** + * Called when the datagram with the given tag has been sent. +**/ +- (void)udpSocket:(QNAsyncUdpSocket *)sock didSendDataWithTag:(long)tag; + +/** + * Called if an error occurs while trying to send a datagram. + * This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet. +**/ +- (void)udpSocket:(QNAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error; + +/** + * Called when the socket has received the requested datagram. +**/ +- (void)udpSocket:(QNAsyncUdpSocket *)sock didReceiveData:(NSData *)data + fromAddress:(NSData *)address + withFilterContext:(nullable id)filterContext; + +/** + * Called when the socket is closed. +**/ +- (void)udpSocketDidClose:(QNAsyncUdpSocket *)sock withError:(NSError * _Nullable)error; + +@end + +/** + * You may optionally set a receive filter for the socket. + * A filter can provide several useful features: + * + * 1. Many times udp packets need to be parsed. + * Since the filter can run in its own independent queue, you can parallelize this parsing quite easily. + * The end result is a parallel socket io, datagram parsing, and packet processing. + * + * 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited. + * The filter can prevent such packets from arriving at the delegate. + * And because the filter can run in its own independent queue, this doesn't slow down the delegate. + * + * - Since the udp protocol does not guarantee delivery, udp packets may be lost. + * Many protocols built atop udp thus provide various resend/re-request algorithms. + * This sometimes results in duplicate packets arriving. + * A filter may allow you to architect the duplicate detection code to run in parallel to normal processing. + * + * - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive. + * Such packets need to be ignored. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * @param data - The packet that was received. + * @param address - The address the data was received from. + * See utilities section for methods to extract info from address. + * @param context - Out parameter you may optionally set, which will then be passed to the delegate method. + * For example, filter block can parse the data and then, + * pass the parsed data to the delegate. + * + * @returns - YES if the received packet should be passed onto the delegate. + * NO if the received packet should be discarded, and not reported to the delegete. + * + * Example: + * + * QNAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) { + * + * MyProtocolMessage *msg = [MyProtocol parseMessage:data]; + * + * *context = response; + * return (response != nil); + * }; + * [udpSocket setReceiveFilter:filter withQueue:myParsingQueue]; + * +**/ +typedef BOOL (^QNAsyncUdpSocketReceiveFilterBlock)(NSData *data, NSData *address, id __nullable * __nonnull context); + +/** + * You may optionally set a send filter for the socket. + * A filter can provide several interesting possibilities: + * + * 1. Optional caching of resolved addresses for domain names. + * The cache could later be consulted, resulting in fewer system calls to getaddrinfo. + * + * 2. Reusable modules of code for bandwidth monitoring. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * @param data - The packet that was received. + * @param address - The address the data was received from. + * See utilities section for methods to extract info from address. + * @param tag - The tag that was passed in the send method. + * + * @returns - YES if the packet should actually be sent over the socket. + * NO if the packet should be silently dropped (not sent over the socket). + * + * Regardless of the return value, the delegate will be informed that the packet was successfully sent. + * +**/ +typedef BOOL (^QNAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address, long tag); + + +@interface QNAsyncUdpSocket : NSObject + +/** + * QNAsyncUdpSocket uses the standard delegate paradigm, + * but executes all delegate callbacks on a given delegate dispatch queue. + * This allows for maximum concurrency, while at the same time providing easy thread safety. + * + * You MUST set a delegate AND delegate dispatch queue before attempting to + * use the socket, or you will get an error. + * + * The socket queue is optional. + * If you pass NULL, GCDAsyncSocket will automatically create its own socket queue. + * If you choose to provide a socket queue, the socket queue must not be a concurrent queue, + * then please see the discussion for the method markSocketQueueTargetQueue. + * + * The delegate queue and socket queue can optionally be the same. +**/ +- (instancetype)init; +- (instancetype)initWithSocketQueue:(nullable dispatch_queue_t)sq; +- (instancetype)initWithDelegate:(nullable id)aDelegate delegateQueue:(nullable dispatch_queue_t)dq; +- (instancetype)initWithDelegate:(nullable id)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq NS_DESIGNATED_INITIALIZER; + +#pragma mark Configuration + +- (nullable id)delegate; +- (void)setDelegate:(nullable id)delegate; +- (void)synchronouslySetDelegate:(nullable id)delegate; + +- (nullable dispatch_queue_t)delegateQueue; +- (void)setDelegateQueue:(nullable dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegateQueue:(nullable dispatch_queue_t)delegateQueue; + +- (void)getDelegate:(id __nullable * __nullable)delegatePtr delegateQueue:(dispatch_queue_t __nullable * __nullable)delegateQueuePtr; +- (void)setDelegate:(nullable id)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegate:(nullable id)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue; + +/** + * By default, both IPv4 and IPv6 are enabled. + * + * This means QNAsyncUdpSocket automatically supports both protocols, + * and can send to IPv4 or IPv6 addresses, + * as well as receive over IPv4 and IPv6. + * + * For operations that require DNS resolution, QNAsyncUdpSocket supports both IPv4 and IPv6. + * If a DNS lookup returns only IPv4 results, QNAsyncUdpSocket will automatically use IPv4. + * If a DNS lookup returns only IPv6 results, QNAsyncUdpSocket will automatically use IPv6. + * If a DNS lookup returns both IPv4 and IPv6 results, then the protocol used depends on the configured preference. + * If IPv4 is preferred, then IPv4 is used. + * If IPv6 is preferred, then IPv6 is used. + * If neutral, then the first IP version in the resolved array will be used. + * + * Starting with Mac OS X 10.7 Lion and iOS 5, the default IP preference is neutral. + * On prior systems the default IP preference is IPv4. + **/ +- (BOOL)isIPv4Enabled; +- (void)setIPv4Enabled:(BOOL)flag; + +- (BOOL)isIPv6Enabled; +- (void)setIPv6Enabled:(BOOL)flag; + +- (BOOL)isIPv4Preferred; +- (BOOL)isIPv6Preferred; +- (BOOL)isIPVersionNeutral; + +- (void)setPreferIPv4; +- (void)setPreferIPv6; +- (void)setIPVersionNeutral; + +/** + * Gets/Sets the maximum size of the buffer that will be allocated for receive operations. + * The default maximum size is 65535 bytes. + * + * The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535. + * The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295. + * + * Since the OS/GCD notifies us of the size of each received UDP packet, + * the actual allocated buffer size for each packet is exact. + * And in practice the size of UDP packets is generally much smaller than the max. + * Indeed most protocols will send and receive packets of only a few bytes, + * or will set a limit on the size of packets to prevent fragmentation in the IP layer. + * + * If you set the buffer size too small, the sockets API in the OS will silently discard + * any extra data, and you will not be notified of the error. +**/ +- (uint16_t)maxReceiveIPv4BufferSize; +- (void)setMaxReceiveIPv4BufferSize:(uint16_t)max; + +- (uint32_t)maxReceiveIPv6BufferSize; +- (void)setMaxReceiveIPv6BufferSize:(uint32_t)max; + +/** + * Gets/Sets the maximum size of the buffer that will be allocated for send operations. + * The default maximum size is 65535 bytes. + * + * Given that a typical link MTU is 1500 bytes, a large UDP datagram will have to be + * fragmented, and that’s both expensive and risky (if one fragment goes missing, the + * entire datagram is lost). You are much better off sending a large number of smaller + * UDP datagrams, preferably using a path MTU algorithm to avoid fragmentation. + * + * You must set it before the sockt is created otherwise it won't work. + * + **/ +- (uint16_t)maxSendBufferSize; +- (void)setMaxSendBufferSize:(uint16_t)max; + +/** + * User data allows you to associate arbitrary information with the socket. + * This data is not used internally in any way. +**/ +- (nullable id)userData; +- (void)setUserData:(nullable id)arbitraryUserData; + +#pragma mark Diagnostics + +/** + * Returns the local address info for the socket. + * + * The localAddress method returns a sockaddr structure wrapped in a NSData object. + * The localHost method returns the human readable IP address as a string. + * + * Note: Address info may not be available until after the socket has been binded, connected + * or until after data has been sent. +**/ +- (nullable NSData *)localAddress; +- (nullable NSString *)localHost; +- (uint16_t)localPort; + +- (nullable NSData *)localAddress_IPv4; +- (nullable NSString *)localHost_IPv4; +- (uint16_t)localPort_IPv4; + +- (nullable NSData *)localAddress_IPv6; +- (nullable NSString *)localHost_IPv6; +- (uint16_t)localPort_IPv6; + +/** + * Returns the remote address info for the socket. + * + * The connectedAddress method returns a sockaddr structure wrapped in a NSData object. + * The connectedHost method returns the human readable IP address as a string. + * + * Note: Since UDP is connectionless by design, connected address info + * will not be available unless the socket is explicitly connected to a remote host/port. + * If the socket is not connected, these methods will return nil / 0. +**/ +- (nullable NSData *)connectedAddress; +- (nullable NSString *)connectedHost; +- (uint16_t)connectedPort; + +/** + * Returns whether or not this socket has been connected to a single host. + * By design, UDP is a connectionless protocol, and connecting is not needed. + * If connected, the socket will only be able to send/receive data to/from the connected host. +**/ +- (BOOL)isConnected; + +/** + * Returns whether or not this socket has been closed. + * The only way a socket can be closed is if you explicitly call one of the close methods. +**/ +- (BOOL)isClosed; + +/** + * Returns whether or not this socket is IPv4. + * + * By default this will be true, unless: + * - IPv4 is disabled (via setIPv4Enabled:) + * - The socket is explicitly bound to an IPv6 address + * - The socket is connected to an IPv6 address +**/ +- (BOOL)isIPv4; + +/** + * Returns whether or not this socket is IPv6. + * + * By default this will be true, unless: + * - IPv6 is disabled (via setIPv6Enabled:) + * - The socket is explicitly bound to an IPv4 address + * _ The socket is connected to an IPv4 address + * + * This method will also return false on platforms that do not support IPv6. + * Note: The iPhone does not currently support IPv6. +**/ +- (BOOL)isIPv6; + +#pragma mark Binding + +/** + * Binds the UDP socket to the given port. + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You may optionally pass a port number of zero to immediately bind the socket, + * yet still allow the OS to automatically assign an available port. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr. +**/ +- (BOOL)bindToPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Binds the UDP socket to the given port and optional interface. + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You may optionally pass a port number of zero to immediately bind the socket, + * yet still allow the OS to automatically assign an available port. + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * You may also use the special strings "localhost" or "loopback" to specify that + * the socket only accept packets from the local machine. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr. +**/ +- (BOOL)bindToPort:(uint16_t)port interface:(nullable NSString *)interface error:(NSError **)errPtr; + +/** + * Binds the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr. +**/ +- (BOOL)bindToAddress:(NSData *)localAddr error:(NSError **)errPtr; + +#pragma mark Connecting + +/** + * Connects the UDP socket to the given host and port. + * By design, UDP is a connectionless protocol, and connecting is not needed. + * + * Choosing to connect to a specific host/port has the following effect: + * - You will only be able to send data to the connected host/port. + * - You will only be able to receive data from the connected host/port. + * - You will receive ICMP messages that come from the connected host/port, such as "connection refused". + * + * The actual process of connecting a UDP socket does not result in any communication on the socket. + * It simply changes the internal state of the socket. + * + * You cannot bind a socket after it has been connected. + * You can only connect a socket once. + * + * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * + * This method is asynchronous as it requires a DNS lookup to resolve the given host name. + * If an obvious error is detected, this method immediately returns NO and sets errPtr. + * If you don't care about the error, you can pass nil for errPtr. + * Otherwise, this method returns YES and begins the asynchronous connection process. + * The result of the asynchronous connection process will be reported via the delegate methods. + **/ +- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Connects the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * By design, UDP is a connectionless protocol, and connecting is not needed. + * + * Choosing to connect to a specific address has the following effect: + * - You will only be able to send data to the connected address. + * - You will only be able to receive data from the connected address. + * - You will receive ICMP messages that come from the connected address, such as "connection refused". + * + * Connecting a UDP socket does not result in any communication on the socket. + * It simply changes the internal state of the socket. + * + * You cannot bind a socket after its been connected. + * You can only connect a socket once. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. + * + * Note: Unlike the connectToHost:onPort:error: method, this method does not require a DNS lookup. + * Thus when this method returns, the connection has either failed or fully completed. + * In other words, this method is synchronous, unlike the asynchronous connectToHost::: method. + * However, for compatibility and simplification of delegate code, if this method returns YES + * then the corresponding delegate method (udpSocket:didConnectToHost:port:) is still invoked. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; + +#pragma mark Multicast + +/** + * Join multicast group. + * Group should be an IP address (eg @"225.228.0.1"). + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. +**/ +- (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr; + +/** + * Join multicast group. + * Group should be an IP address (eg @"225.228.0.1"). + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. +**/ +- (BOOL)joinMulticastGroup:(NSString *)group onInterface:(nullable NSString *)interface error:(NSError **)errPtr; + +- (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr; +- (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(nullable NSString *)interface error:(NSError **)errPtr; + +#pragma mark Reuse Port + +/** + * By default, only one socket can be bound to a given IP address + port at a time. + * To enable multiple processes to simultaneously bind to the same address+port, + * you need to enable this functionality in the socket. All processes that wish to + * use the address+port simultaneously must all enable reuse port on the socket + * bound to that port. + **/ +- (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr; + +#pragma mark Broadcast + +/** + * By default, the underlying socket in the OS will not allow you to send broadcast messages. + * In order to send broadcast messages, you need to enable this functionality in the socket. + * + * A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is + * delivered to every host on the network. + * The reason this is generally disabled by default (by the OS) is to prevent + * accidental broadcast messages from flooding the network. +**/ +- (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr; + +#pragma mark Sending + +/** + * Asynchronously sends the given data, with the given timeout and tag. + * + * This method may only be used with a connected socket. + * Recall that connecting is optional for a UDP socket. + * For connected sockets, data can only be sent to the connected address. + * For non-connected sockets, the remote destination is specified for each packet. + * For more information about optionally connecting udp sockets, see the documentation for the connect methods above. + * + * @param data + * The data to send. + * If data is nil or zero-length, this method does nothing. + * If passing NSMutableData, please read the thread-safety notice below. + * + * @param timeout + * The timeout for the send opeartion. + * If the timeout value is negative, the send operation will not use a timeout. + * + * @param tag + * The tag is for your convenience. + * It is not sent or received over the socket in any manner what-so-ever. + * It is reported back as a parameter in the udpSocket:didSendDataWithTag: + * or udpSocket:didNotSendDataWithTag:dueToError: methods. + * You can use it as an array index, state id, type constant, etc. + * + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method + * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying + * that this particular send operation has completed. + * This is due to the fact that QNAsyncUdpSocket does NOT copy the data. + * It simply retains it for performance reasons. + * Often times, if NSMutableData is passed, it is because a request/response was built up in memory. + * Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Asynchronously sends the given data, with the given timeout and tag, to the given host and port. + * + * This method cannot be used with a connected socket. + * Recall that connecting is optional for a UDP socket. + * For connected sockets, data can only be sent to the connected address. + * For non-connected sockets, the remote destination is specified for each packet. + * For more information about optionally connecting udp sockets, see the documentation for the connect methods above. + * + * @param data + * The data to send. + * If data is nil or zero-length, this method does nothing. + * If passing NSMutableData, please read the thread-safety notice below. + * + * @param host + * The destination to send the udp packet to. + * May be specified as a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * You may also use the convenience strings of "loopback" or "localhost". + * + * @param port + * The port of the host to send to. + * + * @param timeout + * The timeout for the send opeartion. + * If the timeout value is negative, the send operation will not use a timeout. + * + * @param tag + * The tag is for your convenience. + * It is not sent or received over the socket in any manner what-so-ever. + * It is reported back as a parameter in the udpSocket:didSendDataWithTag: + * or udpSocket:didNotSendDataWithTag:dueToError: methods. + * You can use it as an array index, state id, type constant, etc. + * + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method + * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying + * that this particular send operation has completed. + * This is due to the fact that QNAsyncUdpSocket does NOT copy the data. + * It simply retains it for performance reasons. + * Often times, if NSMutableData is passed, it is because a request/response was built up in memory. + * Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)sendData:(NSData *)data + toHost:(NSString *)host + port:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + tag:(long)tag; + +/** + * Asynchronously sends the given data, with the given timeout and tag, to the given address. + * + * This method cannot be used with a connected socket. + * Recall that connecting is optional for a UDP socket. + * For connected sockets, data can only be sent to the connected address. + * For non-connected sockets, the remote destination is specified for each packet. + * For more information about optionally connecting udp sockets, see the documentation for the connect methods above. + * + * @param data + * The data to send. + * If data is nil or zero-length, this method does nothing. + * If passing NSMutableData, please read the thread-safety notice below. + * + * @param remoteAddr + * The address to send the data to (specified as a sockaddr structure wrapped in a NSData object). + * + * @param timeout + * The timeout for the send opeartion. + * If the timeout value is negative, the send operation will not use a timeout. + * + * @param tag + * The tag is for your convenience. + * It is not sent or received over the socket in any manner what-so-ever. + * It is reported back as a parameter in the udpSocket:didSendDataWithTag: + * or udpSocket:didNotSendDataWithTag:dueToError: methods. + * You can use it as an array index, state id, type constant, etc. + * + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method + * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying + * that this particular send operation has completed. + * This is due to the fact that QNAsyncUdpSocket does NOT copy the data. + * It simply retains it for performance reasons. + * Often times, if NSMutableData is passed, it is because a request/response was built up in memory. + * Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * You may optionally set a send filter for the socket. + * A filter can provide several interesting possibilities: + * + * 1. Optional caching of resolved addresses for domain names. + * The cache could later be consulted, resulting in fewer system calls to getaddrinfo. + * + * 2. Reusable modules of code for bandwidth monitoring. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * For more information about QNAsyncUdpSocketSendFilterBlock, see the documentation for its typedef. + * To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue. + * + * Note: This method invokes setSendFilter:withQueue:isAsynchronous: (documented below), + * passing YES for the isAsynchronous parameter. +**/ +- (void)setSendFilter:(nullable QNAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(nullable dispatch_queue_t)filterQueue; + +/** + * The receive filter can be run via dispatch_async or dispatch_sync. + * Most typical situations call for asynchronous operation. + * + * However, there are a few situations in which synchronous operation is preferred. + * Such is the case when the filter is extremely minimal and fast. + * This is because dispatch_sync is faster than dispatch_async. + * + * If you choose synchronous operation, be aware of possible deadlock conditions. + * Since the socket queue is executing your block via dispatch_sync, + * then you cannot perform any tasks which may invoke dispatch_sync on the socket queue. + * For example, you can't query properties on the socket. +**/ +- (void)setSendFilter:(nullable QNAsyncUdpSocketSendFilterBlock)filterBlock + withQueue:(nullable dispatch_queue_t)filterQueue + isAsynchronous:(BOOL)isAsynchronous; + +#pragma mark Receiving + +/** + * There are two modes of operation for receiving packets: one-at-a-time & continuous. + * + * In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet. + * Receiving packets one-at-a-time may be better suited for implementing certain state machine code, + * where your state machine may not always be ready to process incoming packets. + * + * In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received. + * Receiving packets continuously is better suited to real-time streaming applications. + * + * You may switch back and forth between one-at-a-time mode and continuous mode. + * If the socket is currently in continuous mode, calling this method will switch it to one-at-a-time mode. + * + * When a packet is received (and not filtered by the optional receive filter), + * the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked. + * + * If the socket is able to begin receiving packets, this method returns YES. + * Otherwise it returns NO, and sets the errPtr with appropriate error information. + * + * An example error: + * You created a udp socket to act as a server, and immediately called receive. + * You forgot to first bind the socket to a port number, and received a error with a message like: + * "Must bind socket before you can receive data." +**/ +- (BOOL)receiveOnce:(NSError **)errPtr; + +/** + * There are two modes of operation for receiving packets: one-at-a-time & continuous. + * + * In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet. + * Receiving packets one-at-a-time may be better suited for implementing certain state machine code, + * where your state machine may not always be ready to process incoming packets. + * + * In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received. + * Receiving packets continuously is better suited to real-time streaming applications. + * + * You may switch back and forth between one-at-a-time mode and continuous mode. + * If the socket is currently in one-at-a-time mode, calling this method will switch it to continuous mode. + * + * For every received packet (not filtered by the optional receive filter), + * the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked. + * + * If the socket is able to begin receiving packets, this method returns YES. + * Otherwise it returns NO, and sets the errPtr with appropriate error information. + * + * An example error: + * You created a udp socket to act as a server, and immediately called receive. + * You forgot to first bind the socket to a port number, and received a error with a message like: + * "Must bind socket before you can receive data." +**/ +- (BOOL)beginReceiving:(NSError **)errPtr; + +/** + * If the socket is currently receiving (beginReceiving has been called), this method pauses the receiving. + * That is, it won't read any more packets from the underlying OS socket until beginReceiving is called again. + * + * Important Note: + * QNAsyncUdpSocket may be running in parallel with your code. + * That is, your delegate is likely running on a separate thread/dispatch_queue. + * When you invoke this method, QNAsyncUdpSocket may have already dispatched delegate methods to be invoked. + * Thus, if those delegate methods have already been dispatch_async'd, + * your didReceive delegate method may still be invoked after this method has been called. + * You should be aware of this, and program defensively. +**/ +- (void)pauseReceiving; + +/** + * You may optionally set a receive filter for the socket. + * This receive filter may be set to run in its own queue (independent of delegate queue). + * + * A filter can provide several useful features. + * + * 1. Many times udp packets need to be parsed. + * Since the filter can run in its own independent queue, you can parallelize this parsing quite easily. + * The end result is a parallel socket io, datagram parsing, and packet processing. + * + * 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited. + * The filter can prevent such packets from arriving at the delegate. + * And because the filter can run in its own independent queue, this doesn't slow down the delegate. + * + * - Since the udp protocol does not guarantee delivery, udp packets may be lost. + * Many protocols built atop udp thus provide various resend/re-request algorithms. + * This sometimes results in duplicate packets arriving. + * A filter may allow you to architect the duplicate detection code to run in parallel to normal processing. + * + * - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive. + * Such packets need to be ignored. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * Example: + * + * QNAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) { + * + * MyProtocolMessage *msg = [MyProtocol parseMessage:data]; + * + * *context = response; + * return (response != nil); + * }; + * [udpSocket setReceiveFilter:filter withQueue:myParsingQueue]; + * + * For more information about QNAsyncUdpSocketReceiveFilterBlock, see the documentation for its typedef. + * To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue. + * + * Note: This method invokes setReceiveFilter:withQueue:isAsynchronous: (documented below), + * passing YES for the isAsynchronous parameter. +**/ +- (void)setReceiveFilter:(nullable QNAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(nullable dispatch_queue_t)filterQueue; + +/** + * The receive filter can be run via dispatch_async or dispatch_sync. + * Most typical situations call for asynchronous operation. + * + * However, there are a few situations in which synchronous operation is preferred. + * Such is the case when the filter is extremely minimal and fast. + * This is because dispatch_sync is faster than dispatch_async. + * + * If you choose synchronous operation, be aware of possible deadlock conditions. + * Since the socket queue is executing your block via dispatch_sync, + * then you cannot perform any tasks which may invoke dispatch_sync on the socket queue. + * For example, you can't query properties on the socket. +**/ +- (void)setReceiveFilter:(nullable QNAsyncUdpSocketReceiveFilterBlock)filterBlock + withQueue:(nullable dispatch_queue_t)filterQueue + isAsynchronous:(BOOL)isAsynchronous; + +#pragma mark Closing + +/** + * Immediately closes the underlying socket. + * Any pending send operations are discarded. + * + * The QNAsyncUdpSocket instance may optionally be used again. + * (it will setup/configure/use another unnderlying BSD socket). +**/ +- (void)close; + +/** + * Closes the underlying socket after all pending send operations have been sent. + * + * The QNAsyncUdpSocket instance may optionally be used again. + * (it will setup/configure/use another unnderlying BSD socket). +**/ +- (void)closeAfterSending; + +#pragma mark Advanced +/** + * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue. + * In most cases, the instance creates this queue itself. + * However, to allow for maximum flexibility, the internal queue may be passed in the init method. + * This allows for some advanced options such as controlling socket priority via target queues. + * However, when one begins to use target queues like this, they open the door to some specific deadlock issues. + * + * For example, imagine there are 2 queues: + * dispatch_queue_t socketQueue; + * dispatch_queue_t socketTargetQueue; + * + * If you do this (pseudo-code): + * socketQueue.targetQueue = socketTargetQueue; + * + * Then all socketQueue operations will actually get run on the given socketTargetQueue. + * This is fine and works great in most situations. + * But if you run code directly from within the socketTargetQueue that accesses the socket, + * you could potentially get deadlock. Imagine the following code: + * + * - (BOOL)socketHasSomething + * { + * __block BOOL result = NO; + * dispatch_block_t block = ^{ + * result = [self someInternalMethodToBeRunOnlyOnSocketQueue]; + * } + * if (is_executing_on_queue(socketQueue)) + * block(); + * else + * dispatch_sync(socketQueue, block); + * + * return result; + * } + * + * What happens if you call this method from the socketTargetQueue? The result is deadlock. + * This is because the GCD API offers no mechanism to discover a queue's targetQueue. + * Thus we have no idea if our socketQueue is configured with a targetQueue. + * If we had this information, we could easily avoid deadlock. + * But, since these API's are missing or unfeasible, you'll have to explicitly set it. + * + * IF you pass a socketQueue via the init method, + * AND you've configured the passed socketQueue with a targetQueue, + * THEN you should pass the end queue in the target hierarchy. + * + * For example, consider the following queue hierarchy: + * socketQueue -> ipQueue -> moduleQueue + * + * This example demonstrates priority shaping within some server. + * All incoming client connections from the same IP address are executed on the same target queue. + * And all connections for a particular module are executed on the same target queue. + * Thus, the priority of all networking for the entire module can be changed on the fly. + * Additionally, networking traffic from a single IP cannot monopolize the module. + * + * Here's how you would accomplish something like that: + * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock + * { + * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL); + * dispatch_queue_t ipQueue = [self ipQueueForAddress:address]; + * + * dispatch_set_target_queue(socketQueue, ipQueue); + * dispatch_set_target_queue(iqQueue, moduleQueue); + * + * return socketQueue; + * } + * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket + * { + * [clientConnections addObject:newSocket]; + * [newSocket markSocketQueueTargetQueue:moduleQueue]; + * } + * + * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue. + * This is often NOT the case, as such queues are used solely for execution shaping. + **/ +- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue; +- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue; + +/** + * It's not thread-safe to access certain variables from outside the socket's internal queue. + * + * For example, the socket file descriptor. + * File descriptors are simply integers which reference an index in the per-process file table. + * However, when one requests a new file descriptor (by opening a file or socket), + * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor. + * So if we're not careful, the following could be possible: + * + * - Thread A invokes a method which returns the socket's file descriptor. + * - The socket is closed via the socket's internal queue on thread B. + * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD. + * - Thread A is now accessing/altering the file instead of the socket. + * + * In addition to this, other variables are not actually objects, + * and thus cannot be retained/released or even autoreleased. + * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct. + * + * Although there are internal variables that make it difficult to maintain thread-safety, + * it is important to provide access to these variables + * to ensure this class can be used in a wide array of environments. + * This method helps to accomplish this by invoking the current block on the socket's internal queue. + * The methods below can be invoked from within the block to access + * those generally thread-unsafe internal variables in a thread-safe manner. + * The given block will be invoked synchronously on the socket's internal queue. + * + * If you save references to any protected variables and use them outside the block, you do so at your own peril. +**/ +- (void)performBlock:(dispatch_block_t)block; + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's file descriptor(s). + * If the socket isn't connected, or explicity bound to a particular interface, + * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6. +**/ +- (int)socketFD; +- (int)socket4FD; +- (int)socket6FD; + +#if TARGET_OS_IPHONE + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Returns (creating if necessary) a CFReadStream/CFWriteStream for the internal socket. + * + * Generally QNAsyncUdpSocket doesn't use CFStream. (It uses the faster GCD API's.) + * However, if you need one for any reason, + * these methods are a convenient way to get access to a safe instance of one. +**/ +- (nullable CFReadStreamRef)readStream; +- (nullable CFWriteStreamRef)writeStream; + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Configures the socket to allow it to operate when the iOS application has been backgrounded. + * In other words, this method creates a read & write stream, and invokes: + * + * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * + * Returns YES if successful, NO otherwise. + * + * Example usage: + * + * [asyncUdpSocket performBlock:^{ + * [asyncUdpSocket enableBackgroundingOnSocket]; + * }]; + * + * + * NOTE : Apple doesn't currently support backgrounding UDP sockets. (Only TCP for now). +**/ +//- (BOOL)enableBackgroundingOnSockets; + +#endif + +#pragma mark Utilities + +/** + * Extracting host/port/family information from raw address data. +**/ + ++ (nullable NSString *)hostFromAddress:(NSData *)address; ++ (uint16_t)portFromAddress:(NSData *)address; ++ (int)familyFromAddress:(NSData *)address; + ++ (BOOL)isIPv4Address:(NSData *)address; ++ (BOOL)isIPv6Address:(NSData *)address; + ++ (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(uint16_t * __nullable)portPtr fromAddress:(NSData *)address; ++ (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(uint16_t * __nullable)portPtr family:(int * __nullable)afPtr fromAddress:(NSData *)address; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.m b/Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.m new file mode 100755 index 0000000..fb9e847 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.m @@ -0,0 +1,5517 @@ +// +// QNAsyncUdpSocket +// +// This class is in the public domain. +// Originally created by Robbie Hanson of Deusty LLC. +// Updated and maintained by Deusty LLC and the Apple development community. +// +// https://github.com/robbiehanson/CocoaAsyncSocket +// + +#import "QNAsyncUdpSocket.h" + +#if ! __has_feature(objc_arc) +#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +// For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC +#endif + +#if TARGET_OS_IPHONE + #import + #import +#endif + +#import +#import +#import +#import +#import +#import +#import + + +#if 0 + +// Logging Enabled - See log level below + +// Logging uses the CocoaLumberjack framework (which is also GCD based). +// https://github.com/robbiehanson/CocoaLumberjack +// +// It allows us to do a lot of logging without significantly slowing down the code. +#import "DDLog.h" + +#define LogAsync NO +#define LogContext 65535 + +#define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__) +#define LogC(flg, frmt, ...) LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__) + +#define LogError(frmt, ...) LogObjc(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogWarn(frmt, ...) LogObjc(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogInfo(frmt, ...) LogObjc(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogVerbose(frmt, ...) LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) + +#define LogCError(frmt, ...) LogC(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogCWarn(frmt, ...) LogC(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogCInfo(frmt, ...) LogC(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) +#define LogCVerbose(frmt, ...) LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__) + +#define LogTrace() LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD) +#define LogCTrace() LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__) + +// Log levels : off, error, warn, info, verbose +static const int logLevel = LOG_LEVEL_VERBOSE; + +#else + +// Logging Disabled + +#define LogError(frmt, ...) {} +#define LogWarn(frmt, ...) {} +#define LogInfo(frmt, ...) {} +#define LogVerbose(frmt, ...) {} + +#define LogCError(frmt, ...) {} +#define LogCWarn(frmt, ...) {} +#define LogCInfo(frmt, ...) {} +#define LogCVerbose(frmt, ...) {} + +#define LogTrace() {} +#define LogCTrace(frmt, ...) {} + +#endif + +/** + * Seeing a return statements within an inner block + * can sometimes be mistaken for a return point of the enclosing method. + * This makes inline blocks a bit easier to read. +**/ +#define return_from_block return + +/** + * A socket file descriptor is really just an integer. + * It represents the index of the socket within the kernel. + * This makes invalid file descriptor comparisons easier to read. +**/ +#define SOCKET_NULL -1 + +/** + * Just to type less code. +**/ +#define AutoreleasedBlock(block) ^{ @autoreleasepool { block(); }} + + +@class QNAsyncUdpSendPacket; + +NSString *const QNAsyncUdpSocketException = @"QNAsyncUdpSocketException"; +NSString *const QNAsyncUdpSocketErrorDomain = @"QNAsyncUdpSocketErrorDomain"; + +NSString *const QNAsyncUdpSocketQueueName = @"QNAsyncUdpSocket"; +NSString *const QNAsyncUdpSocketThreadName = @"QNAsyncUdpSocket-CFStream"; + +enum QNAsyncUdpSocketFlags +{ + kDidCreateSockets = 1 << 0, // If set, the sockets have been created. + kDidBind = 1 << 1, // If set, bind has been called. + kConnecting = 1 << 2, // If set, a connection attempt is in progress. + kDidConnect = 1 << 3, // If set, socket is connected. + kReceiveOnce = 1 << 4, // If set, one-at-a-time receive is enabled + kReceiveContinuous = 1 << 5, // If set, continuous receive is enabled + kIPv4Deactivated = 1 << 6, // If set, socket4 was closed due to bind or connect on IPv6. + kIPv6Deactivated = 1 << 7, // If set, socket6 was closed due to bind or connect on IPv4. + kSend4SourceSuspended = 1 << 8, // If set, send4Source is suspended. + kSend6SourceSuspended = 1 << 9, // If set, send6Source is suspended. + kReceive4SourceSuspended = 1 << 10, // If set, receive4Source is suspended. + kReceive6SourceSuspended = 1 << 11, // If set, receive6Source is suspended. + kSock4CanAcceptBytes = 1 << 12, // If set, we know socket4 can accept bytes. If unset, it's unknown. + kSock6CanAcceptBytes = 1 << 13, // If set, we know socket6 can accept bytes. If unset, it's unknown. + kForbidSendReceive = 1 << 14, // If set, no new send or receive operations are allowed to be queued. + kCloseAfterSends = 1 << 15, // If set, close as soon as no more sends are queued. + kFlipFlop = 1 << 16, // Used to alternate between IPv4 and IPv6 sockets. +#if TARGET_OS_IPHONE + kAddedStreamListener = 1 << 17, // If set, CFStreams have been added to listener thread +#endif +}; + +enum QNAsyncUdpSocketConfig +{ + kIPv4Disabled = 1 << 0, // If set, IPv4 is disabled + kIPv6Disabled = 1 << 1, // If set, IPv6 is disabled + kPreferIPv4 = 1 << 2, // If set, IPv4 is preferred over IPv6 + kPreferIPv6 = 1 << 3, // If set, IPv6 is preferred over IPv4 +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface QNAsyncUdpSocket () +{ +#if __has_feature(objc_arc_weak) + __weak id delegate; +#else + __unsafe_unretained id delegate; +#endif + dispatch_queue_t delegateQueue; + + QNAsyncUdpSocketReceiveFilterBlock receiveFilterBlock; + dispatch_queue_t receiveFilterQueue; + BOOL receiveFilterAsync; + + QNAsyncUdpSocketSendFilterBlock sendFilterBlock; + dispatch_queue_t sendFilterQueue; + BOOL sendFilterAsync; + + uint32_t flags; + uint16_t config; + + uint16_t max4ReceiveSize; + uint32_t max6ReceiveSize; + + uint16_t maxSendSize; + + int socket4FD; + int socket6FD; + + dispatch_queue_t socketQueue; + + dispatch_source_t send4Source; + dispatch_source_t send6Source; + dispatch_source_t receive4Source; + dispatch_source_t receive6Source; + dispatch_source_t sendTimer; + + QNAsyncUdpSendPacket *currentSend; + NSMutableArray *sendQueue; + + unsigned long socket4FDBytesAvailable; + unsigned long socket6FDBytesAvailable; + + uint32_t pendingFilterOperations; + + NSData *cachedLocalAddress4; + NSString *cachedLocalHost4; + uint16_t cachedLocalPort4; + + NSData *cachedLocalAddress6; + NSString *cachedLocalHost6; + uint16_t cachedLocalPort6; + + NSData *cachedConnectedAddress; + NSString *cachedConnectedHost; + uint16_t cachedConnectedPort; + int cachedConnectedFamily; + + void *IsOnSocketQueueOrTargetQueueKey; + +#if TARGET_OS_IPHONE + CFStreamClientContext streamContext; + CFReadStreamRef readStream4; + CFReadStreamRef readStream6; + CFWriteStreamRef writeStream4; + CFWriteStreamRef writeStream6; +#endif + + id userData; +} + +- (void)resumeSend4Source; +- (void)resumeSend6Source; +- (void)resumeReceive4Source; +- (void)resumeReceive6Source; +- (void)closeSockets; + +- (void)maybeConnect; +- (BOOL)connectWithAddress4:(NSData *)address4 error:(NSError **)errPtr; +- (BOOL)connectWithAddress6:(NSData *)address6 error:(NSError **)errPtr; + +- (void)maybeDequeueSend; +- (void)doPreSend; +- (void)doSend; +- (void)endCurrentSend; +- (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout; + +- (void)doReceive; +- (void)doReceiveEOF; + +- (void)closeWithError:(NSError *)error; + +- (BOOL)performMulticastRequest:(int)requestType forGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr; + +#if TARGET_OS_IPHONE +- (BOOL)createReadAndWriteStreams:(NSError **)errPtr; +- (BOOL)registerForStreamCallbacks:(NSError **)errPtr; +- (BOOL)addStreamsToRunLoop:(NSError **)errPtr; +- (BOOL)openStreams:(NSError **)errPtr; +- (void)removeStreamsFromRunLoop; +- (void)closeReadAndWriteStreams; +#endif + ++ (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4; ++ (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6; ++ (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4; ++ (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6; + +#if TARGET_OS_IPHONE +// Forward declaration ++ (void)listenerThread:(id)unused; +#endif + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * The QNAsyncUdpSendPacket encompasses the instructions for a single send/write. +**/ +@interface QNAsyncUdpSendPacket : NSObject { +@public + NSData *buffer; + NSTimeInterval timeout; + long tag; + + BOOL resolveInProgress; + BOOL filterInProgress; + + NSArray *resolvedAddresses; + NSError *resolveError; + + NSData *address; + int addressFamily; +} + +- (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i NS_DESIGNATED_INITIALIZER; + +@end + +@implementation QNAsyncUdpSendPacket + +// Cover the superclass' designated initializer +- (instancetype)init NS_UNAVAILABLE +{ + NSAssert(0, @"Use the designated initializer"); + return nil; +} + +- (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i +{ + if ((self = [super init])) + { + buffer = d; + timeout = t; + tag = i; + + resolveInProgress = NO; + } + return self; +} + + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface QNAsyncUdpSpecialPacket : NSObject { +@public +// uint8_t type; + + BOOL resolveInProgress; + + NSArray *addresses; + NSError *error; +} + +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +@end + +@implementation QNAsyncUdpSpecialPacket + +- (instancetype)init +{ + self = [super init]; + return self; +} + + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation QNAsyncUdpSocket + +- (instancetype)init +{ + LogTrace(); + + return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL]; +} + +- (instancetype)initWithSocketQueue:(dispatch_queue_t)sq +{ + LogTrace(); + + return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq]; +} + +- (instancetype)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq +{ + LogTrace(); + + return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL]; +} + +- (instancetype)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq +{ + LogTrace(); + + if ((self = [super init])) + { + delegate = aDelegate; + + if (dq) + { + delegateQueue = dq; + #if !OS_OBJECT_USE_OBJC + dispatch_retain(delegateQueue); + #endif + } + + max4ReceiveSize = 65535; + max6ReceiveSize = 65535; + + maxSendSize = 65535; + + socket4FD = SOCKET_NULL; + socket6FD = SOCKET_NULL; + + if (sq) + { + NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), + @"The given socketQueue parameter must not be a concurrent queue."); + NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), + @"The given socketQueue parameter must not be a concurrent queue."); + NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + @"The given socketQueue parameter must not be a concurrent queue."); + + socketQueue = sq; + #if !OS_OBJECT_USE_OBJC + dispatch_retain(socketQueue); + #endif + } + else + { + socketQueue = dispatch_queue_create([QNAsyncUdpSocketQueueName UTF8String], NULL); + } + + // The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter. + // From the documentation: + // + // > Keys are only compared as pointers and are never dereferenced. + // > Thus, you can use a pointer to a static variable for a specific subsystem or + // > any other value that allows you to identify the value uniquely. + // + // We're just going to use the memory address of an ivar. + // Specifically an ivar that is explicitly named for our purpose to make the code more readable. + // + // However, it feels tedious (and less readable) to include the "&" all the time: + // dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey) + // + // So we're going to make it so it doesn't matter if we use the '&' or not, + // by assigning the value of the ivar to the address of the ivar. + // Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey; + + IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey; + + void *nonNullUnusedPointer = (__bridge void *)self; + dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL); + + currentSend = nil; + sendQueue = [[NSMutableArray alloc] initWithCapacity:5]; + + #if TARGET_OS_IPHONE + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + #endif + } + return self; +} + +- (void)dealloc +{ + LogInfo(@"%@ - %@ (start)", THIS_METHOD, self); + +#if TARGET_OS_IPHONE + [[NSNotificationCenter defaultCenter] removeObserver:self]; +#endif + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + [self closeWithError:nil]; + } + else + { + dispatch_sync(socketQueue, ^{ + [self closeWithError:nil]; + }); + } + + delegate = nil; + #if !OS_OBJECT_USE_OBJC + if (delegateQueue) dispatch_release(delegateQueue); + #endif + delegateQueue = NULL; + + #if !OS_OBJECT_USE_OBJC + if (socketQueue) dispatch_release(socketQueue); + #endif + socketQueue = NULL; + + LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Configuration +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (id)delegate +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return delegate; + } + else + { + __block id result = nil; + + dispatch_sync(socketQueue, ^{ + result = self->delegate; + }); + + return result; + } +} + +- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously +{ + dispatch_block_t block = ^{ + self->delegate = newDelegate; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } + else { + if (synchronously) + dispatch_sync(socketQueue, block); + else + dispatch_async(socketQueue, block); + } +} + +- (void)setDelegate:(id)newDelegate +{ + [self setDelegate:newDelegate synchronously:NO]; +} + +- (void)synchronouslySetDelegate:(id)newDelegate +{ + [self setDelegate:newDelegate synchronously:YES]; +} + +- (dispatch_queue_t)delegateQueue +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + return delegateQueue; + } + else + { + __block dispatch_queue_t result = NULL; + + dispatch_sync(socketQueue, ^{ + result = self->delegateQueue; + }); + + return result; + } +} + +- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously +{ + dispatch_block_t block = ^{ + + #if !OS_OBJECT_USE_OBJC + if (self->delegateQueue) dispatch_release(self->delegateQueue); + if (newDelegateQueue) dispatch_retain(newDelegateQueue); + #endif + + self->delegateQueue = newDelegateQueue; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } + else { + if (synchronously) + dispatch_sync(socketQueue, block); + else + dispatch_async(socketQueue, block); + } +} + +- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegateQueue:newDelegateQueue synchronously:NO]; +} + +- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegateQueue:newDelegateQueue synchronously:YES]; +} + +- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + if (delegatePtr) *delegatePtr = delegate; + if (delegateQueuePtr) *delegateQueuePtr = delegateQueue; + } + else + { + __block id dPtr = NULL; + __block dispatch_queue_t dqPtr = NULL; + + dispatch_sync(socketQueue, ^{ + dPtr = self->delegate; + dqPtr = self->delegateQueue; + }); + + if (delegatePtr) *delegatePtr = dPtr; + if (delegateQueuePtr) *delegateQueuePtr = dqPtr; + } +} + +- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously +{ + dispatch_block_t block = ^{ + + self->delegate = newDelegate; + + #if !OS_OBJECT_USE_OBJC + if (self->delegateQueue) dispatch_release(self->delegateQueue); + if (newDelegateQueue) dispatch_retain(newDelegateQueue); + #endif + + self->delegateQueue = newDelegateQueue; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } + else { + if (synchronously) + dispatch_sync(socketQueue, block); + else + dispatch_async(socketQueue, block); + } +} + +- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO]; +} + +- (void)synchronouslySetDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue +{ + [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES]; +} + +- (BOOL)isIPv4Enabled +{ + // Note: YES means kIPv4Disabled is OFF + + __block BOOL result = NO; + + dispatch_block_t block = ^{ + + result = ((self->config & kIPv4Disabled) == 0); + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setIPv4Enabled:(BOOL)flag +{ + // Note: YES means kIPv4Disabled is OFF + + dispatch_block_t block = ^{ + + LogVerbose(@"%@ %@", THIS_METHOD, (flag ? @"YES" : @"NO")); + + if (flag) + self->config &= ~kIPv4Disabled; + else + self->config |= kIPv4Disabled; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (BOOL)isIPv6Enabled +{ + // Note: YES means kIPv6Disabled is OFF + + __block BOOL result = NO; + + dispatch_block_t block = ^{ + + result = ((self->config & kIPv6Disabled) == 0); + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setIPv6Enabled:(BOOL)flag +{ + // Note: YES means kIPv6Disabled is OFF + + dispatch_block_t block = ^{ + + LogVerbose(@"%@ %@", THIS_METHOD, (flag ? @"YES" : @"NO")); + + if (flag) + self->config &= ~kIPv6Disabled; + else + self->config |= kIPv6Disabled; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (BOOL)isIPv4Preferred +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + result = (self->config & kPreferIPv4) ? YES : NO; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isIPv6Preferred +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + result = (self->config & kPreferIPv6) ? YES : NO; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isIPVersionNeutral +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + result = (self->config & (kPreferIPv4 | kPreferIPv6)) == 0; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setPreferIPv4 +{ + dispatch_block_t block = ^{ + + LogTrace(); + + self->config |= kPreferIPv4; + self->config &= ~kPreferIPv6; + + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (void)setPreferIPv6 +{ + dispatch_block_t block = ^{ + + LogTrace(); + + self->config &= ~kPreferIPv4; + self->config |= kPreferIPv6; + + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (void)setIPVersionNeutral +{ + dispatch_block_t block = ^{ + + LogTrace(); + + self->config &= ~kPreferIPv4; + self->config &= ~kPreferIPv6; + + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (uint16_t)maxReceiveIPv4BufferSize +{ + __block uint16_t result = 0; + + dispatch_block_t block = ^{ + + result = self->max4ReceiveSize; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setMaxReceiveIPv4BufferSize:(uint16_t)max +{ + dispatch_block_t block = ^{ + + LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max); + + self->max4ReceiveSize = max; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (uint32_t)maxReceiveIPv6BufferSize +{ + __block uint32_t result = 0; + + dispatch_block_t block = ^{ + + result = self->max6ReceiveSize; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setMaxReceiveIPv6BufferSize:(uint32_t)max +{ + dispatch_block_t block = ^{ + + LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max); + + self->max6ReceiveSize = max; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (void)setMaxSendBufferSize:(uint16_t)max +{ + dispatch_block_t block = ^{ + + LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max); + + self->maxSendSize = max; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (uint16_t)maxSendBufferSize +{ + __block uint16_t result = 0; + + dispatch_block_t block = ^{ + + result = self->maxSendSize; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (id)userData +{ + __block id result = nil; + + dispatch_block_t block = ^{ + + result = self->userData; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (void)setUserData:(id)arbitraryUserData +{ + dispatch_block_t block = ^{ + + if (self->userData != arbitraryUserData) + { + self->userData = arbitraryUserData; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Delegate Helpers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)notifyDidConnectToAddress:(NSData *)anAddress +{ + LogTrace(); + + __strong id theDelegate = delegate; + if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didConnectToAddress:)]) + { + NSData *address = [anAddress copy]; // In case param is NSMutableData + + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate udpSocket:self didConnectToAddress:address]; + }}); + } +} + +- (void)notifyDidNotConnect:(NSError *)error +{ + LogTrace(); + + __strong id theDelegate = delegate; + if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didNotConnect:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate udpSocket:self didNotConnect:error]; + }}); + } +} + +- (void)notifyDidSendDataWithTag:(long)tag +{ + LogTrace(); + + __strong id theDelegate = delegate; + if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didSendDataWithTag:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate udpSocket:self didSendDataWithTag:tag]; + }}); + } +} + +- (void)notifyDidNotSendDataWithTag:(long)tag dueToError:(NSError *)error +{ + LogTrace(); + + __strong id theDelegate = delegate; + if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didNotSendDataWithTag:dueToError:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate udpSocket:self didNotSendDataWithTag:tag dueToError:error]; + }}); + } +} + +- (void)notifyDidReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)context +{ + LogTrace(); + + SEL selector = @selector(udpSocket:didReceiveData:fromAddress:withFilterContext:); + + __strong id theDelegate = delegate; + if (delegateQueue && [theDelegate respondsToSelector:selector]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate udpSocket:self didReceiveData:data fromAddress:address withFilterContext:context]; + }}); + } +} + +- (void)notifyDidCloseWithError:(NSError *)error +{ + LogTrace(); + + __strong id theDelegate = delegate; + if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocketDidClose:withError:)]) + { + dispatch_async(delegateQueue, ^{ @autoreleasepool { + + [theDelegate udpSocketDidClose:self withError:error]; + }}); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Errors +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSError *)badConfigError:(NSString *)errMsg +{ + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:QNAsyncUdpSocketErrorDomain + code:QNAsyncUdpSocketBadConfigError + userInfo:userInfo]; +} + +- (NSError *)badParamError:(NSString *)errMsg +{ + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:QNAsyncUdpSocketErrorDomain + code:QNAsyncUdpSocketBadParamError + userInfo:userInfo]; +} + +- (NSError *)gaiError:(int)gai_error +{ + NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding]; + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:userInfo]; +} + +- (NSError *)errnoErrorWithReason:(NSString *)reason +{ + NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)]; + NSDictionary *userInfo; + + if (reason) + userInfo = @{NSLocalizedDescriptionKey : errMsg, + NSLocalizedFailureReasonErrorKey : reason}; + else + userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo]; +} + +- (NSError *)errnoError +{ + return [self errnoErrorWithReason:nil]; +} + +/** + * Returns a standard send timeout error. +**/ +- (NSError *)sendTimeoutError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"QNAsyncUdpSocketSendTimeoutError", + @"QNAsyncUdpSocket", [NSBundle mainBundle], + @"Send operation timed out", nil); + + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:QNAsyncUdpSocketErrorDomain + code:QNAsyncUdpSocketSendTimeoutError + userInfo:userInfo]; +} + +- (NSError *)socketClosedError +{ + NSString *errMsg = NSLocalizedStringWithDefaultValue(@"QNAsyncUdpSocketClosedError", + @"QNAsyncUdpSocket", [NSBundle mainBundle], + @"Socket closed", nil); + + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:QNAsyncUdpSocketErrorDomain code:QNAsyncUdpSocketClosedError userInfo:userInfo]; +} + +- (NSError *)otherError:(NSString *)errMsg +{ + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg}; + + return [NSError errorWithDomain:QNAsyncUdpSocketErrorDomain + code:QNAsyncUdpSocketOtherError + userInfo:userInfo]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Utilities +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)preOp:(NSError **)errPtr +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if (delegate == nil) // Must have delegate set + { + if (errPtr) + { + NSString *msg = @"Attempting to use socket without a delegate. Set a delegate first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + if (delegateQueue == NULL) // Must have delegate queue set + { + if (errPtr) + { + NSString *msg = @"Attempting to use socket without a delegate queue. Set a delegate queue first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + return YES; +} + +/** + * This method executes on a global concurrent queue. + * When complete, it executes the given completion block on the socketQueue. +**/ +- (void)asyncResolveHost:(NSString *)aHost + port:(uint16_t)port + withCompletionBlock:(void (^)(NSArray *addresses, NSError *error))completionBlock +{ + LogTrace(); + + // Check parameter(s) + + if (aHost == nil) + { + NSString *msg = @"The host param is nil. Should be domain name or IP address string."; + NSError *error = [self badParamError:msg]; + + // We should still use dispatch_async since this method is expected to be asynchronous + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + completionBlock(nil, error); + }}); + + return; + } + + // It's possible that the given aHost parameter is actually a NSMutableString. + // So we want to copy it now, within this block that will be executed synchronously. + // This way the asynchronous lookup block below doesn't have to worry about it changing. + + NSString *host = [aHost copy]; + + + dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool { + + NSMutableArray *addresses = [NSMutableArray arrayWithCapacity:2]; + NSError *error = nil; + + if ([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"]) + { + // Use LOOPBACK address + struct sockaddr_in sockaddr4; + memset(&sockaddr4, 0, sizeof(sockaddr4)); + + sockaddr4.sin_len = sizeof(struct sockaddr_in); + sockaddr4.sin_family = AF_INET; + sockaddr4.sin_port = htons(port); + sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + struct sockaddr_in6 sockaddr6; + memset(&sockaddr6, 0, sizeof(sockaddr6)); + + sockaddr6.sin6_len = sizeof(struct sockaddr_in6); + sockaddr6.sin6_family = AF_INET6; + sockaddr6.sin6_port = htons(port); + sockaddr6.sin6_addr = in6addr_loopback; + + // Wrap the native address structures and add to list + [addresses addObject:[NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]]; + [addresses addObject:[NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]]; + } + else + { + NSString *portStr = [NSString stringWithFormat:@"%hu", port]; + + struct addrinfo hints, *res, *res0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0); + + if (gai_error) + { + error = [self gaiError:gai_error]; + } + else + { + for(res = res0; res; res = res->ai_next) + { + if (res->ai_family == AF_INET) + { + // Found IPv4 address + // Wrap the native address structure and add to list + + [addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]]; + } + else if (res->ai_family == AF_INET6) + { + + // Fixes connection issues with IPv6, it is the same solution for udp socket. + // https://github.com/robbiehanson/CocoaAsyncSocket/issues/429#issuecomment-222477158 + struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)(void *)res->ai_addr; + in_port_t *portPtr = &sockaddr->sin6_port; + if ((portPtr != NULL) && (*portPtr == 0)) { + *portPtr = htons(port); + } + + // Found IPv6 address + // Wrap the native address structure and add to list + [addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]]; + } + } + freeaddrinfo(res0); + + if ([addresses count] == 0) + { + error = [self gaiError:EAI_FAIL]; + } + } + } + + dispatch_async(self->socketQueue, ^{ @autoreleasepool { + + completionBlock(addresses, error); + }}); + + }}); +} + +/** + * This method picks an address from the given list of addresses. + * The address picked depends upon which protocols are disabled, deactived, & preferred. + * + * Returns the address family (AF_INET or AF_INET6) of the picked address, + * or AF_UNSPEC and the corresponding error is there's a problem. +**/ +- (int)getAddress:(NSData **)addressPtr error:(NSError **)errorPtr fromAddresses:(NSArray *)addresses +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert([addresses count] > 0, @"Expected at least one address"); + + int resultAF = AF_UNSPEC; + NSData *resultAddress = nil; + NSError *resultError = nil; + + // Check for problems + + BOOL resolvedIPv4Address = NO; + BOOL resolvedIPv6Address = NO; + + for (NSData *address in addresses) + { + switch ([[self class] familyFromAddress:address]) + { + case AF_INET : resolvedIPv4Address = YES; break; + case AF_INET6 : resolvedIPv6Address = YES; break; + + default : NSAssert(NO, @"Addresses array contains invalid address"); + } + } + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && !resolvedIPv6Address) + { + NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address(es)."; + resultError = [self otherError:msg]; + + if (addressPtr) *addressPtr = resultAddress; + if (errorPtr) *errorPtr = resultError; + + return resultAF; + } + + if (isIPv6Disabled && !resolvedIPv4Address) + { + NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address(es)."; + resultError = [self otherError:msg]; + + if (addressPtr) *addressPtr = resultAddress; + if (errorPtr) *errorPtr = resultError; + + return resultAF; + } + + BOOL isIPv4Deactivated = (flags & kIPv4Deactivated) ? YES : NO; + BOOL isIPv6Deactivated = (flags & kIPv6Deactivated) ? YES : NO; + + if (isIPv4Deactivated && !resolvedIPv6Address) + { + NSString *msg = @"IPv4 has been deactivated due to bind/connect, and DNS lookup found no IPv6 address(es)."; + resultError = [self otherError:msg]; + + if (addressPtr) *addressPtr = resultAddress; + if (errorPtr) *errorPtr = resultError; + + return resultAF; + } + + if (isIPv6Deactivated && !resolvedIPv4Address) + { + NSString *msg = @"IPv6 has been deactivated due to bind/connect, and DNS lookup found no IPv4 address(es)."; + resultError = [self otherError:msg]; + + if (addressPtr) *addressPtr = resultAddress; + if (errorPtr) *errorPtr = resultError; + + return resultAF; + } + + // Extract first IPv4 and IPv6 address in list + + BOOL ipv4WasFirstInList = YES; + NSData *address4 = nil; + NSData *address6 = nil; + + for (NSData *address in addresses) + { + int af = [[self class] familyFromAddress:address]; + + if (af == AF_INET) + { + if (address4 == nil) + { + address4 = address; + + if (address6) + break; + else + ipv4WasFirstInList = YES; + } + } + else // af == AF_INET6 + { + if (address6 == nil) + { + address6 = address; + + if (address4) + break; + else + ipv4WasFirstInList = NO; + } + } + } + + // Determine socket type + + BOOL preferIPv4 = (config & kPreferIPv4) ? YES : NO; + BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO; + + BOOL useIPv4 = ((preferIPv4 && address4) || (address6 == nil)); + BOOL useIPv6 = ((preferIPv6 && address6) || (address4 == nil)); + + NSAssert(!(preferIPv4 && preferIPv6), @"Invalid config state"); + NSAssert(!(useIPv4 && useIPv6), @"Invalid logic"); + + if (useIPv4 || (!useIPv6 && ipv4WasFirstInList)) + { + resultAF = AF_INET; + resultAddress = address4; + } + else + { + resultAF = AF_INET6; + resultAddress = address6; + } + + if (addressPtr) *addressPtr = resultAddress; + if (errorPtr) *errorPtr = resultError; + + return resultAF; +} + +/** + * Finds the address(es) of an interface description. + * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34). +**/ +- (void)convertIntefaceDescription:(NSString *)interfaceDescription + port:(uint16_t)port + intoAddress4:(NSData **)interfaceAddr4Ptr + address6:(NSData **)interfaceAddr6Ptr +{ + NSData *addr4 = nil; + NSData *addr6 = nil; + + if (interfaceDescription == nil) + { + // ANY address + + struct sockaddr_in sockaddr4; + memset(&sockaddr4, 0, sizeof(sockaddr4)); + + sockaddr4.sin_len = sizeof(sockaddr4); + sockaddr4.sin_family = AF_INET; + sockaddr4.sin_port = htons(port); + sockaddr4.sin_addr.s_addr = htonl(INADDR_ANY); + + struct sockaddr_in6 sockaddr6; + memset(&sockaddr6, 0, sizeof(sockaddr6)); + + sockaddr6.sin6_len = sizeof(sockaddr6); + sockaddr6.sin6_family = AF_INET6; + sockaddr6.sin6_port = htons(port); + sockaddr6.sin6_addr = in6addr_any; + + addr4 = [NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]; + addr6 = [NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]; + } + else if ([interfaceDescription isEqualToString:@"localhost"] || + [interfaceDescription isEqualToString:@"loopback"]) + { + // LOOPBACK address + + struct sockaddr_in sockaddr4; + memset(&sockaddr4, 0, sizeof(sockaddr4)); + + sockaddr4.sin_len = sizeof(struct sockaddr_in); + sockaddr4.sin_family = AF_INET; + sockaddr4.sin_port = htons(port); + sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + struct sockaddr_in6 sockaddr6; + memset(&sockaddr6, 0, sizeof(sockaddr6)); + + sockaddr6.sin6_len = sizeof(struct sockaddr_in6); + sockaddr6.sin6_family = AF_INET6; + sockaddr6.sin6_port = htons(port); + sockaddr6.sin6_addr = in6addr_loopback; + + addr4 = [NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]; + addr6 = [NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]; + } + else + { + const char *iface = [interfaceDescription UTF8String]; + + struct ifaddrs *addrs; + const struct ifaddrs *cursor; + + if ((getifaddrs(&addrs) == 0)) + { + cursor = addrs; + while (cursor != NULL) + { + if ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET)) + { + // IPv4 + + struct sockaddr_in *addr = (struct sockaddr_in *)(void *)cursor->ifa_addr; + + if (strcmp(cursor->ifa_name, iface) == 0) + { + // Name match + + struct sockaddr_in nativeAddr4 = *addr; + nativeAddr4.sin_port = htons(port); + + addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; + } + else + { + char ip[INET_ADDRSTRLEN]; + + const char *conversion; + conversion = inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip)); + + if ((conversion != NULL) && (strcmp(ip, iface) == 0)) + { + // IP match + + struct sockaddr_in nativeAddr4 = *addr; + nativeAddr4.sin_port = htons(port); + + addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; + } + } + } + else if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6)) + { + // IPv6 + + const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)cursor->ifa_addr; + + if (strcmp(cursor->ifa_name, iface) == 0) + { + // Name match + + struct sockaddr_in6 nativeAddr6 = *addr; + nativeAddr6.sin6_port = htons(port); + + addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + else + { + char ip[INET6_ADDRSTRLEN]; + + const char *conversion; + conversion = inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip)); + + if ((conversion != NULL) && (strcmp(ip, iface) == 0)) + { + // IP match + + struct sockaddr_in6 nativeAddr6 = *addr; + nativeAddr6.sin6_port = htons(port); + + addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + } + } + + cursor = cursor->ifa_next; + } + + freeifaddrs(addrs); + } + } + + if (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4; + if (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6; +} + +/** + * Converts a numeric hostname into its corresponding address. + * The hostname is expected to be an IPv4 or IPv6 address represented as a human-readable string. (e.g. 192.168.4.34) +**/ +- (void)convertNumericHost:(NSString *)numericHost + port:(uint16_t)port + intoAddress4:(NSData **)addr4Ptr + address6:(NSData **)addr6Ptr +{ + NSData *addr4 = nil; + NSData *addr6 = nil; + + if (numericHost) + { + NSString *portStr = [NSString stringWithFormat:@"%hu", port]; + + struct addrinfo hints, *res, *res0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST; // No name resolution should be attempted + + if (getaddrinfo([numericHost UTF8String], [portStr UTF8String], &hints, &res0) == 0) + { + for (res = res0; res; res = res->ai_next) + { + if ((addr4 == nil) && (res->ai_family == AF_INET)) + { + // Found IPv4 address + // Wrap the native address structure + addr4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]; + } + else if ((addr6 == nil) && (res->ai_family == AF_INET6)) + { + // Found IPv6 address + // Wrap the native address structure + addr6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]; + } + } + freeaddrinfo(res0); + } + } + + if (addr4Ptr) *addr4Ptr = addr4; + if (addr6Ptr) *addr6Ptr = addr6; +} + +- (BOOL)isConnectedToAddress4:(NSData *)someAddr4 +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(flags & kDidConnect, @"Not connected"); + NSAssert(cachedConnectedAddress, @"Expected cached connected address"); + + if (cachedConnectedFamily != AF_INET) + { + return NO; + } + + const struct sockaddr_in *sSockaddr4 = (const struct sockaddr_in *)[someAddr4 bytes]; + const struct sockaddr_in *cSockaddr4 = (const struct sockaddr_in *)[cachedConnectedAddress bytes]; + + if (memcmp(&sSockaddr4->sin_addr, &cSockaddr4->sin_addr, sizeof(struct in_addr)) != 0) + { + return NO; + } + if (memcmp(&sSockaddr4->sin_port, &cSockaddr4->sin_port, sizeof(in_port_t)) != 0) + { + return NO; + } + + return YES; +} + +- (BOOL)isConnectedToAddress6:(NSData *)someAddr6 +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(flags & kDidConnect, @"Not connected"); + NSAssert(cachedConnectedAddress, @"Expected cached connected address"); + + if (cachedConnectedFamily != AF_INET6) + { + return NO; + } + + const struct sockaddr_in6 *sSockaddr6 = (const struct sockaddr_in6 *)[someAddr6 bytes]; + const struct sockaddr_in6 *cSockaddr6 = (const struct sockaddr_in6 *)[cachedConnectedAddress bytes]; + + if (memcmp(&sSockaddr6->sin6_addr, &cSockaddr6->sin6_addr, sizeof(struct in6_addr)) != 0) + { + return NO; + } + if (memcmp(&sSockaddr6->sin6_port, &cSockaddr6->sin6_port, sizeof(in_port_t)) != 0) + { + return NO; + } + + return YES; +} + +- (unsigned int)indexOfInterfaceAddr4:(NSData *)interfaceAddr4 +{ + if (interfaceAddr4 == nil) + return 0; + if ([interfaceAddr4 length] != sizeof(struct sockaddr_in)) + return 0; + + int result = 0; + const struct sockaddr_in *ifaceAddr = (const struct sockaddr_in *)[interfaceAddr4 bytes]; + + struct ifaddrs *addrs; + const struct ifaddrs *cursor; + + if ((getifaddrs(&addrs) == 0)) + { + cursor = addrs; + while (cursor != NULL) + { + if (cursor->ifa_addr->sa_family == AF_INET) + { + // IPv4 + + const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)cursor->ifa_addr; + + if (memcmp(&addr->sin_addr, &ifaceAddr->sin_addr, sizeof(struct in_addr)) == 0) + { + result = if_nametoindex(cursor->ifa_name); + break; + } + } + + cursor = cursor->ifa_next; + } + + freeifaddrs(addrs); + } + + return result; +} + +- (unsigned int)indexOfInterfaceAddr6:(NSData *)interfaceAddr6 +{ + if (interfaceAddr6 == nil) + return 0; + if ([interfaceAddr6 length] != sizeof(struct sockaddr_in6)) + return 0; + + int result = 0; + const struct sockaddr_in6 *ifaceAddr = (const struct sockaddr_in6 *)[interfaceAddr6 bytes]; + + struct ifaddrs *addrs; + const struct ifaddrs *cursor; + + if ((getifaddrs(&addrs) == 0)) + { + cursor = addrs; + while (cursor != NULL) + { + if (cursor->ifa_addr->sa_family == AF_INET6) + { + // IPv6 + + const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)cursor->ifa_addr; + + if (memcmp(&addr->sin6_addr, &ifaceAddr->sin6_addr, sizeof(struct in6_addr)) == 0) + { + result = if_nametoindex(cursor->ifa_name); + break; + } + } + + cursor = cursor->ifa_next; + } + + freeifaddrs(addrs); + } + + return result; +} + +- (void)setupSendAndReceiveSourcesForSocket4 +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + send4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket4FD, 0, socketQueue); + receive4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue); + + // Setup event handlers + + dispatch_source_set_event_handler(send4Source, ^{ @autoreleasepool { + + LogVerbose(@"send4EventBlock"); + LogVerbose(@"dispatch_source_get_data(send4Source) = %lu", dispatch_source_get_data(send4Source)); + + self->flags |= kSock4CanAcceptBytes; + + // If we're ready to send data, do so immediately. + // Otherwise pause the send source or it will continue to fire over and over again. + + if (self->currentSend == nil) + { + LogVerbose(@"Nothing to send"); + [self suspendSend4Source]; + } + else if (self->currentSend->resolveInProgress) + { + LogVerbose(@"currentSend - waiting for address resolve"); + [self suspendSend4Source]; + } + else if (self->currentSend->filterInProgress) + { + LogVerbose(@"currentSend - waiting on sendFilter"); + [self suspendSend4Source]; + } + else + { + [self doSend]; + } + + }}); + + dispatch_source_set_event_handler(receive4Source, ^{ @autoreleasepool { + + LogVerbose(@"receive4EventBlock"); + + self->socket4FDBytesAvailable = dispatch_source_get_data(self->receive4Source); + LogVerbose(@"socket4FDBytesAvailable: %lu", socket4FDBytesAvailable); + + if (self->socket4FDBytesAvailable > 0) + [self doReceive]; + else + [self doReceiveEOF]; + + }}); + + // Setup cancel handlers + + __block int socketFDRefCount = 2; + + int theSocketFD = socket4FD; + + #if !OS_OBJECT_USE_OBJC + dispatch_source_t theSendSource = send4Source; + dispatch_source_t theReceiveSource = receive4Source; + #endif + + dispatch_source_set_cancel_handler(send4Source, ^{ + + LogVerbose(@"send4CancelBlock"); + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(send4Source)"); + dispatch_release(theSendSource); + #endif + + if (--socketFDRefCount == 0) + { + LogVerbose(@"close(socket4FD)"); + close(theSocketFD); + } + }); + + dispatch_source_set_cancel_handler(receive4Source, ^{ + + LogVerbose(@"receive4CancelBlock"); + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(receive4Source)"); + dispatch_release(theReceiveSource); + #endif + + if (--socketFDRefCount == 0) + { + LogVerbose(@"close(socket4FD)"); + close(theSocketFD); + } + }); + + // We will not be able to receive until the socket is bound to a port, + // either explicitly via bind, or implicitly by connect or by sending data. + // + // But we should be able to send immediately. + + socket4FDBytesAvailable = 0; + flags |= kSock4CanAcceptBytes; + + flags |= kSend4SourceSuspended; + flags |= kReceive4SourceSuspended; +} + +- (void)setupSendAndReceiveSourcesForSocket6 +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + send6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket6FD, 0, socketQueue); + receive6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket6FD, 0, socketQueue); + + // Setup event handlers + + dispatch_source_set_event_handler(send6Source, ^{ @autoreleasepool { + + LogVerbose(@"send6EventBlock"); + LogVerbose(@"dispatch_source_get_data(send6Source) = %lu", dispatch_source_get_data(send6Source)); + + self->flags |= kSock6CanAcceptBytes; + + // If we're ready to send data, do so immediately. + // Otherwise pause the send source or it will continue to fire over and over again. + + if (self->currentSend == nil) + { + LogVerbose(@"Nothing to send"); + [self suspendSend6Source]; + } + else if (self->currentSend->resolveInProgress) + { + LogVerbose(@"currentSend - waiting for address resolve"); + [self suspendSend6Source]; + } + else if (self->currentSend->filterInProgress) + { + LogVerbose(@"currentSend - waiting on sendFilter"); + [self suspendSend6Source]; + } + else + { + [self doSend]; + } + + }}); + + dispatch_source_set_event_handler(receive6Source, ^{ @autoreleasepool { + + LogVerbose(@"receive6EventBlock"); + + self->socket6FDBytesAvailable = dispatch_source_get_data(self->receive6Source); + LogVerbose(@"socket6FDBytesAvailable: %lu", socket6FDBytesAvailable); + + if (self->socket6FDBytesAvailable > 0) + [self doReceive]; + else + [self doReceiveEOF]; + + }}); + + // Setup cancel handlers + + __block int socketFDRefCount = 2; + + int theSocketFD = socket6FD; + + #if !OS_OBJECT_USE_OBJC + dispatch_source_t theSendSource = send6Source; + dispatch_source_t theReceiveSource = receive6Source; + #endif + + dispatch_source_set_cancel_handler(send6Source, ^{ + + LogVerbose(@"send6CancelBlock"); + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(send6Source)"); + dispatch_release(theSendSource); + #endif + + if (--socketFDRefCount == 0) + { + LogVerbose(@"close(socket6FD)"); + close(theSocketFD); + } + }); + + dispatch_source_set_cancel_handler(receive6Source, ^{ + + LogVerbose(@"receive6CancelBlock"); + + #if !OS_OBJECT_USE_OBJC + LogVerbose(@"dispatch_release(receive6Source)"); + dispatch_release(theReceiveSource); + #endif + + if (--socketFDRefCount == 0) + { + LogVerbose(@"close(socket6FD)"); + close(theSocketFD); + } + }); + + // We will not be able to receive until the socket is bound to a port, + // either explicitly via bind, or implicitly by connect or by sending data. + // + // But we should be able to send immediately. + + socket6FDBytesAvailable = 0; + flags |= kSock6CanAcceptBytes; + + flags |= kSend6SourceSuspended; + flags |= kReceive6SourceSuspended; +} + +- (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError * __autoreleasing *)errPtr +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(((flags & kDidCreateSockets) == 0), @"Sockets have already been created"); + + // CreateSocket Block + // This block will be invoked below. + + int(^createSocket)(int) = ^int (int domain) { + + int socketFD = socket(domain, SOCK_DGRAM, 0); + + if (socketFD == SOCKET_NULL) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error in socket() function"]; + + return SOCKET_NULL; + } + + int status; + + // Set socket options + + status = fcntl(socketFD, F_SETFL, O_NONBLOCK); + if (status == -1) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error enabling non-blocking IO on socket (fcntl)"]; + + close(socketFD); + return SOCKET_NULL; + } + + int reuseaddr = 1; + status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); + if (status == -1) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error enabling address reuse (setsockopt)"]; + + close(socketFD); + return SOCKET_NULL; + } + + int nosigpipe = 1; + status = setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe)); + if (status == -1) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error disabling sigpipe (setsockopt)"]; + + close(socketFD); + return SOCKET_NULL; + } + + /** + * The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535. + * The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295. + * + * The default maximum size of the UDP buffer in iOS is 9216 bytes. + * + * This is the reason of #222(GCD does not necessarily return the size of an entire UDP packet) and + * #535(QNAsyncUdpSocket can not send data when data is greater than 9K) + * + * + * Enlarge the maximum size of UDP packet. + * I can not ensure the protocol type now so that the max size is set to 65535 :) + **/ + + status = setsockopt(socketFD, SOL_SOCKET, SO_SNDBUF, (const char*)&self->maxSendSize, sizeof(int)); + if (status == -1) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error setting send buffer size (setsockopt)"]; + close(socketFD); + return SOCKET_NULL; + } + + status = setsockopt(socketFD, SOL_SOCKET, SO_RCVBUF, (const char*)&self->maxSendSize, sizeof(int)); + if (status == -1) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error setting receive buffer size (setsockopt)"]; + close(socketFD); + return SOCKET_NULL; + } + + + return socketFD; + }; + + // Create sockets depending upon given configuration. + + if (useIPv4) + { + LogVerbose(@"Creating IPv4 socket"); + + socket4FD = createSocket(AF_INET); + if (socket4FD == SOCKET_NULL) + { + // errPtr set in local createSocket() block + return NO; + } + } + + if (useIPv6) + { + LogVerbose(@"Creating IPv6 socket"); + + socket6FD = createSocket(AF_INET6); + if (socket6FD == SOCKET_NULL) + { + // errPtr set in local createSocket() block + + if (socket4FD != SOCKET_NULL) + { + close(socket4FD); + socket4FD = SOCKET_NULL; + } + + return NO; + } + } + + // Setup send and receive sources + + if (useIPv4) + [self setupSendAndReceiveSourcesForSocket4]; + if (useIPv6) + [self setupSendAndReceiveSourcesForSocket6]; + + flags |= kDidCreateSockets; + return YES; +} + +- (BOOL)createSockets:(NSError **)errPtr +{ + LogTrace(); + + BOOL useIPv4 = [self isIPv4Enabled]; + BOOL useIPv6 = [self isIPv6Enabled]; + + return [self createSocket4:useIPv4 socket6:useIPv6 error:errPtr]; +} + +- (void)suspendSend4Source +{ + if (send4Source && !(flags & kSend4SourceSuspended)) + { + LogVerbose(@"dispatch_suspend(send4Source)"); + + dispatch_suspend(send4Source); + flags |= kSend4SourceSuspended; + } +} + +- (void)suspendSend6Source +{ + if (send6Source && !(flags & kSend6SourceSuspended)) + { + LogVerbose(@"dispatch_suspend(send6Source)"); + + dispatch_suspend(send6Source); + flags |= kSend6SourceSuspended; + } +} + +- (void)resumeSend4Source +{ + if (send4Source && (flags & kSend4SourceSuspended)) + { + LogVerbose(@"dispatch_resume(send4Source)"); + + dispatch_resume(send4Source); + flags &= ~kSend4SourceSuspended; + } +} + +- (void)resumeSend6Source +{ + if (send6Source && (flags & kSend6SourceSuspended)) + { + LogVerbose(@"dispatch_resume(send6Source)"); + + dispatch_resume(send6Source); + flags &= ~kSend6SourceSuspended; + } +} + +- (void)suspendReceive4Source +{ + if (receive4Source && !(flags & kReceive4SourceSuspended)) + { + LogVerbose(@"dispatch_suspend(receive4Source)"); + + dispatch_suspend(receive4Source); + flags |= kReceive4SourceSuspended; + } +} + +- (void)suspendReceive6Source +{ + if (receive6Source && !(flags & kReceive6SourceSuspended)) + { + LogVerbose(@"dispatch_suspend(receive6Source)"); + + dispatch_suspend(receive6Source); + flags |= kReceive6SourceSuspended; + } +} + +- (void)resumeReceive4Source +{ + if (receive4Source && (flags & kReceive4SourceSuspended)) + { + LogVerbose(@"dispatch_resume(receive4Source)"); + + dispatch_resume(receive4Source); + flags &= ~kReceive4SourceSuspended; + } +} + +- (void)resumeReceive6Source +{ + if (receive6Source && (flags & kReceive6SourceSuspended)) + { + LogVerbose(@"dispatch_resume(receive6Source)"); + + dispatch_resume(receive6Source); + flags &= ~kReceive6SourceSuspended; + } +} + +- (void)closeSocket4 +{ + if (socket4FD != SOCKET_NULL) + { + LogVerbose(@"dispatch_source_cancel(send4Source)"); + dispatch_source_cancel(send4Source); + + LogVerbose(@"dispatch_source_cancel(receive4Source)"); + dispatch_source_cancel(receive4Source); + + // For some crazy reason (in my opinion), cancelling a dispatch source doesn't + // invoke the cancel handler if the dispatch source is paused. + // So we have to unpause the source if needed. + // This allows the cancel handler to be run, which in turn releases the source and closes the socket. + + [self resumeSend4Source]; + [self resumeReceive4Source]; + + // The sockets will be closed by the cancel handlers of the corresponding source + + send4Source = NULL; + receive4Source = NULL; + + socket4FD = SOCKET_NULL; + + // Clear socket states + + socket4FDBytesAvailable = 0; + flags &= ~kSock4CanAcceptBytes; + + // Clear cached info + + cachedLocalAddress4 = nil; + cachedLocalHost4 = nil; + cachedLocalPort4 = 0; + } +} + +- (void)closeSocket6 +{ + if (socket6FD != SOCKET_NULL) + { + LogVerbose(@"dispatch_source_cancel(send6Source)"); + dispatch_source_cancel(send6Source); + + LogVerbose(@"dispatch_source_cancel(receive6Source)"); + dispatch_source_cancel(receive6Source); + + // For some crazy reason (in my opinion), cancelling a dispatch source doesn't + // invoke the cancel handler if the dispatch source is paused. + // So we have to unpause the source if needed. + // This allows the cancel handler to be run, which in turn releases the source and closes the socket. + + [self resumeSend6Source]; + [self resumeReceive6Source]; + + send6Source = NULL; + receive6Source = NULL; + + // The sockets will be closed by the cancel handlers of the corresponding source + + socket6FD = SOCKET_NULL; + + // Clear socket states + + socket6FDBytesAvailable = 0; + flags &= ~kSock6CanAcceptBytes; + + // Clear cached info + + cachedLocalAddress6 = nil; + cachedLocalHost6 = nil; + cachedLocalPort6 = 0; + } +} + +- (void)closeSockets +{ + [self closeSocket4]; + [self closeSocket6]; + + flags &= ~kDidCreateSockets; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Diagnostics +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)getLocalAddress:(NSData **)dataPtr + host:(NSString **)hostPtr + port:(uint16_t *)portPtr + forSocket:(int)socketFD + withFamily:(int)socketFamily +{ + + NSData *data = nil; + NSString *host = nil; + uint16_t port = 0; + + if (socketFamily == AF_INET) + { + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0) + { + data = [NSData dataWithBytes:&sockaddr4 length:sockaddr4len]; + host = [[self class] hostFromSockaddr4:&sockaddr4]; + port = [[self class] portFromSockaddr4:&sockaddr4]; + } + else + { + LogWarn(@"Error in getsockname: %@", [self errnoError]); + } + } + else if (socketFamily == AF_INET6) + { + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0) + { + data = [NSData dataWithBytes:&sockaddr6 length:sockaddr6len]; + host = [[self class] hostFromSockaddr6:&sockaddr6]; + port = [[self class] portFromSockaddr6:&sockaddr6]; + } + else + { + LogWarn(@"Error in getsockname: %@", [self errnoError]); + } + } + + if (dataPtr) *dataPtr = data; + if (hostPtr) *hostPtr = host; + if (portPtr) *portPtr = port; + + return (data != nil); +} + +- (void)maybeUpdateCachedLocalAddress4Info +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if ( cachedLocalAddress4 || ((flags & kDidBind) == 0) || (socket4FD == SOCKET_NULL) ) + { + return; + } + + NSData *address = nil; + NSString *host = nil; + uint16_t port = 0; + + if ([self getLocalAddress:&address host:&host port:&port forSocket:socket4FD withFamily:AF_INET]) + { + + cachedLocalAddress4 = address; + cachedLocalHost4 = host; + cachedLocalPort4 = port; + } +} + +- (void)maybeUpdateCachedLocalAddress6Info +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if ( cachedLocalAddress6 || ((flags & kDidBind) == 0) || (socket6FD == SOCKET_NULL) ) + { + return; + } + + NSData *address = nil; + NSString *host = nil; + uint16_t port = 0; + + if ([self getLocalAddress:&address host:&host port:&port forSocket:socket6FD withFamily:AF_INET6]) + { + + cachedLocalAddress6 = address; + cachedLocalHost6 = host; + cachedLocalPort6 = port; + } +} + +- (NSData *)localAddress +{ + __block NSData *result = nil; + + dispatch_block_t block = ^{ + + if (self->socket4FD != SOCKET_NULL) + { + [self maybeUpdateCachedLocalAddress4Info]; + result = self->cachedLocalAddress4; + } + else + { + [self maybeUpdateCachedLocalAddress6Info]; + result = self->cachedLocalAddress6; + } + + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (NSString *)localHost +{ + __block NSString *result = nil; + + dispatch_block_t block = ^{ + + if (self->socket4FD != SOCKET_NULL) + { + [self maybeUpdateCachedLocalAddress4Info]; + result = self->cachedLocalHost4; + } + else + { + [self maybeUpdateCachedLocalAddress6Info]; + result = self->cachedLocalHost6; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (uint16_t)localPort +{ + __block uint16_t result = 0; + + dispatch_block_t block = ^{ + + if (self->socket4FD != SOCKET_NULL) + { + [self maybeUpdateCachedLocalAddress4Info]; + result = self->cachedLocalPort4; + } + else + { + [self maybeUpdateCachedLocalAddress6Info]; + result = self->cachedLocalPort6; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (NSData *)localAddress_IPv4 +{ + __block NSData *result = nil; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedLocalAddress4Info]; + result = self->cachedLocalAddress4; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (NSString *)localHost_IPv4 +{ + __block NSString *result = nil; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedLocalAddress4Info]; + result = self->cachedLocalHost4; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (uint16_t)localPort_IPv4 +{ + __block uint16_t result = 0; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedLocalAddress4Info]; + result = self->cachedLocalPort4; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (NSData *)localAddress_IPv6 +{ + __block NSData *result = nil; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedLocalAddress6Info]; + result = self->cachedLocalAddress6; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (NSString *)localHost_IPv6 +{ + __block NSString *result = nil; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedLocalAddress6Info]; + result = self->cachedLocalHost6; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (uint16_t)localPort_IPv6 +{ + __block uint16_t result = 0; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedLocalAddress6Info]; + result = self->cachedLocalPort6; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (void)maybeUpdateCachedConnectedAddressInfo +{ + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if (cachedConnectedAddress || (flags & kDidConnect) == 0) + { + return; + } + + NSData *data = nil; + NSString *host = nil; + uint16_t port = 0; + int family = AF_UNSPEC; + + if (socket4FD != SOCKET_NULL) + { + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + if (getpeername(socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0) + { + data = [NSData dataWithBytes:&sockaddr4 length:sockaddr4len]; + host = [[self class] hostFromSockaddr4:&sockaddr4]; + port = [[self class] portFromSockaddr4:&sockaddr4]; + family = AF_INET; + } + else + { + LogWarn(@"Error in getpeername: %@", [self errnoError]); + } + } + else if (socket6FD != SOCKET_NULL) + { + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + if (getpeername(socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0) + { + data = [NSData dataWithBytes:&sockaddr6 length:sockaddr6len]; + host = [[self class] hostFromSockaddr6:&sockaddr6]; + port = [[self class] portFromSockaddr6:&sockaddr6]; + family = AF_INET6; + } + else + { + LogWarn(@"Error in getpeername: %@", [self errnoError]); + } + } + + + cachedConnectedAddress = data; + cachedConnectedHost = host; + cachedConnectedPort = port; + cachedConnectedFamily = family; +} + +- (NSData *)connectedAddress +{ + __block NSData *result = nil; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedConnectedAddressInfo]; + result = self->cachedConnectedAddress; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (NSString *)connectedHost +{ + __block NSString *result = nil; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedConnectedAddressInfo]; + result = self->cachedConnectedHost; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (uint16_t)connectedPort +{ + __block uint16_t result = 0; + + dispatch_block_t block = ^{ + + [self maybeUpdateCachedConnectedAddressInfo]; + result = self->cachedConnectedPort; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, AutoreleasedBlock(block)); + + return result; +} + +- (BOOL)isConnected +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + result = (self->flags & kDidConnect) ? YES : NO; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isClosed +{ + __block BOOL result = YES; + + dispatch_block_t block = ^{ + + result = (self->flags & kDidCreateSockets) ? NO : YES; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isIPv4 +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + + if (self->flags & kDidCreateSockets) + { + result = (self->socket4FD != SOCKET_NULL); + } + else + { + result = [self isIPv4Enabled]; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +- (BOOL)isIPv6 +{ + __block BOOL result = NO; + + dispatch_block_t block = ^{ + + if (self->flags & kDidCreateSockets) + { + result = (self->socket6FD != SOCKET_NULL); + } + else + { + result = [self isIPv6Enabled]; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Binding +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * This method runs through the various checks required prior to a bind attempt. + * It is shared between the various bind methods. +**/ +- (BOOL)preBind:(NSError **)errPtr +{ + if (![self preOp:errPtr]) + { + return NO; + } + + if (flags & kDidBind) + { + if (errPtr) + { + NSString *msg = @"Cannot bind a socket more than once."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + if ((flags & kConnecting) || (flags & kDidConnect)) + { + if (errPtr) + { + NSString *msg = @"Cannot bind after connecting. If needed, bind first, then connect."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled + { + if (errPtr) + { + NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + return YES; +} + +- (BOOL)bindToPort:(uint16_t)port error:(NSError **)errPtr +{ + return [self bindToPort:port interface:nil error:errPtr]; +} + +- (BOOL)bindToPort:(uint16_t)port interface:(NSString *)interface error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Run through sanity checks + + if (![self preBind:&err]) + { + return_from_block; + } + + // Check the given interface + + NSData *interface4 = nil; + NSData *interface6 = nil; + + [self convertIntefaceDescription:interface port:port intoAddress4:&interface4 address6:&interface6]; + + if ((interface4 == nil) && (interface6 == nil)) + { + NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address."; + err = [self badParamError:msg]; + + return_from_block; + } + + BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && (interface6 == nil)) + { + NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6."; + err = [self badParamError:msg]; + + return_from_block; + } + + if (isIPv6Disabled && (interface4 == nil)) + { + NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Determine protocol(s) + + BOOL useIPv4 = !isIPv4Disabled && (interface4 != nil); + BOOL useIPv6 = !isIPv6Disabled && (interface6 != nil); + + // Create the socket(s) if needed + + if ((self->flags & kDidCreateSockets) == 0) + { + if (![self createSocket4:useIPv4 socket6:useIPv6 error:&err]) + { + return_from_block; + } + } + + // Bind the socket(s) + + LogVerbose(@"Binding socket to port(%hu) interface(%@)", port, interface); + + if (useIPv4) + { + int status = bind(self->socket4FD, (const struct sockaddr *)[interface4 bytes], (socklen_t)[interface4 length]); + if (status == -1) + { + [self closeSockets]; + + NSString *reason = @"Error in bind() function"; + err = [self errnoErrorWithReason:reason]; + + return_from_block; + } + } + + if (useIPv6) + { + int status = bind(self->socket6FD, (const struct sockaddr *)[interface6 bytes], (socklen_t)[interface6 length]); + if (status == -1) + { + [self closeSockets]; + + NSString *reason = @"Error in bind() function"; + err = [self errnoErrorWithReason:reason]; + + return_from_block; + } + } + + // Update flags + + self->flags |= kDidBind; + + if (!useIPv4) self->flags |= kIPv4Deactivated; + if (!useIPv6) self->flags |= kIPv6Deactivated; + + result = YES; + + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (err) + LogError(@"Error binding to port/interface: %@", err); + + if (errPtr) + *errPtr = err; + + return result; +} + +- (BOOL)bindToAddress:(NSData *)localAddr error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Run through sanity checks + + if (![self preBind:&err]) + { + return_from_block; + } + + // Check the given address + + int addressFamily = [[self class] familyFromAddress:localAddr]; + + if (addressFamily == AF_UNSPEC) + { + NSString *msg = @"A valid IPv4 or IPv6 address was not given"; + err = [self badParamError:msg]; + + return_from_block; + } + + NSData *localAddr4 = (addressFamily == AF_INET) ? localAddr : nil; + NSData *localAddr6 = (addressFamily == AF_INET6) ? localAddr : nil; + + BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && localAddr4) + { + NSString *msg = @"IPv4 has been disabled and an IPv4 address was passed."; + err = [self badParamError:msg]; + + return_from_block; + } + + if (isIPv6Disabled && localAddr6) + { + NSString *msg = @"IPv6 has been disabled and an IPv6 address was passed."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Determine protocol(s) + + BOOL useIPv4 = !isIPv4Disabled && (localAddr4 != nil); + BOOL useIPv6 = !isIPv6Disabled && (localAddr6 != nil); + + // Create the socket(s) if needed + + if ((self->flags & kDidCreateSockets) == 0) + { + if (![self createSocket4:useIPv4 socket6:useIPv6 error:&err]) + { + return_from_block; + } + } + + // Bind the socket(s) + + if (useIPv4) + { + LogVerbose(@"Binding socket to address(%@:%hu)", + [[self class] hostFromAddress:localAddr4], + [[self class] portFromAddress:localAddr4]); + + int status = bind(self->socket4FD, (const struct sockaddr *)[localAddr4 bytes], (socklen_t)[localAddr4 length]); + if (status == -1) + { + [self closeSockets]; + + NSString *reason = @"Error in bind() function"; + err = [self errnoErrorWithReason:reason]; + + return_from_block; + } + } + else + { + LogVerbose(@"Binding socket to address(%@:%hu)", + [[self class] hostFromAddress:localAddr6], + [[self class] portFromAddress:localAddr6]); + + int status = bind(self->socket6FD, (const struct sockaddr *)[localAddr6 bytes], (socklen_t)[localAddr6 length]); + if (status == -1) + { + [self closeSockets]; + + NSString *reason = @"Error in bind() function"; + err = [self errnoErrorWithReason:reason]; + + return_from_block; + } + } + + // Update flags + + self->flags |= kDidBind; + + if (!useIPv4) self->flags |= kIPv4Deactivated; + if (!useIPv6) self->flags |= kIPv6Deactivated; + + result = YES; + + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (err) + LogError(@"Error binding to address: %@", err); + + if (errPtr) + *errPtr = err; + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Connecting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * This method runs through the various checks required prior to a connect attempt. + * It is shared between the various connect methods. +**/ +- (BOOL)preConnect:(NSError **)errPtr +{ + if (![self preOp:errPtr]) + { + return NO; + } + + if ((flags & kConnecting) || (flags & kDidConnect)) + { + if (errPtr) + { + NSString *msg = @"Cannot connect a socket more than once."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO; + BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO; + + if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled + { + if (errPtr) + { + NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + return YES; +} + +- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Run through sanity checks. + + if (![self preConnect:&err]) + { + return_from_block; + } + + // Check parameter(s) + + if (host == nil) + { + NSString *msg = @"The host param is nil. Should be domain name or IP address string."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Create the socket(s) if needed + + if ((self->flags & kDidCreateSockets) == 0) + { + if (![self createSockets:&err]) + { + return_from_block; + } + } + + // Create special connect packet + + QNAsyncUdpSpecialPacket *packet = [[QNAsyncUdpSpecialPacket alloc] init]; + packet->resolveInProgress = YES; + + // Start asynchronous DNS resolve for host:port on background queue + + LogVerbose(@"Dispatching DNS resolve for connect..."); + + [self asyncResolveHost:host port:port withCompletionBlock:^(NSArray *addresses, NSError *error) { + + // The asyncResolveHost:port:: method asynchronously dispatches a task onto the global concurrent queue, + // and immediately returns. Once the async resolve task completes, + // this block is executed on our socketQueue. + + packet->resolveInProgress = NO; + + packet->addresses = addresses; + packet->error = error; + + [self maybeConnect]; + }]; + + // Updates flags, add connect packet to send queue, and pump send queue + + self->flags |= kConnecting; + + [self->sendQueue addObject:packet]; + [self maybeDequeueSend]; + + result = YES; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (err) + LogError(@"Error connecting to host/port: %@", err); + + if (errPtr) + *errPtr = err; + + return result; +} + +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Run through sanity checks. + + if (![self preConnect:&err]) + { + return_from_block; + } + + // Check parameter(s) + + if (remoteAddr == nil) + { + NSString *msg = @"The address param is nil. Should be a valid address."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Create the socket(s) if needed + + if ((self->flags & kDidCreateSockets) == 0) + { + if (![self createSockets:&err]) + { + return_from_block; + } + } + + // The remoteAddr parameter could be of type NSMutableData. + // So we copy it to be safe. + + NSData *address = [remoteAddr copy]; + NSArray *addresses = [NSArray arrayWithObject:address]; + + QNAsyncUdpSpecialPacket *packet = [[QNAsyncUdpSpecialPacket alloc] init]; + packet->addresses = addresses; + + // Updates flags, add connect packet to send queue, and pump send queue + + self->flags |= kConnecting; + + [self->sendQueue addObject:packet]; + [self maybeDequeueSend]; + + result = YES; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (err) + LogError(@"Error connecting to address: %@", err); + + if (errPtr) + *errPtr = err; + + return result; +} + +- (void)maybeConnect +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + + BOOL sendQueueReady = [currentSend isKindOfClass:[QNAsyncUdpSpecialPacket class]]; + + if (sendQueueReady) + { + QNAsyncUdpSpecialPacket *connectPacket = (QNAsyncUdpSpecialPacket *)currentSend; + + if (connectPacket->resolveInProgress) + { + LogVerbose(@"Waiting for DNS resolve..."); + } + else + { + if (connectPacket->error) + { + [self notifyDidNotConnect:connectPacket->error]; + } + else + { + NSData *address = nil; + NSError *error = nil; + + int addressFamily = [self getAddress:&address error:&error fromAddresses:connectPacket->addresses]; + + // Perform connect + + BOOL result = NO; + + switch (addressFamily) + { + case AF_INET : result = [self connectWithAddress4:address error:&error]; break; + case AF_INET6 : result = [self connectWithAddress6:address error:&error]; break; + } + + if (result) + { + flags |= kDidBind; + flags |= kDidConnect; + + cachedConnectedAddress = address; + cachedConnectedHost = [[self class] hostFromAddress:address]; + cachedConnectedPort = [[self class] portFromAddress:address]; + cachedConnectedFamily = addressFamily; + + [self notifyDidConnectToAddress:address]; + } + else + { + [self notifyDidNotConnect:error]; + } + } + + flags &= ~kConnecting; + + [self endCurrentSend]; + [self maybeDequeueSend]; + } + } +} + +- (BOOL)connectWithAddress4:(NSData *)address4 error:(NSError **)errPtr +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + int status = connect(socket4FD, (const struct sockaddr *)[address4 bytes], (socklen_t)[address4 length]); + if (status != 0) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error in connect() function"]; + + return NO; + } + + [self closeSocket6]; + flags |= kIPv6Deactivated; + + return YES; +} + +- (BOOL)connectWithAddress6:(NSData *)address6 error:(NSError **)errPtr +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + int status = connect(socket6FD, (const struct sockaddr *)[address6 bytes], (socklen_t)[address6 length]); + if (status != 0) + { + if (errPtr) + *errPtr = [self errnoErrorWithReason:@"Error in connect() function"]; + + return NO; + } + + [self closeSocket4]; + flags |= kIPv4Deactivated; + + return YES; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Multicast +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)preJoin:(NSError **)errPtr +{ + if (![self preOp:errPtr]) + { + return NO; + } + + if (!(flags & kDidBind)) + { + if (errPtr) + { + NSString *msg = @"Must bind a socket before joining a multicast group."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + if ((flags & kConnecting) || (flags & kDidConnect)) + { + if (errPtr) + { + NSString *msg = @"Cannot join a multicast group if connected."; + *errPtr = [self badConfigError:msg]; + } + return NO; + } + + return YES; +} + +- (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr +{ + return [self joinMulticastGroup:group onInterface:nil error:errPtr]; +} + +- (BOOL)joinMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr +{ + // IP_ADD_MEMBERSHIP == IPV6_JOIN_GROUP + return [self performMulticastRequest:IP_ADD_MEMBERSHIP forGroup:group onInterface:interface error:errPtr]; +} + +- (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr +{ + return [self leaveMulticastGroup:group onInterface:nil error:errPtr]; +} + +- (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr +{ + // IP_DROP_MEMBERSHIP == IPV6_LEAVE_GROUP + return [self performMulticastRequest:IP_DROP_MEMBERSHIP forGroup:group onInterface:interface error:errPtr]; +} + +- (BOOL)performMulticastRequest:(int)requestType + forGroup:(NSString *)group + onInterface:(NSString *)interface + error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + // Run through sanity checks + + if (![self preJoin:&err]) + { + return_from_block; + } + + // Convert group to address + + NSData *groupAddr4 = nil; + NSData *groupAddr6 = nil; + + [self convertNumericHost:group port:0 intoAddress4:&groupAddr4 address6:&groupAddr6]; + + if ((groupAddr4 == nil) && (groupAddr6 == nil)) + { + NSString *msg = @"Unknown group. Specify valid group IP address."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Convert interface to address + + NSData *interfaceAddr4 = nil; + NSData *interfaceAddr6 = nil; + + [self convertIntefaceDescription:interface port:0 intoAddress4:&interfaceAddr4 address6:&interfaceAddr6]; + + if ((interfaceAddr4 == nil) && (interfaceAddr6 == nil)) + { + NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address."; + err = [self badParamError:msg]; + + return_from_block; + } + + // Perform join + + if ((self->socket4FD != SOCKET_NULL) && groupAddr4 && interfaceAddr4) + { + const struct sockaddr_in *nativeGroup = (const struct sockaddr_in *)[groupAddr4 bytes]; + const struct sockaddr_in *nativeIface = (const struct sockaddr_in *)[interfaceAddr4 bytes]; + + struct ip_mreq imreq; + imreq.imr_multiaddr = nativeGroup->sin_addr; + imreq.imr_interface = nativeIface->sin_addr; + + int status = setsockopt(self->socket4FD, IPPROTO_IP, requestType, (const void *)&imreq, sizeof(imreq)); + if (status != 0) + { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + + // Using IPv4 only + [self closeSocket6]; + + result = YES; + } + else if ((self->socket6FD != SOCKET_NULL) && groupAddr6 && interfaceAddr6) + { + const struct sockaddr_in6 *nativeGroup = (const struct sockaddr_in6 *)[groupAddr6 bytes]; + + struct ipv6_mreq imreq; + imreq.ipv6mr_multiaddr = nativeGroup->sin6_addr; + imreq.ipv6mr_interface = [self indexOfInterfaceAddr6:interfaceAddr6]; + + int status = setsockopt(self->socket6FD, IPPROTO_IPV6, requestType, (const void *)&imreq, sizeof(imreq)); + if (status != 0) + { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + + // Using IPv6 only + [self closeSocket4]; + + result = YES; + } + else + { + NSString *msg = @"Socket, group, and interface do not have matching IP versions"; + err = [self badParamError:msg]; + + return_from_block; + } + + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (errPtr) + *errPtr = err; + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Reuse port +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + if (![self preOp:&err]) + { + return_from_block; + } + + if ((self->flags & kDidCreateSockets) == 0) + { + if (![self createSockets:&err]) + { + return_from_block; + } + } + + int value = flag ? 1 : 0; + if (self->socket4FD != SOCKET_NULL) + { + int error = setsockopt(self->socket4FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value)); + + if (error) + { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + result = YES; + } + + if (self->socket6FD != SOCKET_NULL) + { + int error = setsockopt(self->socket6FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value)); + + if (error) + { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + result = YES; + } + + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (errPtr) + *errPtr = err; + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Broadcast +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr +{ + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ @autoreleasepool { + + if (![self preOp:&err]) + { + return_from_block; + } + + if ((self->flags & kDidCreateSockets) == 0) + { + if (![self createSockets:&err]) + { + return_from_block; + } + } + + if (self->socket4FD != SOCKET_NULL) + { + int value = flag ? 1 : 0; + int error = setsockopt(self->socket4FD, SOL_SOCKET, SO_BROADCAST, (const void *)&value, sizeof(value)); + + if (error) + { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + result = YES; + } + + // IPv6 does not implement broadcast, the ability to send a packet to all hosts on the attached link. + // The same effect can be achieved by sending a packet to the link-local all hosts multicast group. + + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (errPtr) + *errPtr = err; + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Sending +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)sendData:(NSData *)data withTag:(long)tag +{ + [self sendData:data withTimeout:-1.0 tag:tag]; +} + +- (void)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag +{ + LogTrace(); + + if ([data length] == 0) + { + LogWarn(@"Ignoring attempt to send nil/empty data."); + return; + } + + + + QNAsyncUdpSendPacket *packet = [[QNAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self->sendQueue addObject:packet]; + [self maybeDequeueSend]; + }}); + +} + +- (void)sendData:(NSData *)data + toHost:(NSString *)host + port:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + tag:(long)tag +{ + LogTrace(); + + if ([data length] == 0) + { + LogWarn(@"Ignoring attempt to send nil/empty data."); + return; + } + + QNAsyncUdpSendPacket *packet = [[QNAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag]; + packet->resolveInProgress = YES; + + [self asyncResolveHost:host port:port withCompletionBlock:^(NSArray *addresses, NSError *error) { + + // The asyncResolveHost:port:: method asynchronously dispatches a task onto the global concurrent queue, + // and immediately returns. Once the async resolve task completes, + // this block is executed on our socketQueue. + + packet->resolveInProgress = NO; + + packet->resolvedAddresses = addresses; + packet->resolveError = error; + + if (packet == self->currentSend) + { + LogVerbose(@"currentSend - address resolved"); + [self doPreSend]; + } + }]; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self->sendQueue addObject:packet]; + [self maybeDequeueSend]; + + }}); + +} + +- (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag +{ + LogTrace(); + + if ([data length] == 0) + { + LogWarn(@"Ignoring attempt to send nil/empty data."); + return; + } + + QNAsyncUdpSendPacket *packet = [[QNAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag]; + packet->addressFamily = [QNAsyncUdpSocket familyFromAddress:remoteAddr]; + packet->address = remoteAddr; + + dispatch_async(socketQueue, ^{ @autoreleasepool { + + [self->sendQueue addObject:packet]; + [self maybeDequeueSend]; + }}); +} + +- (void)setSendFilter:(QNAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue +{ + [self setSendFilter:filterBlock withQueue:filterQueue isAsynchronous:YES]; +} + +- (void)setSendFilter:(QNAsyncUdpSocketSendFilterBlock)filterBlock + withQueue:(dispatch_queue_t)filterQueue + isAsynchronous:(BOOL)isAsynchronous +{ + QNAsyncUdpSocketSendFilterBlock newFilterBlock = NULL; + dispatch_queue_t newFilterQueue = NULL; + + if (filterBlock) + { + NSAssert(filterQueue, @"Must provide a dispatch_queue in which to run the filter block."); + + newFilterBlock = [filterBlock copy]; + newFilterQueue = filterQueue; + #if !OS_OBJECT_USE_OBJC + dispatch_retain(newFilterQueue); + #endif + } + + dispatch_block_t block = ^{ + + #if !OS_OBJECT_USE_OBJC + if (self->sendFilterQueue) dispatch_release(self->sendFilterQueue); + #endif + + self->sendFilterBlock = newFilterBlock; + self->sendFilterQueue = newFilterQueue; + self->sendFilterAsync = isAsynchronous; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (void)maybeDequeueSend +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + // If we don't have a send operation already in progress + if (currentSend == nil) + { + // Create the sockets if needed + if ((flags & kDidCreateSockets) == 0) + { + NSError *err = nil; + if (![self createSockets:&err]) + { + [self closeWithError:err]; + return; + } + } + + while ([sendQueue count] > 0) + { + // Dequeue the next object in the queue + currentSend = [sendQueue objectAtIndex:0]; + [sendQueue removeObjectAtIndex:0]; + + if ([currentSend isKindOfClass:[QNAsyncUdpSpecialPacket class]]) + { + [self maybeConnect]; + + return; // The maybeConnect method, if it connects, will invoke this method again + } + else if (currentSend->resolveError) + { + // Notify delegate + [self notifyDidNotSendDataWithTag:currentSend->tag dueToError:currentSend->resolveError]; + + // Clear currentSend + currentSend = nil; + + continue; + } + else + { + // Start preprocessing checks on the send packet + [self doPreSend]; + + break; + } + } + + if ((currentSend == nil) && (flags & kCloseAfterSends)) + { + [self closeWithError:nil]; + } + } +} + +/** + * This method is called after a sendPacket has been dequeued. + * It performs various preprocessing checks on the packet, + * and queries the sendFilter (if set) to determine if the packet can be sent. + * + * If the packet passes all checks, it will be passed on to the doSend method. +**/ +- (void)doPreSend +{ + LogTrace(); + + // + // 1. Check for problems with send packet + // + + BOOL waitingForResolve = NO; + NSError *error = nil; + + if (flags & kDidConnect) + { + // Connected socket + + if (currentSend->resolveInProgress || currentSend->resolvedAddresses || currentSend->resolveError) + { + NSString *msg = @"Cannot specify destination of packet for connected socket"; + error = [self badConfigError:msg]; + } + else + { + currentSend->address = cachedConnectedAddress; + currentSend->addressFamily = cachedConnectedFamily; + } + } + else + { + // Non-Connected socket + + if (currentSend->resolveInProgress) + { + // We're waiting for the packet's destination to be resolved. + waitingForResolve = YES; + } + else if (currentSend->resolveError) + { + error = currentSend->resolveError; + } + else if (currentSend->address == nil) + { + if (currentSend->resolvedAddresses == nil) + { + NSString *msg = @"You must specify destination of packet for a non-connected socket"; + error = [self badConfigError:msg]; + } + else + { + // Pick the proper address to use (out of possibly several resolved addresses) + + NSData *address = nil; + int addressFamily = AF_UNSPEC; + + addressFamily = [self getAddress:&address error:&error fromAddresses:currentSend->resolvedAddresses]; + + currentSend->address = address; + currentSend->addressFamily = addressFamily; + } + } + } + + if (waitingForResolve) + { + // We're waiting for the packet's destination to be resolved. + + LogVerbose(@"currentSend - waiting for address resolve"); + + if (flags & kSock4CanAcceptBytes) { + [self suspendSend4Source]; + } + if (flags & kSock6CanAcceptBytes) { + [self suspendSend6Source]; + } + + return; + } + + if (error) + { + // Unable to send packet due to some error. + // Notify delegate and move on. + + [self notifyDidNotSendDataWithTag:currentSend->tag dueToError:error]; + [self endCurrentSend]; + [self maybeDequeueSend]; + + return; + } + + // + // 2. Query sendFilter (if applicable) + // + + if (sendFilterBlock && sendFilterQueue) + { + // Query sendFilter + + if (sendFilterAsync) + { + // Scenario 1 of 3 - Need to asynchronously query sendFilter + + currentSend->filterInProgress = YES; + QNAsyncUdpSendPacket *sendPacket = currentSend; + + dispatch_async(sendFilterQueue, ^{ @autoreleasepool { + + BOOL allowed = self->sendFilterBlock(sendPacket->buffer, sendPacket->address, sendPacket->tag); + + dispatch_async(self->socketQueue, ^{ @autoreleasepool { + + sendPacket->filterInProgress = NO; + if (sendPacket == self->currentSend) + { + if (allowed) + { + [self doSend]; + } + else + { + LogVerbose(@"currentSend - silently dropped by sendFilter"); + + [self notifyDidSendDataWithTag:self->currentSend->tag]; + [self endCurrentSend]; + [self maybeDequeueSend]; + } + } + }}); + }}); + } + else + { + // Scenario 2 of 3 - Need to synchronously query sendFilter + + __block BOOL allowed = YES; + + dispatch_sync(sendFilterQueue, ^{ @autoreleasepool { + + allowed = self->sendFilterBlock(self->currentSend->buffer, self->currentSend->address, self->currentSend->tag); + }}); + + if (allowed) + { + [self doSend]; + } + else + { + LogVerbose(@"currentSend - silently dropped by sendFilter"); + + [self notifyDidSendDataWithTag:currentSend->tag]; + [self endCurrentSend]; + [self maybeDequeueSend]; + } + } + } + else // if (!sendFilterBlock || !sendFilterQueue) + { + // Scenario 3 of 3 - No sendFilter. Just go straight into sending. + + [self doSend]; + } +} + +/** + * This method performs the actual sending of data in the currentSend packet. + * It should only be called if the +**/ +- (void)doSend +{ + LogTrace(); + + NSAssert(currentSend != nil, @"Invalid logic"); + + // Perform the actual send + + ssize_t result = 0; + + if (flags & kDidConnect) + { + // Connected socket + + const void *buffer = [currentSend->buffer bytes]; + size_t length = (size_t)[currentSend->buffer length]; + + if (currentSend->addressFamily == AF_INET) + { + result = send(socket4FD, buffer, length, 0); + LogVerbose(@"send(socket4FD) = %d", result); + } + else + { + result = send(socket6FD, buffer, length, 0); + LogVerbose(@"send(socket6FD) = %d", result); + } + } + else + { + // Non-Connected socket + + const void *buffer = [currentSend->buffer bytes]; + size_t length = (size_t)[currentSend->buffer length]; + + const void *dst = [currentSend->address bytes]; + socklen_t dstSize = (socklen_t)[currentSend->address length]; + + if (currentSend->addressFamily == AF_INET) + { + result = sendto(socket4FD, buffer, length, 0, dst, dstSize); + LogVerbose(@"sendto(socket4FD) = %d", result); + } + else + { + result = sendto(socket6FD, buffer, length, 0, dst, dstSize); + LogVerbose(@"sendto(socket6FD) = %d", result); + } + } + + // If the socket wasn't bound before, it is now + + if ((flags & kDidBind) == 0) + { + flags |= kDidBind; + } + + // Check the results. + // + // From the send() & sendto() manpage: + // + // Upon successful completion, the number of bytes which were sent is returned. + // Otherwise, -1 is returned and the global variable errno is set to indicate the error. + + BOOL waitingForSocket = NO; + NSError *socketError = nil; + + if (result == 0) + { + waitingForSocket = YES; + } + else if (result < 0) + { + if (errno == EAGAIN) + waitingForSocket = YES; + else + socketError = [self errnoErrorWithReason:@"Error in send() function."]; + } + + if (waitingForSocket) + { + // Not enough room in the underlying OS socket send buffer. + // Wait for a notification of available space. + + LogVerbose(@"currentSend - waiting for socket"); + + if (!(flags & kSock4CanAcceptBytes)) { + [self resumeSend4Source]; + } + if (!(flags & kSock6CanAcceptBytes)) { + [self resumeSend6Source]; + } + + if ((sendTimer == NULL) && (currentSend->timeout >= 0.0)) + { + // Unable to send packet right away. + // Start timer to timeout the send operation. + + [self setupSendTimerWithTimeout:currentSend->timeout]; + } + } + else if (socketError) + { + [self closeWithError:socketError]; + } + else // done + { + [self notifyDidSendDataWithTag:currentSend->tag]; + [self endCurrentSend]; + [self maybeDequeueSend]; + } +} + +/** + * Releases all resources associated with the currentSend. +**/ +- (void)endCurrentSend +{ + if (sendTimer) + { + dispatch_source_cancel(sendTimer); + #if !OS_OBJECT_USE_OBJC + dispatch_release(sendTimer); + #endif + sendTimer = NULL; + } + + currentSend = nil; +} + +/** + * Performs the operations to timeout the current send operation, and move on. +**/ +- (void)doSendTimeout +{ + LogTrace(); + + [self notifyDidNotSendDataWithTag:currentSend->tag dueToError:[self sendTimeoutError]]; + [self endCurrentSend]; + [self maybeDequeueSend]; +} + +/** + * Sets up a timer that fires to timeout the current send operation. + * This method should only be called once per send packet. +**/ +- (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout +{ + NSAssert(sendTimer == NULL, @"Invalid logic"); + NSAssert(timeout >= 0.0, @"Invalid logic"); + + LogTrace(); + + sendTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue); + + dispatch_source_set_event_handler(sendTimer, ^{ @autoreleasepool { + + [self doSendTimeout]; + }}); + + dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); + + dispatch_source_set_timer(sendTimer, tt, DISPATCH_TIME_FOREVER, 0); + dispatch_resume(sendTimer); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Receiving +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)receiveOnce:(NSError **)errPtr +{ + LogTrace(); + + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ + + if ((self->flags & kReceiveOnce) == 0) + { + if ((self->flags & kDidCreateSockets) == 0) + { + NSString *msg = @"Must bind socket before you can receive data. " + @"You can do this explicitly via bind, or implicitly via connect or by sending data."; + + err = [self badConfigError:msg]; + return_from_block; + } + + self->flags |= kReceiveOnce; // Enable + self->flags &= ~kReceiveContinuous; // Disable + + dispatch_async(self->socketQueue, ^{ @autoreleasepool { + + [self doReceive]; + }}); + } + + result = YES; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (err) + LogError(@"Error in beginReceiving: %@", err); + + if (errPtr) + *errPtr = err; + + return result; +} + +- (BOOL)beginReceiving:(NSError **)errPtr +{ + LogTrace(); + + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ + + if ((self->flags & kReceiveContinuous) == 0) + { + if ((self->flags & kDidCreateSockets) == 0) + { + NSString *msg = @"Must bind socket before you can receive data. " + @"You can do this explicitly via bind, or implicitly via connect or by sending data."; + + err = [self badConfigError:msg]; + return_from_block; + } + + self->flags |= kReceiveContinuous; // Enable + self->flags &= ~kReceiveOnce; // Disable + + dispatch_async(self->socketQueue, ^{ @autoreleasepool { + + [self doReceive]; + }}); + } + + result = YES; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); + + if (err) + LogError(@"Error in beginReceiving: %@", err); + + if (errPtr) + *errPtr = err; + + return result; +} + +- (void)pauseReceiving +{ + LogTrace(); + + dispatch_block_t block = ^{ + + self->flags &= ~kReceiveOnce; // Disable + self->flags &= ~kReceiveContinuous; // Disable + + if (self->socket4FDBytesAvailable > 0) { + [self suspendReceive4Source]; + } + if (self->socket6FDBytesAvailable > 0) { + [self suspendReceive6Source]; + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (void)setReceiveFilter:(QNAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue +{ + [self setReceiveFilter:filterBlock withQueue:filterQueue isAsynchronous:YES]; +} + +- (void)setReceiveFilter:(QNAsyncUdpSocketReceiveFilterBlock)filterBlock + withQueue:(dispatch_queue_t)filterQueue + isAsynchronous:(BOOL)isAsynchronous +{ + QNAsyncUdpSocketReceiveFilterBlock newFilterBlock = NULL; + dispatch_queue_t newFilterQueue = NULL; + + if (filterBlock) + { + NSAssert(filterQueue, @"Must provide a dispatch_queue in which to run the filter block."); + + newFilterBlock = [filterBlock copy]; + newFilterQueue = filterQueue; + #if !OS_OBJECT_USE_OBJC + dispatch_retain(newFilterQueue); + #endif + } + + dispatch_block_t block = ^{ + + #if !OS_OBJECT_USE_OBJC + if (self->receiveFilterQueue) dispatch_release(self->receiveFilterQueue); + #endif + + self->receiveFilterBlock = newFilterBlock; + self->receiveFilterQueue = newFilterQueue; + self->receiveFilterAsync = isAsynchronous; + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +- (void)doReceive +{ + LogTrace(); + + if ((flags & (kReceiveOnce | kReceiveContinuous)) == 0) + { + LogVerbose(@"Receiving is paused..."); + + if (socket4FDBytesAvailable > 0) { + [self suspendReceive4Source]; + } + if (socket6FDBytesAvailable > 0) { + [self suspendReceive6Source]; + } + + return; + } + + if ((flags & kReceiveOnce) && (pendingFilterOperations > 0)) + { + LogVerbose(@"Receiving is temporarily paused (pending filter operations)..."); + + if (socket4FDBytesAvailable > 0) { + [self suspendReceive4Source]; + } + if (socket6FDBytesAvailable > 0) { + [self suspendReceive6Source]; + } + + return; + } + + if ((socket4FDBytesAvailable == 0) && (socket6FDBytesAvailable == 0)) + { + LogVerbose(@"No data available to receive..."); + + if (socket4FDBytesAvailable == 0) { + [self resumeReceive4Source]; + } + if (socket6FDBytesAvailable == 0) { + [self resumeReceive6Source]; + } + + return; + } + + // Figure out if we should receive on socket4 or socket6 + + BOOL doReceive4; + + if (flags & kDidConnect) + { + // Connected socket + + doReceive4 = (socket4FD != SOCKET_NULL); + } + else + { + // Non-Connected socket + + if (socket4FDBytesAvailable > 0) + { + if (socket6FDBytesAvailable > 0) + { + // Bytes available on socket4 & socket6 + + doReceive4 = (flags & kFlipFlop) ? YES : NO; + + flags ^= kFlipFlop; // flags = flags xor kFlipFlop; (toggle flip flop bit) + } + else { + // Bytes available on socket4, but not socket6 + doReceive4 = YES; + } + } + else { + // Bytes available on socket6, but not socket4 + doReceive4 = NO; + } + } + + // Perform socket IO + + ssize_t result = 0; + + NSData *data = nil; + NSData *addr4 = nil; + NSData *addr6 = nil; + + if (doReceive4) + { + NSAssert(socket4FDBytesAvailable > 0, @"Invalid logic"); + LogVerbose(@"Receiving on IPv4"); + + struct sockaddr_in sockaddr4; + socklen_t sockaddr4len = sizeof(sockaddr4); + + // #222: GCD does not necessarily return the size of an entire UDP packet + // from dispatch_source_get_data(), so we must use the maximum packet size. + size_t bufSize = max4ReceiveSize; + void *buf = malloc(bufSize); + + result = recvfrom(socket4FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr4, &sockaddr4len); + LogVerbose(@"recvfrom(socket4FD) = %i", (int)result); + + if (result > 0) + { + if ((size_t)result >= socket4FDBytesAvailable) + socket4FDBytesAvailable = 0; + else + socket4FDBytesAvailable -= result; + + if ((size_t)result != bufSize) { + buf = realloc(buf, result); + } + + data = [NSData dataWithBytesNoCopy:buf length:result freeWhenDone:YES]; + addr4 = [NSData dataWithBytes:&sockaddr4 length:sockaddr4len]; + } + else + { + LogVerbose(@"recvfrom(socket4FD) = %@", [self errnoError]); + socket4FDBytesAvailable = 0; + free(buf); + } + } + else + { + NSAssert(socket6FDBytesAvailable > 0, @"Invalid logic"); + LogVerbose(@"Receiving on IPv6"); + + struct sockaddr_in6 sockaddr6; + socklen_t sockaddr6len = sizeof(sockaddr6); + + // #222: GCD does not necessarily return the size of an entire UDP packet + // from dispatch_source_get_data(), so we must use the maximum packet size. + size_t bufSize = max6ReceiveSize; + void *buf = malloc(bufSize); + + result = recvfrom(socket6FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr6, &sockaddr6len); + LogVerbose(@"recvfrom(socket6FD) -> %i", (int)result); + + if (result > 0) + { + if ((size_t)result >= socket6FDBytesAvailable) + socket6FDBytesAvailable = 0; + else + socket6FDBytesAvailable -= result; + + if ((size_t)result != bufSize) { + buf = realloc(buf, result); + } + + data = [NSData dataWithBytesNoCopy:buf length:result freeWhenDone:YES]; + addr6 = [NSData dataWithBytes:&sockaddr6 length:sockaddr6len]; + } + else + { + LogVerbose(@"recvfrom(socket6FD) = %@", [self errnoError]); + socket6FDBytesAvailable = 0; + free(buf); + } + } + + + BOOL waitingForSocket = NO; + BOOL notifiedDelegate = NO; + BOOL ignored = NO; + + NSError *socketError = nil; + + if (result == 0) + { + waitingForSocket = YES; + } + else if (result < 0) + { + if (errno == EAGAIN) + waitingForSocket = YES; + else + socketError = [self errnoErrorWithReason:@"Error in recvfrom() function"]; + } + else + { + if (flags & kDidConnect) + { + if (addr4 && ![self isConnectedToAddress4:addr4]) + ignored = YES; + if (addr6 && ![self isConnectedToAddress6:addr6]) + ignored = YES; + } + + NSData *addr = (addr4 != nil) ? addr4 : addr6; + + if (!ignored) + { + if (receiveFilterBlock && receiveFilterQueue) + { + // Run data through filter, and if approved, notify delegate + + __block id filterContext = nil; + __block BOOL allowed = NO; + + if (receiveFilterAsync) + { + pendingFilterOperations++; + dispatch_async(receiveFilterQueue, ^{ @autoreleasepool { + + allowed = self->receiveFilterBlock(data, addr, &filterContext); + + // Transition back to socketQueue to get the current delegate / delegateQueue + dispatch_async(self->socketQueue, ^{ @autoreleasepool { + + self->pendingFilterOperations--; + + if (allowed) + { + [self notifyDidReceiveData:data fromAddress:addr withFilterContext:filterContext]; + } + else + { + LogVerbose(@"received packet silently dropped by receiveFilter"); + } + + if (self->flags & kReceiveOnce) + { + if (allowed) + { + // The delegate has been notified, + // so our receive once operation has completed. + self->flags &= ~kReceiveOnce; + } + else if (self->pendingFilterOperations == 0) + { + // All pending filter operations have completed, + // and none were allowed through. + // Our receive once operation hasn't completed yet. + [self doReceive]; + } + } + }}); + }}); + } + else // if (!receiveFilterAsync) + { + dispatch_sync(receiveFilterQueue, ^{ @autoreleasepool { + + allowed = self->receiveFilterBlock(data, addr, &filterContext); + }}); + + if (allowed) + { + [self notifyDidReceiveData:data fromAddress:addr withFilterContext:filterContext]; + notifiedDelegate = YES; + } + else + { + LogVerbose(@"received packet silently dropped by receiveFilter"); + ignored = YES; + } + } + } + else // if (!receiveFilterBlock || !receiveFilterQueue) + { + [self notifyDidReceiveData:data fromAddress:addr withFilterContext:nil]; + notifiedDelegate = YES; + } + } + } + + if (waitingForSocket) + { + // Wait for a notification of available data. + + if (socket4FDBytesAvailable == 0) { + [self resumeReceive4Source]; + } + if (socket6FDBytesAvailable == 0) { + [self resumeReceive6Source]; + } + } + else if (socketError) + { + [self closeWithError:socketError]; + } + else + { + if (flags & kReceiveContinuous) + { + // Continuous receive mode + [self doReceive]; + } + else + { + // One-at-a-time receive mode + if (notifiedDelegate) + { + // The delegate has been notified (no set filter). + // So our receive once operation has completed. + flags &= ~kReceiveOnce; + } + else if (ignored) + { + [self doReceive]; + } + else + { + // Waiting on asynchronous receive filter... + } + } + } +} + +- (void)doReceiveEOF +{ + LogTrace(); + + [self closeWithError:[self socketClosedError]]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Closing +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)closeWithError:(NSError *)error +{ + LogVerbose(@"closeWithError: %@", error); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if (currentSend) [self endCurrentSend]; + + [sendQueue removeAllObjects]; + + // If a socket has been created, we should notify the delegate. + BOOL shouldCallDelegate = (flags & kDidCreateSockets) ? YES : NO; + + // Close all sockets, send/receive sources, cfstreams, etc +#if TARGET_OS_IPHONE + [self removeStreamsFromRunLoop]; + [self closeReadAndWriteStreams]; +#endif + [self closeSockets]; + + // Clear all flags (config remains as is) + flags = 0; + + if (shouldCallDelegate) + { + [self notifyDidCloseWithError:error]; + } +} + +- (void)close +{ + LogTrace(); + + dispatch_block_t block = ^{ @autoreleasepool { + + [self closeWithError:nil]; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); +} + +- (void)closeAfterSending +{ + LogTrace(); + + dispatch_block_t block = ^{ @autoreleasepool { + + self->flags |= kCloseAfterSends; + + if (self->currentSend == nil && [self->sendQueue count] == 0) + { + [self closeWithError:nil]; + } + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark CFStream +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if TARGET_OS_IPHONE + +static NSThread *listenerThread; + ++ (void)ignore:(id)_ +{} + ++ (void)startListenerThreadIfNeeded +{ + static dispatch_once_t predicate; + dispatch_once(&predicate, ^{ + + listenerThread = [[NSThread alloc] initWithTarget:self + selector:@selector(listenerThread:) + object:nil]; + [listenerThread start]; + }); +} + ++ (void)listenerThread:(id)unused +{ + @autoreleasepool { + + [[NSThread currentThread] setName:QNAsyncUdpSocketThreadName]; + + LogInfo(@"ListenerThread: Started"); + + // We can't run the run loop unless it has an associated input source or a timer. + // So we'll just create a timer that will never fire - unless the server runs for a decades. + [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow] + target:self + selector:@selector(ignore:) + userInfo:nil + repeats:YES]; + + [[NSRunLoop currentRunLoop] run]; + + LogInfo(@"ListenerThread: Stopped"); + } +} + ++ (void)addStreamListener:(QNAsyncUdpSocket *)asyncUdpSocket +{ + LogTrace(); + NSAssert([NSThread currentThread] == listenerThread, @"Invoked on wrong thread"); + + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + + if (asyncUdpSocket->readStream4) + CFReadStreamScheduleWithRunLoop(asyncUdpSocket->readStream4, runLoop, kCFRunLoopDefaultMode); + + if (asyncUdpSocket->readStream6) + CFReadStreamScheduleWithRunLoop(asyncUdpSocket->readStream6, runLoop, kCFRunLoopDefaultMode); + + if (asyncUdpSocket->writeStream4) + CFWriteStreamScheduleWithRunLoop(asyncUdpSocket->writeStream4, runLoop, kCFRunLoopDefaultMode); + + if (asyncUdpSocket->writeStream6) + CFWriteStreamScheduleWithRunLoop(asyncUdpSocket->writeStream6, runLoop, kCFRunLoopDefaultMode); +} + ++ (void)removeStreamListener:(QNAsyncUdpSocket *)asyncUdpSocket +{ + LogTrace(); + NSAssert([NSThread currentThread] == listenerThread, @"Invoked on wrong thread"); + + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + + if (asyncUdpSocket->readStream4) + CFReadStreamUnscheduleFromRunLoop(asyncUdpSocket->readStream4, runLoop, kCFRunLoopDefaultMode); + + if (asyncUdpSocket->readStream6) + CFReadStreamUnscheduleFromRunLoop(asyncUdpSocket->readStream6, runLoop, kCFRunLoopDefaultMode); + + if (asyncUdpSocket->writeStream4) + CFWriteStreamUnscheduleFromRunLoop(asyncUdpSocket->writeStream4, runLoop, kCFRunLoopDefaultMode); + + if (asyncUdpSocket->writeStream6) + CFWriteStreamUnscheduleFromRunLoop(asyncUdpSocket->writeStream6, runLoop, kCFRunLoopDefaultMode); +} + +static void CFReadStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *pInfo) +{ + @autoreleasepool { + QNAsyncUdpSocket *asyncUdpSocket = (__bridge QNAsyncUdpSocket *)pInfo; + + switch(type) + { + case kCFStreamEventOpenCompleted: + { + LogCVerbose(@"CFReadStreamCallback - Open"); + break; + } + case kCFStreamEventHasBytesAvailable: + { + LogCVerbose(@"CFReadStreamCallback - HasBytesAvailable"); + break; + } + case kCFStreamEventErrorOccurred: + case kCFStreamEventEndEncountered: + { + NSError *error = (__bridge_transfer NSError *)CFReadStreamCopyError(stream); + if (error == nil && type == kCFStreamEventEndEncountered) + { + error = [asyncUdpSocket socketClosedError]; + } + + dispatch_async(asyncUdpSocket->socketQueue, ^{ @autoreleasepool { + + LogCVerbose(@"CFReadStreamCallback - %@", + (type == kCFStreamEventErrorOccurred) ? @"Error" : @"EndEncountered"); + + if (stream != asyncUdpSocket->readStream4 && + stream != asyncUdpSocket->readStream6 ) + { + LogCVerbose(@"CFReadStreamCallback - Ignored"); + return_from_block; + } + + [asyncUdpSocket closeWithError:error]; + + }}); + + break; + } + default: + { + LogCError(@"CFReadStreamCallback - UnknownType: %i", (int)type); + } + } + } +} + +static void CFWriteStreamCallback(CFWriteStreamRef stream, CFStreamEventType type, void *pInfo) +{ + @autoreleasepool { + QNAsyncUdpSocket *asyncUdpSocket = (__bridge QNAsyncUdpSocket *)pInfo; + + switch(type) + { + case kCFStreamEventOpenCompleted: + { + LogCVerbose(@"CFWriteStreamCallback - Open"); + break; + } + case kCFStreamEventCanAcceptBytes: + { + LogCVerbose(@"CFWriteStreamCallback - CanAcceptBytes"); + break; + } + case kCFStreamEventErrorOccurred: + case kCFStreamEventEndEncountered: + { + NSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream); + if (error == nil && type == kCFStreamEventEndEncountered) + { + error = [asyncUdpSocket socketClosedError]; + } + + dispatch_async(asyncUdpSocket->socketQueue, ^{ @autoreleasepool { + + LogCVerbose(@"CFWriteStreamCallback - %@", + (type == kCFStreamEventErrorOccurred) ? @"Error" : @"EndEncountered"); + + if (stream != asyncUdpSocket->writeStream4 && + stream != asyncUdpSocket->writeStream6 ) + { + LogCVerbose(@"CFWriteStreamCallback - Ignored"); + return_from_block; + } + + [asyncUdpSocket closeWithError:error]; + + }}); + + break; + } + default: + { + LogCError(@"CFWriteStreamCallback - UnknownType: %i", (int)type); + } + } + } +} + +- (BOOL)createReadAndWriteStreams:(NSError **)errPtr +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + NSError *err = nil; + + if (readStream4 || writeStream4 || readStream6 || writeStream6) + { + // Streams already created + return YES; + } + + if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL) + { + err = [self otherError:@"Cannot create streams without a file descriptor"]; + goto Failed; + } + + // Create streams + + LogVerbose(@"Creating read and write stream(s)..."); + + if (socket4FD != SOCKET_NULL) + { + CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socket4FD, &readStream4, &writeStream4); + if (!readStream4 || !writeStream4) + { + err = [self otherError:@"Error in CFStreamCreatePairWithSocket() [IPv4]"]; + goto Failed; + } + } + + if (socket6FD != SOCKET_NULL) + { + CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socket6FD, &readStream6, &writeStream6); + if (!readStream6 || !writeStream6) + { + err = [self otherError:@"Error in CFStreamCreatePairWithSocket() [IPv6]"]; + goto Failed; + } + } + + // Ensure the CFStream's don't close our underlying socket + + CFReadStreamSetProperty(readStream4, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); + CFWriteStreamSetProperty(writeStream4, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); + + CFReadStreamSetProperty(readStream6, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); + CFWriteStreamSetProperty(writeStream6, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); + + return YES; + +Failed: + if (readStream4) + { + CFReadStreamClose(readStream4); + CFRelease(readStream4); + readStream4 = NULL; + } + if (writeStream4) + { + CFWriteStreamClose(writeStream4); + CFRelease(writeStream4); + writeStream4 = NULL; + } + if (readStream6) + { + CFReadStreamClose(readStream6); + CFRelease(readStream6); + readStream6 = NULL; + } + if (writeStream6) + { + CFWriteStreamClose(writeStream6); + CFRelease(writeStream6); + writeStream6 = NULL; + } + + if (errPtr) + *errPtr = err; + + return NO; +} + +- (BOOL)registerForStreamCallbacks:(NSError **)errPtr +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(readStream4 || writeStream4 || readStream6 || writeStream6, @"Read/Write streams are null"); + + NSError *err = nil; + + streamContext.version = 0; + streamContext.info = (__bridge void *)self; + streamContext.retain = nil; + streamContext.release = nil; + streamContext.copyDescription = nil; + + CFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; + CFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; + +// readStreamEvents |= (kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable); +// writeStreamEvents |= (kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes); + + if (socket4FD != SOCKET_NULL) + { + if (readStream4 == NULL || writeStream4 == NULL) + { + err = [self otherError:@"Read/Write stream4 is null"]; + goto Failed; + } + + BOOL r1 = CFReadStreamSetClient(readStream4, readStreamEvents, &CFReadStreamCallback, &streamContext); + BOOL r2 = CFWriteStreamSetClient(writeStream4, writeStreamEvents, &CFWriteStreamCallback, &streamContext); + + if (!r1 || !r2) + { + err = [self otherError:@"Error in CFStreamSetClient(), [IPv4]"]; + goto Failed; + } + } + + if (socket6FD != SOCKET_NULL) + { + if (readStream6 == NULL || writeStream6 == NULL) + { + err = [self otherError:@"Read/Write stream6 is null"]; + goto Failed; + } + + BOOL r1 = CFReadStreamSetClient(readStream6, readStreamEvents, &CFReadStreamCallback, &streamContext); + BOOL r2 = CFWriteStreamSetClient(writeStream6, writeStreamEvents, &CFWriteStreamCallback, &streamContext); + + if (!r1 || !r2) + { + err = [self otherError:@"Error in CFStreamSetClient() [IPv6]"]; + goto Failed; + } + } + + return YES; + +Failed: + if (readStream4) { + CFReadStreamSetClient(readStream4, kCFStreamEventNone, NULL, NULL); + } + if (writeStream4) { + CFWriteStreamSetClient(writeStream4, kCFStreamEventNone, NULL, NULL); + } + if (readStream6) { + CFReadStreamSetClient(readStream6, kCFStreamEventNone, NULL, NULL); + } + if (writeStream6) { + CFWriteStreamSetClient(writeStream6, kCFStreamEventNone, NULL, NULL); + } + + if (errPtr) *errPtr = err; + return NO; +} + +- (BOOL)addStreamsToRunLoop:(NSError **)errPtr +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(readStream4 || writeStream4 || readStream6 || writeStream6, @"Read/Write streams are null"); + + if (!(flags & kAddedStreamListener)) + { + [[self class] startListenerThreadIfNeeded]; + [[self class] performSelector:@selector(addStreamListener:) + onThread:listenerThread + withObject:self + waitUntilDone:YES]; + + flags |= kAddedStreamListener; + } + + return YES; +} + +- (BOOL)openStreams:(NSError **)errPtr +{ + LogTrace(); + + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + NSAssert(readStream4 || writeStream4 || readStream6 || writeStream6, @"Read/Write streams are null"); + + NSError *err = nil; + + if (socket4FD != SOCKET_NULL) + { + BOOL r1 = CFReadStreamOpen(readStream4); + BOOL r2 = CFWriteStreamOpen(writeStream4); + + if (!r1 || !r2) + { + err = [self otherError:@"Error in CFStreamOpen() [IPv4]"]; + goto Failed; + } + } + + if (socket6FD != SOCKET_NULL) + { + BOOL r1 = CFReadStreamOpen(readStream6); + BOOL r2 = CFWriteStreamOpen(writeStream6); + + if (!r1 || !r2) + { + err = [self otherError:@"Error in CFStreamOpen() [IPv6]"]; + goto Failed; + } + } + + return YES; + +Failed: + if (errPtr) *errPtr = err; + return NO; +} + +- (void)removeStreamsFromRunLoop +{ + LogTrace(); + NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); + + if (flags & kAddedStreamListener) + { + [[self class] performSelector:@selector(removeStreamListener:) + onThread:listenerThread + withObject:self + waitUntilDone:YES]; + + flags &= ~kAddedStreamListener; + } +} + +- (void)closeReadAndWriteStreams +{ + LogTrace(); + + if (readStream4) + { + CFReadStreamSetClient(readStream4, kCFStreamEventNone, NULL, NULL); + CFReadStreamClose(readStream4); + CFRelease(readStream4); + readStream4 = NULL; + } + if (writeStream4) + { + CFWriteStreamSetClient(writeStream4, kCFStreamEventNone, NULL, NULL); + CFWriteStreamClose(writeStream4); + CFRelease(writeStream4); + writeStream4 = NULL; + } + if (readStream6) + { + CFReadStreamSetClient(readStream6, kCFStreamEventNone, NULL, NULL); + CFReadStreamClose(readStream6); + CFRelease(readStream6); + readStream6 = NULL; + } + if (writeStream6) + { + CFWriteStreamSetClient(writeStream6, kCFStreamEventNone, NULL, NULL); + CFWriteStreamClose(writeStream6); + CFRelease(writeStream6); + writeStream6 = NULL; + } +} + +#endif + +#if TARGET_OS_IPHONE +- (void)applicationWillEnterForeground:(NSNotification *)notification +{ + LogTrace(); + + // If the application was backgrounded, then iOS may have shut down our sockets. + // So we take a quick look to see if any of them received an EOF. + + dispatch_block_t block = ^{ @autoreleasepool { + + [self resumeReceive4Source]; + [self resumeReceive6Source]; + }}; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_async(socketQueue, block); +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Advanced +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * See header file for big discussion of this method. + **/ +- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue +{ + void *nonNullUnusedPointer = (__bridge void *)self; + dispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL); +} + +/** + * See header file for big discussion of this method. + **/ +- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue +{ + dispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL); +} + +- (void)performBlock:(dispatch_block_t)block +{ + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + block(); + else + dispatch_sync(socketQueue, block); +} + +- (int)socketFD +{ + if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", + THIS_FILE, THIS_METHOD); + return SOCKET_NULL; + } + + if (socket4FD != SOCKET_NULL) + return socket4FD; + else + return socket6FD; +} + +- (int)socket4FD +{ + if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", + THIS_FILE, THIS_METHOD); + return SOCKET_NULL; + } + + return socket4FD; +} + +- (int)socket6FD +{ + if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", + THIS_FILE, THIS_METHOD); + return SOCKET_NULL; + } + + return socket6FD; +} + +#if TARGET_OS_IPHONE + +- (CFReadStreamRef)readStream +{ + if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", + THIS_FILE, THIS_METHOD); + return NULL; + } + + NSError *err = nil; + if (![self createReadAndWriteStreams:&err]) + { + LogError(@"Error creating CFStream(s): %@", err); + return NULL; + } + + // Todo... + + if (readStream4) + return readStream4; + else + return readStream6; +} + +- (CFWriteStreamRef)writeStream +{ + if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", + THIS_FILE, THIS_METHOD); + return NULL; + } + + NSError *err = nil; + if (![self createReadAndWriteStreams:&err]) + { + LogError(@"Error creating CFStream(s): %@", err); + return NULL; + } + + if (writeStream4) + return writeStream4; + else + return writeStream6; +} + +- (BOOL)enableBackgroundingOnSockets +{ + if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + { + LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", + THIS_FILE, THIS_METHOD); + return NO; + } + + // Why is this commented out? + // See comments below. + +// NSError *err = nil; +// if (![self createReadAndWriteStreams:&err]) +// { +// LogError(@"Error creating CFStream(s): %@", err); +// return NO; +// } +// +// LogVerbose(@"Enabling backgrouding on socket"); +// +// BOOL r1, r2; +// +// if (readStream4 && writeStream4) +// { +// r1 = CFReadStreamSetProperty(readStream4, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); +// r2 = CFWriteStreamSetProperty(writeStream4, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); +// +// if (!r1 || !r2) +// { +// LogError(@"Error setting voip type (IPv4)"); +// return NO; +// } +// } +// +// if (readStream6 && writeStream6) +// { +// r1 = CFReadStreamSetProperty(readStream6, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); +// r2 = CFWriteStreamSetProperty(writeStream6, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); +// +// if (!r1 || !r2) +// { +// LogError(@"Error setting voip type (IPv6)"); +// return NO; +// } +// } +// +// return YES; + + // The above code will actually appear to work. + // The methods will return YES, and everything will appear fine. + // + // One tiny problem: the sockets will still get closed when the app gets backgrounded. + // + // Apple does not officially support backgrounding UDP sockets. + + return NO; +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Class Methods +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ++ (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4 +{ + char addrBuf[INET_ADDRSTRLEN]; + + if (inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL) + { + addrBuf[0] = '\0'; + } + + return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding]; +} + ++ (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6 +{ + char addrBuf[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL) + { + addrBuf[0] = '\0'; + } + + return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding]; +} + ++ (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4 +{ + return ntohs(pSockaddr4->sin_port); +} + ++ (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6 +{ + return ntohs(pSockaddr6->sin6_port); +} + ++ (NSString *)hostFromAddress:(NSData *)address +{ + NSString *host = nil; + [self getHost:&host port:NULL family:NULL fromAddress:address]; + + return host; +} + ++ (uint16_t)portFromAddress:(NSData *)address +{ + uint16_t port = 0; + [self getHost:NULL port:&port family:NULL fromAddress:address]; + + return port; +} + ++ (int)familyFromAddress:(NSData *)address +{ + int af = AF_UNSPEC; + [self getHost:NULL port:NULL family:&af fromAddress:address]; + + return af; +} + ++ (BOOL)isIPv4Address:(NSData *)address +{ + int af = AF_UNSPEC; + [self getHost:NULL port:NULL family:&af fromAddress:address]; + + return (af == AF_INET); +} + ++ (BOOL)isIPv6Address:(NSData *)address +{ + int af = AF_UNSPEC; + [self getHost:NULL port:NULL family:&af fromAddress:address]; + + return (af == AF_INET6); +} + ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address +{ + return [self getHost:hostPtr port:portPtr family:NULL fromAddress:address]; +} + ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(int *)afPtr fromAddress:(NSData *)address +{ + if ([address length] >= sizeof(struct sockaddr)) + { + const struct sockaddr *addrX = (const struct sockaddr *)[address bytes]; + + if (addrX->sa_family == AF_INET) + { + if ([address length] >= sizeof(struct sockaddr_in)) + { + const struct sockaddr_in *addr4 = (const struct sockaddr_in *)(const void *)addrX; + + if (hostPtr) *hostPtr = [self hostFromSockaddr4:addr4]; + if (portPtr) *portPtr = [self portFromSockaddr4:addr4]; + if (afPtr) *afPtr = AF_INET; + + return YES; + } + } + else if (addrX->sa_family == AF_INET6) + { + if ([address length] >= sizeof(struct sockaddr_in6)) + { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)(const void *)addrX; + + if (hostPtr) *hostPtr = [self hostFromSockaddr6:addr6]; + if (portPtr) *portPtr = [self portFromSockaddr6:addr6]; + if (afPtr) *afPtr = AF_INET6; + + return YES; + } + } + } + + if (hostPtr) *hostPtr = nil; + if (portPtr) *portPtr = 0; + if (afPtr) *afPtr = AF_UNSPEC; + + return NO; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNDes.h b/Pods/HappyDNS/HappyDNS/Util/QNDes.h new file mode 100644 index 0000000..fa8a011 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNDes.h @@ -0,0 +1,22 @@ +// +// QNDes.h +// HappyDNS +// +// Created by bailong on 15/8/1. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +extern const int kQN_ENCRYPT_FAILED; +extern const int kQN_DECRYPT_FAILED; + +@interface QNDes : NSObject + +- (NSData *)encrypt:(NSData *)input; + +- (NSData *)decrpyt:(NSData *)input; + +- (instancetype)init:(NSData *)key; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNDes.m b/Pods/HappyDNS/HappyDNS/Util/QNDes.m new file mode 100644 index 0000000..8be5ef5 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNDes.m @@ -0,0 +1,92 @@ +// +// QNDes.m +// HappyDNS +// +// Created by bailong on 15/8/1. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +#import "QNDes.h" + +@interface QNDes () +@property (nonatomic, strong) NSData *key; +@end + +@implementation QNDes + +- (NSData *)encrypt:(NSData *)data { + const void *input = data.bytes; + size_t inputSize = data.length; + + size_t bufferSize = (inputSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1); + uint8_t *buffer = malloc(bufferSize * sizeof(uint8_t)); + memset((void *)buffer, 0x0, bufferSize); + size_t movedBytes = 0; + + const void *vkey = _key.bytes; + + CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt, + kCCAlgorithmDES, + kCCOptionECBMode | kCCOptionPKCS7Padding, + vkey, + kCCKeySizeDES, + NULL, + input, + inputSize, + (void *)buffer, + bufferSize, + &movedBytes); + if (ccStatus != kCCSuccess) { + NSLog(@"error code %d", ccStatus); + free(buffer); + return nil; + } + NSData *encrypted = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)movedBytes]; + free(buffer); + return encrypted; +} + +- (NSData *)decrpyt:(NSData *)raw { + const void *input = raw.bytes; + size_t inputSize = raw.length; + + size_t bufferSize = 1024; + uint8_t *buffer = malloc(bufferSize * sizeof(uint8_t)); + memset((void *)buffer, 0x0, bufferSize); + size_t movedBytes = 0; + + const void *vkey = _key.bytes; + + CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt, + kCCAlgorithmDES, + kCCOptionECBMode | kCCOptionPKCS7Padding, + vkey, + kCCKeySizeDES, + NULL, + input, + inputSize, + (void *)buffer, + bufferSize, + &movedBytes); + + if (ccStatus != kCCSuccess) { + NSLog(@"error code %d", ccStatus); + free(buffer); + return nil; + } + + NSData *decrypted = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)movedBytes]; + free(buffer); + return decrypted; +} + +- (instancetype)init:(NSData *)key { + if (self = [super init]) { + _key = key; + } + return self; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.h b/Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.h new file mode 100644 index 0000000..5e1cf8b --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.h @@ -0,0 +1,40 @@ +// +// QNGetAddrInfo.h +// HappyDNS +// +// Created by bailong on 16/7/19. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#ifndef QNGetAddrInfo_h +#define QNGetAddrInfo_h + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct qn_ips_ret { + char *ips[1]; +} qn_ips_ret; + +typedef qn_ips_ret *(*qn_dns_callback)(const char *host); + +typedef void (*qn_ip_report_callback)(const char *ip, int code, int time_ms); + +extern void qn_free_ips_ret(qn_ips_ret *ip_list); + +extern int qn_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res); + +extern void qn_freeaddrinfo(struct addrinfo *ai); + +extern void qn_set_dns_callback(qn_dns_callback cb); + +extern void qn_set_ip_report_callback(qn_ip_report_callback cb); + +extern void qn_ip_report(const struct addrinfo *info, int code, int time_ms); + +#ifdef __cplusplus +}; +#endif + +#endif /* QNGetAddrInfo_h */ diff --git a/Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.m b/Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.m new file mode 100644 index 0000000..26cddd3 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.m @@ -0,0 +1,147 @@ +// +// QNGetAddrInfo.c +// HappyDNS +// +// Created by bailong on 16/7/19. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#include +#include +#include +#include + +#include "QNGetAddrInfo.h" + +//fast judge domain or ip, not verify ip right. +static int isIp(const char* domain) { + size_t l = strlen(domain); + if (l > 15 || l < 7) { + return 0; + } + + for (const char* p = domain; p < domain + l; p++) { + if ((*p < '0' || *p > '9') && *p != '.') { + return 0; + } + } + return 1; +} + +static struct addrinfo* addrinfo_clone(struct addrinfo* addr) { + struct addrinfo* ai; + ai = (struct addrinfo*)calloc(sizeof(struct addrinfo) + addr->ai_addrlen, 1); + if (ai) { + memcpy(ai, addr, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr*)(ai + 1); + memcpy(ai->ai_addr, addr->ai_addr, addr->ai_addrlen); + if (addr->ai_canonname) { + ai->ai_canonname = strdup(addr->ai_canonname); + } + ai->ai_next = NULL; + } + return ai; +} + +static void append_addrinfo(struct addrinfo** head, struct addrinfo* addr) { + if (*head == NULL) { + *head = addr; + return; + } + struct addrinfo* ai = *head; + while (ai->ai_next != NULL) { + ai = ai->ai_next; + } + ai->ai_next = addr; +} + +void qn_free_ips_ret(qn_ips_ret* ip_list) { + if (ip_list == NULL) { + return; + } + char** p = ip_list->ips; + while (*p != NULL) { + free(*p); + p++; + } + free(ip_list); +} + +static qn_dns_callback dns_callback = NULL; +int qn_getaddrinfo(const char* hostname, const char* servname, const struct addrinfo* hints, struct addrinfo** res) { + if (dns_callback == NULL || hostname == NULL || isIp(hostname)) { + return getaddrinfo(hostname, servname, hints, res); + } + + qn_ips_ret* ret = dns_callback(hostname); + if (ret == NULL) { + return EAI_NODATA; + } + if (ret->ips[0] == NULL) { + qn_free_ips_ret(ret); + return EAI_NODATA; + } + int i; + struct addrinfo* ai = NULL; + struct addrinfo* store = NULL; + int r = 0; + for (i = 0; ret->ips[i] != NULL; i++) { + r = getaddrinfo(ret->ips[i], servname, hints, &ai); + if (r != 0) { + break; + } + struct addrinfo* temp = ai; + ai = addrinfo_clone(ai); + append_addrinfo(&store, ai); + freeaddrinfo(temp); + ai = NULL; + } + qn_free_ips_ret(ret); + if (r != 0) { + qn_freeaddrinfo(store); + return r; + } + *res = store; + return 0; +} + +void qn_freeaddrinfo(struct addrinfo* ai) { + if (ai == NULL) { + return; + } + struct addrinfo* next; + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + ai = next; + } while (ai); +} + +void qn_set_dns_callback(qn_dns_callback cb) { + dns_callback = cb; +} + +static qn_ip_report_callback ip_report_cb = NULL; +void qn_set_ip_report_callback(qn_ip_report_callback cb) { + ip_report_cb = cb; +} + +void qn_ip_report(const struct addrinfo* info, int code, int time_ms) { + if (ip_report_cb == NULL || info == NULL) { + return; + } + char ip_str_buf[32] = {0}; + const char* c_ip; + if (info->ai_family == AF_INET6) { + c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in6*)(info->ai_addr))->sin6_addr, ip_str_buf, sizeof(ip_str_buf)); + } else { + c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in*)(info->ai_addr))->sin_addr, ip_str_buf, sizeof(ip_str_buf)); + } + if (c_ip == NULL) { + c_ip = ""; + } + ip_report_cb(c_ip, code, time_ms); +} diff --git a/Pods/HappyDNS/HappyDNS/Util/QNHex.h b/Pods/HappyDNS/HappyDNS/Util/QNHex.h new file mode 100644 index 0000000..a0bdbe7 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNHex.h @@ -0,0 +1,21 @@ +// +// QNHex.h +// HappyDNS +// +// Created by bailong on 15/7/31. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +char *qn_encodeHexData(char *output_buf, const char *data, int data_size, BOOL up); + +@interface QNHex : NSObject + ++ (NSString *)encodeHexData:(NSData *)data; ++ (NSString *)encodeHexString:(NSString *)str; + ++ (NSData *)decodeHexString:(NSString *)hex; ++ (NSString *)decodeHexToString:(NSString *)hex; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNHex.m b/Pods/HappyDNS/HappyDNS/Util/QNHex.m new file mode 100644 index 0000000..e32584d --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNHex.m @@ -0,0 +1,108 @@ +// +// QNHex.m +// HappyDNS +// +// Created by bailong on 15/7/31. +// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNHex.h" + +static char DIGITS_LOWER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +static char DIGITS_UPPER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +static int hexDigit(char c) { + int result = -1; + if ('0' <= c && c <= '9') { + result = c - '0'; + } else if ('a' <= c && c <= 'f') { + result = 10 + (c - 'a'); + } else if ('A' <= c && c <= 'F') { + result = 10 + (c - 'A'); + } + return result; +} + +static char *decodeHex(const char *data, int size) { + if ((size & 0x01) != 0) { + return NULL; + } + char *output = malloc(size / 2); + int outLimit = 0; + for (int i = 0, j = 0; j < size; i++) { + int f = hexDigit(data[j]); + if (f < 0) { + outLimit = 1; + break; + } + j++; + int f2 = hexDigit(data[j]); + if (f2 < 0) { + outLimit = 1; + break; + } + f = (f << 4) | f2; + j++; + output[i] = (char)(f & 0xff); + } + if (outLimit) { + free(output); + return NULL; + } + return output; +} + +static char *encodeHexInternal(char *output_buf, const char *data, int size, char hexTable[]) { + for (int i = 0, j = 0; i < size; i++) { + output_buf[j++] = hexTable[((0XF0 & data[i]) >> 4) & 0X0F]; + output_buf[j++] = hexTable[((0X0F & data[i])) & 0X0F]; + } + return output_buf; +} + +static char *encodeHex(const char *data, int size, char hexTable[]) { + char *output = malloc(size * 2); + return encodeHexInternal(output, data, size, hexTable); +} + +char *qn_encodeHexData(char *buff, const char *data, int data_size, BOOL up) { + char *hexTable = DIGITS_UPPER; + if (!up) { + hexTable = DIGITS_LOWER; + } + return encodeHexInternal(buff, data, data_size, hexTable); +} + +@implementation QNHex + ++ (NSString *)encodeHexData:(NSData *)data { + char *e = encodeHex(data.bytes, (int)data.length, DIGITS_UPPER); + NSString *str = [[NSString alloc] initWithBytes:e length:data.length * 2 encoding:NSASCIIStringEncoding]; + free(e); + return str; +} + ++ (NSString *)encodeHexString:(NSString *)str { + return [QNHex encodeHexData:[str dataUsingEncoding:NSUTF8StringEncoding]]; +} + ++ (NSData *)decodeHexString:(NSString *)hex { + char *d = decodeHex(hex.UTF8String, (int)hex.length); + if (d == NULL) { + return nil; + } + NSData *data = [NSData dataWithBytes:d length:hex.length / 2]; + free(d); + return data; +} + ++ (NSString *)decodeHexToString:(NSString *)hex { + NSData *data = [QNHex decodeHexString:hex]; + if (data == nil) { + return nil; + } + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNIP.h b/Pods/HappyDNS/HappyDNS/Util/QNIP.h new file mode 100644 index 0000000..d425b68 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNIP.h @@ -0,0 +1,31 @@ +// +// QNIPV6.h +// HappyDNS +// +// Created by bailong on 16/5/25. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +extern int qn_localIp(char *buf, int buf_size); +extern void qn_nat64(char *buf, int buf_size, uint32_t ipv4_addr); + +@interface QNIP : NSObject + ++ (BOOL)isV6; + ++ (NSString *)adaptiveIp:(NSString *)ipv4; + ++ (NSString *)local; + +// ipv6 in url like http://[::xxx]/ ++ (NSString *)ipHost:(NSString *)ip; + ++ (NSString *)nat64:(NSString *)ip; + ++ (BOOL)isIpV6FullySupported; + ++ (BOOL)mayBeIpV4:(NSString *)domain; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNIP.m b/Pods/HappyDNS/HappyDNS/Util/QNIP.m new file mode 100644 index 0000000..3c79e25 --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNIP.m @@ -0,0 +1,240 @@ +// +// QNIPV6.m +// HappyDNS +// +// Created by bailong on 16/5/25. +// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved. +// + +#import +#import +#import +#import + +#include +#include + +#import "QNHex.h" +#import "QNIP.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#import +#endif + +#ifndef kQNDnsDefaultIPv4IP +#define kQNDnsDefaultIPv4IP "114.114.114.114" +#endif + +#ifndef kQNDnsDefaultIPv6IP +#define kQNDnsDefaultIPv6IP "2400:3200::1" +#endif + +void qn_nat64(char *buf, int buf_size, uint32_t ipv4addr) { + bzero(buf, buf_size); + //nat 4 to ipv6 + const char *p = (const char *)&ipv4addr; + const char prefix[] = "64:ff9b::"; + memcpy(buf, prefix, sizeof(prefix)); + char *phex = buf + sizeof(prefix) - 1; + qn_encodeHexData(phex, p, 2, false); + if (*phex == '0') { + memmove(phex, phex + 1, 3); + phex += 3; + } else { + phex += 4; + } + *phex = ':'; + phex++; + qn_encodeHexData(phex, p + 2, 2, false); + if (*phex == '0') { + memmove(phex, phex + 1, 3); + phex[3] = 0; + } +} + +int qn_local_ip_internal(char *buf, int buf_size, const char *t_ip) { + struct addrinfo hints = {0}, *ai; + int err = 0; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + int ret = getaddrinfo(t_ip, "53", &hints, &ai); + if (ret != 0) { + err = errno; + return err; + } + + int family = ai->ai_family; + int sock = socket(family, ai->ai_socktype, 0); + if (sock < 0) { + err = errno; + freeaddrinfo(ai); + return err; + } + + //fix getaddrinfo bug in ipv4 to ipv6 + if (ai->ai_family == AF_INET6) { + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53); + } + + err = connect(sock, ai->ai_addr, ai->ai_addrlen); + freeaddrinfo(ai); + if (err < 0) { + close(sock); + err = errno; + return err; + } + + uint32_t localAddress[16] = {0}; + + socklen_t addressLength = sizeof(localAddress); + err = getsockname(sock, (struct sockaddr *)&localAddress, &addressLength); + close(sock); + if (err != 0) { + return err; + } + void *addr; + if (family == AF_INET6) { + addr = &((struct sockaddr_in6 *)&localAddress)->sin6_addr; + } else { + addr = &((struct sockaddr_in *)&localAddress)->sin_addr; + } + const char *ip = inet_ntop(family, addr, buf, buf_size); + if (ip == nil) { + return -1; + } + return 0; +} + +int qn_localIp(char *buf, int buf_size) { + int ret = qn_local_ip_internal(buf, buf_size, kQNDnsDefaultIPv4IP); + if (ret != 0) { +#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED + if (![QNIP isIpV6FullySupported]) { + ret = qn_local_ip_internal(buf, buf_size, kQNDnsDefaultIPv6IP); + } +#endif + } + return ret; +} + +@implementation QNIP + ++ (BOOL)isV6 { + struct addrinfo hints = {0}, *ai; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + int ret = getaddrinfo(kQNDnsDefaultIPv4IP, "http", &hints, &ai); + if (ret != 0) { + return NO; + } + int family = ai->ai_family; + freeaddrinfo(ai); + BOOL result = family == AF_INET6; +#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED + if (![QNIP isIpV6FullySupported] && !ret) { + char buf[64] = {0}; + ret = qn_local_ip_internal(buf, sizeof(buf), kQNDnsDefaultIPv6IP); + if (strchr(buf, ':') != NULL) { + result = YES; + } + } +#endif + return result; +} + ++ (NSString *)adaptiveIp:(NSString *)ipv4 { + struct addrinfo hints = {0}, *ai; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + int ret = getaddrinfo(ipv4.UTF8String, "http", &hints, &ai); + if (ret != 0) { + return nil; + } + int family = ai->ai_family; + + void *addr; + if (family == AF_INET6) { + addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; + } else { + addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr; + } + char buf[64] = {0}; + const char *ip = inet_ntop(family, addr, buf, sizeof(buf)); +#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED + if (![QNIP isIpV6FullySupported] && family == AF_INET) { + char buf2[64] = {0}; + ret = qn_local_ip_internal(buf2, sizeof(buf2), kQNDnsDefaultIPv6IP); + if (strchr(buf2, ':') != NULL) { + bzero(buf, sizeof(buf)); + qn_nat64(buf, sizeof(buf), *((uint32_t *)addr)); + } + } +#endif + + freeaddrinfo(ai); + return [NSString stringWithUTF8String:ip]; +} + ++ (NSString *)local { + char buf[64] = {0}; + int err = qn_localIp(buf, sizeof(buf)); + if (err != 0) { + return nil; + } + return [NSString stringWithUTF8String:buf]; +} + ++ (NSString *)ipHost:(NSString *)ip { + NSRange range = [ip rangeOfString:@":"]; + if (range.location != NSNotFound) { + return [NSString stringWithFormat:@"[%@]", ip]; + } + return ip; +} + ++ (NSString *)nat64:(NSString *)ip { + struct in_addr s = {0}; + inet_pton(AF_INET, ip.UTF8String, (void *)&s); + char buf[64] = {0}; + qn_nat64(buf, sizeof(buf), (uint32_t)s.s_addr); + return [NSString stringWithUTF8String:buf]; +} + ++ (BOOL)isIpV6FullySupported { +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) + float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; + if (sysVersion < 9.0) { + return NO; + } +#else + NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + if (sysVersion.majorVersion < 10) { + return NO; + } else if (sysVersion.majorVersion == 10) { + return sysVersion.minorVersion >= 11; + } +#endif + return YES; +} + ++ (BOOL)mayBeIpV4:(NSString *)domain { + NSUInteger l = domain.length; + if (l > 15 || l < 7) { + return NO; + } + const char *str = domain.UTF8String; + if (str == nil) { + return NO; + } + + for (const char *p = str; p < str + l; p++) { + if ((*p < '0' || *p > '9') && *p != '.') { + return NO; + } + } + return YES; +} + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNMD5.h b/Pods/HappyDNS/HappyDNS/Util/QNMD5.h new file mode 100644 index 0000000..88ddfdb --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNMD5.h @@ -0,0 +1,15 @@ +// +// QNMD5.h +// HappyDNS_Mac +// +// Created by 何昊宇 on 2018/4/25. +// Copyright © 2018年 Qiniu Cloud Storage. All rights reserved. +// + +#import + +@interface QNMD5 : NSObject + ++(NSString *)MD5:(NSString *)string; + +@end diff --git a/Pods/HappyDNS/HappyDNS/Util/QNMD5.m b/Pods/HappyDNS/HappyDNS/Util/QNMD5.m new file mode 100644 index 0000000..ee7bf6c --- /dev/null +++ b/Pods/HappyDNS/HappyDNS/Util/QNMD5.m @@ -0,0 +1,28 @@ +// +// QNMD5.m +// HappyDNS_Mac +// +// Created by 何昊宇 on 2018/4/25. +// Copyright © 2018年 Qiniu Cloud Storage. All rights reserved. +// + +#import "QNMD5.h" +#import + +@implementation QNMD5 + ++ (NSString *)MD5:(NSString *)string{ + + const char* input = [string UTF8String]; + unsigned char result[CC_MD5_DIGEST_LENGTH]; + CC_MD5(input, (CC_LONG)strlen(input), result); + + NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; + for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { + [digest appendFormat:@"%02x", result[i]]; + } + + return digest; +} + +@end diff --git a/Pods/HappyDNS/LICENSE b/Pods/HappyDNS/LICENSE new file mode 100644 index 0000000..f635da2 --- /dev/null +++ b/Pods/HappyDNS/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Qiniu, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Pods/HappyDNS/README.md b/Pods/HappyDNS/README.md new file mode 100644 index 0000000..b005d33 --- /dev/null +++ b/Pods/HappyDNS/README.md @@ -0,0 +1,122 @@ +# Happy DNS for Objective-C + +[![@qiniu on weibo](http://img.shields.io/badge/weibo-%40qiniutek-blue.svg)](http://weibo.com/qiniutek) +[![LICENSE](https://img.shields.io/github/license/qiniu/happy-dns-objc.svg)](https://github.com/qiniu/happy-dns-objc/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/qiniu/happy-dns-objc.svg?branch=master)](https://travis-ci.org/qiniu/happy-dns-objc) +[![GitHub release](https://img.shields.io/github/v/tag/qiniu/happy-dns-objc.svg?label=release)](https://github.com/qiniu/happy-dns-objc/releases) +[![codecov](https://codecov.io/gh/qiniu/happy-dns-objc/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/happy-dns-objc) +![Platform](http://img.shields.io/cocoapods/p/HappyDNS.svg) + +## 用途 + +调用系统底层Dns解析库,可以使用 114 等第三方 dns 解析,可以使用 Doh 协议的 Dns 解析方案,也可以集成 dnspod 等 httpdns。另外也有丰富的 hosts 域名配置。 + +## 安装 + +通过 CocoaPods +```ruby +pod "HappyDNS" +``` + +通过 Swift Package Manager (Xcode 11+) +``` +App 对接: +File -> Swift Packages -> Add Package Dependency,输入 HappyDNS 库链接,选择相应版本即可 +库链接: https://github.com/qiniu/happy-dns-objc + +库对接: +let package = Package( + dependencies: [ + .package(url: "https://github.com/qiniu/happy-dns-objc", from: "1.0.4") + ], + // ... +) + +``` + +## 运行环境 + + +## 使用方法 +* 返回 IP 列表 +``` + NSMutableArray *array = [[NSMutableArray alloc] init]; +[array addObject:[QNResolver systemResolver]]; +[array addObject:[[QNResolver alloc] initWithAddress:@"119.29.29.29"]]; +[array addObject:[QNDohResolver resolverWithServer:@"https://dns.alidns.com/dns-query"]]; +QNDnsManager *dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]]; +NSArray *records = [dns queryRecords:@"www.qiniu.com"]; +``` +* url 请求,返回一个IP 替换URL 里的domain +``` +NSMutableArray *array = [[NSMutableArray alloc] init]; +[array addObject:[QNResolver systemResolver]]; +[array addObject:[[QNResolver alloc] initWithAddress:@"119.29.29.29"]]; +QNDnsManager *dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]]; +NSURL *u = [[NSURL alloc] initWithString:@"rtmp://www.qiniu.com/abc?q=1"]; +NSURL *u2 = [dns queryAndReplaceWithIP:u]; +``` +* 兼容 getaddrinfo, 方便底层 C 代码接入 +``` +static QNDnsManager *dns = nil; +dns = [[QNDnsManager alloc] init:@[ [QNResolver systemResolver] ] networkInfo:nil]; +[QNDnsManager setGetAddrInfoBlock:^NSArray *(NSString *host) { + return [dns query:host]; + }]; +struct addrinfo hints = {0}; +struct addrinfo *ai = NULL; +int x = qn_getaddrinfo(host, "http", &hints, &ai); +qn_freeaddrinfo(ai); // 也可以用系统的freeaddrinfo, 代码一致,不过最好用这个 +``` +### 运行测试 + +``` bash +$ xctool -workspace HappyDNS.xcworkspace -scheme "HappyDNS_Mac" -sdk macosx -configuration Release test -test-sdk macosx +``` + +### 指定测试 + +可以在单元测试上修改,熟悉使用 + +``` bash +``` + +## 常见问题 + +- 如果碰到其他编译错误,请参考 CocoaPods 的 [troubleshooting](http://guides.cocoapods.org/using/troubleshooting.html) +- httpdns 在**ios8** 时不支持 nat64 模式下 IP 直接访问url,原因是 NSUrlConnection 不支持。无论是用http://119.29.29.29/d 还是http://[64:ff9b::771d:1d1d]/d 都不行,此时可以使用localdns方式。 +- 如果软件有国外的使用情况时,建议初始化程序采取这样的方式 +```Objective-C +QNDnsManager *dns; +if([QNDnsManager needHttpDns]){ + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObject:[[QNResolver alloc] initWithAddress:@"119.29.29.29"]]; + [array addObject:[QNResolver systemResolver]]; + dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]]; +}else{ + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObject:[QNResolver systemResolver]]; + [array addObject:[[QNResolver alloc] initWithAddress:@"114.114.114.114"]]; + dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]]; +} +``` + +## 代码贡献 + +详情参考[代码提交指南](https://github.com/qiniu/happy-dns-objc/blob/master/CONTRIBUTING.md)。 + +## 贡献记录 + +- [所有贡献者](https://github.com/qiniu/happy-dns-objc/contributors) + +## 联系我们 + +- 如果有什么问题,可以到问答社区提问,[问答社区](http://qiniu.segmentfault.com/) +- 如果发现了bug, 欢迎提交 [issue](https://github.com/qiniu/happy-dns-objc/issues) +- 如果有功能需求,欢迎提交 [issue](https://github.com/qiniu/happy-dns-objc/issues) +- 如果要提交代码,欢迎提交 pull request +- 欢迎关注我们的[微信](http://www.qiniu.com/#weixin) [微博](http://weibo.com/qiniutek),及时获取动态信息。 + +## 代码许可 + +The MIT License (MIT).详情见 [License文件](https://github.com/qiniu/happy-dns-objc/blob/master/LICENSE). diff --git a/Pods/Headers/Private/HappyDNS/HappyDNS.h b/Pods/Headers/Private/HappyDNS/HappyDNS.h new file mode 120000 index 0000000..ff90e04 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/HappyDNS.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/HappyDNS.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/NSData+QNRW.h b/Pods/Headers/Private/HappyDNS/NSData+QNRW.h new file mode 120000 index 0000000..94a9f0b --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/NSData+QNRW.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/NSData+QNRW.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNAsyncUdpSocket.h b/Pods/Headers/Private/HappyDNS/QNAsyncUdpSocket.h new file mode 120000 index 0000000..cd290d4 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNAsyncUdpSocket.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDes.h b/Pods/Headers/Private/HappyDNS/QNDes.h new file mode 120000 index 0000000..6191c44 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDes.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNDes.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsDefine.h b/Pods/Headers/Private/HappyDNS/QNDnsDefine.h new file mode 120000 index 0000000..ce357a8 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsDefine.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsDefine.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsError.h b/Pods/Headers/Private/HappyDNS/QNDnsError.h new file mode 120000 index 0000000..420a84e --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsError.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNDnsError.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsManager.h b/Pods/Headers/Private/HappyDNS/QNDnsManager.h new file mode 120000 index 0000000..1346862 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsManager.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNDnsManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsMessage.h b/Pods/Headers/Private/HappyDNS/QNDnsMessage.h new file mode 120000 index 0000000..90ace90 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsMessage.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsMessage.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsRequest.h b/Pods/Headers/Private/HappyDNS/QNDnsRequest.h new file mode 120000 index 0000000..ea29157 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsRequest.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsRequest.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsResolver.h b/Pods/Headers/Private/HappyDNS/QNDnsResolver.h new file mode 120000 index 0000000..a1051fa --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsResolver.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsResponse.h b/Pods/Headers/Private/HappyDNS/QNDnsResponse.h new file mode 120000 index 0000000..c22fbc0 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsResponse.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsResponse.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnsUdpResolver.h b/Pods/Headers/Private/HappyDNS/QNDnsUdpResolver.h new file mode 120000 index 0000000..03284a7 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnsUdpResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDnspodEnterprise.h b/Pods/Headers/Private/HappyDNS/QNDnspodEnterprise.h new file mode 120000 index 0000000..80cd5fc --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDnspodEnterprise.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDohResolver.h b/Pods/Headers/Private/HappyDNS/QNDohResolver.h new file mode 120000 index 0000000..fb15080 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDohResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDohResolver.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNDomain.h b/Pods/Headers/Private/HappyDNS/QNDomain.h new file mode 120000 index 0000000..51f4104 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNDomain.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNDomain.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNGetAddrInfo.h b/Pods/Headers/Private/HappyDNS/QNGetAddrInfo.h new file mode 120000 index 0000000..26fed88 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNGetAddrInfo.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNGetAddrInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNHex.h b/Pods/Headers/Private/HappyDNS/QNHex.h new file mode 120000 index 0000000..4ed494c --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNHex.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNHex.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNHijackingDetectWrapper.h b/Pods/Headers/Private/HappyDNS/QNHijackingDetectWrapper.h new file mode 120000 index 0000000..2d69460 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNHijackingDetectWrapper.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNHosts.h b/Pods/Headers/Private/HappyDNS/QNHosts.h new file mode 120000 index 0000000..36b968d --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNHosts.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNHosts.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNIP.h b/Pods/Headers/Private/HappyDNS/QNIP.h new file mode 120000 index 0000000..26a6718 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNIP.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNIP.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNLruCache.h b/Pods/Headers/Private/HappyDNS/QNLruCache.h new file mode 120000 index 0000000..fdd32f1 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNLruCache.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNLruCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNMD5.h b/Pods/Headers/Private/HappyDNS/QNMD5.h new file mode 120000 index 0000000..e2b0e8f --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNMD5.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNMD5.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNNetworkInfo.h b/Pods/Headers/Private/HappyDNS/QNNetworkInfo.h new file mode 120000 index 0000000..04216b6 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNNetworkInfo.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNNetworkInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNRecord.h b/Pods/Headers/Private/HappyDNS/QNRecord.h new file mode 120000 index 0000000..55a4e6f --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNRecord.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNRecord.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNResolvUtil.h b/Pods/Headers/Private/HappyDNS/QNResolvUtil.h new file mode 120000 index 0000000..889e5b3 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNResolvUtil.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNResolvUtil.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNResolver.h b/Pods/Headers/Private/HappyDNS/QNResolver.h new file mode 120000 index 0000000..dc6f93c --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNResolver.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNResolverDelegate.h b/Pods/Headers/Private/HappyDNS/QNResolverDelegate.h new file mode 120000 index 0000000..6d29451 --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNResolverDelegate.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNResolverDelegate.h \ No newline at end of file diff --git a/Pods/Headers/Private/HappyDNS/QNTxtResolver.h b/Pods/Headers/Private/HappyDNS/QNTxtResolver.h new file mode 120000 index 0000000..5a1799f --- /dev/null +++ b/Pods/Headers/Private/HappyDNS/QNTxtResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNTxtResolver.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/NSData+QNGZip.h b/Pods/Headers/Private/Qiniu/NSData+QNGZip.h new file mode 120000 index 0000000..dee375d --- /dev/null +++ b/Pods/Headers/Private/Qiniu/NSData+QNGZip.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/NSData+QNGZip.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/NSData+QNMD5.h b/Pods/Headers/Private/Qiniu/NSData+QNMD5.h new file mode 120000 index 0000000..6e4114d --- /dev/null +++ b/Pods/Headers/Private/Qiniu/NSData+QNMD5.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/NSData+QNMD5.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/NSObject+QNSwizzle.h b/Pods/Headers/Private/Qiniu/NSObject+QNSwizzle.h new file mode 120000 index 0000000..daf36d0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/NSObject+QNSwizzle.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/NSURLRequest+QNRequest.h b/Pods/Headers/Private/Qiniu/NSURLRequest+QNRequest.h new file mode 120000 index 0000000..94c66e8 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/NSURLRequest+QNRequest.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNALAssetFile.h b/Pods/Headers/Private/Qiniu/QNALAssetFile.h new file mode 120000 index 0000000..b4b54e0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNALAssetFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNALAssetFile.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNAsyncRun.h b/Pods/Headers/Private/Qiniu/QNAsyncRun.h new file mode 120000 index 0000000..8a7ca71 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNAsyncRun.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNAsyncRun.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNAutoZone.h b/Pods/Headers/Private/Qiniu/QNAutoZone.h new file mode 120000 index 0000000..4477eb6 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNAutoZone.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNAutoZone.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNBaseUpload.h b/Pods/Headers/Private/Qiniu/QNBaseUpload.h new file mode 120000 index 0000000..f30abf8 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNBaseUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNBaseUpload.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNCFHttpClient.h b/Pods/Headers/Private/Qiniu/QNCFHttpClient.h new file mode 120000 index 0000000..5efc7f4 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNCFHttpClient.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNCFHttpClientInner.h b/Pods/Headers/Private/Qiniu/QNCFHttpClientInner.h new file mode 120000 index 0000000..8145b22 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNCFHttpClientInner.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNCFHttpThreadPool.h b/Pods/Headers/Private/Qiniu/QNCFHttpThreadPool.h new file mode 120000 index 0000000..0d6f647 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNCFHttpThreadPool.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNCache.h b/Pods/Headers/Private/Qiniu/QNCache.h new file mode 120000 index 0000000..c500868 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNCache.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNConcurrentResumeUpload.h b/Pods/Headers/Private/Qiniu/QNConcurrentResumeUpload.h new file mode 120000 index 0000000..e3792c0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNConcurrentResumeUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNConfig.h b/Pods/Headers/Private/Qiniu/QNConfig.h new file mode 120000 index 0000000..7744c6b --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNConfig.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNConfiguration.h b/Pods/Headers/Private/Qiniu/QNConfiguration.h new file mode 120000 index 0000000..bc0cf16 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNConfiguration.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNConfiguration.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNConnectChecker.h b/Pods/Headers/Private/Qiniu/QNConnectChecker.h new file mode 120000 index 0000000..cfc4689 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNConnectChecker.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNCrc32.h b/Pods/Headers/Private/Qiniu/QNCrc32.h new file mode 120000 index 0000000..f0eca56 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNCrc32.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNCrc32.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNDefine.h b/Pods/Headers/Private/Qiniu/QNDefine.h new file mode 120000 index 0000000..c7f2b11 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNDefine.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNDefine.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNDns.h b/Pods/Headers/Private/Qiniu/QNDns.h new file mode 120000 index 0000000..0ef9649 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNDns.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDns.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNDnsCacheFile.h b/Pods/Headers/Private/Qiniu/QNDnsCacheFile.h new file mode 120000 index 0000000..a34e23e --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNDnsCacheFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNDnsCacheInfo.h b/Pods/Headers/Private/Qiniu/QNDnsCacheInfo.h new file mode 120000 index 0000000..33eb5b5 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNDnsCacheInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNDnsPrefetch.h b/Pods/Headers/Private/Qiniu/QNDnsPrefetch.h new file mode 120000 index 0000000..8144f54 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNDnsPrefetch.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNErrorCode.h b/Pods/Headers/Private/Qiniu/QNErrorCode.h new file mode 120000 index 0000000..f0cdc19 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNErrorCode.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNErrorCode.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNEtag.h b/Pods/Headers/Private/Qiniu/QNEtag.h new file mode 120000 index 0000000..af36980 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNEtag.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNEtag.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNFile.h b/Pods/Headers/Private/Qiniu/QNFile.h new file mode 120000 index 0000000..5cf922c --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNFile.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNFileDelegate.h b/Pods/Headers/Private/Qiniu/QNFileDelegate.h new file mode 120000 index 0000000..61b43f8 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNFileDelegate.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNFileDelegate.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNFileRecorder.h b/Pods/Headers/Private/Qiniu/QNFileRecorder.h new file mode 120000 index 0000000..d37da5d --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNFileRecorder.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Recorder/QNFileRecorder.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNFixedZone.h b/Pods/Headers/Private/Qiniu/QNFixedZone.h new file mode 120000 index 0000000..2cdcdb1 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNFixedZone.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNFixedZone.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNFormUpload.h b/Pods/Headers/Private/Qiniu/QNFormUpload.h new file mode 120000 index 0000000..e06b00e --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNFormUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNFormUpload.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNHttpRegionRequest.h b/Pods/Headers/Private/Qiniu/QNHttpRegionRequest.h new file mode 120000 index 0000000..565dba0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNHttpRegionRequest.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNHttpSingleRequest.h b/Pods/Headers/Private/Qiniu/QNHttpSingleRequest.h new file mode 120000 index 0000000..f5f61f6 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNHttpSingleRequest.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNIUploadServer.h b/Pods/Headers/Private/Qiniu/QNIUploadServer.h new file mode 120000 index 0000000..0cc7c51 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNIUploadServer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNIUploadServer.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNInetAddress.h b/Pods/Headers/Private/Qiniu/QNInetAddress.h new file mode 120000 index 0000000..4a4ef92 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNInetAddress.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNInetAddress.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNLogUtil.h b/Pods/Headers/Private/Qiniu/QNLogUtil.h new file mode 120000 index 0000000..a6f7f88 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNLogUtil.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNLogUtil.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNMutableArray.h b/Pods/Headers/Private/Qiniu/QNMutableArray.h new file mode 120000 index 0000000..5b248e6 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNMutableArray.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNMutableArray.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNNetworkStatusManager.h b/Pods/Headers/Private/Qiniu/QNNetworkStatusManager.h new file mode 120000 index 0000000..9ad5d45 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNNetworkStatusManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPHAssetFile.h b/Pods/Headers/Private/Qiniu/QNPHAssetFile.h new file mode 120000 index 0000000..89fde44 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPHAssetFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNPHAssetFile.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPHAssetResource.h b/Pods/Headers/Private/Qiniu/QNPHAssetResource.h new file mode 120000 index 0000000..29cbba2 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPHAssetResource.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNPHAssetResource.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPartsUpload.h b/Pods/Headers/Private/Qiniu/QNPartsUpload.h new file mode 120000 index 0000000..257bf89 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPartsUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUpload.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPartsUploadPerformer.h b/Pods/Headers/Private/Qiniu/QNPartsUploadPerformer.h new file mode 120000 index 0000000..2fac265 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPartsUploadPerformer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPartsUploadPerformerV1.h b/Pods/Headers/Private/Qiniu/QNPartsUploadPerformerV1.h new file mode 120000 index 0000000..eda4913 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPartsUploadPerformerV1.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPartsUploadPerformerV2.h b/Pods/Headers/Private/Qiniu/QNPartsUploadPerformerV2.h new file mode 120000 index 0000000..43a8cac --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPartsUploadPerformerV2.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNPipeline.h b/Pods/Headers/Private/Qiniu/QNPipeline.h new file mode 120000 index 0000000..98d880e --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNPipeline.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/BigData/QNPipeline.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNRecorderDelegate.h b/Pods/Headers/Private/Qiniu/QNRecorderDelegate.h new file mode 120000 index 0000000..ab9f121 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNRecorderDelegate.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Recorder/QNRecorderDelegate.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNReportConfig.h b/Pods/Headers/Private/Qiniu/QNReportConfig.h new file mode 120000 index 0000000..85402e9 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNReportConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Collect/QNReportConfig.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNReportItem.h b/Pods/Headers/Private/Qiniu/QNReportItem.h new file mode 120000 index 0000000..c9e5188 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNReportItem.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Collect/QNReportItem.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNRequestClient.h b/Pods/Headers/Private/Qiniu/QNRequestClient.h new file mode 120000 index 0000000..b85c922 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNRequestClient.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNRequestClient.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNRequestTransaction.h b/Pods/Headers/Private/Qiniu/QNRequestTransaction.h new file mode 120000 index 0000000..bebed5f --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNRequestTransaction.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNResponseInfo.h b/Pods/Headers/Private/Qiniu/QNResponseInfo.h new file mode 120000 index 0000000..52c8cbd --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNResponseInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNResponseInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNServerConfig.h b/Pods/Headers/Private/Qiniu/QNServerConfig.h new file mode 120000 index 0000000..1a09c03 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNServerConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNServerConfigCache.h b/Pods/Headers/Private/Qiniu/QNServerConfigCache.h new file mode 120000 index 0000000..2aa0e5e --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNServerConfigCache.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNServerConfigMonitor.h b/Pods/Headers/Private/Qiniu/QNServerConfigMonitor.h new file mode 120000 index 0000000..3a946fb --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNServerConfigMonitor.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNServerConfigSynchronizer.h b/Pods/Headers/Private/Qiniu/QNServerConfigSynchronizer.h new file mode 120000 index 0000000..5e62a0e --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNServerConfigSynchronizer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNServerUserConfig.h b/Pods/Headers/Private/Qiniu/QNServerUserConfig.h new file mode 120000 index 0000000..312e3f6 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNServerUserConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNSessionManager.h b/Pods/Headers/Private/Qiniu/QNSessionManager.h new file mode 120000 index 0000000..ac67558 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNSessionManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/BigData/QNSessionManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNSingleFlight.h b/Pods/Headers/Private/Qiniu/QNSingleFlight.h new file mode 120000 index 0000000..3f5daa0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNSingleFlight.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNSingleFlight.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNSystem.h b/Pods/Headers/Private/Qiniu/QNSystem.h new file mode 120000 index 0000000..41dfbb4 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNSystem.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNSystem.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNTransactionManager.h b/Pods/Headers/Private/Qiniu/QNTransactionManager.h new file mode 120000 index 0000000..edcce6e --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNTransactionManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Transaction/QNTransactionManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUpProgress.h b/Pods/Headers/Private/Qiniu/QNUpProgress.h new file mode 120000 index 0000000..2480c93 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUpProgress.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUpProgress.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUpToken.h b/Pods/Headers/Private/Qiniu/QNUpToken.h new file mode 120000 index 0000000..ec9be2a --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUpToken.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUpToken.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadBlock.h b/Pods/Headers/Private/Qiniu/QNUploadBlock.h new file mode 120000 index 0000000..2681415 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadBlock.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadBlock.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadData.h b/Pods/Headers/Private/Qiniu/QNUploadData.h new file mode 120000 index 0000000..dce9752 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadData.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadData.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadDomainRegion.h b/Pods/Headers/Private/Qiniu/QNUploadDomainRegion.h new file mode 120000 index 0000000..fe02cbb --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadDomainRegion.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadInfo.h b/Pods/Headers/Private/Qiniu/QNUploadInfo.h new file mode 120000 index 0000000..64ceac5 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadInfoReporter.h b/Pods/Headers/Private/Qiniu/QNUploadInfoReporter.h new file mode 120000 index 0000000..11fbd64 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadInfoReporter.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadInfoV1.h b/Pods/Headers/Private/Qiniu/QNUploadInfoV1.h new file mode 120000 index 0000000..2ac7940 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadInfoV1.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadInfoV2.h b/Pods/Headers/Private/Qiniu/QNUploadInfoV2.h new file mode 120000 index 0000000..dc0d3a1 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadInfoV2.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadManager.h b/Pods/Headers/Private/Qiniu/QNUploadManager.h new file mode 120000 index 0000000..0245f71 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadOption.h b/Pods/Headers/Private/Qiniu/QNUploadOption.h new file mode 120000 index 0000000..aceaf38 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadOption.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadOption.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadRegionInfo.h b/Pods/Headers/Private/Qiniu/QNUploadRegionInfo.h new file mode 120000 index 0000000..62ecb19 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadRegionInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNUploadRegionInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadRequestInfo.h b/Pods/Headers/Private/Qiniu/QNUploadRequestInfo.h new file mode 120000 index 0000000..3f95299 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadRequestInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadRequestMetrics.h b/Pods/Headers/Private/Qiniu/QNUploadRequestMetrics.h new file mode 120000 index 0000000..60f49f9 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadRequestMetrics.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadRequestState.h b/Pods/Headers/Private/Qiniu/QNUploadRequestState.h new file mode 120000 index 0000000..4c3b2dd --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadRequestState.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNUploadRequestState.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadServer.h b/Pods/Headers/Private/Qiniu/QNUploadServer.h new file mode 120000 index 0000000..d1539e3 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadServer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadServerFreezeManager.h b/Pods/Headers/Private/Qiniu/QNUploadServerFreezeManager.h new file mode 120000 index 0000000..75ba650 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadServerFreezeManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadServerFreezeUtil.h b/Pods/Headers/Private/Qiniu/QNUploadServerFreezeUtil.h new file mode 120000 index 0000000..24282d3 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadServerFreezeUtil.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadServerNetworkStatus.h b/Pods/Headers/Private/Qiniu/QNUploadServerNetworkStatus.h new file mode 120000 index 0000000..01901ed --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadServerNetworkStatus.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadSource.h b/Pods/Headers/Private/Qiniu/QNUploadSource.h new file mode 120000 index 0000000..5c27c60 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadSource.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadSource.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadSourceFile.h b/Pods/Headers/Private/Qiniu/QNUploadSourceFile.h new file mode 120000 index 0000000..9d77ab0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadSourceFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadSourceStream.h b/Pods/Headers/Private/Qiniu/QNUploadSourceStream.h new file mode 120000 index 0000000..a288d00 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadSourceStream.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUploadSystemClient.h b/Pods/Headers/Private/Qiniu/QNUploadSystemClient.h new file mode 120000 index 0000000..562b4b3 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUploadSystemClient.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUrlSafeBase64.h b/Pods/Headers/Private/Qiniu/QNUrlSafeBase64.h new file mode 120000 index 0000000..e9cdd76 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUrlSafeBase64.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUrlUtils.h b/Pods/Headers/Private/Qiniu/QNUrlUtils.h new file mode 120000 index 0000000..30e2e40 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUrlUtils.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNUrlUtils.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUserAgent.h b/Pods/Headers/Private/Qiniu/QNUserAgent.h new file mode 120000 index 0000000..3161068 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUserAgent.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNUserAgent.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNUtils.h b/Pods/Headers/Private/Qiniu/QNUtils.h new file mode 120000 index 0000000..38dfbd4 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNUtils.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNUtils.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNVersion.h b/Pods/Headers/Private/Qiniu/QNVersion.h new file mode 120000 index 0000000..8616ad0 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNVersion.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNVersion.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNZone.h b/Pods/Headers/Private/Qiniu/QNZone.h new file mode 120000 index 0000000..f3875a3 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNZone.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNZone.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QNZoneInfo.h b/Pods/Headers/Private/Qiniu/QNZoneInfo.h new file mode 120000 index 0000000..555f143 --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QNZoneInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNZoneInfo.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QN_GTM_Base64.h b/Pods/Headers/Private/Qiniu/QN_GTM_Base64.h new file mode 120000 index 0000000..3af4d1d --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QN_GTM_Base64.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QN_GTM_Base64.h \ No newline at end of file diff --git a/Pods/Headers/Private/Qiniu/QiniuSDK.h b/Pods/Headers/Private/Qiniu/QiniuSDK.h new file mode 120000 index 0000000..d2292bb --- /dev/null +++ b/Pods/Headers/Private/Qiniu/QiniuSDK.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/QiniuSDK.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/HappyDNS.h b/Pods/Headers/Public/HappyDNS/HappyDNS.h new file mode 120000 index 0000000..ff90e04 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/HappyDNS.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/HappyDNS.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/NSData+QNRW.h b/Pods/Headers/Public/HappyDNS/NSData+QNRW.h new file mode 120000 index 0000000..94a9f0b --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/NSData+QNRW.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/NSData+QNRW.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNAsyncUdpSocket.h b/Pods/Headers/Public/HappyDNS/QNAsyncUdpSocket.h new file mode 120000 index 0000000..cd290d4 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNAsyncUdpSocket.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDes.h b/Pods/Headers/Public/HappyDNS/QNDes.h new file mode 120000 index 0000000..6191c44 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDes.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNDes.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsDefine.h b/Pods/Headers/Public/HappyDNS/QNDnsDefine.h new file mode 120000 index 0000000..ce357a8 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsDefine.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsDefine.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsError.h b/Pods/Headers/Public/HappyDNS/QNDnsError.h new file mode 120000 index 0000000..420a84e --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsError.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNDnsError.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsManager.h b/Pods/Headers/Public/HappyDNS/QNDnsManager.h new file mode 120000 index 0000000..1346862 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsManager.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNDnsManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsMessage.h b/Pods/Headers/Public/HappyDNS/QNDnsMessage.h new file mode 120000 index 0000000..90ace90 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsMessage.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsMessage.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsRequest.h b/Pods/Headers/Public/HappyDNS/QNDnsRequest.h new file mode 120000 index 0000000..ea29157 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsRequest.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsRequest.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsResolver.h b/Pods/Headers/Public/HappyDNS/QNDnsResolver.h new file mode 120000 index 0000000..a1051fa --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsResolver.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsResponse.h b/Pods/Headers/Public/HappyDNS/QNDnsResponse.h new file mode 120000 index 0000000..c22fbc0 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsResponse.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsResponse.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnsUdpResolver.h b/Pods/Headers/Public/HappyDNS/QNDnsUdpResolver.h new file mode 120000 index 0000000..03284a7 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnsUdpResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDnspodEnterprise.h b/Pods/Headers/Public/HappyDNS/QNDnspodEnterprise.h new file mode 120000 index 0000000..80cd5fc --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDnspodEnterprise.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDohResolver.h b/Pods/Headers/Public/HappyDNS/QNDohResolver.h new file mode 120000 index 0000000..fb15080 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDohResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Dns/QNDohResolver.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNDomain.h b/Pods/Headers/Public/HappyDNS/QNDomain.h new file mode 120000 index 0000000..51f4104 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNDomain.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNDomain.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNGetAddrInfo.h b/Pods/Headers/Public/HappyDNS/QNGetAddrInfo.h new file mode 120000 index 0000000..26fed88 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNGetAddrInfo.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNGetAddrInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNHex.h b/Pods/Headers/Public/HappyDNS/QNHex.h new file mode 120000 index 0000000..4ed494c --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNHex.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNHex.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNHijackingDetectWrapper.h b/Pods/Headers/Public/HappyDNS/QNHijackingDetectWrapper.h new file mode 120000 index 0000000..2d69460 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNHijackingDetectWrapper.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNHosts.h b/Pods/Headers/Public/HappyDNS/QNHosts.h new file mode 120000 index 0000000..36b968d --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNHosts.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNHosts.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNIP.h b/Pods/Headers/Public/HappyDNS/QNIP.h new file mode 120000 index 0000000..26a6718 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNIP.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNIP.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNLruCache.h b/Pods/Headers/Public/HappyDNS/QNLruCache.h new file mode 120000 index 0000000..fdd32f1 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNLruCache.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNLruCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNMD5.h b/Pods/Headers/Public/HappyDNS/QNMD5.h new file mode 120000 index 0000000..e2b0e8f --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNMD5.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Util/QNMD5.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNNetworkInfo.h b/Pods/Headers/Public/HappyDNS/QNNetworkInfo.h new file mode 120000 index 0000000..04216b6 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNNetworkInfo.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNNetworkInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNRecord.h b/Pods/Headers/Public/HappyDNS/QNRecord.h new file mode 120000 index 0000000..55a4e6f --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNRecord.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNRecord.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNResolvUtil.h b/Pods/Headers/Public/HappyDNS/QNResolvUtil.h new file mode 120000 index 0000000..889e5b3 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNResolvUtil.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNResolvUtil.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNResolver.h b/Pods/Headers/Public/HappyDNS/QNResolver.h new file mode 120000 index 0000000..dc6f93c --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNResolver.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNResolverDelegate.h b/Pods/Headers/Public/HappyDNS/QNResolverDelegate.h new file mode 120000 index 0000000..6d29451 --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNResolverDelegate.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Common/QNResolverDelegate.h \ No newline at end of file diff --git a/Pods/Headers/Public/HappyDNS/QNTxtResolver.h b/Pods/Headers/Public/HappyDNS/QNTxtResolver.h new file mode 120000 index 0000000..5a1799f --- /dev/null +++ b/Pods/Headers/Public/HappyDNS/QNTxtResolver.h @@ -0,0 +1 @@ +../../../HappyDNS/HappyDNS/Local/QNTxtResolver.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/NSData+QNGZip.h b/Pods/Headers/Public/Qiniu/NSData+QNGZip.h new file mode 120000 index 0000000..dee375d --- /dev/null +++ b/Pods/Headers/Public/Qiniu/NSData+QNGZip.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/NSData+QNGZip.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/NSData+QNMD5.h b/Pods/Headers/Public/Qiniu/NSData+QNMD5.h new file mode 120000 index 0000000..6e4114d --- /dev/null +++ b/Pods/Headers/Public/Qiniu/NSData+QNMD5.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/NSData+QNMD5.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/NSObject+QNSwizzle.h b/Pods/Headers/Public/Qiniu/NSObject+QNSwizzle.h new file mode 120000 index 0000000..daf36d0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/NSObject+QNSwizzle.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/NSURLRequest+QNRequest.h b/Pods/Headers/Public/Qiniu/NSURLRequest+QNRequest.h new file mode 120000 index 0000000..94c66e8 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/NSURLRequest+QNRequest.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNALAssetFile.h b/Pods/Headers/Public/Qiniu/QNALAssetFile.h new file mode 120000 index 0000000..b4b54e0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNALAssetFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNALAssetFile.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNAsyncRun.h b/Pods/Headers/Public/Qiniu/QNAsyncRun.h new file mode 120000 index 0000000..8a7ca71 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNAsyncRun.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNAsyncRun.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNAutoZone.h b/Pods/Headers/Public/Qiniu/QNAutoZone.h new file mode 120000 index 0000000..4477eb6 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNAutoZone.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNAutoZone.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNBaseUpload.h b/Pods/Headers/Public/Qiniu/QNBaseUpload.h new file mode 120000 index 0000000..f30abf8 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNBaseUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNBaseUpload.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNCFHttpClient.h b/Pods/Headers/Public/Qiniu/QNCFHttpClient.h new file mode 120000 index 0000000..5efc7f4 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNCFHttpClient.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNCFHttpClientInner.h b/Pods/Headers/Public/Qiniu/QNCFHttpClientInner.h new file mode 120000 index 0000000..8145b22 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNCFHttpClientInner.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNCFHttpThreadPool.h b/Pods/Headers/Public/Qiniu/QNCFHttpThreadPool.h new file mode 120000 index 0000000..0d6f647 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNCFHttpThreadPool.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNCache.h b/Pods/Headers/Public/Qiniu/QNCache.h new file mode 120000 index 0000000..c500868 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNCache.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNConcurrentResumeUpload.h b/Pods/Headers/Public/Qiniu/QNConcurrentResumeUpload.h new file mode 120000 index 0000000..e3792c0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNConcurrentResumeUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNConfig.h b/Pods/Headers/Public/Qiniu/QNConfig.h new file mode 120000 index 0000000..7744c6b --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNConfig.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNConfiguration.h b/Pods/Headers/Public/Qiniu/QNConfiguration.h new file mode 120000 index 0000000..bc0cf16 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNConfiguration.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNConfiguration.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNConnectChecker.h b/Pods/Headers/Public/Qiniu/QNConnectChecker.h new file mode 120000 index 0000000..cfc4689 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNConnectChecker.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNCrc32.h b/Pods/Headers/Public/Qiniu/QNCrc32.h new file mode 120000 index 0000000..f0eca56 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNCrc32.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNCrc32.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNDefine.h b/Pods/Headers/Public/Qiniu/QNDefine.h new file mode 120000 index 0000000..c7f2b11 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNDefine.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNDefine.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNDns.h b/Pods/Headers/Public/Qiniu/QNDns.h new file mode 120000 index 0000000..0ef9649 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNDns.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDns.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNDnsCacheFile.h b/Pods/Headers/Public/Qiniu/QNDnsCacheFile.h new file mode 120000 index 0000000..a34e23e --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNDnsCacheFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNDnsCacheInfo.h b/Pods/Headers/Public/Qiniu/QNDnsCacheInfo.h new file mode 120000 index 0000000..33eb5b5 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNDnsCacheInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNDnsPrefetch.h b/Pods/Headers/Public/Qiniu/QNDnsPrefetch.h new file mode 120000 index 0000000..8144f54 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNDnsPrefetch.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNErrorCode.h b/Pods/Headers/Public/Qiniu/QNErrorCode.h new file mode 120000 index 0000000..f0cdc19 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNErrorCode.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNErrorCode.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNEtag.h b/Pods/Headers/Public/Qiniu/QNEtag.h new file mode 120000 index 0000000..af36980 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNEtag.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNEtag.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNFile.h b/Pods/Headers/Public/Qiniu/QNFile.h new file mode 120000 index 0000000..5cf922c --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNFile.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNFileDelegate.h b/Pods/Headers/Public/Qiniu/QNFileDelegate.h new file mode 120000 index 0000000..61b43f8 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNFileDelegate.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNFileDelegate.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNFileRecorder.h b/Pods/Headers/Public/Qiniu/QNFileRecorder.h new file mode 120000 index 0000000..d37da5d --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNFileRecorder.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Recorder/QNFileRecorder.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNFixedZone.h b/Pods/Headers/Public/Qiniu/QNFixedZone.h new file mode 120000 index 0000000..2cdcdb1 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNFixedZone.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNFixedZone.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNFormUpload.h b/Pods/Headers/Public/Qiniu/QNFormUpload.h new file mode 120000 index 0000000..e06b00e --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNFormUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNFormUpload.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNHttpRegionRequest.h b/Pods/Headers/Public/Qiniu/QNHttpRegionRequest.h new file mode 120000 index 0000000..565dba0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNHttpRegionRequest.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNHttpSingleRequest.h b/Pods/Headers/Public/Qiniu/QNHttpSingleRequest.h new file mode 120000 index 0000000..f5f61f6 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNHttpSingleRequest.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNIUploadServer.h b/Pods/Headers/Public/Qiniu/QNIUploadServer.h new file mode 120000 index 0000000..0cc7c51 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNIUploadServer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNIUploadServer.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNInetAddress.h b/Pods/Headers/Public/Qiniu/QNInetAddress.h new file mode 120000 index 0000000..4a4ef92 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNInetAddress.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Dns/QNInetAddress.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNLogUtil.h b/Pods/Headers/Public/Qiniu/QNLogUtil.h new file mode 120000 index 0000000..a6f7f88 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNLogUtil.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNLogUtil.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNMutableArray.h b/Pods/Headers/Public/Qiniu/QNMutableArray.h new file mode 120000 index 0000000..5b248e6 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNMutableArray.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNMutableArray.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNNetworkStatusManager.h b/Pods/Headers/Public/Qiniu/QNNetworkStatusManager.h new file mode 120000 index 0000000..9ad5d45 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNNetworkStatusManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPHAssetFile.h b/Pods/Headers/Public/Qiniu/QNPHAssetFile.h new file mode 120000 index 0000000..89fde44 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPHAssetFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNPHAssetFile.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPHAssetResource.h b/Pods/Headers/Public/Qiniu/QNPHAssetResource.h new file mode 120000 index 0000000..29cbba2 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPHAssetResource.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNPHAssetResource.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPartsUpload.h b/Pods/Headers/Public/Qiniu/QNPartsUpload.h new file mode 120000 index 0000000..257bf89 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPartsUpload.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUpload.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPartsUploadPerformer.h b/Pods/Headers/Public/Qiniu/QNPartsUploadPerformer.h new file mode 120000 index 0000000..2fac265 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPartsUploadPerformer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPartsUploadPerformerV1.h b/Pods/Headers/Public/Qiniu/QNPartsUploadPerformerV1.h new file mode 120000 index 0000000..eda4913 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPartsUploadPerformerV1.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPartsUploadPerformerV2.h b/Pods/Headers/Public/Qiniu/QNPartsUploadPerformerV2.h new file mode 120000 index 0000000..43a8cac --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPartsUploadPerformerV2.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNPipeline.h b/Pods/Headers/Public/Qiniu/QNPipeline.h new file mode 120000 index 0000000..98d880e --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNPipeline.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/BigData/QNPipeline.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNRecorderDelegate.h b/Pods/Headers/Public/Qiniu/QNRecorderDelegate.h new file mode 120000 index 0000000..ab9f121 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNRecorderDelegate.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Recorder/QNRecorderDelegate.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNReportConfig.h b/Pods/Headers/Public/Qiniu/QNReportConfig.h new file mode 120000 index 0000000..85402e9 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNReportConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Collect/QNReportConfig.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNReportItem.h b/Pods/Headers/Public/Qiniu/QNReportItem.h new file mode 120000 index 0000000..c9e5188 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNReportItem.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Collect/QNReportItem.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNRequestClient.h b/Pods/Headers/Public/Qiniu/QNRequestClient.h new file mode 120000 index 0000000..b85c922 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNRequestClient.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNRequestClient.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNRequestTransaction.h b/Pods/Headers/Public/Qiniu/QNRequestTransaction.h new file mode 120000 index 0000000..bebed5f --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNRequestTransaction.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNResponseInfo.h b/Pods/Headers/Public/Qiniu/QNResponseInfo.h new file mode 120000 index 0000000..52c8cbd --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNResponseInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNResponseInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNServerConfig.h b/Pods/Headers/Public/Qiniu/QNServerConfig.h new file mode 120000 index 0000000..1a09c03 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNServerConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNServerConfigCache.h b/Pods/Headers/Public/Qiniu/QNServerConfigCache.h new file mode 120000 index 0000000..2aa0e5e --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNServerConfigCache.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNServerConfigMonitor.h b/Pods/Headers/Public/Qiniu/QNServerConfigMonitor.h new file mode 120000 index 0000000..3a946fb --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNServerConfigMonitor.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNServerConfigSynchronizer.h b/Pods/Headers/Public/Qiniu/QNServerConfigSynchronizer.h new file mode 120000 index 0000000..5e62a0e --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNServerConfigSynchronizer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNServerUserConfig.h b/Pods/Headers/Public/Qiniu/QNServerUserConfig.h new file mode 120000 index 0000000..312e3f6 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNServerUserConfig.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNSessionManager.h b/Pods/Headers/Public/Qiniu/QNSessionManager.h new file mode 120000 index 0000000..ac67558 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNSessionManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/BigData/QNSessionManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNSingleFlight.h b/Pods/Headers/Public/Qiniu/QNSingleFlight.h new file mode 120000 index 0000000..3f5daa0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNSingleFlight.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNSingleFlight.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNSystem.h b/Pods/Headers/Public/Qiniu/QNSystem.h new file mode 120000 index 0000000..41dfbb4 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNSystem.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNSystem.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNTransactionManager.h b/Pods/Headers/Public/Qiniu/QNTransactionManager.h new file mode 120000 index 0000000..edcce6e --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNTransactionManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Transaction/QNTransactionManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUpProgress.h b/Pods/Headers/Public/Qiniu/QNUpProgress.h new file mode 120000 index 0000000..2480c93 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUpProgress.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUpProgress.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUpToken.h b/Pods/Headers/Public/Qiniu/QNUpToken.h new file mode 120000 index 0000000..ec9be2a --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUpToken.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUpToken.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadBlock.h b/Pods/Headers/Public/Qiniu/QNUploadBlock.h new file mode 120000 index 0000000..2681415 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadBlock.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadBlock.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadData.h b/Pods/Headers/Public/Qiniu/QNUploadData.h new file mode 120000 index 0000000..dce9752 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadData.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadData.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadDomainRegion.h b/Pods/Headers/Public/Qiniu/QNUploadDomainRegion.h new file mode 120000 index 0000000..fe02cbb --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadDomainRegion.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadInfo.h b/Pods/Headers/Public/Qiniu/QNUploadInfo.h new file mode 120000 index 0000000..64ceac5 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadInfoReporter.h b/Pods/Headers/Public/Qiniu/QNUploadInfoReporter.h new file mode 120000 index 0000000..11fbd64 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadInfoReporter.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadInfoV1.h b/Pods/Headers/Public/Qiniu/QNUploadInfoV1.h new file mode 120000 index 0000000..2ac7940 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadInfoV1.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadInfoV2.h b/Pods/Headers/Public/Qiniu/QNUploadInfoV2.h new file mode 120000 index 0000000..dc0d3a1 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadInfoV2.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadManager.h b/Pods/Headers/Public/Qiniu/QNUploadManager.h new file mode 120000 index 0000000..0245f71 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadOption.h b/Pods/Headers/Public/Qiniu/QNUploadOption.h new file mode 120000 index 0000000..aceaf38 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadOption.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadOption.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadRegionInfo.h b/Pods/Headers/Public/Qiniu/QNUploadRegionInfo.h new file mode 120000 index 0000000..62ecb19 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadRegionInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNUploadRegionInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadRequestInfo.h b/Pods/Headers/Public/Qiniu/QNUploadRequestInfo.h new file mode 120000 index 0000000..3f95299 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadRequestInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadRequestMetrics.h b/Pods/Headers/Public/Qiniu/QNUploadRequestMetrics.h new file mode 120000 index 0000000..60f49f9 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadRequestMetrics.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadRequestState.h b/Pods/Headers/Public/Qiniu/QNUploadRequestState.h new file mode 120000 index 0000000..4c3b2dd --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadRequestState.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNUploadRequestState.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadServer.h b/Pods/Headers/Public/Qiniu/QNUploadServer.h new file mode 120000 index 0000000..d1539e3 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadServer.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadServerFreezeManager.h b/Pods/Headers/Public/Qiniu/QNUploadServerFreezeManager.h new file mode 120000 index 0000000..75ba650 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadServerFreezeManager.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadServerFreezeUtil.h b/Pods/Headers/Public/Qiniu/QNUploadServerFreezeUtil.h new file mode 120000 index 0000000..24282d3 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadServerFreezeUtil.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadServerNetworkStatus.h b/Pods/Headers/Public/Qiniu/QNUploadServerNetworkStatus.h new file mode 120000 index 0000000..01901ed --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadServerNetworkStatus.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadSource.h b/Pods/Headers/Public/Qiniu/QNUploadSource.h new file mode 120000 index 0000000..5c27c60 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadSource.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadSource.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadSourceFile.h b/Pods/Headers/Public/Qiniu/QNUploadSourceFile.h new file mode 120000 index 0000000..9d77ab0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadSourceFile.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadSourceStream.h b/Pods/Headers/Public/Qiniu/QNUploadSourceStream.h new file mode 120000 index 0000000..a288d00 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadSourceStream.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUploadSystemClient.h b/Pods/Headers/Public/Qiniu/QNUploadSystemClient.h new file mode 120000 index 0000000..562b4b3 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUploadSystemClient.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUrlSafeBase64.h b/Pods/Headers/Public/Qiniu/QNUrlSafeBase64.h new file mode 120000 index 0000000..e9cdd76 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUrlSafeBase64.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUrlUtils.h b/Pods/Headers/Public/Qiniu/QNUrlUtils.h new file mode 120000 index 0000000..30e2e40 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUrlUtils.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNUrlUtils.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUserAgent.h b/Pods/Headers/Public/Qiniu/QNUserAgent.h new file mode 120000 index 0000000..3161068 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUserAgent.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Http/QNUserAgent.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNUtils.h b/Pods/Headers/Public/Qiniu/QNUtils.h new file mode 120000 index 0000000..38dfbd4 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNUtils.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNUtils.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNVersion.h b/Pods/Headers/Public/Qiniu/QNVersion.h new file mode 120000 index 0000000..8616ad0 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNVersion.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QNVersion.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNZone.h b/Pods/Headers/Public/Qiniu/QNZone.h new file mode 120000 index 0000000..f3875a3 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNZone.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNZone.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QNZoneInfo.h b/Pods/Headers/Public/Qiniu/QNZoneInfo.h new file mode 120000 index 0000000..555f143 --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QNZoneInfo.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Common/QNZoneInfo.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QN_GTM_Base64.h b/Pods/Headers/Public/Qiniu/QN_GTM_Base64.h new file mode 120000 index 0000000..3af4d1d --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QN_GTM_Base64.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/Utils/QN_GTM_Base64.h \ No newline at end of file diff --git a/Pods/Headers/Public/Qiniu/QiniuSDK.h b/Pods/Headers/Public/Qiniu/QiniuSDK.h new file mode 120000 index 0000000..d2292bb --- /dev/null +++ b/Pods/Headers/Public/Qiniu/QiniuSDK.h @@ -0,0 +1 @@ +../../../Qiniu/QiniuSDK/QiniuSDK.h \ No newline at end of file diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..03f6997 --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,20 @@ +PODS: + - HappyDNS (1.0.4) + - Qiniu (8.8.1): + - HappyDNS (~> 1.0.4) + +DEPENDENCIES: + - Qiniu (~> 8.0) + +SPEC REPOS: + https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git: + - HappyDNS + - Qiniu + +SPEC CHECKSUMS: + HappyDNS: aefbd28cdcda93cffac64013dfe3342a2f87ed0a + Qiniu: 37131e52fdf43fe70da0c89dd0df3c9ce25bb74b + +PODFILE CHECKSUM: 4aa3a53aaead366c96efe2b5f93ec0e4c4468bc0 + +COCOAPODS: 1.15.2 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..60c7403 --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1769 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 02A083AEC78EF330E5C39206EB889767 /* HappyDNS.h in Headers */ = {isa = PBXBuildFile; fileRef = D09D565D1E250BA14443C5CB9EE9E121 /* HappyDNS.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 03CF2E60A1FB26757508B214FC87799B /* QNPartsUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE2EC2EAB1D927C6F8AC74197397801 /* QNPartsUpload.m */; }; + 04B893D78D27F949C3D4277A55F8D901 /* QNCFHttpThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = A2042A4CAAD516E394F5E58CB98F4F67 /* QNCFHttpThreadPool.m */; }; + 06CAA44656EE8D6DF0BAA7DF05E4E688 /* QNCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 028A189C700ACF2B6BC166A38D700E4F /* QNCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 06F1903F54A8DDF66A82D2E5D537C317 /* QNUploadBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B32FC01328C766500672A215C59451D /* QNUploadBlock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 07A097D3A80AD5C1C15390FF67FC3D43 /* QNTxtResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = F94078825997C7453132A941A4043D93 /* QNTxtResolver.m */; }; + 0AF4318A84E386CAA327F9486CE33305 /* QNHttpRegionRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC025156C6D660168C76A14CCEF4D16 /* QNHttpRegionRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0BD4BEF49315D4B86ADB42814F5D1717 /* QNServerConfigSynchronizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 094C51DA204B14E7F7F9BD450C4F238B /* QNServerConfigSynchronizer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0D0833AA36AECB16625AA706D5944377 /* NSData+QNGZip.h in Headers */ = {isa = PBXBuildFile; fileRef = 44CFFF5253D00A2A2A8EB8C49651B310 /* NSData+QNGZip.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0D22728A968DA2F4795180502772A312 /* QNAsyncRun.h in Headers */ = {isa = PBXBuildFile; fileRef = 05E66D896E39EA29440DA388C7E7D6AE /* QNAsyncRun.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0D7177D8F5C17A34D11F62BD372829D6 /* QNDnsResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = 78717F975ACB392DA55804B14D6A4FE9 /* QNDnsResolver.m */; }; + 0E90885C76402D175D402F00667EF458 /* QNRequestTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B8002C86FF660BE74F43AE588C4FF5C /* QNRequestTransaction.m */; }; + 0ECFDB569CD22BCC653C059D0C22AEF6 /* QNRecorderDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 057857FCC29DFF01C90D8B01B5DA5DBC /* QNRecorderDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1326830E2575C410AFF33BCCC359EEE4 /* QNResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = F9BA7D8B8AA8EBA304E0145EE6948CF7 /* QNResolver.m */; }; + 135D4A975978A237714038BB97457759 /* QNUserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 59AAA1299154D08C7063B7BBB53FDA90 /* QNUserAgent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 13EC910AF995F97C00865AE9E4D27968 /* QNConnectChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCE804B544C9595D683E96A3E7E2677 /* QNConnectChecker.m */; }; + 1402D3398B3BCDAFAE7AC853E9836B5B /* QNDes.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E5EC0DED9848A2FE8A0306B981392D /* QNDes.m */; }; + 14ED80411BF849B1E2486A95736D170B /* QNEtag.m in Sources */ = {isa = PBXBuildFile; fileRef = D91F08368AAE25D4490CD8D3D057C75A /* QNEtag.m */; }; + 150258D2108F43868AE5A2DD52A9C35A /* QNAutoZone.m in Sources */ = {isa = PBXBuildFile; fileRef = A63AF106E1DDEEBA3B15178E7DFDB2D6 /* QNAutoZone.m */; }; + 15D304827B03F9132761E5B0BCEEBCA1 /* NSData+QNRW.h in Headers */ = {isa = PBXBuildFile; fileRef = F2E92BA3056D35FF76FF9577CBCEAF3B /* NSData+QNRW.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1700E3D64E8F4C4FBB222AC931E91772 /* QNRequestTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C04D7E0CD2BFD4CA3473BFB67D94948 /* QNRequestTransaction.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 173A5425E1E35DA2166549F45720D174 /* QNZoneInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A623EA2BD31BC270E877148FBAD5114 /* QNZoneInfo.m */; }; + 18D0BD421372CC4E0E57CA5E4E5154C3 /* QNDnsRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9F59C91B1A3769BCE5FDF891A9A7BD /* QNDnsRequest.m */; }; + 1C8490F9EECBD7EA0603EC530BC48FD3 /* QNMutableArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 418E1B7F76831263DC2AF0D63297F6D8 /* QNMutableArray.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1D441B98373562CCA7FB95D76753D272 /* QNFormUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7C504D96C137090D555AB79D5FAF1 /* QNFormUpload.m */; }; + 1EE96E29E503FFD4B215E6DBACCFE9AA /* QNUploadBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 585CD993F6AFD84EA26ED2C66323D21B /* QNUploadBlock.m */; }; + 21D27E481AA7957CE62DEE8A56F2D9DD /* QNResponseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FD28D7585D033EAC425B8EC3F7F0C899 /* QNResponseInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2398FC53D239AC5DFA888BF380600933 /* QNHex.m in Sources */ = {isa = PBXBuildFile; fileRef = A0931AAEFF7DC633008639C7FC4F94A5 /* QNHex.m */; }; + 2451555DE2EAD5C7C006BEAA459AED91 /* QNHosts.h in Headers */ = {isa = PBXBuildFile; fileRef = 7F9F4BCBAA7B2EC9BC06267BCBB67794 /* QNHosts.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 24597D2833A7ACCD165103B39EA93595 /* QNUrlUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 20B62CDF9AE854DEA6014419025D9CCF /* QNUrlUtils.m */; }; + 26646F43D02499FE87DA1BE49BA5B7FF /* QNBaseUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 2778E90F840997960E8B3B55F7C4212F /* QNBaseUpload.m */; }; + 27F0E87B9DFC06E515C2C5FC1FAFD5F2 /* QNSingleFlight.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EE6448CDF48B5C634F2DF06BE1E61DD /* QNSingleFlight.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 28E32DFEFA19DFD9E0263C6A984B991B /* QNServerConfigCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 274039B1888766E5D9B1F50DF56F622A /* QNServerConfigCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2959CD52FFCAEE61EA28488C7779BC21 /* QNUrlSafeBase64.h in Headers */ = {isa = PBXBuildFile; fileRef = F0CD75989071374CACB370D591D1B209 /* QNUrlSafeBase64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2B20C6F4D8FA47BB7D9382624F3A33CB /* QNUploadInfoV2.h in Headers */ = {isa = PBXBuildFile; fileRef = 812EC1822605C9634F6C3E9546BAC454 /* QNUploadInfoV2.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2B7717BAE65809CD70FA2E5E75C9E69F /* QNMD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 16543171422AD405FDB49363A534D902 /* QNMD5.m */; }; + 2CB0891388E2B78EF5D3E266E608CCEB /* QNDnsPrefetch.h in Headers */ = {isa = PBXBuildFile; fileRef = C48C4859E5FF23089802FEFE1F29EE20 /* QNDnsPrefetch.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2DC683AC4D377D10CA932E9EBBEAB382 /* QNRequestClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FD41DA6014B9614009729A6F837DEFB /* QNRequestClient.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 35177229827C7A5D7B45C347C771693C /* QNHijackingDetectWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 18314E905A8D5C182A33669B5675B997 /* QNHijackingDetectWrapper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 363DE1D3B870502EB2E305EF9871FFF6 /* QNSessionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 723162DA2F24F7C74D707F106FDACD23 /* QNSessionManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 367D73701DC968EF3EE5B0C0F016ABA1 /* QNCFHttpClientInner.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E226B77A5388AB12F501E7CCF28D24 /* QNCFHttpClientInner.m */; }; + 3749F8CC97522F9A2B547DF1DBFF7006 /* QNLruCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F2AE448D52382DC14F29987B684F78A /* QNLruCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 385CEE7F0C894B5E97B88F54AE3BC5DD /* QNResolvUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = BE64EFA6EDCFD5B12C920671149D028C /* QNResolvUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 38E31F7C37E339C230705769D6D97E16 /* QNCrc32.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6D3A487AB9CCA73FD67AF727FED561 /* QNCrc32.m */; }; + 3B9A335BE2F04D8730E51235D9940706 /* QNLogUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 761F2F78628D1D5262D05A37FB741441 /* QNLogUtil.m */; }; + 3CFB2AC7B866A779334F6C272C4A6106 /* QNUploadInfoV1.m in Sources */ = {isa = PBXBuildFile; fileRef = A221251C091AF510A609C108982CB1D1 /* QNUploadInfoV1.m */; }; + 3D29D0A2DAFD0F68A283B83923342EFA /* QNFileRecorder.h in Headers */ = {isa = PBXBuildFile; fileRef = C90152077EF63F3F4D7BEA4A0A418241 /* QNFileRecorder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3EE37B2F4BBDB5005900567AED18EEE1 /* QNConnectChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 398256C46D6CA44A36703929A8FA52DD /* QNConnectChecker.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3F2036038444EAAA7460311634006271 /* QNUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B808218FFC5C59359D25FD81D9EAEA76 /* QNUtils.m */; }; + 3F862AAE5E80AB4F322E5FF0E5AE78A5 /* QNDnsError.m in Sources */ = {isa = PBXBuildFile; fileRef = 184788383616F05C6E48C10981453705 /* QNDnsError.m */; }; + 3F96CE99838C2E14350B3BFC1792EBA9 /* QNRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F0275D010EB9CBB29C4FFC8C60E35B6 /* QNRecord.m */; }; + 3FD6650A7191C84085414CFC36E9B1E3 /* NSURLRequest+QNRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 178A385885F03FA4AB365C9BE594F4DA /* NSURLRequest+QNRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3FFF23D5DE39C0350405CC3F8C6B9F45 /* QNUploadData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0AC5921E07E0B3B4358EA90EED983278 /* QNUploadData.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 405CC9638A609D7F7D6E49873712819A /* QNUploadSystemClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5123B4029742776B759BCC99F43391EF /* QNUploadSystemClient.m */; }; + 415348F2C83EBEC5D3ABC5431431591E /* QNInetAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = 280814F276C6CCADD2A94E3518223671 /* QNInetAddress.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 42C3D26D5D194EB4DB3902A572D71A54 /* QNUploadServerNetworkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A44E8CFC5EE315D8942BE4A88ACC66 /* QNUploadServerNetworkStatus.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4591A679BAC668B56EB1F7A2EFC9F808 /* QNUploadDomainRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 74D331F51CA2F803B4129019B829C378 /* QNUploadDomainRegion.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 46B63D86394B3291BE411401395310A9 /* QNUploadRequestState.h in Headers */ = {isa = PBXBuildFile; fileRef = 444901F5C99E84244FFABCB93FF16030 /* QNUploadRequestState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 473C7955E89B70660DEAE4C3E3E5024E /* QNAutoZone.h in Headers */ = {isa = PBXBuildFile; fileRef = F4558BBEBB365756430BBF5A9C690C65 /* QNAutoZone.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 484D0A4FE804F8EBF2B05502B0573408 /* QNUploadRequestInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0CFFFA0B3C4B5C29949A00485F47F6 /* QNUploadRequestInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 489C1E3F7ADE55836D1985A1C987510F /* QNReportConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AF4376FF1077F9375D1B61F8BBEC8B5 /* QNReportConfig.m */; }; + 4B37902C0C10D624F59FE47D44FEE9AF /* QNIUploadServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9001544182AD65FAD65692A10D67D47B /* QNIUploadServer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4D34246FF5D9D461B4A8D3CAE4DDF57B /* QNConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 356872ACF48824DAB546350FB71559B4 /* QNConfig.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4F7133BD631BA5390DB12C26857506C4 /* QNDnspodEnterprise.m in Sources */ = {isa = PBXBuildFile; fileRef = 26B144A2038C8AB7D0F006999AE1565D /* QNDnspodEnterprise.m */; }; + 4FC05CDB5A30BA59CADB788F23E8AE2B /* QNConcurrentResumeUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = C49CE688BF6B04792B5E434362B352D5 /* QNConcurrentResumeUpload.m */; }; + 585E9BAC551DE7A99A2410B730490AFD /* QNPartsUploadPerformerV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FE6ED2A6018975A571C0123A5AA358E /* QNPartsUploadPerformerV1.m */; }; + 5908A709FB3D0482D49C605579285ABF /* QNDnsMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AD7BA30DFCC0E13BC273492233D986 /* QNDnsMessage.m */; }; + 59833830D6F5A62384C7633868173637 /* QNUrlUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = D6056BE4A98153C8435CEC49BD61D35D /* QNUrlUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 59D40A6C6813736ED3A4CBF32C93FECF /* QNDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB90C502C7D2C2B26CDA037FE01F24F /* QNDefine.m */; }; + 5A9899709C100B809F8D6B7DCE5BB287 /* QNPipeline.m in Sources */ = {isa = PBXBuildFile; fileRef = 480E9C0A1D7837BE60AA9B83DC6A204D /* QNPipeline.m */; }; + 5BA1335B49C511B3D87B81A40E7E12DC /* NSURLRequest+QNRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 24171AC23C0F552CD190532B6001762B /* NSURLRequest+QNRequest.m */; }; + 5C7E774E2F7CDFB706E513D1A929B869 /* QNUploadInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AE1E212922B29A2A6E1161328C2A78B /* QNUploadInfo.m */; }; + 5C991FFF5EE367FBA0103A83097046C4 /* QNUpToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 4943A7294DB91F20EC946148A39D3F89 /* QNUpToken.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5E3FF93391E2AF6351A6CF3DFC824078 /* QN_GTM_Base64.h in Headers */ = {isa = PBXBuildFile; fileRef = BA9C543D6B3611C59AA82A173029570E /* QN_GTM_Base64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5E6341E69B47D49F122396A7E6E651CC /* QNSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D6B72513683F5ABE16C23F2152DD32 /* QNSystem.m */; }; + 5F1B572DC0D7C1FCDB67DAD9BE6E111F /* QNPartsUploadPerformerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B2EAA225A02A04218D535E3F679B6FB /* QNPartsUploadPerformerV2.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5FDA798B15A4205E6E2B9C1F8F665172 /* QNReportItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E8A77999BCB1027863490ABB6DC80B91 /* QNReportItem.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6272AAE5A8D3620D0A9D208337EC61D1 /* QNDnsResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = B5735E782B3714FA446524FDB5516BD4 /* QNDnsResolver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 669EF6B39BA02ED775D46B05520A048E /* QNPartsUploadPerformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 81321B7225B94E7A17C0931B3E7F276E /* QNPartsUploadPerformer.m */; }; + 66E86F47697FCD1CC27A1247EC10101D /* QNDnsDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B89E5C4FDF8462D78A9925A1013F6B /* QNDnsDefine.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 69829BF26F50A3C6D4F4EB2637CE6ADD /* QNDnsResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 31E55124AAF41DFCF688CC9B5CBD6EC7 /* QNDnsResponse.m */; }; + 6A6A458420D1BE1361FE96781053F642 /* QNAsyncRun.m in Sources */ = {isa = PBXBuildFile; fileRef = 1859C82BF05504A3872D673DF40C126E /* QNAsyncRun.m */; }; + 6A70F40277F516EB42992EAF407CFE94 /* QNHijackingDetectWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 93C5FED255F5DBEADBA829F691DE22C6 /* QNHijackingDetectWrapper.m */; }; + 6B38AE9316D2278D3E3AEFF51652E53A /* QNServerConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E086CB41F588914AEBD9A24D21A98E6 /* QNServerConfig.m */; }; + 6B3939A552F78BEE85CFBEB1E3416D27 /* QNPartsUploadPerformerV1.h in Headers */ = {isa = PBXBuildFile; fileRef = 847CFC23C914A7CCBF75F5D4CE865C0A /* QNPartsUploadPerformerV1.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6BCC18A46877288300F5CFD6447911E2 /* QNUploadSourceFile.m in Sources */ = {isa = PBXBuildFile; fileRef = E30A65BA27A072F1306DB2388089DC98 /* QNUploadSourceFile.m */; }; + 6C63211BC21A39FAD6E6015A3405711D /* QNEtag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8769E4D9DFFCF732E4B72DDB04773D41 /* QNEtag.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6CCF545D1D6B85614337C6898FF1CF74 /* QNCFHttpClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D0D158A0121537C0E7409292DD0424D /* QNCFHttpClient.m */; }; + 6E0D258E7FE0D7BB16D43B8342EF8D6B /* QNDohResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = A88A6DD28323644A265297F8B56DE3FD /* QNDohResolver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 70EE7F6FF2FF14FA32C18BC6C41E535E /* QNCrc32.h in Headers */ = {isa = PBXBuildFile; fileRef = 56D0F4F676D3CAD396D6E9982A959443 /* QNCrc32.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 717A7EFB6329E63CE5E7B1C6E0C72740 /* QNUpToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 698E018EB0D0899DD2C2F38E94FD5A74 /* QNUpToken.m */; }; + 724317CFCD8068536814E5BC4AC61206 /* QNCFHttpClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B6D3D2A6853FE1F4C6307DB661D5298 /* QNCFHttpClient.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 733D0FCECAD516495EE942B89A039736 /* QNFileRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A2B2D7D5C6DD060C84D8ADF6D7A43E9 /* QNFileRecorder.m */; }; + 73C1BD6DFCDC22B5EF624966A694DC9C /* QNFile.m in Sources */ = {isa = PBXBuildFile; fileRef = EBE6C6FD459A6B45F96D5FE944BFB2AF /* QNFile.m */; }; + 74303C0DBE03E18723D96226E57C5881 /* QNVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = F6A558BD64030C2B22BF8240EB72BFAB /* QNVersion.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 763372E4397A0215700BC32F135F88B3 /* QNLogUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = F51916885BBA58862D3FF72A162AE04E /* QNLogUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 767A512C8BEFBF38A1BDA2A5ECF960BA /* QNSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D900D5948B2E17B67406B3B414511F5 /* QNSessionManager.m */; }; + 7A54221F669E5F5D6080DC84FDA509D5 /* QNDnsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E10E0CC798232339FEEE1B93058C6A /* QNDnsManager.m */; }; + 7A55C1B8B2FE941ED304408CC6E4EC5C /* QNUploadServerNetworkStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = AB431F11F56810275DDF177CBCBB9765 /* QNUploadServerNetworkStatus.m */; }; + 7A9FA33117D259372ED3DA4DC8079FBC /* QNUploadOption.m in Sources */ = {isa = PBXBuildFile; fileRef = AA5369E025BA75B4CFBFC684A8DEE017 /* QNUploadOption.m */; }; + 7C108C063AFF9B03A828D12F464A27EB /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 97A9BA70792CFF5303724379B3B2925C /* PrivacyInfo.xcprivacy */; }; + 7C89DD86FB0E55F0B866406B3A495F1B /* QNDnsMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC4EF66A8F63391B34202E52DA4AFDB /* QNDnsMessage.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7CA28D4A7D112F49D534E3F80C09A192 /* QNUploadSourceFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C0AF86EBE5E8F64D381431E106CD267 /* QNUploadSourceFile.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7D7D685CF5A7D05369D3E29CFB1B2697 /* QNUploadOption.h in Headers */ = {isa = PBXBuildFile; fileRef = A4AA31A61B3937CBA327208E5243717A /* QNUploadOption.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7E4B72EB37E47855AB243028FFA0163D /* QNMutableArray.m in Sources */ = {isa = PBXBuildFile; fileRef = B34134035FD1744909633BE9A62D6FA3 /* QNMutableArray.m */; }; + 7E88D8A94EF09815FCB86A6A6A66ADA9 /* QNUploadManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 905CB0F3866B1BA95985D9BCA2305F36 /* QNUploadManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7ED048BB1E5B4EB7405C240AB76D8073 /* QNErrorCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 6175C670769797A256146AF781DBBD73 /* QNErrorCode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 808F7DB0E79091D174C9A518690DD625 /* QNDes.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F8128F42BD18C409B18FAFC01939A52 /* QNDes.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 855FCDC8D7F3FB9E24A0C43E95A9FCA1 /* QNServerConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 176313049470B50BE436395B1808C94C /* QNServerConfig.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 882D09186FEA0EC925809CA81CEF1163 /* QNResolverDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = C8BC1F8A67ED28C334BBE2228C13DBFB /* QNResolverDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 894EBD2230B12EFED01B2B4AE3077D36 /* Qiniu-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8912CA14784BE3548E5AC2CA8873C415 /* Qiniu-dummy.m */; }; + 8A888179E0FA52A16C56976369B99E08 /* QNDnsError.h in Headers */ = {isa = PBXBuildFile; fileRef = FA38D537E3338AF8DADCCBE577891E6F /* QNDnsError.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8B2ABDF28B570378EA014EE420D4ECBB /* QNResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = F8B35140EE209B55F842ADD443DEDAC6 /* QNResponseInfo.m */; }; + 8C22120136505CBA1FFB225CD8EC8A4A /* QNHttpSingleRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 82C6291B76209256C5812698BB612A72 /* QNHttpSingleRequest.m */; }; + 8D076A0238B61C0198777D6BD60007EC /* QNZone.m in Sources */ = {isa = PBXBuildFile; fileRef = 37F27BAB3C256685B6F7B083570383A8 /* QNZone.m */; }; + 8D1D9FB08C8756A4D74E2685C5467EF6 /* QNNetworkStatusManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B1A913E99B99654FCF59E37B02A3CC9E /* QNNetworkStatusManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8F03076C785260B6B5C5C2330AEDB5EF /* QNLruCache.m in Sources */ = {isa = PBXBuildFile; fileRef = E683DD5A2FDA4732513D90C1370A730B /* QNLruCache.m */; }; + 8F6B6F0FFD097D845ECE9AF83CD4C632 /* QNNetworkStatusManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 448FBEEDDFA17AF962D540807C427EF7 /* QNNetworkStatusManager.m */; }; + 8FA9C4F70E09C19AE9FBF64994ACC644 /* NSObject+QNSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = B19CD69FFBED4C0022227CF0B702B461 /* NSObject+QNSwizzle.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 90061ABFA2D4EF2F4FE4B549F4023636 /* QNGetAddrInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BC74568D261EDC4C83E16AE36224866 /* QNGetAddrInfo.m */; }; + 9160C9AC30DB40529A7D6E9D7AC17902 /* QNDnsResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 78A9C0282EA043EF000B013B8ED13CCC /* QNDnsResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 91B8A06A000B48A8395C6D8B2E8F7DEB /* QNServerConfigSynchronizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 23E71E2266AD47CCD8EAD036BD531740 /* QNServerConfigSynchronizer.m */; }; + 9424078AFB474AAFAD7D39962D8349CD /* QNDnsCacheInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AC4D30A22DE4773F329B74F57240856 /* QNDnsCacheInfo.m */; }; + 946D1DD24031C34170E3579F1A38C793 /* QNServerUserConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 0285B2AEED83B6C8D72681824542EDD6 /* QNServerUserConfig.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 953C8C62F01E4D7A671255FE829BC55D /* QNUploadRequestMetrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 9138B03A4492B1E01308EF4EFEC48596 /* QNUploadRequestMetrics.m */; }; + 96A907D7939D268628181CF3629C1D17 /* QNUploadServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 85A39400B7C9B7F8ED9F73DDE08D198A /* QNUploadServer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 97BC329AD753970C6819E7A109F1311D /* QNDnsCacheFile.h in Headers */ = {isa = PBXBuildFile; fileRef = D01B03918D576895B40B8342EF6F1D47 /* QNDnsCacheFile.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 982472E334C700D72497EC940AA2BFC3 /* QNUrlSafeBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = DFD1F913622154A3DAE8AB27305B0AE8 /* QNUrlSafeBase64.m */; }; + 9A5AB7480FE3B1046B72D563C3E23227 /* NSData+QNMD5.h in Headers */ = {isa = PBXBuildFile; fileRef = 32AC495FE5B637859C36EE43D9964E7D /* NSData+QNMD5.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9A6230B72E0E9B1C1DF284F53ACDA93C /* QNRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = B73356693E5EEF47E767298D61C49BB1 /* QNRecord.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9AA3EC42D3CE90F42073B4B58120FAA2 /* QNUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D32A2356F12F322696C043687D9CB /* QNUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9AF6C1B102D31AC8BAC3EAB146EDC790 /* QNALAssetFile.m in Sources */ = {isa = PBXBuildFile; fileRef = B79D8FBE5D620418D3A501E423413042 /* QNALAssetFile.m */; }; + 9AFE877066FA5C68F5930C212D55F70C /* QNNetworkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 353B822ED27D83F48A5DA3355A50F986 /* QNNetworkInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9BF0AE41367B8419DF4D8EBF67C572A9 /* QNFormUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 987951A732C83F0EDD2686A3113C1660 /* QNFormUpload.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9C1C24540C82F0E248CB51890A8B7B97 /* QNIP.h in Headers */ = {isa = PBXBuildFile; fileRef = 77184E055AF16747C5C596E7FBF3D761 /* QNIP.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9CF8E34B4317D621EE0232FAA2DF1948 /* QNUploadRequestInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EBFEA24EA474C5982FF42213814675B0 /* QNUploadRequestInfo.m */; }; + 9F6DA1079338BEFBEFCD028D9EDF25A9 /* QNUploadSourceStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 52092A3E4758686C88E09A8A822CB1A4 /* QNUploadSourceStream.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9FB875938AB160392C3F27B9EFAC225A /* QNHosts.m in Sources */ = {isa = PBXBuildFile; fileRef = BECC8F14377F57CFC98229493CDCDAFB /* QNHosts.m */; }; + 9FDF3A1C81A4154E5A6EC7884EDC0D90 /* QNUploadDomainRegion.m in Sources */ = {isa = PBXBuildFile; fileRef = 3232761147507B185CCD3513BEEF7268 /* QNUploadDomainRegion.m */; }; + A249FCE2F96F20A4A1932948CC03B1E2 /* QNDnsUdpResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F80E9292C6EA5A58ECBC8A9F7922D9C /* QNDnsUdpResolver.m */; }; + A29C1CD46174CEE0AABA2E14FBA287AF /* QNPartsUploadPerformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A3F45D03BB2D93F8407499089BBC7A6 /* QNPartsUploadPerformer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A2FC5BC59A585CDF875B9212FD0BEA3E /* QNUploadServerFreezeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B304DE091973BDA5DDE597DA01132F /* QNUploadServerFreezeUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A3F79FB07293047BEDB0B84AE65F9FA0 /* QNFixedZone.h in Headers */ = {isa = PBXBuildFile; fileRef = 99FF2CB42958DAB7AEAD203B545B8C4F /* QNFixedZone.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A415F883A08C66E6CEFCB9116B55D988 /* QNTransactionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 18CC0031705262E5C46EE9216B742CED /* QNTransactionManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A443954283E84BB2A7A7A4A5FF125919 /* QNConcurrentResumeUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CA54DBB52133EB7A4078A90C9250155 /* QNConcurrentResumeUpload.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A6C304C5CA01298CCA63B0682A67D429 /* QNDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = EE22A2E95A47055E0ED97D4242DABAEB /* QNDefine.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A898190C4D8A375891F9AD0BCF6098EF /* QNUploadServerFreezeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E95A7C67CE2E7B37438781CA58210F3E /* QNUploadServerFreezeManager.m */; }; + AA9CC59FA8A5802D4BE4EC3C4FB1FB26 /* QNHttpSingleRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E65EBC7EE87A25E4F86AC87FF9587D1A /* QNHttpSingleRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ACAA9DF5E3D136039B5B20B6718021F1 /* QNMD5.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B38FD6D54D8204FC57D6B5BF8CE227B /* QNMD5.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ADC81B97EDC1DB1D79FF57EE155519C3 /* QNPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = D7B7BDCBBD76A334D639EA44C8143EBB /* QNPipeline.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ADF491411922480EBB12FC5A5E70A597 /* NSData+QNMD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D527C7D6CE7620052ECB6BE2DB3DAC3 /* NSData+QNMD5.m */; }; + AF0495C59F2EF44B4FE824B037A6B8B7 /* QNCFHttpThreadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = C13A4ACFA53E6DFA5883CED6D5BA6E7B /* QNCFHttpThreadPool.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AF50E8CC3F8AAB90A5C80431EC18E0ED /* QNResolvUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 403607B58842099BD4730AC22C6B96AD /* QNResolvUtil.m */; }; + AF5CD587AF6A59AE8C0D3E45170DB1DB /* QNErrorCode.m in Sources */ = {isa = PBXBuildFile; fileRef = EF0AA010DBD42A3ED8F737464F10CA40 /* QNErrorCode.m */; }; + B18110A3A71EB88226791A8C109B16F6 /* QNDohResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A19CA58F24BC3E2893FD436BF033798 /* QNDohResolver.m */; }; + B2D10BF8F71C361F2BA535635DAB58A7 /* QNZone.h in Headers */ = {isa = PBXBuildFile; fileRef = 15F05795FAC4894BDDCFD80B437D7D76 /* QNZone.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B3618BAA20910B8F77AF0EDB3AD9E844 /* QNNetworkInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A87D10C90FD4E8F9EBEA561533291C /* QNNetworkInfo.m */; }; + B365B17375120498EFE98AB5B591515F /* QNFile.h in Headers */ = {isa = PBXBuildFile; fileRef = E5548E5A291581440C8BC636F55BC7E3 /* QNFile.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B48DCDB6DEA5342877AA3C828F44728E /* QNHttpRegionRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B5092555676E150E1F88993C23FD24E /* QNHttpRegionRequest.m */; }; + B497520E58241CCE602D4C8B24FAC713 /* QNUploadSourceStream.m in Sources */ = {isa = PBXBuildFile; fileRef = B33E60A599A4CA1193C414960E161861 /* QNUploadSourceStream.m */; }; + B82A7979B386F40049FD3C6A4DD84481 /* QNBaseUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = E14F45FE51A8B43155BB0F0233CFB106 /* QNBaseUpload.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B8B6988F7579AE02B9F25FF91A224A29 /* QNAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 24E893AB5487C90972A197592614F131 /* QNAsyncUdpSocket.m */; }; + B9E9091DD3ED2393598E9EE88964B57E /* QNSingleFlight.m in Sources */ = {isa = PBXBuildFile; fileRef = 893C9FDD66BF35A81502E28E4F767721 /* QNSingleFlight.m */; }; + BAA2BBA102CE99F026E7BD5CE97F4BEE /* QNTransactionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B61A1E1CF720A9FF98E627A3A603BC1C /* QNTransactionManager.m */; }; + BE57EC6144D79300FF2A75239FE02E24 /* QNFileDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CFAAAB79E2A7C50B4C1E94A72D2BD2 /* QNFileDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BEF431B2EBD8AC01B5B1FF699A431997 /* QNServerUserConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9561C8F7DC0CAADB1217ED15C85DEC /* QNServerUserConfig.m */; }; + C26EA245C7645920A2CF9367BF2A0C8E /* QNUploadInfoV2.m in Sources */ = {isa = PBXBuildFile; fileRef = 0851E3157B70B1A32465DAD0BFD4A810 /* QNUploadInfoV2.m */; }; + C32B3680837042FC9FA39426F82C1AA4 /* QNDnsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 94D19C7474694E4FD4651D0CC2303865 /* QNDnsManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C3C2F5260C57DFE6D0BA9969624DFF9D /* QNInetAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = A56D833FAE5B35240EE1D9026A8EFD45 /* QNInetAddress.m */; }; + C4EA63600AB11CAA6F17633CD819ADEE /* QNDnsCacheFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 075FFD3100B1BBB8B7FF8D6B19A23421 /* QNDnsCacheFile.m */; }; + C7C5E1372EA44C2018CDD834C370D4DE /* QNUploadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B8549EF474251783802766729B86324F /* QNUploadManager.m */; }; + CA3FD26F7CB9C0F2F14D6EB521011CA3 /* QNDnsCacheInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 83203BFAB9C4F655B2B88ABF0D3CEB4E /* QNDnsCacheInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CA691A0115418B2188C7F6FE35A9C5AE /* Pods-msext-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B880536FAA662603F8BB45F2165001 /* Pods-msext-dummy.m */; }; + CC503F756A70AAEDF0579FF5F242F0F0 /* QNIP.m in Sources */ = {isa = PBXBuildFile; fileRef = 6006E7736851F5B2C9571FE2D8E91377 /* QNIP.m */; }; + CC9106180C5AA9C406F4F4007EBC4046 /* QNPartsUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 54A78797CE409C762D6C6554451D8A70 /* QNPartsUpload.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CCE0B36CBCB3736491FC05113E8A1EEB /* QNUploadSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D4EDE0519DF8027C47DA50CCAB1126E7 /* QNUploadSource.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD410ED96FBD61E08CE67118469DD46D /* QNPHAssetResource.m in Sources */ = {isa = PBXBuildFile; fileRef = 510585ACBFC40783C8804931EC4FFB8C /* QNPHAssetResource.m */; }; + CE513C3EFCAEEC35561F4991A8280140 /* QNServerConfigMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3572172784A174F5D92E48C15953FD25 /* QNServerConfigMonitor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CE859E5343307B140147194B4503795C /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 9FB0F5E1925AF6E3C165F92F34D8B7A7 /* PrivacyInfo.xcprivacy */; }; + D200E2C73915172912A26A08ABE6BE6D /* NSData+QNRW.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D515E3C7EF405627BF376F69EE1EBB3 /* NSData+QNRW.m */; }; + D21A9839F1C6B483B80D40A8CF73EF0C /* QNUploadData.m in Sources */ = {isa = PBXBuildFile; fileRef = E07CEC148C3EE2019D2D5D99C4BC53A2 /* QNUploadData.m */; }; + D2BD8BABE7D83BCFFFC5BFEE8CD186D9 /* NSData+QNGZip.m in Sources */ = {isa = PBXBuildFile; fileRef = E95C1A7355A7F40777F55E9BF9965D56 /* NSData+QNGZip.m */; }; + D442FD256526D202FD299D438A643EF7 /* QNDnspodEnterprise.h in Headers */ = {isa = PBXBuildFile; fileRef = 69EC4C1DF6A56827B78E4AF0E907F8CF /* QNDnspodEnterprise.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D53D2F967B996224701F0DD2CDCE9A2B /* QNAsyncUdpSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D5EE68B000E7EE5CEEA789E11D159E9 /* QNAsyncUdpSocket.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D5EC1C29F5EBD9D97D5BA35882B58847 /* QNConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = B846104C566BA5F2F5D11EA9CC5BEE54 /* QNConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D621165613F37CA7673A6FA9D4DD647A /* QNCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 44F5CFD75D34546DB23D1DDD35D69D33 /* QNCache.m */; }; + D63B21A3D0D58731F5573CFB435CA112 /* QNUploadServerFreezeManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 11794B20AAADFAD4CB9D91909B755401 /* QNUploadServerFreezeManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D70C9653FF7781BC9C6D7344D1270088 /* QNCFHttpClientInner.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E342E62A09C3771212E0E69A51728B7 /* QNCFHttpClientInner.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D82914CE4B1D29124FB5C94E83B9A866 /* QNZoneInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 64FDDBA6B9281D67C7214592245FBF15 /* QNZoneInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D8D480C9255D0B4F985AFAF8298FBBD6 /* QNPartsUploadPerformerV2.m in Sources */ = {isa = PBXBuildFile; fileRef = 8534930B178F9203470A253A3AC523F4 /* QNPartsUploadPerformerV2.m */; }; + D9366EAEB2D487C91DED410C2E7CCED9 /* QNGetAddrInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 83ABF04A2FACD1E8E29B1A7E552BB215 /* QNGetAddrInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DC08FF1C20D79E48B2D0E21BF55E399E /* QNUploadServer.m in Sources */ = {isa = PBXBuildFile; fileRef = AD78C2CF832D0A30ABBF42BFE19FED10 /* QNUploadServer.m */; }; + DC60811FEA708CB183D8116520E28029 /* QNServerConfigMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = E96FD00F54A57EB23E8709808E290E4C /* QNServerConfigMonitor.m */; }; + DD00AF12D400FC423D3A8F11EAED2D06 /* QNALAssetFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 30585F72C35E6288F2BA997013BD1CFB /* QNALAssetFile.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DD9C6436F9F327A5A17B641C11600EBA /* QNDomain.h in Headers */ = {isa = PBXBuildFile; fileRef = CE2E26E93574B31F7B5D747C65C84AF4 /* QNDomain.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DDB11E51FD0A0D524B82439DE3B2A383 /* QN_GTM_Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 04617DCCCBC5FA60EEC23070FADC017D /* QN_GTM_Base64.m */; }; + E02767AB5C6A1D535A02F66D2CF839C5 /* QNPHAssetFile.m in Sources */ = {isa = PBXBuildFile; fileRef = DE70BD948705691EAC0035AF087C3FA3 /* QNPHAssetFile.m */; }; + E060C21FDA95CA3C351EB8D38DB3D058 /* QiniuSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 92A9A7A4E30C5792E5BB535F5C7BE536 /* QiniuSDK.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E20B6B19EA2202F68DE792AB4C597D8F /* QNUploadInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 40A726DB59657716867C8B1AB36E6C30 /* QNUploadInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E41FFF977E6BCDBE48DCF814AC6A7D01 /* QNUploadServerFreezeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A8E13048620040754D4A99B474D82AC8 /* QNUploadServerFreezeUtil.m */; }; + E464D148BAC75561AB59829D3A8E2BFD /* QNConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E979EF9BB067B89CAD0B86DFC8810 /* QNConfiguration.m */; }; + E47813CBEA853F14D46FD7C678C44FE3 /* QNIUploadServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 255D992969763494AEF336410D9F1387 /* QNIUploadServer.m */; }; + E4E5CB367C20590CFA957CA043D6B64B /* QNSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F6DC7D2D01596F560201E643A8599F1 /* QNSystem.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E60A8C1D4C3E482E7AC8FAE8564A0B1C /* QNReportItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 1243C9BFC24EFEEFCE151188C0898D5E /* QNReportItem.m */; }; + E6956B3F97E72CCFCCC6D7F9CA41DFB3 /* QNUploadInfoV1.h in Headers */ = {isa = PBXBuildFile; fileRef = B43E6A6F8478BC76541791BF5653CAB0 /* QNUploadInfoV1.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6A0F7BC3C240BB99A10F68966609B24 /* QNDnsRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = BF99C6558B7471DA7A4328679436DC81 /* QNDnsRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E731B10A06AA446C150BF74563799B72 /* QNHex.h in Headers */ = {isa = PBXBuildFile; fileRef = A815861313DCAFC2F88A9F5D3ACB7440 /* QNHex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E76C4F9D71154DB8178C490ADC101A83 /* QNTxtResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B5384A1FF2AF8B288A151F7B2AF4D1 /* QNTxtResolver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E8EEA1F3AC75797FA4184E3F19BC0104 /* QNDnsPrefetch.m in Sources */ = {isa = PBXBuildFile; fileRef = 74D0E736E89F1197E45102F0F5318EE2 /* QNDnsPrefetch.m */; }; + EA3ECA68F00C0BE8532F6B447F2884DA /* QNUploadSystemClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8F5C80C6BA42C7ECF7D30A038C03F95A /* QNUploadSystemClient.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EA44072035221904D252B61DC73663B4 /* QNUserAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = B2F9A345F5B6BE60F7F5BDF34295C5A2 /* QNUserAgent.m */; }; + EA53570E898921D3C55D221EBCC8253F /* QNFixedZone.m in Sources */ = {isa = PBXBuildFile; fileRef = 9135242B986EAD01754CDE556F563E5F /* QNFixedZone.m */; }; + EAD6E08D8EF66A4FE875E0912B4DB2C5 /* HappyDNS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 464AAB9B64DCDBB86575B4B1BDDFE93D /* HappyDNS-dummy.m */; }; + EB643CC7ECBD0E730AA2CFE56CCBC841 /* QNResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 8695E9F0766A202C652B1CF7105422C6 /* QNResolver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EC4570B92D85135EC82E963683F9A2D0 /* QNDnsUdpResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = D3B4D656F820DA00F5E43B02CDC559B1 /* QNDnsUdpResolver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ED23065233F840C1C4555FDCA90689B0 /* QNReportConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = A1966DFF26B064B6A60AF2568F9982B3 /* QNReportConfig.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EDD9A63F8B68A5B1C2663A4C129F1F6F /* QNServerConfigCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 231357D720AFF7AA4132AF1E7B7BE790 /* QNServerConfigCache.m */; }; + EF2C14B88B6B529CE7D8F8AC35BFA4D4 /* QNUpProgress.h in Headers */ = {isa = PBXBuildFile; fileRef = E93456BD99FE4C120360C8EE467C4E25 /* QNUpProgress.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F053710CF7EF686A17F97F53D5C4D3EA /* QNUploadRequestMetrics.h in Headers */ = {isa = PBXBuildFile; fileRef = 538BD2F88175C3CBDA73EBB63DC767C5 /* QNUploadRequestMetrics.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F1D5510D28197722188E6117EAD39E0A /* QNUploadRequestState.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C05983D208A6981DC4D5B323BBFF703 /* QNUploadRequestState.m */; }; + F228B8157C015BF76EEAF35011CE7964 /* QNUploadRegionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB37F8534A03ACD356B47AC1FA44D93 /* QNUploadRegionInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F5103D7221410A9E09BFE61AC019207A /* QNDomain.m in Sources */ = {isa = PBXBuildFile; fileRef = F6D7B36D918469680BA194548DC1EFCC /* QNDomain.m */; }; + F5EFAEAA108D793D1BFCD37874FA0499 /* QNPHAssetResource.h in Headers */ = {isa = PBXBuildFile; fileRef = 994182C7C3D68278988EF0FA6F371AA0 /* QNPHAssetResource.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F6AD7847B0A90D145BDC52C7BA0A4574 /* QNUploadInfoReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F52E6FDCEB0481BDE0AC37643FE2F11 /* QNUploadInfoReporter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F809D996BF339D9A529395CDAD9372A2 /* QNUpProgress.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F3EA4CCB4F3228A06B466537A6E4AF3 /* QNUpProgress.m */; }; + FA24759B66D376AB97F2F2005901349B /* QNPHAssetFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 864616D11289C3BF4E6C872C01A8CA39 /* QNPHAssetFile.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FAE1AC9D1ED1441E4BC32D687E2EEFE3 /* QNDns.h in Headers */ = {isa = PBXBuildFile; fileRef = C767D72C454BBCA7A797CD7596C85A4B /* QNDns.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FD18657084D3369C6C4F6E069B8A28FC /* NSObject+QNSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = E0DC9F438E70C3804A5F385E5F8D3917 /* NSObject+QNSwizzle.m */; }; + FFA86E79FD5423EF3C2C67998EE49403 /* QNUploadInfoReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D4BA683411586A786AE0B4B3C0F4C3D /* QNUploadInfoReporter.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 2ADF5A10DA7064EAC6F49B43641237D4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 96F820A9CBD7912A405650AC238D1F8E; + remoteInfo = HappyDNS; + }; + 54A545E1269A216BB66F64257970CDD3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9713F55E29CF00C3231002DC45C4EEB8; + remoteInfo = Qiniu; + }; + BF9C4F7CC1734743F25FA1B595A350D3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 96F820A9CBD7912A405650AC238D1F8E; + remoteInfo = HappyDNS; + }; + DE13900329DCF53935B17FC6CDC5FC46 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D659E6FBA2AF2BC7DAFE73043983AFD0; + remoteInfo = "HappyDNS-HappyDNS.privacy"; + }; + E0C0B4CC0E659E2F863A6803415401A7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 52FA323A1EAF50642C502468818C03F2; + remoteInfo = "Qiniu-Qiniu.privacy"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00E5EC0DED9848A2FE8A0306B981392D /* QNDes.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDes.m; path = HappyDNS/Util/QNDes.m; sourceTree = ""; }; + 0285B2AEED83B6C8D72681824542EDD6 /* QNServerUserConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNServerUserConfig.h; path = QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h; sourceTree = ""; }; + 028A189C700ACF2B6BC166A38D700E4F /* QNCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNCache.h; path = QiniuSDK/Utils/QNCache.h; sourceTree = ""; }; + 04617DCCCBC5FA60EEC23070FADC017D /* QN_GTM_Base64.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QN_GTM_Base64.m; path = QiniuSDK/Utils/QN_GTM_Base64.m; sourceTree = ""; }; + 04E226B77A5388AB12F501E7CCF28D24 /* QNCFHttpClientInner.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNCFHttpClientInner.m; path = QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.m; sourceTree = ""; }; + 057857FCC29DFF01C90D8B01B5DA5DBC /* QNRecorderDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNRecorderDelegate.h; path = QiniuSDK/Recorder/QNRecorderDelegate.h; sourceTree = ""; }; + 05E66D896E39EA29440DA388C7E7D6AE /* QNAsyncRun.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNAsyncRun.h; path = QiniuSDK/Utils/QNAsyncRun.h; sourceTree = ""; }; + 075FFD3100B1BBB8B7FF8D6B19A23421 /* QNDnsCacheFile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsCacheFile.m; path = QiniuSDK/Http/Dns/QNDnsCacheFile.m; sourceTree = ""; }; + 0851E3157B70B1A32465DAD0BFD4A810 /* QNUploadInfoV2.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadInfoV2.m; path = QiniuSDK/Storage/QNUploadInfoV2.m; sourceTree = ""; }; + 094C51DA204B14E7F7F9BD450C4F238B /* QNServerConfigSynchronizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNServerConfigSynchronizer.h; path = QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h; sourceTree = ""; }; + 0AC5921E07E0B3B4358EA90EED983278 /* QNUploadData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadData.h; path = QiniuSDK/Storage/QNUploadData.h; sourceTree = ""; }; + 0C2D32A2356F12F322696C043687D9CB /* QNUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUtils.h; path = QiniuSDK/Utils/QNUtils.h; sourceTree = ""; }; + 0E342E62A09C3771212E0E69A51728B7 /* QNCFHttpClientInner.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNCFHttpClientInner.h; path = QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h; sourceTree = ""; }; + 0F3BDD2BEB953DE540BC6185DE2E2714 /* ResourceBundle-Qiniu.privacy-Qiniu-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-Qiniu.privacy-Qiniu-Info.plist"; sourceTree = ""; }; + 11794B20AAADFAD4CB9D91909B755401 /* QNUploadServerFreezeManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadServerFreezeManager.h; path = QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.h; sourceTree = ""; }; + 1243C9BFC24EFEEFCE151188C0898D5E /* QNReportItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNReportItem.m; path = QiniuSDK/Collect/QNReportItem.m; sourceTree = ""; }; + 13AD7BA30DFCC0E13BC273492233D986 /* QNDnsMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsMessage.m; path = HappyDNS/Dns/QNDnsMessage.m; sourceTree = ""; }; + 15F05795FAC4894BDDCFD80B437D7D76 /* QNZone.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNZone.h; path = QiniuSDK/Common/QNZone.h; sourceTree = ""; }; + 16543171422AD405FDB49363A534D902 /* QNMD5.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNMD5.m; path = HappyDNS/Util/QNMD5.m; sourceTree = ""; }; + 176313049470B50BE436395B1808C94C /* QNServerConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNServerConfig.h; path = QiniuSDK/Storage/ServerConfig/QNServerConfig.h; sourceTree = ""; }; + 178A385885F03FA4AB365C9BE594F4DA /* NSURLRequest+QNRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSURLRequest+QNRequest.h"; path = "QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h"; sourceTree = ""; }; + 17F37BE73155DE146F00578D9B0C2DE1 /* Pods-msext-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-msext-acknowledgements.plist"; sourceTree = ""; }; + 18314E905A8D5C182A33669B5675B997 /* QNHijackingDetectWrapper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNHijackingDetectWrapper.h; path = HappyDNS/Local/QNHijackingDetectWrapper.h; sourceTree = ""; }; + 184788383616F05C6E48C10981453705 /* QNDnsError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsError.m; path = HappyDNS/Common/QNDnsError.m; sourceTree = ""; }; + 1859C82BF05504A3872D673DF40C126E /* QNAsyncRun.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNAsyncRun.m; path = QiniuSDK/Utils/QNAsyncRun.m; sourceTree = ""; }; + 18CC0031705262E5C46EE9216B742CED /* QNTransactionManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNTransactionManager.h; path = QiniuSDK/Transaction/QNTransactionManager.h; sourceTree = ""; }; + 1A2B2D7D5C6DD060C84D8ADF6D7A43E9 /* QNFileRecorder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNFileRecorder.m; path = QiniuSDK/Recorder/QNFileRecorder.m; sourceTree = ""; }; + 1A3F45D03BB2D93F8407499089BBC7A6 /* QNPartsUploadPerformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPartsUploadPerformer.h; path = QiniuSDK/Storage/QNPartsUploadPerformer.h; sourceTree = ""; }; + 1A623EA2BD31BC270E877148FBAD5114 /* QNZoneInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNZoneInfo.m; path = QiniuSDK/Common/QNZoneInfo.m; sourceTree = ""; }; + 1AE1E212922B29A2A6E1161328C2A78B /* QNUploadInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadInfo.m; path = QiniuSDK/Storage/QNUploadInfo.m; sourceTree = ""; }; + 1B8002C86FF660BE74F43AE588C4FF5C /* QNRequestTransaction.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNRequestTransaction.m; path = QiniuSDK/Http/Request/QNRequestTransaction.m; sourceTree = ""; }; + 1C04D7E0CD2BFD4CA3473BFB67D94948 /* QNRequestTransaction.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNRequestTransaction.h; path = QiniuSDK/Http/Request/QNRequestTransaction.h; sourceTree = ""; }; + 1D5EE68B000E7EE5CEEA789E11D159E9 /* QNAsyncUdpSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNAsyncUdpSocket.h; path = HappyDNS/Util/QNAsyncUdpSocket.h; sourceTree = ""; }; + 1D900D5948B2E17B67406B3B414511F5 /* QNSessionManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNSessionManager.m; path = QiniuSDK/BigData/QNSessionManager.m; sourceTree = ""; }; + 20B62CDF9AE854DEA6014419025D9CCF /* QNUrlUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUrlUtils.m; path = QiniuSDK/Utils/QNUrlUtils.m; sourceTree = ""; }; + 231357D720AFF7AA4132AF1E7B7BE790 /* QNServerConfigCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNServerConfigCache.m; path = QiniuSDK/Storage/ServerConfig/QNServerConfigCache.m; sourceTree = ""; }; + 23E71E2266AD47CCD8EAD036BD531740 /* QNServerConfigSynchronizer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNServerConfigSynchronizer.m; path = QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.m; sourceTree = ""; }; + 24171AC23C0F552CD190532B6001762B /* NSURLRequest+QNRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSURLRequest+QNRequest.m"; path = "QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.m"; sourceTree = ""; }; + 24E893AB5487C90972A197592614F131 /* QNAsyncUdpSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNAsyncUdpSocket.m; path = HappyDNS/Util/QNAsyncUdpSocket.m; sourceTree = ""; }; + 255D992969763494AEF336410D9F1387 /* QNIUploadServer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNIUploadServer.m; path = QiniuSDK/Http/Request/QNIUploadServer.m; sourceTree = ""; }; + 26B144A2038C8AB7D0F006999AE1565D /* QNDnspodEnterprise.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnspodEnterprise.m; path = HappyDNS/Http/QNDnspodEnterprise.m; sourceTree = ""; }; + 274039B1888766E5D9B1F50DF56F622A /* QNServerConfigCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNServerConfigCache.h; path = QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h; sourceTree = ""; }; + 2778E90F840997960E8B3B55F7C4212F /* QNBaseUpload.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNBaseUpload.m; path = QiniuSDK/Storage/QNBaseUpload.m; sourceTree = ""; }; + 280814F276C6CCADD2A94E3518223671 /* QNInetAddress.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNInetAddress.h; path = QiniuSDK/Http/Dns/QNInetAddress.h; sourceTree = ""; }; + 2B38FD6D54D8204FC57D6B5BF8CE227B /* QNMD5.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNMD5.h; path = HappyDNS/Util/QNMD5.h; sourceTree = ""; }; + 2EE6448CDF48B5C634F2DF06BE1E61DD /* QNSingleFlight.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNSingleFlight.h; path = QiniuSDK/Utils/QNSingleFlight.h; sourceTree = ""; }; + 2F8128F42BD18C409B18FAFC01939A52 /* QNDes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDes.h; path = HappyDNS/Util/QNDes.h; sourceTree = ""; }; + 30585F72C35E6288F2BA997013BD1CFB /* QNALAssetFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNALAssetFile.h; path = QiniuSDK/Utils/QNALAssetFile.h; sourceTree = ""; }; + 309A4D58300D2B60B1C816A189E2B722 /* Pods-msext-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-msext-resources.sh"; sourceTree = ""; }; + 31E55124AAF41DFCF688CC9B5CBD6EC7 /* QNDnsResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsResponse.m; path = HappyDNS/Dns/QNDnsResponse.m; sourceTree = ""; }; + 3232761147507B185CCD3513BEEF7268 /* QNUploadDomainRegion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadDomainRegion.m; path = QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.m; sourceTree = ""; }; + 32AC495FE5B637859C36EE43D9964E7D /* NSData+QNMD5.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+QNMD5.h"; path = "QiniuSDK/Utils/NSData+QNMD5.h"; sourceTree = ""; }; + 33E10E0CC798232339FEEE1B93058C6A /* QNDnsManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsManager.m; path = HappyDNS/Common/QNDnsManager.m; sourceTree = ""; }; + 34D6B72513683F5ABE16C23F2152DD32 /* QNSystem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNSystem.m; path = QiniuSDK/Utils/QNSystem.m; sourceTree = ""; }; + 353B822ED27D83F48A5DA3355A50F986 /* QNNetworkInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNNetworkInfo.h; path = HappyDNS/Common/QNNetworkInfo.h; sourceTree = ""; }; + 356872ACF48824DAB546350FB71559B4 /* QNConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNConfig.h; path = QiniuSDK/Common/QNConfig.h; sourceTree = ""; }; + 3572172784A174F5D92E48C15953FD25 /* QNServerConfigMonitor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNServerConfigMonitor.h; path = QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h; sourceTree = ""; }; + 3667B5F6798CDC2ADA1BBC70D052FF68 /* HappyDNS */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = HappyDNS; path = libHappyDNS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 37F27BAB3C256685B6F7B083570383A8 /* QNZone.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNZone.m; path = QiniuSDK/Common/QNZone.m; sourceTree = ""; }; + 398256C46D6CA44A36703929A8FA52DD /* QNConnectChecker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNConnectChecker.h; path = QiniuSDK/Http/ConnectCheck/QNConnectChecker.h; sourceTree = ""; }; + 3B32FC01328C766500672A215C59451D /* QNUploadBlock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadBlock.h; path = QiniuSDK/Storage/QNUploadBlock.h; sourceTree = ""; }; + 3BC74568D261EDC4C83E16AE36224866 /* QNGetAddrInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNGetAddrInfo.m; path = HappyDNS/Util/QNGetAddrInfo.m; sourceTree = ""; }; + 3C05983D208A6981DC4D5B323BBFF703 /* QNUploadRequestState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadRequestState.m; path = QiniuSDK/Http/QNUploadRequestState.m; sourceTree = ""; }; + 3D527C7D6CE7620052ECB6BE2DB3DAC3 /* NSData+QNMD5.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+QNMD5.m"; path = "QiniuSDK/Utils/NSData+QNMD5.m"; sourceTree = ""; }; + 3E065100D0F21B3ECBB3E4B3C31DB32E /* HappyDNS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HappyDNS-prefix.pch"; sourceTree = ""; }; + 3F3EA4CCB4F3228A06B466537A6E4AF3 /* QNUpProgress.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUpProgress.m; path = QiniuSDK/Storage/QNUpProgress.m; sourceTree = ""; }; + 3FD41DA6014B9614009729A6F837DEFB /* QNRequestClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNRequestClient.h; path = QiniuSDK/Http/Request/QNRequestClient.h; sourceTree = ""; }; + 3FE6ED2A6018975A571C0123A5AA358E /* QNPartsUploadPerformerV1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPartsUploadPerformerV1.m; path = QiniuSDK/Storage/QNPartsUploadPerformerV1.m; sourceTree = ""; }; + 403607B58842099BD4730AC22C6B96AD /* QNResolvUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNResolvUtil.m; path = HappyDNS/Local/QNResolvUtil.m; sourceTree = ""; }; + 40A726DB59657716867C8B1AB36E6C30 /* QNUploadInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadInfo.h; path = QiniuSDK/Storage/QNUploadInfo.h; sourceTree = ""; }; + 418E1B7F76831263DC2AF0D63297F6D8 /* QNMutableArray.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNMutableArray.h; path = QiniuSDK/Utils/QNMutableArray.h; sourceTree = ""; }; + 41A44E8CFC5EE315D8942BE4A88ACC66 /* QNUploadServerNetworkStatus.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadServerNetworkStatus.h; path = QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.h; sourceTree = ""; }; + 444901F5C99E84244FFABCB93FF16030 /* QNUploadRequestState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadRequestState.h; path = QiniuSDK/Http/QNUploadRequestState.h; sourceTree = ""; }; + 448FBEEDDFA17AF962D540807C427EF7 /* QNNetworkStatusManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNNetworkStatusManager.m; path = QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.m; sourceTree = ""; }; + 44CFFF5253D00A2A2A8EB8C49651B310 /* NSData+QNGZip.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+QNGZip.h"; path = "QiniuSDK/Utils/NSData+QNGZip.h"; sourceTree = ""; }; + 44F5CFD75D34546DB23D1DDD35D69D33 /* QNCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNCache.m; path = QiniuSDK/Utils/QNCache.m; sourceTree = ""; }; + 464AAB9B64DCDBB86575B4B1BDDFE93D /* HappyDNS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "HappyDNS-dummy.m"; sourceTree = ""; }; + 480E9C0A1D7837BE60AA9B83DC6A204D /* QNPipeline.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPipeline.m; path = QiniuSDK/BigData/QNPipeline.m; sourceTree = ""; }; + 493046A050F831EF8BE1ABEAC11D8B1B /* HappyDNS-HappyDNS.privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "HappyDNS-HappyDNS.privacy"; path = HappyDNS.privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 4943A7294DB91F20EC946148A39D3F89 /* QNUpToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUpToken.h; path = QiniuSDK/Storage/QNUpToken.h; sourceTree = ""; }; + 4B5092555676E150E1F88993C23FD24E /* QNHttpRegionRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNHttpRegionRequest.m; path = QiniuSDK/Http/Request/QNHttpRegionRequest.m; sourceTree = ""; }; + 4C39991E85951B0BC0E8F0B209AF0DAF /* Qiniu-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Qiniu-prefix.pch"; sourceTree = ""; }; + 4C6E979EF9BB067B89CAD0B86DFC8810 /* QNConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNConfiguration.m; path = QiniuSDK/Storage/QNConfiguration.m; sourceTree = ""; }; + 4D515E3C7EF405627BF376F69EE1EBB3 /* NSData+QNRW.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+QNRW.m"; path = "HappyDNS/Util/NSData+QNRW.m"; sourceTree = ""; }; + 4ECBA8228CFBB4C28FF79A203C2BB27D /* Qiniu.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Qiniu.release.xcconfig; sourceTree = ""; }; + 4F2AE448D52382DC14F29987B684F78A /* QNLruCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNLruCache.h; path = HappyDNS/Common/QNLruCache.h; sourceTree = ""; }; + 4F52E6FDCEB0481BDE0AC37643FE2F11 /* QNUploadInfoReporter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadInfoReporter.h; path = QiniuSDK/Collect/QNUploadInfoReporter.h; sourceTree = ""; }; + 4F6DC7D2D01596F560201E643A8599F1 /* QNSystem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNSystem.h; path = QiniuSDK/Utils/QNSystem.h; sourceTree = ""; }; + 510585ACBFC40783C8804931EC4FFB8C /* QNPHAssetResource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPHAssetResource.m; path = QiniuSDK/Utils/QNPHAssetResource.m; sourceTree = ""; }; + 5123B4029742776B759BCC99F43391EF /* QNUploadSystemClient.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadSystemClient.m; path = QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.m; sourceTree = ""; }; + 52092A3E4758686C88E09A8A822CB1A4 /* QNUploadSourceStream.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadSourceStream.h; path = QiniuSDK/Storage/QNUploadSourceStream.h; sourceTree = ""; }; + 538BD2F88175C3CBDA73EBB63DC767C5 /* QNUploadRequestMetrics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadRequestMetrics.h; path = QiniuSDK/Http/QNUploadRequestMetrics.h; sourceTree = ""; }; + 53B880536FAA662603F8BB45F2165001 /* Pods-msext-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-msext-dummy.m"; sourceTree = ""; }; + 54A78797CE409C762D6C6554451D8A70 /* QNPartsUpload.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPartsUpload.h; path = QiniuSDK/Storage/QNPartsUpload.h; sourceTree = ""; }; + 56D0F4F676D3CAD396D6E9982A959443 /* QNCrc32.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNCrc32.h; path = QiniuSDK/Utils/QNCrc32.h; sourceTree = ""; }; + 57B304DE091973BDA5DDE597DA01132F /* QNUploadServerFreezeUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadServerFreezeUtil.h; path = QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.h; sourceTree = ""; }; + 585CD993F6AFD84EA26ED2C66323D21B /* QNUploadBlock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadBlock.m; path = QiniuSDK/Storage/QNUploadBlock.m; sourceTree = ""; }; + 58DD6EF473E719379913E15C40F7C94D /* Qiniu.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Qiniu.debug.xcconfig; sourceTree = ""; }; + 59A87D10C90FD4E8F9EBEA561533291C /* QNNetworkInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNNetworkInfo.m; path = HappyDNS/Common/QNNetworkInfo.m; sourceTree = ""; }; + 59AAA1299154D08C7063B7BBB53FDA90 /* QNUserAgent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUserAgent.h; path = QiniuSDK/Http/QNUserAgent.h; sourceTree = ""; }; + 5AF7BCFE0AF33AD63278E420FC517304 /* HappyDNS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = HappyDNS.debug.xcconfig; sourceTree = ""; }; + 5D4BA683411586A786AE0B4B3C0F4C3D /* QNUploadInfoReporter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadInfoReporter.m; path = QiniuSDK/Collect/QNUploadInfoReporter.m; sourceTree = ""; }; + 5F0275D010EB9CBB29C4FFC8C60E35B6 /* QNRecord.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNRecord.m; path = HappyDNS/Common/QNRecord.m; sourceTree = ""; }; + 5F80E9292C6EA5A58ECBC8A9F7922D9C /* QNDnsUdpResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsUdpResolver.m; path = HappyDNS/Dns/QNDnsUdpResolver.m; sourceTree = ""; }; + 5FF7C504D96C137090D555AB79D5FAF1 /* QNFormUpload.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNFormUpload.m; path = QiniuSDK/Storage/QNFormUpload.m; sourceTree = ""; }; + 6006E7736851F5B2C9571FE2D8E91377 /* QNIP.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNIP.m; path = HappyDNS/Util/QNIP.m; sourceTree = ""; }; + 6175C670769797A256146AF781DBBD73 /* QNErrorCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNErrorCode.h; path = QiniuSDK/Common/QNErrorCode.h; sourceTree = ""; }; + 64FDDBA6B9281D67C7214592245FBF15 /* QNZoneInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNZoneInfo.h; path = QiniuSDK/Common/QNZoneInfo.h; sourceTree = ""; }; + 698E018EB0D0899DD2C2F38E94FD5A74 /* QNUpToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUpToken.m; path = QiniuSDK/Storage/QNUpToken.m; sourceTree = ""; }; + 69EC4C1DF6A56827B78E4AF0E907F8CF /* QNDnspodEnterprise.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnspodEnterprise.h; path = HappyDNS/Http/QNDnspodEnterprise.h; sourceTree = ""; }; + 6B2EAA225A02A04218D535E3F679B6FB /* QNPartsUploadPerformerV2.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPartsUploadPerformerV2.h; path = QiniuSDK/Storage/QNPartsUploadPerformerV2.h; sourceTree = ""; }; + 6E086CB41F588914AEBD9A24D21A98E6 /* QNServerConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNServerConfig.m; path = QiniuSDK/Storage/ServerConfig/QNServerConfig.m; sourceTree = ""; }; + 723162DA2F24F7C74D707F106FDACD23 /* QNSessionManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNSessionManager.h; path = QiniuSDK/BigData/QNSessionManager.h; sourceTree = ""; }; + 74D0E736E89F1197E45102F0F5318EE2 /* QNDnsPrefetch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsPrefetch.m; path = QiniuSDK/Http/Dns/QNDnsPrefetch.m; sourceTree = ""; }; + 74D331F51CA2F803B4129019B829C378 /* QNUploadDomainRegion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadDomainRegion.h; path = QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.h; sourceTree = ""; }; + 761F2F78628D1D5262D05A37FB741441 /* QNLogUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNLogUtil.m; path = QiniuSDK/Utils/QNLogUtil.m; sourceTree = ""; }; + 77184E055AF16747C5C596E7FBF3D761 /* QNIP.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNIP.h; path = HappyDNS/Util/QNIP.h; sourceTree = ""; }; + 78717F975ACB392DA55804B14D6A4FE9 /* QNDnsResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsResolver.m; path = HappyDNS/Dns/QNDnsResolver.m; sourceTree = ""; }; + 78A9C0282EA043EF000B013B8ED13CCC /* QNDnsResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsResponse.h; path = HappyDNS/Dns/QNDnsResponse.h; sourceTree = ""; }; + 7A19CA58F24BC3E2893FD436BF033798 /* QNDohResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDohResolver.m; path = HappyDNS/Dns/QNDohResolver.m; sourceTree = ""; }; + 7AF4376FF1077F9375D1B61F8BBEC8B5 /* QNReportConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNReportConfig.m; path = QiniuSDK/Collect/QNReportConfig.m; sourceTree = ""; }; + 7C0AF86EBE5E8F64D381431E106CD267 /* QNUploadSourceFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadSourceFile.h; path = QiniuSDK/Storage/QNUploadSourceFile.h; sourceTree = ""; }; + 7CA54DBB52133EB7A4078A90C9250155 /* QNConcurrentResumeUpload.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNConcurrentResumeUpload.h; path = QiniuSDK/Storage/QNConcurrentResumeUpload.h; sourceTree = ""; }; + 7D0D158A0121537C0E7409292DD0424D /* QNCFHttpClient.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNCFHttpClient.m; path = QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.m; sourceTree = ""; }; + 7F9F4BCBAA7B2EC9BC06267BCBB67794 /* QNHosts.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNHosts.h; path = HappyDNS/Local/QNHosts.h; sourceTree = ""; }; + 812EC1822605C9634F6C3E9546BAC454 /* QNUploadInfoV2.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadInfoV2.h; path = QiniuSDK/Storage/QNUploadInfoV2.h; sourceTree = ""; }; + 81321B7225B94E7A17C0931B3E7F276E /* QNPartsUploadPerformer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPartsUploadPerformer.m; path = QiniuSDK/Storage/QNPartsUploadPerformer.m; sourceTree = ""; }; + 82C6291B76209256C5812698BB612A72 /* QNHttpSingleRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNHttpSingleRequest.m; path = QiniuSDK/Http/Request/QNHttpSingleRequest.m; sourceTree = ""; }; + 83203BFAB9C4F655B2B88ABF0D3CEB4E /* QNDnsCacheInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsCacheInfo.h; path = QiniuSDK/Http/Dns/QNDnsCacheInfo.h; sourceTree = ""; }; + 83ABF04A2FACD1E8E29B1A7E552BB215 /* QNGetAddrInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNGetAddrInfo.h; path = HappyDNS/Util/QNGetAddrInfo.h; sourceTree = ""; }; + 847CFC23C914A7CCBF75F5D4CE865C0A /* QNPartsUploadPerformerV1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPartsUploadPerformerV1.h; path = QiniuSDK/Storage/QNPartsUploadPerformerV1.h; sourceTree = ""; }; + 8534930B178F9203470A253A3AC523F4 /* QNPartsUploadPerformerV2.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPartsUploadPerformerV2.m; path = QiniuSDK/Storage/QNPartsUploadPerformerV2.m; sourceTree = ""; }; + 85A39400B7C9B7F8ED9F73DDE08D198A /* QNUploadServer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadServer.h; path = QiniuSDK/Http/ServerRegion/QNUploadServer.h; sourceTree = ""; }; + 864616D11289C3BF4E6C872C01A8CA39 /* QNPHAssetFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPHAssetFile.h; path = QiniuSDK/Utils/QNPHAssetFile.h; sourceTree = ""; }; + 8695E9F0766A202C652B1CF7105422C6 /* QNResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNResolver.h; path = HappyDNS/Local/QNResolver.h; sourceTree = ""; }; + 86B89E5C4FDF8462D78A9925A1013F6B /* QNDnsDefine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsDefine.h; path = HappyDNS/Dns/QNDnsDefine.h; sourceTree = ""; }; + 86CFAAAB79E2A7C50B4C1E94A72D2BD2 /* QNFileDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNFileDelegate.h; path = QiniuSDK/Utils/QNFileDelegate.h; sourceTree = ""; }; + 8769E4D9DFFCF732E4B72DDB04773D41 /* QNEtag.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNEtag.h; path = QiniuSDK/Utils/QNEtag.h; sourceTree = ""; }; + 8912CA14784BE3548E5AC2CA8873C415 /* Qiniu-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Qiniu-dummy.m"; sourceTree = ""; }; + 893C9FDD66BF35A81502E28E4F767721 /* QNSingleFlight.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNSingleFlight.m; path = QiniuSDK/Utils/QNSingleFlight.m; sourceTree = ""; }; + 8BCE804B544C9595D683E96A3E7E2677 /* QNConnectChecker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNConnectChecker.m; path = QiniuSDK/Http/ConnectCheck/QNConnectChecker.m; sourceTree = ""; }; + 8CB37F8534A03ACD356B47AC1FA44D93 /* QNUploadRegionInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadRegionInfo.h; path = QiniuSDK/Http/Request/QNUploadRegionInfo.h; sourceTree = ""; }; + 8F5C80C6BA42C7ECF7D30A038C03F95A /* QNUploadSystemClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadSystemClient.h; path = QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.h; sourceTree = ""; }; + 9001544182AD65FAD65692A10D67D47B /* QNIUploadServer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNIUploadServer.h; path = QiniuSDK/Http/Request/QNIUploadServer.h; sourceTree = ""; }; + 905CB0F3866B1BA95985D9BCA2305F36 /* QNUploadManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadManager.h; path = QiniuSDK/Storage/QNUploadManager.h; sourceTree = ""; }; + 9135242B986EAD01754CDE556F563E5F /* QNFixedZone.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNFixedZone.m; path = QiniuSDK/Common/QNFixedZone.m; sourceTree = ""; }; + 9138B03A4492B1E01308EF4EFEC48596 /* QNUploadRequestMetrics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadRequestMetrics.m; path = QiniuSDK/Http/QNUploadRequestMetrics.m; sourceTree = ""; }; + 91E994A08B81C1236866B44231D17142 /* Pods-msext-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-msext-acknowledgements.markdown"; sourceTree = ""; }; + 92A9A7A4E30C5792E5BB535F5C7BE536 /* QiniuSDK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QiniuSDK.h; path = QiniuSDK/QiniuSDK.h; sourceTree = ""; }; + 93C5FED255F5DBEADBA829F691DE22C6 /* QNHijackingDetectWrapper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNHijackingDetectWrapper.m; path = HappyDNS/Local/QNHijackingDetectWrapper.m; sourceTree = ""; }; + 94D19C7474694E4FD4651D0CC2303865 /* QNDnsManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsManager.h; path = HappyDNS/Common/QNDnsManager.h; sourceTree = ""; }; + 97A9BA70792CFF5303724379B3B2925C /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = QiniuSDK/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 987951A732C83F0EDD2686A3113C1660 /* QNFormUpload.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNFormUpload.h; path = QiniuSDK/Storage/QNFormUpload.h; sourceTree = ""; }; + 994182C7C3D68278988EF0FA6F371AA0 /* QNPHAssetResource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPHAssetResource.h; path = QiniuSDK/Utils/QNPHAssetResource.h; sourceTree = ""; }; + 99FF2CB42958DAB7AEAD203B545B8C4F /* QNFixedZone.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNFixedZone.h; path = QiniuSDK/Common/QNFixedZone.h; sourceTree = ""; }; + 9AC4D30A22DE4773F329B74F57240856 /* QNDnsCacheInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsCacheInfo.m; path = QiniuSDK/Http/Dns/QNDnsCacheInfo.m; sourceTree = ""; }; + 9B6D3D2A6853FE1F4C6307DB661D5298 /* QNCFHttpClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNCFHttpClient.h; path = QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h; sourceTree = ""; }; + 9B9561C8F7DC0CAADB1217ED15C85DEC /* QNServerUserConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNServerUserConfig.m; path = QiniuSDK/Storage/ServerConfig/QNServerUserConfig.m; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9FB0F5E1925AF6E3C165F92F34D8B7A7 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = HappyDNS/PrivacyInfo.xcprivacy; sourceTree = ""; }; + A0931AAEFF7DC633008639C7FC4F94A5 /* QNHex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNHex.m; path = HappyDNS/Util/QNHex.m; sourceTree = ""; }; + A1966DFF26B064B6A60AF2568F9982B3 /* QNReportConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNReportConfig.h; path = QiniuSDK/Collect/QNReportConfig.h; sourceTree = ""; }; + A2042A4CAAD516E394F5E58CB98F4F67 /* QNCFHttpThreadPool.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNCFHttpThreadPool.m; path = QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.m; sourceTree = ""; }; + A221251C091AF510A609C108982CB1D1 /* QNUploadInfoV1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadInfoV1.m; path = QiniuSDK/Storage/QNUploadInfoV1.m; sourceTree = ""; }; + A4AA31A61B3937CBA327208E5243717A /* QNUploadOption.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadOption.h; path = QiniuSDK/Storage/QNUploadOption.h; sourceTree = ""; }; + A56D833FAE5B35240EE1D9026A8EFD45 /* QNInetAddress.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNInetAddress.m; path = QiniuSDK/Http/Dns/QNInetAddress.m; sourceTree = ""; }; + A63AF106E1DDEEBA3B15178E7DFDB2D6 /* QNAutoZone.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNAutoZone.m; path = QiniuSDK/Common/QNAutoZone.m; sourceTree = ""; }; + A7B82792B39240C408DA7D6FEB677DA6 /* Qiniu */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = Qiniu; path = libQiniu.a; sourceTree = BUILT_PRODUCTS_DIR; }; + A815861313DCAFC2F88A9F5D3ACB7440 /* QNHex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNHex.h; path = HappyDNS/Util/QNHex.h; sourceTree = ""; }; + A88A6DD28323644A265297F8B56DE3FD /* QNDohResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDohResolver.h; path = HappyDNS/Dns/QNDohResolver.h; sourceTree = ""; }; + A8E13048620040754D4A99B474D82AC8 /* QNUploadServerFreezeUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadServerFreezeUtil.m; path = QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.m; sourceTree = ""; }; + AA5369E025BA75B4CFBFC684A8DEE017 /* QNUploadOption.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadOption.m; path = QiniuSDK/Storage/QNUploadOption.m; sourceTree = ""; }; + AB431F11F56810275DDF177CBCBB9765 /* QNUploadServerNetworkStatus.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadServerNetworkStatus.m; path = QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.m; sourceTree = ""; }; + ABA75D968E076B1C3939AF39502DC993 /* Pods-msext.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-msext.release.xcconfig"; sourceTree = ""; }; + AD78C2CF832D0A30ABBF42BFE19FED10 /* QNUploadServer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadServer.m; path = QiniuSDK/Http/ServerRegion/QNUploadServer.m; sourceTree = ""; }; + B19CD69FFBED4C0022227CF0B702B461 /* NSObject+QNSwizzle.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSObject+QNSwizzle.h"; path = "QiniuSDK/Utils/NSObject+QNSwizzle.h"; sourceTree = ""; }; + B1A913E99B99654FCF59E37B02A3CC9E /* QNNetworkStatusManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNNetworkStatusManager.h; path = QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.h; sourceTree = ""; }; + B2F9A345F5B6BE60F7F5BDF34295C5A2 /* QNUserAgent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUserAgent.m; path = QiniuSDK/Http/QNUserAgent.m; sourceTree = ""; }; + B33E60A599A4CA1193C414960E161861 /* QNUploadSourceStream.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadSourceStream.m; path = QiniuSDK/Storage/QNUploadSourceStream.m; sourceTree = ""; }; + B34134035FD1744909633BE9A62D6FA3 /* QNMutableArray.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNMutableArray.m; path = QiniuSDK/Utils/QNMutableArray.m; sourceTree = ""; }; + B43E6A6F8478BC76541791BF5653CAB0 /* QNUploadInfoV1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadInfoV1.h; path = QiniuSDK/Storage/QNUploadInfoV1.h; sourceTree = ""; }; + B5735E782B3714FA446524FDB5516BD4 /* QNDnsResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsResolver.h; path = HappyDNS/Dns/QNDnsResolver.h; sourceTree = ""; }; + B61A1E1CF720A9FF98E627A3A603BC1C /* QNTransactionManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNTransactionManager.m; path = QiniuSDK/Transaction/QNTransactionManager.m; sourceTree = ""; }; + B73356693E5EEF47E767298D61C49BB1 /* QNRecord.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNRecord.h; path = HappyDNS/Common/QNRecord.h; sourceTree = ""; }; + B79D8FBE5D620418D3A501E423413042 /* QNALAssetFile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNALAssetFile.m; path = QiniuSDK/Utils/QNALAssetFile.m; sourceTree = ""; }; + B808218FFC5C59359D25FD81D9EAEA76 /* QNUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUtils.m; path = QiniuSDK/Utils/QNUtils.m; sourceTree = ""; }; + B846104C566BA5F2F5D11EA9CC5BEE54 /* QNConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNConfiguration.h; path = QiniuSDK/Storage/QNConfiguration.h; sourceTree = ""; }; + B8549EF474251783802766729B86324F /* QNUploadManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadManager.m; path = QiniuSDK/Storage/QNUploadManager.m; sourceTree = ""; }; + BA9C543D6B3611C59AA82A173029570E /* QN_GTM_Base64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QN_GTM_Base64.h; path = QiniuSDK/Utils/QN_GTM_Base64.h; sourceTree = ""; }; + BD0CFFFA0B3C4B5C29949A00485F47F6 /* QNUploadRequestInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadRequestInfo.h; path = QiniuSDK/Http/Request/QNUploadRequestInfo.h; sourceTree = ""; }; + BE64EFA6EDCFD5B12C920671149D028C /* QNResolvUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNResolvUtil.h; path = HappyDNS/Local/QNResolvUtil.h; sourceTree = ""; }; + BECC8F14377F57CFC98229493CDCDAFB /* QNHosts.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNHosts.m; path = HappyDNS/Local/QNHosts.m; sourceTree = ""; }; + BF99C6558B7471DA7A4328679436DC81 /* QNDnsRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsRequest.h; path = HappyDNS/Dns/QNDnsRequest.h; sourceTree = ""; }; + C13A4ACFA53E6DFA5883CED6D5BA6E7B /* QNCFHttpThreadPool.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNCFHttpThreadPool.h; path = QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h; sourceTree = ""; }; + C48C4859E5FF23089802FEFE1F29EE20 /* QNDnsPrefetch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsPrefetch.h; path = QiniuSDK/Http/Dns/QNDnsPrefetch.h; sourceTree = ""; }; + C49CE688BF6B04792B5E434362B352D5 /* QNConcurrentResumeUpload.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNConcurrentResumeUpload.m; path = QiniuSDK/Storage/QNConcurrentResumeUpload.m; sourceTree = ""; }; + C767D72C454BBCA7A797CD7596C85A4B /* QNDns.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDns.h; path = QiniuSDK/Http/Dns/QNDns.h; sourceTree = ""; }; + C8BC1F8A67ED28C334BBE2228C13DBFB /* QNResolverDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNResolverDelegate.h; path = HappyDNS/Common/QNResolverDelegate.h; sourceTree = ""; }; + C90152077EF63F3F4D7BEA4A0A418241 /* QNFileRecorder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNFileRecorder.h; path = QiniuSDK/Recorder/QNFileRecorder.h; sourceTree = ""; }; + CBE2EC2EAB1D927C6F8AC74197397801 /* QNPartsUpload.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPartsUpload.m; path = QiniuSDK/Storage/QNPartsUpload.m; sourceTree = ""; }; + CDC025156C6D660168C76A14CCEF4D16 /* QNHttpRegionRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNHttpRegionRequest.h; path = QiniuSDK/Http/Request/QNHttpRegionRequest.h; sourceTree = ""; }; + CE2E26E93574B31F7B5D747C65C84AF4 /* QNDomain.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDomain.h; path = HappyDNS/Common/QNDomain.h; sourceTree = ""; }; + CE6D3A487AB9CCA73FD67AF727FED561 /* QNCrc32.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNCrc32.m; path = QiniuSDK/Utils/QNCrc32.m; sourceTree = ""; }; + D01B03918D576895B40B8342EF6F1D47 /* QNDnsCacheFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsCacheFile.h; path = QiniuSDK/Http/Dns/QNDnsCacheFile.h; sourceTree = ""; }; + D09D565D1E250BA14443C5CB9EE9E121 /* HappyDNS.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HappyDNS.h; path = HappyDNS/HappyDNS.h; sourceTree = ""; }; + D0B5384A1FF2AF8B288A151F7B2AF4D1 /* QNTxtResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNTxtResolver.h; path = HappyDNS/Local/QNTxtResolver.h; sourceTree = ""; }; + D10401361DC3A413263B24FDCD1CC291 /* HappyDNS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = HappyDNS.release.xcconfig; sourceTree = ""; }; + D3B4D656F820DA00F5E43B02CDC559B1 /* QNDnsUdpResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsUdpResolver.h; path = HappyDNS/Dns/QNDnsUdpResolver.h; sourceTree = ""; }; + D4EDE0519DF8027C47DA50CCAB1126E7 /* QNUploadSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUploadSource.h; path = QiniuSDK/Storage/QNUploadSource.h; sourceTree = ""; }; + D6056BE4A98153C8435CEC49BD61D35D /* QNUrlUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUrlUtils.h; path = QiniuSDK/Utils/QNUrlUtils.h; sourceTree = ""; }; + D7B7BDCBBD76A334D639EA44C8143EBB /* QNPipeline.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNPipeline.h; path = QiniuSDK/BigData/QNPipeline.h; sourceTree = ""; }; + D91F08368AAE25D4490CD8D3D057C75A /* QNEtag.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNEtag.m; path = QiniuSDK/Utils/QNEtag.m; sourceTree = ""; }; + DB3F837186266522119EFD22479B38E5 /* ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist"; sourceTree = ""; }; + DCB90C502C7D2C2B26CDA037FE01F24F /* QNDefine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDefine.m; path = QiniuSDK/Utils/QNDefine.m; sourceTree = ""; }; + DE70BD948705691EAC0035AF087C3FA3 /* QNPHAssetFile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNPHAssetFile.m; path = QiniuSDK/Utils/QNPHAssetFile.m; sourceTree = ""; }; + DFD1F913622154A3DAE8AB27305B0AE8 /* QNUrlSafeBase64.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUrlSafeBase64.m; path = QiniuSDK/Utils/QNUrlSafeBase64.m; sourceTree = ""; }; + E07CEC148C3EE2019D2D5D99C4BC53A2 /* QNUploadData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadData.m; path = QiniuSDK/Storage/QNUploadData.m; sourceTree = ""; }; + E0951FD86AC45A788DC9511EC022A61F /* Pods-msext */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "Pods-msext"; path = "libPods-msext.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + E0DC9F438E70C3804A5F385E5F8D3917 /* NSObject+QNSwizzle.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSObject+QNSwizzle.m"; path = "QiniuSDK/Utils/NSObject+QNSwizzle.m"; sourceTree = ""; }; + E14F45FE51A8B43155BB0F0233CFB106 /* QNBaseUpload.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNBaseUpload.h; path = QiniuSDK/Storage/QNBaseUpload.h; sourceTree = ""; }; + E30A65BA27A072F1306DB2388089DC98 /* QNUploadSourceFile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadSourceFile.m; path = QiniuSDK/Storage/QNUploadSourceFile.m; sourceTree = ""; }; + E5548E5A291581440C8BC636F55BC7E3 /* QNFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNFile.h; path = QiniuSDK/Utils/QNFile.h; sourceTree = ""; }; + E65EBC7EE87A25E4F86AC87FF9587D1A /* QNHttpSingleRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNHttpSingleRequest.h; path = QiniuSDK/Http/Request/QNHttpSingleRequest.h; sourceTree = ""; }; + E683DD5A2FDA4732513D90C1370A730B /* QNLruCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNLruCache.m; path = HappyDNS/Common/QNLruCache.m; sourceTree = ""; }; + E8A77999BCB1027863490ABB6DC80B91 /* QNReportItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNReportItem.h; path = QiniuSDK/Collect/QNReportItem.h; sourceTree = ""; }; + E93456BD99FE4C120360C8EE467C4E25 /* QNUpProgress.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUpProgress.h; path = QiniuSDK/Storage/QNUpProgress.h; sourceTree = ""; }; + E95A7C67CE2E7B37438781CA58210F3E /* QNUploadServerFreezeManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadServerFreezeManager.m; path = QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.m; sourceTree = ""; }; + E95C1A7355A7F40777F55E9BF9965D56 /* NSData+QNGZip.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+QNGZip.m"; path = "QiniuSDK/Utils/NSData+QNGZip.m"; sourceTree = ""; }; + E96FD00F54A57EB23E8709808E290E4C /* QNServerConfigMonitor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNServerConfigMonitor.m; path = QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.m; sourceTree = ""; }; + EBE6C6FD459A6B45F96D5FE944BFB2AF /* QNFile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNFile.m; path = QiniuSDK/Utils/QNFile.m; sourceTree = ""; }; + EBFEA24EA474C5982FF42213814675B0 /* QNUploadRequestInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNUploadRequestInfo.m; path = QiniuSDK/Http/Request/QNUploadRequestInfo.m; sourceTree = ""; }; + EDDC6B89123EBB9EF93590F05879F928 /* Pods-msext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-msext.debug.xcconfig"; sourceTree = ""; }; + EE22A2E95A47055E0ED97D4242DABAEB /* QNDefine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDefine.h; path = QiniuSDK/Utils/QNDefine.h; sourceTree = ""; }; + EF0AA010DBD42A3ED8F737464F10CA40 /* QNErrorCode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNErrorCode.m; path = QiniuSDK/Common/QNErrorCode.m; sourceTree = ""; }; + F0CD75989071374CACB370D591D1B209 /* QNUrlSafeBase64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNUrlSafeBase64.h; path = QiniuSDK/Utils/QNUrlSafeBase64.h; sourceTree = ""; }; + F2E92BA3056D35FF76FF9577CBCEAF3B /* NSData+QNRW.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+QNRW.h"; path = "HappyDNS/Util/NSData+QNRW.h"; sourceTree = ""; }; + F4558BBEBB365756430BBF5A9C690C65 /* QNAutoZone.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNAutoZone.h; path = QiniuSDK/Common/QNAutoZone.h; sourceTree = ""; }; + F51916885BBA58862D3FF72A162AE04E /* QNLogUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNLogUtil.h; path = QiniuSDK/Utils/QNLogUtil.h; sourceTree = ""; }; + F6A558BD64030C2B22BF8240EB72BFAB /* QNVersion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNVersion.h; path = QiniuSDK/Utils/QNVersion.h; sourceTree = ""; }; + F6D7B36D918469680BA194548DC1EFCC /* QNDomain.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDomain.m; path = HappyDNS/Common/QNDomain.m; sourceTree = ""; }; + F8B35140EE209B55F842ADD443DEDAC6 /* QNResponseInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNResponseInfo.m; path = QiniuSDK/Http/QNResponseInfo.m; sourceTree = ""; }; + F94078825997C7453132A941A4043D93 /* QNTxtResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNTxtResolver.m; path = HappyDNS/Local/QNTxtResolver.m; sourceTree = ""; }; + F9BA7D8B8AA8EBA304E0145EE6948CF7 /* QNResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNResolver.m; path = HappyDNS/Local/QNResolver.m; sourceTree = ""; }; + FA38D537E3338AF8DADCCBE577891E6F /* QNDnsError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsError.h; path = HappyDNS/Common/QNDnsError.h; sourceTree = ""; }; + FAC4EF66A8F63391B34202E52DA4AFDB /* QNDnsMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNDnsMessage.h; path = HappyDNS/Dns/QNDnsMessage.h; sourceTree = ""; }; + FB9F59C91B1A3769BCE5FDF891A9A7BD /* QNDnsRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = QNDnsRequest.m; path = HappyDNS/Dns/QNDnsRequest.m; sourceTree = ""; }; + FD28D7585D033EAC425B8EC3F7F0C899 /* QNResponseInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = QNResponseInfo.h; path = QiniuSDK/Http/QNResponseInfo.h; sourceTree = ""; }; + FDBAD2031CCEA0251D342DB039D2D1BA /* Qiniu-Qiniu.privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "Qiniu-Qiniu.privacy"; path = Qiniu.privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 043BE0650B2256A2C98C0E761C8AED66 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 23A583BF81A570380F7F257201EBF26F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3077435C5524607F90998DBB65138927 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 71E4E122F3A1990A51B0797F9611F60C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E097643998A1750F452B28CE7747F0D9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0799DE43BC62D6220ADA29A00BFA0414 /* HappyDNS */ = { + isa = PBXGroup; + children = ( + D09D565D1E250BA14443C5CB9EE9E121 /* HappyDNS.h */, + F2E92BA3056D35FF76FF9577CBCEAF3B /* NSData+QNRW.h */, + 4D515E3C7EF405627BF376F69EE1EBB3 /* NSData+QNRW.m */, + 1D5EE68B000E7EE5CEEA789E11D159E9 /* QNAsyncUdpSocket.h */, + 24E893AB5487C90972A197592614F131 /* QNAsyncUdpSocket.m */, + 2F8128F42BD18C409B18FAFC01939A52 /* QNDes.h */, + 00E5EC0DED9848A2FE8A0306B981392D /* QNDes.m */, + 86B89E5C4FDF8462D78A9925A1013F6B /* QNDnsDefine.h */, + FA38D537E3338AF8DADCCBE577891E6F /* QNDnsError.h */, + 184788383616F05C6E48C10981453705 /* QNDnsError.m */, + 94D19C7474694E4FD4651D0CC2303865 /* QNDnsManager.h */, + 33E10E0CC798232339FEEE1B93058C6A /* QNDnsManager.m */, + FAC4EF66A8F63391B34202E52DA4AFDB /* QNDnsMessage.h */, + 13AD7BA30DFCC0E13BC273492233D986 /* QNDnsMessage.m */, + 69EC4C1DF6A56827B78E4AF0E907F8CF /* QNDnspodEnterprise.h */, + 26B144A2038C8AB7D0F006999AE1565D /* QNDnspodEnterprise.m */, + BF99C6558B7471DA7A4328679436DC81 /* QNDnsRequest.h */, + FB9F59C91B1A3769BCE5FDF891A9A7BD /* QNDnsRequest.m */, + B5735E782B3714FA446524FDB5516BD4 /* QNDnsResolver.h */, + 78717F975ACB392DA55804B14D6A4FE9 /* QNDnsResolver.m */, + 78A9C0282EA043EF000B013B8ED13CCC /* QNDnsResponse.h */, + 31E55124AAF41DFCF688CC9B5CBD6EC7 /* QNDnsResponse.m */, + D3B4D656F820DA00F5E43B02CDC559B1 /* QNDnsUdpResolver.h */, + 5F80E9292C6EA5A58ECBC8A9F7922D9C /* QNDnsUdpResolver.m */, + A88A6DD28323644A265297F8B56DE3FD /* QNDohResolver.h */, + 7A19CA58F24BC3E2893FD436BF033798 /* QNDohResolver.m */, + CE2E26E93574B31F7B5D747C65C84AF4 /* QNDomain.h */, + F6D7B36D918469680BA194548DC1EFCC /* QNDomain.m */, + 83ABF04A2FACD1E8E29B1A7E552BB215 /* QNGetAddrInfo.h */, + 3BC74568D261EDC4C83E16AE36224866 /* QNGetAddrInfo.m */, + A815861313DCAFC2F88A9F5D3ACB7440 /* QNHex.h */, + A0931AAEFF7DC633008639C7FC4F94A5 /* QNHex.m */, + 18314E905A8D5C182A33669B5675B997 /* QNHijackingDetectWrapper.h */, + 93C5FED255F5DBEADBA829F691DE22C6 /* QNHijackingDetectWrapper.m */, + 7F9F4BCBAA7B2EC9BC06267BCBB67794 /* QNHosts.h */, + BECC8F14377F57CFC98229493CDCDAFB /* QNHosts.m */, + 77184E055AF16747C5C596E7FBF3D761 /* QNIP.h */, + 6006E7736851F5B2C9571FE2D8E91377 /* QNIP.m */, + 4F2AE448D52382DC14F29987B684F78A /* QNLruCache.h */, + E683DD5A2FDA4732513D90C1370A730B /* QNLruCache.m */, + 2B38FD6D54D8204FC57D6B5BF8CE227B /* QNMD5.h */, + 16543171422AD405FDB49363A534D902 /* QNMD5.m */, + 353B822ED27D83F48A5DA3355A50F986 /* QNNetworkInfo.h */, + 59A87D10C90FD4E8F9EBEA561533291C /* QNNetworkInfo.m */, + B73356693E5EEF47E767298D61C49BB1 /* QNRecord.h */, + 5F0275D010EB9CBB29C4FFC8C60E35B6 /* QNRecord.m */, + 8695E9F0766A202C652B1CF7105422C6 /* QNResolver.h */, + F9BA7D8B8AA8EBA304E0145EE6948CF7 /* QNResolver.m */, + C8BC1F8A67ED28C334BBE2228C13DBFB /* QNResolverDelegate.h */, + BE64EFA6EDCFD5B12C920671149D028C /* QNResolvUtil.h */, + 403607B58842099BD4730AC22C6B96AD /* QNResolvUtil.m */, + D0B5384A1FF2AF8B288A151F7B2AF4D1 /* QNTxtResolver.h */, + F94078825997C7453132A941A4043D93 /* QNTxtResolver.m */, + 69EA23E50DF3C52548940AED9C606A40 /* Resources */, + C13AA13E00E4EDB1B831B61C17F4943F /* Support Files */, + ); + name = HappyDNS; + path = HappyDNS; + sourceTree = ""; + }; + 3846F526D55A1CFA8BC6D5F266DD6B6F /* Resources */ = { + isa = PBXGroup; + children = ( + 97A9BA70792CFF5303724379B3B2925C /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + 4DDE0989CCFEAAB6233C4BB989226A4F /* Qiniu */ = { + isa = PBXGroup; + children = ( + 44CFFF5253D00A2A2A8EB8C49651B310 /* NSData+QNGZip.h */, + E95C1A7355A7F40777F55E9BF9965D56 /* NSData+QNGZip.m */, + 32AC495FE5B637859C36EE43D9964E7D /* NSData+QNMD5.h */, + 3D527C7D6CE7620052ECB6BE2DB3DAC3 /* NSData+QNMD5.m */, + B19CD69FFBED4C0022227CF0B702B461 /* NSObject+QNSwizzle.h */, + E0DC9F438E70C3804A5F385E5F8D3917 /* NSObject+QNSwizzle.m */, + 178A385885F03FA4AB365C9BE594F4DA /* NSURLRequest+QNRequest.h */, + 24171AC23C0F552CD190532B6001762B /* NSURLRequest+QNRequest.m */, + 92A9A7A4E30C5792E5BB535F5C7BE536 /* QiniuSDK.h */, + BA9C543D6B3611C59AA82A173029570E /* QN_GTM_Base64.h */, + 04617DCCCBC5FA60EEC23070FADC017D /* QN_GTM_Base64.m */, + 30585F72C35E6288F2BA997013BD1CFB /* QNALAssetFile.h */, + B79D8FBE5D620418D3A501E423413042 /* QNALAssetFile.m */, + 05E66D896E39EA29440DA388C7E7D6AE /* QNAsyncRun.h */, + 1859C82BF05504A3872D673DF40C126E /* QNAsyncRun.m */, + F4558BBEBB365756430BBF5A9C690C65 /* QNAutoZone.h */, + A63AF106E1DDEEBA3B15178E7DFDB2D6 /* QNAutoZone.m */, + E14F45FE51A8B43155BB0F0233CFB106 /* QNBaseUpload.h */, + 2778E90F840997960E8B3B55F7C4212F /* QNBaseUpload.m */, + 028A189C700ACF2B6BC166A38D700E4F /* QNCache.h */, + 44F5CFD75D34546DB23D1DDD35D69D33 /* QNCache.m */, + 9B6D3D2A6853FE1F4C6307DB661D5298 /* QNCFHttpClient.h */, + 7D0D158A0121537C0E7409292DD0424D /* QNCFHttpClient.m */, + 0E342E62A09C3771212E0E69A51728B7 /* QNCFHttpClientInner.h */, + 04E226B77A5388AB12F501E7CCF28D24 /* QNCFHttpClientInner.m */, + C13A4ACFA53E6DFA5883CED6D5BA6E7B /* QNCFHttpThreadPool.h */, + A2042A4CAAD516E394F5E58CB98F4F67 /* QNCFHttpThreadPool.m */, + 7CA54DBB52133EB7A4078A90C9250155 /* QNConcurrentResumeUpload.h */, + C49CE688BF6B04792B5E434362B352D5 /* QNConcurrentResumeUpload.m */, + 356872ACF48824DAB546350FB71559B4 /* QNConfig.h */, + B846104C566BA5F2F5D11EA9CC5BEE54 /* QNConfiguration.h */, + 4C6E979EF9BB067B89CAD0B86DFC8810 /* QNConfiguration.m */, + 398256C46D6CA44A36703929A8FA52DD /* QNConnectChecker.h */, + 8BCE804B544C9595D683E96A3E7E2677 /* QNConnectChecker.m */, + 56D0F4F676D3CAD396D6E9982A959443 /* QNCrc32.h */, + CE6D3A487AB9CCA73FD67AF727FED561 /* QNCrc32.m */, + EE22A2E95A47055E0ED97D4242DABAEB /* QNDefine.h */, + DCB90C502C7D2C2B26CDA037FE01F24F /* QNDefine.m */, + C767D72C454BBCA7A797CD7596C85A4B /* QNDns.h */, + D01B03918D576895B40B8342EF6F1D47 /* QNDnsCacheFile.h */, + 075FFD3100B1BBB8B7FF8D6B19A23421 /* QNDnsCacheFile.m */, + 83203BFAB9C4F655B2B88ABF0D3CEB4E /* QNDnsCacheInfo.h */, + 9AC4D30A22DE4773F329B74F57240856 /* QNDnsCacheInfo.m */, + C48C4859E5FF23089802FEFE1F29EE20 /* QNDnsPrefetch.h */, + 74D0E736E89F1197E45102F0F5318EE2 /* QNDnsPrefetch.m */, + 6175C670769797A256146AF781DBBD73 /* QNErrorCode.h */, + EF0AA010DBD42A3ED8F737464F10CA40 /* QNErrorCode.m */, + 8769E4D9DFFCF732E4B72DDB04773D41 /* QNEtag.h */, + D91F08368AAE25D4490CD8D3D057C75A /* QNEtag.m */, + E5548E5A291581440C8BC636F55BC7E3 /* QNFile.h */, + EBE6C6FD459A6B45F96D5FE944BFB2AF /* QNFile.m */, + 86CFAAAB79E2A7C50B4C1E94A72D2BD2 /* QNFileDelegate.h */, + C90152077EF63F3F4D7BEA4A0A418241 /* QNFileRecorder.h */, + 1A2B2D7D5C6DD060C84D8ADF6D7A43E9 /* QNFileRecorder.m */, + 99FF2CB42958DAB7AEAD203B545B8C4F /* QNFixedZone.h */, + 9135242B986EAD01754CDE556F563E5F /* QNFixedZone.m */, + 987951A732C83F0EDD2686A3113C1660 /* QNFormUpload.h */, + 5FF7C504D96C137090D555AB79D5FAF1 /* QNFormUpload.m */, + CDC025156C6D660168C76A14CCEF4D16 /* QNHttpRegionRequest.h */, + 4B5092555676E150E1F88993C23FD24E /* QNHttpRegionRequest.m */, + E65EBC7EE87A25E4F86AC87FF9587D1A /* QNHttpSingleRequest.h */, + 82C6291B76209256C5812698BB612A72 /* QNHttpSingleRequest.m */, + 280814F276C6CCADD2A94E3518223671 /* QNInetAddress.h */, + A56D833FAE5B35240EE1D9026A8EFD45 /* QNInetAddress.m */, + 9001544182AD65FAD65692A10D67D47B /* QNIUploadServer.h */, + 255D992969763494AEF336410D9F1387 /* QNIUploadServer.m */, + F51916885BBA58862D3FF72A162AE04E /* QNLogUtil.h */, + 761F2F78628D1D5262D05A37FB741441 /* QNLogUtil.m */, + 418E1B7F76831263DC2AF0D63297F6D8 /* QNMutableArray.h */, + B34134035FD1744909633BE9A62D6FA3 /* QNMutableArray.m */, + B1A913E99B99654FCF59E37B02A3CC9E /* QNNetworkStatusManager.h */, + 448FBEEDDFA17AF962D540807C427EF7 /* QNNetworkStatusManager.m */, + 54A78797CE409C762D6C6554451D8A70 /* QNPartsUpload.h */, + CBE2EC2EAB1D927C6F8AC74197397801 /* QNPartsUpload.m */, + 1A3F45D03BB2D93F8407499089BBC7A6 /* QNPartsUploadPerformer.h */, + 81321B7225B94E7A17C0931B3E7F276E /* QNPartsUploadPerformer.m */, + 847CFC23C914A7CCBF75F5D4CE865C0A /* QNPartsUploadPerformerV1.h */, + 3FE6ED2A6018975A571C0123A5AA358E /* QNPartsUploadPerformerV1.m */, + 6B2EAA225A02A04218D535E3F679B6FB /* QNPartsUploadPerformerV2.h */, + 8534930B178F9203470A253A3AC523F4 /* QNPartsUploadPerformerV2.m */, + 864616D11289C3BF4E6C872C01A8CA39 /* QNPHAssetFile.h */, + DE70BD948705691EAC0035AF087C3FA3 /* QNPHAssetFile.m */, + 994182C7C3D68278988EF0FA6F371AA0 /* QNPHAssetResource.h */, + 510585ACBFC40783C8804931EC4FFB8C /* QNPHAssetResource.m */, + D7B7BDCBBD76A334D639EA44C8143EBB /* QNPipeline.h */, + 480E9C0A1D7837BE60AA9B83DC6A204D /* QNPipeline.m */, + 057857FCC29DFF01C90D8B01B5DA5DBC /* QNRecorderDelegate.h */, + A1966DFF26B064B6A60AF2568F9982B3 /* QNReportConfig.h */, + 7AF4376FF1077F9375D1B61F8BBEC8B5 /* QNReportConfig.m */, + E8A77999BCB1027863490ABB6DC80B91 /* QNReportItem.h */, + 1243C9BFC24EFEEFCE151188C0898D5E /* QNReportItem.m */, + 3FD41DA6014B9614009729A6F837DEFB /* QNRequestClient.h */, + 1C04D7E0CD2BFD4CA3473BFB67D94948 /* QNRequestTransaction.h */, + 1B8002C86FF660BE74F43AE588C4FF5C /* QNRequestTransaction.m */, + FD28D7585D033EAC425B8EC3F7F0C899 /* QNResponseInfo.h */, + F8B35140EE209B55F842ADD443DEDAC6 /* QNResponseInfo.m */, + 176313049470B50BE436395B1808C94C /* QNServerConfig.h */, + 6E086CB41F588914AEBD9A24D21A98E6 /* QNServerConfig.m */, + 274039B1888766E5D9B1F50DF56F622A /* QNServerConfigCache.h */, + 231357D720AFF7AA4132AF1E7B7BE790 /* QNServerConfigCache.m */, + 3572172784A174F5D92E48C15953FD25 /* QNServerConfigMonitor.h */, + E96FD00F54A57EB23E8709808E290E4C /* QNServerConfigMonitor.m */, + 094C51DA204B14E7F7F9BD450C4F238B /* QNServerConfigSynchronizer.h */, + 23E71E2266AD47CCD8EAD036BD531740 /* QNServerConfigSynchronizer.m */, + 0285B2AEED83B6C8D72681824542EDD6 /* QNServerUserConfig.h */, + 9B9561C8F7DC0CAADB1217ED15C85DEC /* QNServerUserConfig.m */, + 723162DA2F24F7C74D707F106FDACD23 /* QNSessionManager.h */, + 1D900D5948B2E17B67406B3B414511F5 /* QNSessionManager.m */, + 2EE6448CDF48B5C634F2DF06BE1E61DD /* QNSingleFlight.h */, + 893C9FDD66BF35A81502E28E4F767721 /* QNSingleFlight.m */, + 4F6DC7D2D01596F560201E643A8599F1 /* QNSystem.h */, + 34D6B72513683F5ABE16C23F2152DD32 /* QNSystem.m */, + 18CC0031705262E5C46EE9216B742CED /* QNTransactionManager.h */, + B61A1E1CF720A9FF98E627A3A603BC1C /* QNTransactionManager.m */, + 3B32FC01328C766500672A215C59451D /* QNUploadBlock.h */, + 585CD993F6AFD84EA26ED2C66323D21B /* QNUploadBlock.m */, + 0AC5921E07E0B3B4358EA90EED983278 /* QNUploadData.h */, + E07CEC148C3EE2019D2D5D99C4BC53A2 /* QNUploadData.m */, + 74D331F51CA2F803B4129019B829C378 /* QNUploadDomainRegion.h */, + 3232761147507B185CCD3513BEEF7268 /* QNUploadDomainRegion.m */, + 40A726DB59657716867C8B1AB36E6C30 /* QNUploadInfo.h */, + 1AE1E212922B29A2A6E1161328C2A78B /* QNUploadInfo.m */, + 4F52E6FDCEB0481BDE0AC37643FE2F11 /* QNUploadInfoReporter.h */, + 5D4BA683411586A786AE0B4B3C0F4C3D /* QNUploadInfoReporter.m */, + B43E6A6F8478BC76541791BF5653CAB0 /* QNUploadInfoV1.h */, + A221251C091AF510A609C108982CB1D1 /* QNUploadInfoV1.m */, + 812EC1822605C9634F6C3E9546BAC454 /* QNUploadInfoV2.h */, + 0851E3157B70B1A32465DAD0BFD4A810 /* QNUploadInfoV2.m */, + 905CB0F3866B1BA95985D9BCA2305F36 /* QNUploadManager.h */, + B8549EF474251783802766729B86324F /* QNUploadManager.m */, + A4AA31A61B3937CBA327208E5243717A /* QNUploadOption.h */, + AA5369E025BA75B4CFBFC684A8DEE017 /* QNUploadOption.m */, + 8CB37F8534A03ACD356B47AC1FA44D93 /* QNUploadRegionInfo.h */, + BD0CFFFA0B3C4B5C29949A00485F47F6 /* QNUploadRequestInfo.h */, + EBFEA24EA474C5982FF42213814675B0 /* QNUploadRequestInfo.m */, + 538BD2F88175C3CBDA73EBB63DC767C5 /* QNUploadRequestMetrics.h */, + 9138B03A4492B1E01308EF4EFEC48596 /* QNUploadRequestMetrics.m */, + 444901F5C99E84244FFABCB93FF16030 /* QNUploadRequestState.h */, + 3C05983D208A6981DC4D5B323BBFF703 /* QNUploadRequestState.m */, + 85A39400B7C9B7F8ED9F73DDE08D198A /* QNUploadServer.h */, + AD78C2CF832D0A30ABBF42BFE19FED10 /* QNUploadServer.m */, + 11794B20AAADFAD4CB9D91909B755401 /* QNUploadServerFreezeManager.h */, + E95A7C67CE2E7B37438781CA58210F3E /* QNUploadServerFreezeManager.m */, + 57B304DE091973BDA5DDE597DA01132F /* QNUploadServerFreezeUtil.h */, + A8E13048620040754D4A99B474D82AC8 /* QNUploadServerFreezeUtil.m */, + 41A44E8CFC5EE315D8942BE4A88ACC66 /* QNUploadServerNetworkStatus.h */, + AB431F11F56810275DDF177CBCBB9765 /* QNUploadServerNetworkStatus.m */, + D4EDE0519DF8027C47DA50CCAB1126E7 /* QNUploadSource.h */, + 7C0AF86EBE5E8F64D381431E106CD267 /* QNUploadSourceFile.h */, + E30A65BA27A072F1306DB2388089DC98 /* QNUploadSourceFile.m */, + 52092A3E4758686C88E09A8A822CB1A4 /* QNUploadSourceStream.h */, + B33E60A599A4CA1193C414960E161861 /* QNUploadSourceStream.m */, + 8F5C80C6BA42C7ECF7D30A038C03F95A /* QNUploadSystemClient.h */, + 5123B4029742776B759BCC99F43391EF /* QNUploadSystemClient.m */, + E93456BD99FE4C120360C8EE467C4E25 /* QNUpProgress.h */, + 3F3EA4CCB4F3228A06B466537A6E4AF3 /* QNUpProgress.m */, + 4943A7294DB91F20EC946148A39D3F89 /* QNUpToken.h */, + 698E018EB0D0899DD2C2F38E94FD5A74 /* QNUpToken.m */, + F0CD75989071374CACB370D591D1B209 /* QNUrlSafeBase64.h */, + DFD1F913622154A3DAE8AB27305B0AE8 /* QNUrlSafeBase64.m */, + D6056BE4A98153C8435CEC49BD61D35D /* QNUrlUtils.h */, + 20B62CDF9AE854DEA6014419025D9CCF /* QNUrlUtils.m */, + 59AAA1299154D08C7063B7BBB53FDA90 /* QNUserAgent.h */, + B2F9A345F5B6BE60F7F5BDF34295C5A2 /* QNUserAgent.m */, + 0C2D32A2356F12F322696C043687D9CB /* QNUtils.h */, + B808218FFC5C59359D25FD81D9EAEA76 /* QNUtils.m */, + F6A558BD64030C2B22BF8240EB72BFAB /* QNVersion.h */, + 15F05795FAC4894BDDCFD80B437D7D76 /* QNZone.h */, + 37F27BAB3C256685B6F7B083570383A8 /* QNZone.m */, + 64FDDBA6B9281D67C7214592245FBF15 /* QNZoneInfo.h */, + 1A623EA2BD31BC270E877148FBAD5114 /* QNZoneInfo.m */, + 3846F526D55A1CFA8BC6D5F266DD6B6F /* Resources */, + EC00B623CB52F989F532FCC5E8CE3E3D /* Support Files */, + ); + name = Qiniu; + path = Qiniu; + sourceTree = ""; + }; + 682908B6CE9E5BC5E071D5771A16D5A9 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + FEACF005051A14A125C85C47353BF2A9 /* Pods-msext */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 69EA23E50DF3C52548940AED9C606A40 /* Resources */ = { + isa = PBXGroup; + children = ( + 9FB0F5E1925AF6E3C165F92F34D8B7A7 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + C13AA13E00E4EDB1B831B61C17F4943F /* Support Files */ = { + isa = PBXGroup; + children = ( + 464AAB9B64DCDBB86575B4B1BDDFE93D /* HappyDNS-dummy.m */, + 3E065100D0F21B3ECBB3E4B3C31DB32E /* HappyDNS-prefix.pch */, + 5AF7BCFE0AF33AD63278E420FC517304 /* HappyDNS.debug.xcconfig */, + D10401361DC3A413263B24FDCD1CC291 /* HappyDNS.release.xcconfig */, + DB3F837186266522119EFD22479B38E5 /* ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/HappyDNS"; + sourceTree = ""; + }; + C75B84FF8C557958341401B4989E24C5 /* Products */ = { + isa = PBXGroup; + children = ( + 3667B5F6798CDC2ADA1BBC70D052FF68 /* HappyDNS */, + 493046A050F831EF8BE1ABEAC11D8B1B /* HappyDNS-HappyDNS.privacy */, + E0951FD86AC45A788DC9511EC022A61F /* Pods-msext */, + A7B82792B39240C408DA7D6FEB677DA6 /* Qiniu */, + FDBAD2031CCEA0251D342DB039D2D1BA /* Qiniu-Qiniu.privacy */, + ); + name = Products; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + D89477F20FB1DE18A04690586D7808C4 /* Frameworks */, + DB4F8632C63CB68A4BD6383DED2A7067 /* Pods */, + C75B84FF8C557958341401B4989E24C5 /* Products */, + 682908B6CE9E5BC5E071D5771A16D5A9 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D89477F20FB1DE18A04690586D7808C4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + DB4F8632C63CB68A4BD6383DED2A7067 /* Pods */ = { + isa = PBXGroup; + children = ( + 0799DE43BC62D6220ADA29A00BFA0414 /* HappyDNS */, + 4DDE0989CCFEAAB6233C4BB989226A4F /* Qiniu */, + ); + name = Pods; + sourceTree = ""; + }; + EC00B623CB52F989F532FCC5E8CE3E3D /* Support Files */ = { + isa = PBXGroup; + children = ( + 8912CA14784BE3548E5AC2CA8873C415 /* Qiniu-dummy.m */, + 4C39991E85951B0BC0E8F0B209AF0DAF /* Qiniu-prefix.pch */, + 58DD6EF473E719379913E15C40F7C94D /* Qiniu.debug.xcconfig */, + 4ECBA8228CFBB4C28FF79A203C2BB27D /* Qiniu.release.xcconfig */, + 0F3BDD2BEB953DE540BC6185DE2E2714 /* ResourceBundle-Qiniu.privacy-Qiniu-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/Qiniu"; + sourceTree = ""; + }; + FEACF005051A14A125C85C47353BF2A9 /* Pods-msext */ = { + isa = PBXGroup; + children = ( + 91E994A08B81C1236866B44231D17142 /* Pods-msext-acknowledgements.markdown */, + 17F37BE73155DE146F00578D9B0C2DE1 /* Pods-msext-acknowledgements.plist */, + 53B880536FAA662603F8BB45F2165001 /* Pods-msext-dummy.m */, + 309A4D58300D2B60B1C816A189E2B722 /* Pods-msext-resources.sh */, + EDDC6B89123EBB9EF93590F05879F928 /* Pods-msext.debug.xcconfig */, + ABA75D968E076B1C3939AF39502DC993 /* Pods-msext.release.xcconfig */, + ); + name = "Pods-msext"; + path = "Target Support Files/Pods-msext"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0B71B50D9E469552D0558B0B0BD5F028 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0D0833AA36AECB16625AA706D5944377 /* NSData+QNGZip.h in Headers */, + 9A5AB7480FE3B1046B72D563C3E23227 /* NSData+QNMD5.h in Headers */, + 8FA9C4F70E09C19AE9FBF64994ACC644 /* NSObject+QNSwizzle.h in Headers */, + 3FD6650A7191C84085414CFC36E9B1E3 /* NSURLRequest+QNRequest.h in Headers */, + E060C21FDA95CA3C351EB8D38DB3D058 /* QiniuSDK.h in Headers */, + 5E3FF93391E2AF6351A6CF3DFC824078 /* QN_GTM_Base64.h in Headers */, + DD00AF12D400FC423D3A8F11EAED2D06 /* QNALAssetFile.h in Headers */, + 0D22728A968DA2F4795180502772A312 /* QNAsyncRun.h in Headers */, + 473C7955E89B70660DEAE4C3E3E5024E /* QNAutoZone.h in Headers */, + B82A7979B386F40049FD3C6A4DD84481 /* QNBaseUpload.h in Headers */, + 06CAA44656EE8D6DF0BAA7DF05E4E688 /* QNCache.h in Headers */, + 724317CFCD8068536814E5BC4AC61206 /* QNCFHttpClient.h in Headers */, + D70C9653FF7781BC9C6D7344D1270088 /* QNCFHttpClientInner.h in Headers */, + AF0495C59F2EF44B4FE824B037A6B8B7 /* QNCFHttpThreadPool.h in Headers */, + A443954283E84BB2A7A7A4A5FF125919 /* QNConcurrentResumeUpload.h in Headers */, + 4D34246FF5D9D461B4A8D3CAE4DDF57B /* QNConfig.h in Headers */, + D5EC1C29F5EBD9D97D5BA35882B58847 /* QNConfiguration.h in Headers */, + 3EE37B2F4BBDB5005900567AED18EEE1 /* QNConnectChecker.h in Headers */, + 70EE7F6FF2FF14FA32C18BC6C41E535E /* QNCrc32.h in Headers */, + A6C304C5CA01298CCA63B0682A67D429 /* QNDefine.h in Headers */, + FAE1AC9D1ED1441E4BC32D687E2EEFE3 /* QNDns.h in Headers */, + 97BC329AD753970C6819E7A109F1311D /* QNDnsCacheFile.h in Headers */, + CA3FD26F7CB9C0F2F14D6EB521011CA3 /* QNDnsCacheInfo.h in Headers */, + 2CB0891388E2B78EF5D3E266E608CCEB /* QNDnsPrefetch.h in Headers */, + 7ED048BB1E5B4EB7405C240AB76D8073 /* QNErrorCode.h in Headers */, + 6C63211BC21A39FAD6E6015A3405711D /* QNEtag.h in Headers */, + B365B17375120498EFE98AB5B591515F /* QNFile.h in Headers */, + BE57EC6144D79300FF2A75239FE02E24 /* QNFileDelegate.h in Headers */, + 3D29D0A2DAFD0F68A283B83923342EFA /* QNFileRecorder.h in Headers */, + A3F79FB07293047BEDB0B84AE65F9FA0 /* QNFixedZone.h in Headers */, + 9BF0AE41367B8419DF4D8EBF67C572A9 /* QNFormUpload.h in Headers */, + 0AF4318A84E386CAA327F9486CE33305 /* QNHttpRegionRequest.h in Headers */, + AA9CC59FA8A5802D4BE4EC3C4FB1FB26 /* QNHttpSingleRequest.h in Headers */, + 415348F2C83EBEC5D3ABC5431431591E /* QNInetAddress.h in Headers */, + 4B37902C0C10D624F59FE47D44FEE9AF /* QNIUploadServer.h in Headers */, + 763372E4397A0215700BC32F135F88B3 /* QNLogUtil.h in Headers */, + 1C8490F9EECBD7EA0603EC530BC48FD3 /* QNMutableArray.h in Headers */, + 8D1D9FB08C8756A4D74E2685C5467EF6 /* QNNetworkStatusManager.h in Headers */, + CC9106180C5AA9C406F4F4007EBC4046 /* QNPartsUpload.h in Headers */, + A29C1CD46174CEE0AABA2E14FBA287AF /* QNPartsUploadPerformer.h in Headers */, + 6B3939A552F78BEE85CFBEB1E3416D27 /* QNPartsUploadPerformerV1.h in Headers */, + 5F1B572DC0D7C1FCDB67DAD9BE6E111F /* QNPartsUploadPerformerV2.h in Headers */, + FA24759B66D376AB97F2F2005901349B /* QNPHAssetFile.h in Headers */, + F5EFAEAA108D793D1BFCD37874FA0499 /* QNPHAssetResource.h in Headers */, + ADC81B97EDC1DB1D79FF57EE155519C3 /* QNPipeline.h in Headers */, + 0ECFDB569CD22BCC653C059D0C22AEF6 /* QNRecorderDelegate.h in Headers */, + ED23065233F840C1C4555FDCA90689B0 /* QNReportConfig.h in Headers */, + 5FDA798B15A4205E6E2B9C1F8F665172 /* QNReportItem.h in Headers */, + 2DC683AC4D377D10CA932E9EBBEAB382 /* QNRequestClient.h in Headers */, + 1700E3D64E8F4C4FBB222AC931E91772 /* QNRequestTransaction.h in Headers */, + 21D27E481AA7957CE62DEE8A56F2D9DD /* QNResponseInfo.h in Headers */, + 855FCDC8D7F3FB9E24A0C43E95A9FCA1 /* QNServerConfig.h in Headers */, + 28E32DFEFA19DFD9E0263C6A984B991B /* QNServerConfigCache.h in Headers */, + CE513C3EFCAEEC35561F4991A8280140 /* QNServerConfigMonitor.h in Headers */, + 0BD4BEF49315D4B86ADB42814F5D1717 /* QNServerConfigSynchronizer.h in Headers */, + 946D1DD24031C34170E3579F1A38C793 /* QNServerUserConfig.h in Headers */, + 363DE1D3B870502EB2E305EF9871FFF6 /* QNSessionManager.h in Headers */, + 27F0E87B9DFC06E515C2C5FC1FAFD5F2 /* QNSingleFlight.h in Headers */, + E4E5CB367C20590CFA957CA043D6B64B /* QNSystem.h in Headers */, + A415F883A08C66E6CEFCB9116B55D988 /* QNTransactionManager.h in Headers */, + 06F1903F54A8DDF66A82D2E5D537C317 /* QNUploadBlock.h in Headers */, + 3FFF23D5DE39C0350405CC3F8C6B9F45 /* QNUploadData.h in Headers */, + 4591A679BAC668B56EB1F7A2EFC9F808 /* QNUploadDomainRegion.h in Headers */, + E20B6B19EA2202F68DE792AB4C597D8F /* QNUploadInfo.h in Headers */, + F6AD7847B0A90D145BDC52C7BA0A4574 /* QNUploadInfoReporter.h in Headers */, + E6956B3F97E72CCFCCC6D7F9CA41DFB3 /* QNUploadInfoV1.h in Headers */, + 2B20C6F4D8FA47BB7D9382624F3A33CB /* QNUploadInfoV2.h in Headers */, + 7E88D8A94EF09815FCB86A6A6A66ADA9 /* QNUploadManager.h in Headers */, + 7D7D685CF5A7D05369D3E29CFB1B2697 /* QNUploadOption.h in Headers */, + F228B8157C015BF76EEAF35011CE7964 /* QNUploadRegionInfo.h in Headers */, + 484D0A4FE804F8EBF2B05502B0573408 /* QNUploadRequestInfo.h in Headers */, + F053710CF7EF686A17F97F53D5C4D3EA /* QNUploadRequestMetrics.h in Headers */, + 46B63D86394B3291BE411401395310A9 /* QNUploadRequestState.h in Headers */, + 96A907D7939D268628181CF3629C1D17 /* QNUploadServer.h in Headers */, + D63B21A3D0D58731F5573CFB435CA112 /* QNUploadServerFreezeManager.h in Headers */, + A2FC5BC59A585CDF875B9212FD0BEA3E /* QNUploadServerFreezeUtil.h in Headers */, + 42C3D26D5D194EB4DB3902A572D71A54 /* QNUploadServerNetworkStatus.h in Headers */, + CCE0B36CBCB3736491FC05113E8A1EEB /* QNUploadSource.h in Headers */, + 7CA28D4A7D112F49D534E3F80C09A192 /* QNUploadSourceFile.h in Headers */, + 9F6DA1079338BEFBEFCD028D9EDF25A9 /* QNUploadSourceStream.h in Headers */, + EA3ECA68F00C0BE8532F6B447F2884DA /* QNUploadSystemClient.h in Headers */, + EF2C14B88B6B529CE7D8F8AC35BFA4D4 /* QNUpProgress.h in Headers */, + 5C991FFF5EE367FBA0103A83097046C4 /* QNUpToken.h in Headers */, + 2959CD52FFCAEE61EA28488C7779BC21 /* QNUrlSafeBase64.h in Headers */, + 59833830D6F5A62384C7633868173637 /* QNUrlUtils.h in Headers */, + 135D4A975978A237714038BB97457759 /* QNUserAgent.h in Headers */, + 9AA3EC42D3CE90F42073B4B58120FAA2 /* QNUtils.h in Headers */, + 74303C0DBE03E18723D96226E57C5881 /* QNVersion.h in Headers */, + B2D10BF8F71C361F2BA535635DAB58A7 /* QNZone.h in Headers */, + D82914CE4B1D29124FB5C94E83B9A866 /* QNZoneInfo.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9D0F2D5A01D5062E4D3E25A9A5F9FFD2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 02A083AEC78EF330E5C39206EB889767 /* HappyDNS.h in Headers */, + 15D304827B03F9132761E5B0BCEEBCA1 /* NSData+QNRW.h in Headers */, + D53D2F967B996224701F0DD2CDCE9A2B /* QNAsyncUdpSocket.h in Headers */, + 808F7DB0E79091D174C9A518690DD625 /* QNDes.h in Headers */, + 66E86F47697FCD1CC27A1247EC10101D /* QNDnsDefine.h in Headers */, + 8A888179E0FA52A16C56976369B99E08 /* QNDnsError.h in Headers */, + C32B3680837042FC9FA39426F82C1AA4 /* QNDnsManager.h in Headers */, + 7C89DD86FB0E55F0B866406B3A495F1B /* QNDnsMessage.h in Headers */, + D442FD256526D202FD299D438A643EF7 /* QNDnspodEnterprise.h in Headers */, + E6A0F7BC3C240BB99A10F68966609B24 /* QNDnsRequest.h in Headers */, + 6272AAE5A8D3620D0A9D208337EC61D1 /* QNDnsResolver.h in Headers */, + 9160C9AC30DB40529A7D6E9D7AC17902 /* QNDnsResponse.h in Headers */, + EC4570B92D85135EC82E963683F9A2D0 /* QNDnsUdpResolver.h in Headers */, + 6E0D258E7FE0D7BB16D43B8342EF8D6B /* QNDohResolver.h in Headers */, + DD9C6436F9F327A5A17B641C11600EBA /* QNDomain.h in Headers */, + D9366EAEB2D487C91DED410C2E7CCED9 /* QNGetAddrInfo.h in Headers */, + E731B10A06AA446C150BF74563799B72 /* QNHex.h in Headers */, + 35177229827C7A5D7B45C347C771693C /* QNHijackingDetectWrapper.h in Headers */, + 2451555DE2EAD5C7C006BEAA459AED91 /* QNHosts.h in Headers */, + 9C1C24540C82F0E248CB51890A8B7B97 /* QNIP.h in Headers */, + 3749F8CC97522F9A2B547DF1DBFF7006 /* QNLruCache.h in Headers */, + ACAA9DF5E3D136039B5B20B6718021F1 /* QNMD5.h in Headers */, + 9AFE877066FA5C68F5930C212D55F70C /* QNNetworkInfo.h in Headers */, + 9A6230B72E0E9B1C1DF284F53ACDA93C /* QNRecord.h in Headers */, + EB643CC7ECBD0E730AA2CFE56CCBC841 /* QNResolver.h in Headers */, + 882D09186FEA0EC925809CA81CEF1163 /* QNResolverDelegate.h in Headers */, + 385CEE7F0C894B5E97B88F54AE3BC5DD /* QNResolvUtil.h in Headers */, + E76C4F9D71154DB8178C490ADC101A83 /* QNTxtResolver.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C3C8B9BBB7F0E2224270FE07891F81F9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 52FA323A1EAF50642C502468818C03F2 /* Qiniu-Qiniu.privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5DB029E7772C93B878E572C34867B9A0 /* Build configuration list for PBXNativeTarget "Qiniu-Qiniu.privacy" */; + buildPhases = ( + 7FC9BE6F82B873BAFC5896C1F94E7704 /* Sources */, + E097643998A1750F452B28CE7747F0D9 /* Frameworks */, + A2D658E9C512140976F3DFFC7C24AC6A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Qiniu-Qiniu.privacy"; + productName = Qiniu.privacy; + productReference = FDBAD2031CCEA0251D342DB039D2D1BA /* Qiniu-Qiniu.privacy */; + productType = "com.apple.product-type.bundle"; + }; + 96F820A9CBD7912A405650AC238D1F8E /* HappyDNS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0F2D1EEC04C2EF8E837853661C57C88C /* Build configuration list for PBXNativeTarget "HappyDNS" */; + buildPhases = ( + 9D0F2D5A01D5062E4D3E25A9A5F9FFD2 /* Headers */, + 034572434301FBEDEA23249F95FACE50 /* Sources */, + 3077435C5524607F90998DBB65138927 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + DBF345534408B5B274A530E44113FE46 /* PBXTargetDependency */, + ); + name = HappyDNS; + productName = HappyDNS; + productReference = 3667B5F6798CDC2ADA1BBC70D052FF68 /* HappyDNS */; + productType = "com.apple.product-type.library.static"; + }; + 9713F55E29CF00C3231002DC45C4EEB8 /* Qiniu */ = { + isa = PBXNativeTarget; + buildConfigurationList = B3B430776C346207F7266198FD8F4DB3 /* Build configuration list for PBXNativeTarget "Qiniu" */; + buildPhases = ( + 0B71B50D9E469552D0558B0B0BD5F028 /* Headers */, + E13B64A1828CB7EF0786DB11394817C6 /* Sources */, + 23A583BF81A570380F7F257201EBF26F /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 528387295BC79B46F973F682C3C9F13E /* PBXTargetDependency */, + 996B00D034CD2AA21930FE46C77EC62E /* PBXTargetDependency */, + ); + name = Qiniu; + productName = Qiniu; + productReference = A7B82792B39240C408DA7D6FEB677DA6 /* Qiniu */; + productType = "com.apple.product-type.library.static"; + }; + B06DC0D760F841624B3C2C0AE3BCA36E /* Pods-msext */ = { + isa = PBXNativeTarget; + buildConfigurationList = E9DD3B4DAA1DBB3160C9CDA1305CAB03 /* Build configuration list for PBXNativeTarget "Pods-msext" */; + buildPhases = ( + C3C8B9BBB7F0E2224270FE07891F81F9 /* Headers */, + 4883B42CCA27B0805AF8EBA00C6A1E7D /* Sources */, + 71E4E122F3A1990A51B0797F9611F60C /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 98EC9C924E8D4C2A7A3A1B7881657749 /* PBXTargetDependency */, + 6F7A81BA829358A200D39F89087D1883 /* PBXTargetDependency */, + ); + name = "Pods-msext"; + productName = "Pods-msext"; + productReference = E0951FD86AC45A788DC9511EC022A61F /* Pods-msext */; + productType = "com.apple.product-type.library.static"; + }; + D659E6FBA2AF2BC7DAFE73043983AFD0 /* HappyDNS-HappyDNS.privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = C5224EBECA6BFBD04DDFD47ED1DE6FA2 /* Build configuration list for PBXNativeTarget "HappyDNS-HappyDNS.privacy" */; + buildPhases = ( + 4E2F168A12C7B23EB09B0BFEA23D3ED0 /* Sources */, + 043BE0650B2256A2C98C0E761C8AED66 /* Frameworks */, + C5D190A4DD00A1325ABF2BE062081199 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "HappyDNS-HappyDNS.privacy"; + productName = HappyDNS.privacy; + productReference = 493046A050F831EF8BE1ABEAC11D8B1B /* HappyDNS-HappyDNS.privacy */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = C75B84FF8C557958341401B4989E24C5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 96F820A9CBD7912A405650AC238D1F8E /* HappyDNS */, + D659E6FBA2AF2BC7DAFE73043983AFD0 /* HappyDNS-HappyDNS.privacy */, + B06DC0D760F841624B3C2C0AE3BCA36E /* Pods-msext */, + 9713F55E29CF00C3231002DC45C4EEB8 /* Qiniu */, + 52FA323A1EAF50642C502468818C03F2 /* Qiniu-Qiniu.privacy */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + A2D658E9C512140976F3DFFC7C24AC6A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7C108C063AFF9B03A828D12F464A27EB /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C5D190A4DD00A1325ABF2BE062081199 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CE859E5343307B140147194B4503795C /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 034572434301FBEDEA23249F95FACE50 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAD6E08D8EF66A4FE875E0912B4DB2C5 /* HappyDNS-dummy.m in Sources */, + D200E2C73915172912A26A08ABE6BE6D /* NSData+QNRW.m in Sources */, + B8B6988F7579AE02B9F25FF91A224A29 /* QNAsyncUdpSocket.m in Sources */, + 1402D3398B3BCDAFAE7AC853E9836B5B /* QNDes.m in Sources */, + 3F862AAE5E80AB4F322E5FF0E5AE78A5 /* QNDnsError.m in Sources */, + 7A54221F669E5F5D6080DC84FDA509D5 /* QNDnsManager.m in Sources */, + 5908A709FB3D0482D49C605579285ABF /* QNDnsMessage.m in Sources */, + 4F7133BD631BA5390DB12C26857506C4 /* QNDnspodEnterprise.m in Sources */, + 18D0BD421372CC4E0E57CA5E4E5154C3 /* QNDnsRequest.m in Sources */, + 0D7177D8F5C17A34D11F62BD372829D6 /* QNDnsResolver.m in Sources */, + 69829BF26F50A3C6D4F4EB2637CE6ADD /* QNDnsResponse.m in Sources */, + A249FCE2F96F20A4A1932948CC03B1E2 /* QNDnsUdpResolver.m in Sources */, + B18110A3A71EB88226791A8C109B16F6 /* QNDohResolver.m in Sources */, + F5103D7221410A9E09BFE61AC019207A /* QNDomain.m in Sources */, + 90061ABFA2D4EF2F4FE4B549F4023636 /* QNGetAddrInfo.m in Sources */, + 2398FC53D239AC5DFA888BF380600933 /* QNHex.m in Sources */, + 6A70F40277F516EB42992EAF407CFE94 /* QNHijackingDetectWrapper.m in Sources */, + 9FB875938AB160392C3F27B9EFAC225A /* QNHosts.m in Sources */, + CC503F756A70AAEDF0579FF5F242F0F0 /* QNIP.m in Sources */, + 8F03076C785260B6B5C5C2330AEDB5EF /* QNLruCache.m in Sources */, + 2B7717BAE65809CD70FA2E5E75C9E69F /* QNMD5.m in Sources */, + B3618BAA20910B8F77AF0EDB3AD9E844 /* QNNetworkInfo.m in Sources */, + 3F96CE99838C2E14350B3BFC1792EBA9 /* QNRecord.m in Sources */, + 1326830E2575C410AFF33BCCC359EEE4 /* QNResolver.m in Sources */, + AF50E8CC3F8AAB90A5C80431EC18E0ED /* QNResolvUtil.m in Sources */, + 07A097D3A80AD5C1C15390FF67FC3D43 /* QNTxtResolver.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4883B42CCA27B0805AF8EBA00C6A1E7D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CA691A0115418B2188C7F6FE35A9C5AE /* Pods-msext-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4E2F168A12C7B23EB09B0BFEA23D3ED0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7FC9BE6F82B873BAFC5896C1F94E7704 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E13B64A1828CB7EF0786DB11394817C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D2BD8BABE7D83BCFFFC5BFEE8CD186D9 /* NSData+QNGZip.m in Sources */, + ADF491411922480EBB12FC5A5E70A597 /* NSData+QNMD5.m in Sources */, + FD18657084D3369C6C4F6E069B8A28FC /* NSObject+QNSwizzle.m in Sources */, + 5BA1335B49C511B3D87B81A40E7E12DC /* NSURLRequest+QNRequest.m in Sources */, + 894EBD2230B12EFED01B2B4AE3077D36 /* Qiniu-dummy.m in Sources */, + DDB11E51FD0A0D524B82439DE3B2A383 /* QN_GTM_Base64.m in Sources */, + 9AF6C1B102D31AC8BAC3EAB146EDC790 /* QNALAssetFile.m in Sources */, + 6A6A458420D1BE1361FE96781053F642 /* QNAsyncRun.m in Sources */, + 150258D2108F43868AE5A2DD52A9C35A /* QNAutoZone.m in Sources */, + 26646F43D02499FE87DA1BE49BA5B7FF /* QNBaseUpload.m in Sources */, + D621165613F37CA7673A6FA9D4DD647A /* QNCache.m in Sources */, + 6CCF545D1D6B85614337C6898FF1CF74 /* QNCFHttpClient.m in Sources */, + 367D73701DC968EF3EE5B0C0F016ABA1 /* QNCFHttpClientInner.m in Sources */, + 04B893D78D27F949C3D4277A55F8D901 /* QNCFHttpThreadPool.m in Sources */, + 4FC05CDB5A30BA59CADB788F23E8AE2B /* QNConcurrentResumeUpload.m in Sources */, + E464D148BAC75561AB59829D3A8E2BFD /* QNConfiguration.m in Sources */, + 13EC910AF995F97C00865AE9E4D27968 /* QNConnectChecker.m in Sources */, + 38E31F7C37E339C230705769D6D97E16 /* QNCrc32.m in Sources */, + 59D40A6C6813736ED3A4CBF32C93FECF /* QNDefine.m in Sources */, + C4EA63600AB11CAA6F17633CD819ADEE /* QNDnsCacheFile.m in Sources */, + 9424078AFB474AAFAD7D39962D8349CD /* QNDnsCacheInfo.m in Sources */, + E8EEA1F3AC75797FA4184E3F19BC0104 /* QNDnsPrefetch.m in Sources */, + AF5CD587AF6A59AE8C0D3E45170DB1DB /* QNErrorCode.m in Sources */, + 14ED80411BF849B1E2486A95736D170B /* QNEtag.m in Sources */, + 73C1BD6DFCDC22B5EF624966A694DC9C /* QNFile.m in Sources */, + 733D0FCECAD516495EE942B89A039736 /* QNFileRecorder.m in Sources */, + EA53570E898921D3C55D221EBCC8253F /* QNFixedZone.m in Sources */, + 1D441B98373562CCA7FB95D76753D272 /* QNFormUpload.m in Sources */, + B48DCDB6DEA5342877AA3C828F44728E /* QNHttpRegionRequest.m in Sources */, + 8C22120136505CBA1FFB225CD8EC8A4A /* QNHttpSingleRequest.m in Sources */, + C3C2F5260C57DFE6D0BA9969624DFF9D /* QNInetAddress.m in Sources */, + E47813CBEA853F14D46FD7C678C44FE3 /* QNIUploadServer.m in Sources */, + 3B9A335BE2F04D8730E51235D9940706 /* QNLogUtil.m in Sources */, + 7E4B72EB37E47855AB243028FFA0163D /* QNMutableArray.m in Sources */, + 8F6B6F0FFD097D845ECE9AF83CD4C632 /* QNNetworkStatusManager.m in Sources */, + 03CF2E60A1FB26757508B214FC87799B /* QNPartsUpload.m in Sources */, + 669EF6B39BA02ED775D46B05520A048E /* QNPartsUploadPerformer.m in Sources */, + 585E9BAC551DE7A99A2410B730490AFD /* QNPartsUploadPerformerV1.m in Sources */, + D8D480C9255D0B4F985AFAF8298FBBD6 /* QNPartsUploadPerformerV2.m in Sources */, + E02767AB5C6A1D535A02F66D2CF839C5 /* QNPHAssetFile.m in Sources */, + CD410ED96FBD61E08CE67118469DD46D /* QNPHAssetResource.m in Sources */, + 5A9899709C100B809F8D6B7DCE5BB287 /* QNPipeline.m in Sources */, + 489C1E3F7ADE55836D1985A1C987510F /* QNReportConfig.m in Sources */, + E60A8C1D4C3E482E7AC8FAE8564A0B1C /* QNReportItem.m in Sources */, + 0E90885C76402D175D402F00667EF458 /* QNRequestTransaction.m in Sources */, + 8B2ABDF28B570378EA014EE420D4ECBB /* QNResponseInfo.m in Sources */, + 6B38AE9316D2278D3E3AEFF51652E53A /* QNServerConfig.m in Sources */, + EDD9A63F8B68A5B1C2663A4C129F1F6F /* QNServerConfigCache.m in Sources */, + DC60811FEA708CB183D8116520E28029 /* QNServerConfigMonitor.m in Sources */, + 91B8A06A000B48A8395C6D8B2E8F7DEB /* QNServerConfigSynchronizer.m in Sources */, + BEF431B2EBD8AC01B5B1FF699A431997 /* QNServerUserConfig.m in Sources */, + 767A512C8BEFBF38A1BDA2A5ECF960BA /* QNSessionManager.m in Sources */, + B9E9091DD3ED2393598E9EE88964B57E /* QNSingleFlight.m in Sources */, + 5E6341E69B47D49F122396A7E6E651CC /* QNSystem.m in Sources */, + BAA2BBA102CE99F026E7BD5CE97F4BEE /* QNTransactionManager.m in Sources */, + 1EE96E29E503FFD4B215E6DBACCFE9AA /* QNUploadBlock.m in Sources */, + D21A9839F1C6B483B80D40A8CF73EF0C /* QNUploadData.m in Sources */, + 9FDF3A1C81A4154E5A6EC7884EDC0D90 /* QNUploadDomainRegion.m in Sources */, + 5C7E774E2F7CDFB706E513D1A929B869 /* QNUploadInfo.m in Sources */, + FFA86E79FD5423EF3C2C67998EE49403 /* QNUploadInfoReporter.m in Sources */, + 3CFB2AC7B866A779334F6C272C4A6106 /* QNUploadInfoV1.m in Sources */, + C26EA245C7645920A2CF9367BF2A0C8E /* QNUploadInfoV2.m in Sources */, + C7C5E1372EA44C2018CDD834C370D4DE /* QNUploadManager.m in Sources */, + 7A9FA33117D259372ED3DA4DC8079FBC /* QNUploadOption.m in Sources */, + 9CF8E34B4317D621EE0232FAA2DF1948 /* QNUploadRequestInfo.m in Sources */, + 953C8C62F01E4D7A671255FE829BC55D /* QNUploadRequestMetrics.m in Sources */, + F1D5510D28197722188E6117EAD39E0A /* QNUploadRequestState.m in Sources */, + DC08FF1C20D79E48B2D0E21BF55E399E /* QNUploadServer.m in Sources */, + A898190C4D8A375891F9AD0BCF6098EF /* QNUploadServerFreezeManager.m in Sources */, + E41FFF977E6BCDBE48DCF814AC6A7D01 /* QNUploadServerFreezeUtil.m in Sources */, + 7A55C1B8B2FE941ED304408CC6E4EC5C /* QNUploadServerNetworkStatus.m in Sources */, + 6BCC18A46877288300F5CFD6447911E2 /* QNUploadSourceFile.m in Sources */, + B497520E58241CCE602D4C8B24FAC713 /* QNUploadSourceStream.m in Sources */, + 405CC9638A609D7F7D6E49873712819A /* QNUploadSystemClient.m in Sources */, + F809D996BF339D9A529395CDAD9372A2 /* QNUpProgress.m in Sources */, + 717A7EFB6329E63CE5E7B1C6E0C72740 /* QNUpToken.m in Sources */, + 982472E334C700D72497EC940AA2BFC3 /* QNUrlSafeBase64.m in Sources */, + 24597D2833A7ACCD165103B39EA93595 /* QNUrlUtils.m in Sources */, + EA44072035221904D252B61DC73663B4 /* QNUserAgent.m in Sources */, + 3F2036038444EAAA7460311634006271 /* QNUtils.m in Sources */, + 8D076A0238B61C0198777D6BD60007EC /* QNZone.m in Sources */, + 173A5425E1E35DA2166549F45720D174 /* QNZoneInfo.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 528387295BC79B46F973F682C3C9F13E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = HappyDNS; + target = 96F820A9CBD7912A405650AC238D1F8E /* HappyDNS */; + targetProxy = BF9C4F7CC1734743F25FA1B595A350D3 /* PBXContainerItemProxy */; + }; + 6F7A81BA829358A200D39F89087D1883 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Qiniu; + target = 9713F55E29CF00C3231002DC45C4EEB8 /* Qiniu */; + targetProxy = 54A545E1269A216BB66F64257970CDD3 /* PBXContainerItemProxy */; + }; + 98EC9C924E8D4C2A7A3A1B7881657749 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = HappyDNS; + target = 96F820A9CBD7912A405650AC238D1F8E /* HappyDNS */; + targetProxy = 2ADF5A10DA7064EAC6F49B43641237D4 /* PBXContainerItemProxy */; + }; + 996B00D034CD2AA21930FE46C77EC62E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Qiniu-Qiniu.privacy"; + target = 52FA323A1EAF50642C502468818C03F2 /* Qiniu-Qiniu.privacy */; + targetProxy = E0C0B4CC0E659E2F863A6803415401A7 /* PBXContainerItemProxy */; + }; + DBF345534408B5B274A530E44113FE46 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "HappyDNS-HappyDNS.privacy"; + target = D659E6FBA2AF2BC7DAFE73043983AFD0 /* HappyDNS-HappyDNS.privacy */; + targetProxy = DE13900329DCF53935B17FC6CDC5FC46 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 012B78A0EC86191470A09BD0F093BEBB /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 58DD6EF473E719379913E15C40F7C94D /* Qiniu.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + GCC_PREFIX_HEADER = "Target Support Files/Qiniu/Qiniu-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_MODULE_NAME = Qiniu; + PRODUCT_NAME = Qiniu; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 05C501B36AAE7C0C498826C93D3C1CF5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ABA75D968E076B1C3939AF39502DC993 /* Pods-msext.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MACH_O_TYPE = staticlib; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0CD08548F7D075895B9F460F9DA3CE82 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5AF7BCFE0AF33AD63278E420FC517304 /* HappyDNS.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + GCC_PREFIX_HEADER = "Target Support Files/HappyDNS/HappyDNS-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_MODULE_NAME = HappyDNS; + PRODUCT_NAME = HappyDNS; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 25AD9454612BF454A1E3DC4CD4FA8C6D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 3BA95584AC67FEFB0D39556AE49352B4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5AF7BCFE0AF33AD63278E420FC517304 /* HappyDNS.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/HappyDNS"; + IBSC_MODULE = HappyDNS; + INFOPLIST_FILE = "Target Support Files/HappyDNS/ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = HappyDNS.privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 658260149C2D57F65614F16487E274AC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4ECBA8228CFBB4C28FF79A203C2BB27D /* Qiniu.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Qiniu"; + IBSC_MODULE = Qiniu; + INFOPLIST_FILE = "Target Support Files/Qiniu/ResourceBundle-Qiniu.privacy-Qiniu-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = Qiniu.privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 8FA5DAC52E509368452FC4F3899CBDF0 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EDDC6B89123EBB9EF93590F05879F928 /* Pods-msext.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MACH_O_TYPE = staticlib; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + A4C6A211C31FFAE3BC68F46D89217F81 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D10401361DC3A413263B24FDCD1CC291 /* HappyDNS.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + GCC_PREFIX_HEADER = "Target Support Files/HappyDNS/HappyDNS-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_MODULE_NAME = HappyDNS; + PRODUCT_NAME = HappyDNS; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BD54171C691B6735DA72D8F57DFC69C9 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4ECBA8228CFBB4C28FF79A203C2BB27D /* Qiniu.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + GCC_PREFIX_HEADER = "Target Support Files/Qiniu/Qiniu-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_MODULE_NAME = Qiniu; + PRODUCT_NAME = Qiniu; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BF7E00D6274A9A218D91C217FBC4B60F /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D10401361DC3A413263B24FDCD1CC291 /* HappyDNS.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/HappyDNS"; + IBSC_MODULE = HappyDNS; + INFOPLIST_FILE = "Target Support Files/HappyDNS/ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = HappyDNS.privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + CA547D2C7E9A8A153DC2B27FBE00B112 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + FD9C0576E4D49229805A1A9E7891D19E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 58DD6EF473E719379913E15C40F7C94D /* Qiniu.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Qiniu"; + IBSC_MODULE = Qiniu; + INFOPLIST_FILE = "Target Support Files/Qiniu/ResourceBundle-Qiniu.privacy-Qiniu-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = Qiniu.privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0F2D1EEC04C2EF8E837853661C57C88C /* Build configuration list for PBXNativeTarget "HappyDNS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0CD08548F7D075895B9F460F9DA3CE82 /* Debug */, + A4C6A211C31FFAE3BC68F46D89217F81 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 25AD9454612BF454A1E3DC4CD4FA8C6D /* Debug */, + CA547D2C7E9A8A153DC2B27FBE00B112 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5DB029E7772C93B878E572C34867B9A0 /* Build configuration list for PBXNativeTarget "Qiniu-Qiniu.privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FD9C0576E4D49229805A1A9E7891D19E /* Debug */, + 658260149C2D57F65614F16487E274AC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B3B430776C346207F7266198FD8F4DB3 /* Build configuration list for PBXNativeTarget "Qiniu" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 012B78A0EC86191470A09BD0F093BEBB /* Debug */, + BD54171C691B6735DA72D8F57DFC69C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C5224EBECA6BFBD04DDFD47ED1DE6FA2 /* Build configuration list for PBXNativeTarget "HappyDNS-HappyDNS.privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BA95584AC67FEFB0D39556AE49352B4 /* Debug */, + BF7E00D6274A9A218D91C217FBC4B60F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E9DD3B4DAA1DBB3160C9CDA1305CAB03 /* Build configuration list for PBXNativeTarget "Pods-msext" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8FA5DAC52E509368452FC4F3899CBDF0 /* Debug */, + 05C501B36AAE7C0C498826C93D3C1CF5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/Pods/Qiniu/LICENSE b/Pods/Qiniu/LICENSE new file mode 100755 index 0000000..fffdff7 --- /dev/null +++ b/Pods/Qiniu/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-2016 Qiniu, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Pods/Qiniu/QiniuSDK/BigData/QNPipeline.h b/Pods/Qiniu/QiniuSDK/BigData/QNPipeline.h new file mode 100644 index 0000000..5d697ad --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/BigData/QNPipeline.h @@ -0,0 +1,55 @@ +// +// QNPipeline.h +// QiniuSDK +// +// Created by BaiLong on 2017/7/25. +// Copyright © 2017年 Qiniu. All rights reserved. +// + +#ifndef QNPipeline_h +#define QNPipeline_h + +@class QNResponseInfo; + +@interface QNPipelineConfig : NSObject + +/** + * 上报打点域名 + */ +@property (copy, nonatomic, readonly) NSString *host; + +/** + * 超时时间 单位 秒 + */ +@property (assign) UInt32 timeoutInterval; + +- (instancetype)initWithHost:(NSString *)host; + +- (instancetype)init; + +@end + +/** + * 上传完成后的回调函数 + * + * @param info 上下文信息,包括状态码,错误值 + */ +typedef void (^QNPipelineCompletionHandler)(QNResponseInfo *info); + +@interface QNPipeline : NSObject + +- (instancetype)init:(QNPipelineConfig *)config; + +- (void)pumpRepo:(NSString *)repo + event:(NSDictionary *)data + token:(NSString *)token + handler:(QNPipelineCompletionHandler)handler; + +- (void)pumpRepo:(NSString *)repo + events:(NSArray *)data + token:(NSString *)token + handler:(QNPipelineCompletionHandler)handler; + +@end + +#endif /* QNPipeline_h */ diff --git a/Pods/Qiniu/QiniuSDK/BigData/QNPipeline.m b/Pods/Qiniu/QiniuSDK/BigData/QNPipeline.m new file mode 100644 index 0000000..d149a18 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/BigData/QNPipeline.m @@ -0,0 +1,154 @@ +// +// QNPipeline.m +// QiniuSDK +// +// Created by BaiLong on 2017/7/25. +// Copyright © 2017年 Qiniu. All rights reserved. +// + +#import + +#import "QNSessionManager.h" + +#import "QNPipeline.h" + +@implementation QNPipelineConfig + +- (instancetype)init { + return [self initWithHost:@"https://pipeline.qiniu.com"]; +} + +- (instancetype)initWithHost:(NSString*)host { + if (self = [super init]) { + _host = host; + _timeoutInterval = 10; + } + return self; +} + +@end + +@interface QNPipeline () + +@property (nonatomic) QNSessionManager *httpManager; +@property (nonatomic) QNPipelineConfig* config; + ++ (NSDateFormatter*)dateFormatter; + +@end + +static NSString* buildString(NSObject* obj) { + NSString* v; + if ([obj isKindOfClass:[NSNumber class]]) { + NSNumber* num = (NSNumber*)obj; + if (num == (void*)kCFBooleanFalse) { + v = @"false"; + } else if (num == (void*)kCFBooleanTrue) { + v = @"true"; + } else if (!strcmp(num.objCType, @encode(BOOL))) { + if ([num intValue] == 0) { + v = @"false"; + } else { + v = @"true"; + } + } else { + v = num.stringValue; + } + } else if ([obj isKindOfClass:[NSString class]]) { + v = (NSString*)obj; + v = [v stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; + v = [v stringByReplacingOccurrencesOfString:@"\t" withString:@"\\t"]; + } else if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSSet class]]) { + v = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil] encoding:NSUTF8StringEncoding]; + } else if ([obj isKindOfClass:[NSDate class]]) { + v = [[QNPipeline dateFormatter] stringFromDate:(NSDate*)obj]; + } else { + v = [obj description]; + } + return v; +} + +static void formatPoint(NSDictionary* event, NSMutableString* buffer) { + [event enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSObject* obj, BOOL* stop) { + if (obj == nil || [obj isEqual:[NSNull null]]) { + return; + } + [buffer appendString:key]; + [buffer appendString:@"="]; + [buffer appendString:buildString(obj)]; + [buffer appendString:@"\t"]; + }]; + NSRange range = NSMakeRange(buffer.length - 1, 1); + [buffer replaceCharactersInRange:range withString:@"\n"]; +} + +static NSMutableString* formatPoints(NSArray* events) { + NSMutableString* str = [NSMutableString new]; + [events enumerateObjectsUsingBlock:^(NSDictionary* _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) { + formatPoint(obj, str); + }]; + return str; +} + +@implementation QNPipeline + +- (instancetype)init:(QNPipelineConfig*)config { + if (self = [super init]) { + if (config == nil) { + config = [QNPipelineConfig new]; + } + _config = config; +#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) + _httpManager = [[QNSessionManager alloc] initWithProxy:nil timeout:config.timeoutInterval urlConverter:nil]; +#endif + } + return self; +} + +- (void)pumpRepo:(NSString*)repo + event:(NSDictionary*)data + token:(NSString*)token + handler:(QNPipelineCompletionHandler)handler { + NSMutableString* str = [NSMutableString new]; + formatPoint(data, str); + [self pumpRepo:repo string:str token:token handler:handler]; +} + +- (void)pumpRepo:(NSString*)repo + events:(NSArray*)data + token:(NSString*)token + handler:(QNPipelineCompletionHandler)handler { + NSMutableString* str = formatPoints(data); + [self pumpRepo:repo string:str token:token handler:handler]; +} + +- (NSString*)url:(NSString*)repo { + return [NSString stringWithFormat:@"%@/v2/repos/%@/data", _config.host, repo]; +} + +- (void)pumpRepo:(NSString*)repo + string:(NSString*)str + token:(NSString*)token + handler:(QNPipelineCompletionHandler)handler { + NSDictionary* headers = @{ @"Authorization" : token, + @"Content-Type" : @"text/plain" }; + [_httpManager post:[self url:repo] withData:[str dataUsingEncoding:NSUTF8StringEncoding] withParams:nil withHeaders:headers withIdentifier:nil withCompleteBlock:^(QNResponseInfo *httpResponseInfo, NSDictionary *respBody) { + handler(httpResponseInfo); + } withProgressBlock:nil withCancelBlock:nil withAccess:nil]; +} + ++ (NSDateFormatter*)dateFormatter { + static NSDateFormatter* formatter = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + formatter = [NSDateFormatter new]; + [formatter setLocale:[NSLocale currentLocale]]; + [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"]; + [formatter setTimeZone:[NSTimeZone defaultTimeZone]]; + }); + + return formatter; +} + +@end diff --git a/msext/QiniuSDK/Http/QNSessionManager.h b/Pods/Qiniu/QiniuSDK/BigData/QNSessionManager.h old mode 100755 new mode 100644 similarity index 71% rename from msext/QiniuSDK/Http/QNSessionManager.h rename to Pods/Qiniu/QiniuSDK/BigData/QNSessionManager.h index 7b915d7..77c2a44 --- a/msext/QiniuSDK/Http/QNSessionManager.h +++ b/Pods/Qiniu/QiniuSDK/BigData/QNSessionManager.h @@ -1,22 +1,29 @@ -#import "QNHttpDelegate.h" -#import + +#import #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 +@class QNResponseInfo; + +typedef void (^QNInternalProgressBlock)(long long totalBytesWritten, long long totalBytesExpectedToWrite); +typedef void (^QNCompleteBlock)(QNResponseInfo *httpResponseInfo, NSDictionary *respBody); +typedef BOOL (^QNCancelBlock)(void); + + +@interface QNSessionManager : NSObject - (instancetype)initWithProxy:(NSDictionary *)proxyDict timeout:(UInt32)timeout - urlConverter:(QNUrlConvert)converter - dns:(QNDnsManager *)dns; + urlConverter:(QNUrlConvert)converter; - (void)multipartPost:(NSString *)url withData:(NSData *)data withParams:(NSDictionary *)params withFileName:(NSString *)key withMimeType:(NSString *)mime + withIdentifier:(NSString *)identifier withCompleteBlock:(QNCompleteBlock)completeBlock withProgressBlock:(QNInternalProgressBlock)progressBlock withCancelBlock:(QNCancelBlock)cancelBlock @@ -26,6 +33,7 @@ withData:(NSData *)data withParams:(NSDictionary *)params withHeaders:(NSDictionary *)headers + withIdentifier:(NSString *)identifier withCompleteBlock:(QNCompleteBlock)completeBlock withProgressBlock:(QNInternalProgressBlock)progressBlock withCancelBlock:(QNCancelBlock)cancelBlock @@ -35,6 +43,8 @@ withHeaders:(NSDictionary *)headers withCompleteBlock:(QNCompleteBlock)completeBlock; +- (void)invalidateSessionWithIdentifier:(NSString *)identifier; + @end #endif diff --git a/Pods/Qiniu/QiniuSDK/BigData/QNSessionManager.m b/Pods/Qiniu/QiniuSDK/BigData/QNSessionManager.m new file mode 100644 index 0000000..44ed224 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/BigData/QNSessionManager.m @@ -0,0 +1,265 @@ +// +// QNHttpManager.m +// QiniuSDK +// +// Created by bailong on 14/10/1. +// Copyright (c) 2014年 Qiniu. All rights reserved. +// + +#import "QNAsyncRun.h" +#import "QNConfiguration.h" +#import "QNSessionManager.h" +#import "QNUserAgent.h" + +#import "QNResponseInfo.h" +#import "NSURLRequest+QNRequest.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) + +typedef void (^QNSessionComplete)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error); +@interface QNSessionDelegateHandler : NSObject + +@property (nonatomic, copy) QNInternalProgressBlock progressBlock; +@property (nonatomic, copy) QNCancelBlock cancelBlock; +@property (nonatomic, copy) QNSessionComplete completeBlock; +@property (nonatomic, strong) NSData *responseData; + +@end + +@implementation QNSessionDelegateHandler + +#pragma mark - NSURLSessionDataDelegate +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + _responseData = data; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task +didCompleteWithError:(nullable NSError *)error { + // bytes_sent & bytes_total + self.completeBlock(_responseData, task.response, error); + [session finishTasksAndInvalidate]; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + + if (_progressBlock) { + _progressBlock(totalBytesSent, totalBytesExpectedToSend); + } + if (_cancelBlock && _cancelBlock()) { + [task cancel]; + } +} + +- (uint64_t)getTimeintervalWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate { + + if (!startDate || !endDate) return 0; + NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate]; + return interval * 1000; +} + +@end + +@interface QNSessionManager () +@property UInt32 timeout; +@property (nonatomic, strong) QNUrlConvert converter; +@property (nonatomic, strong) NSDictionary *proxyDict; +@property (nonatomic, strong) NSOperationQueue *delegateQueue; +@property (nonatomic, strong) NSMutableArray *sessionArray; +@property (nonatomic, strong) NSLock *lock; +@end + +@implementation QNSessionManager + +- (instancetype)initWithProxy:(NSDictionary *)proxyDict + timeout:(UInt32)timeout + urlConverter:(QNUrlConvert)converter { + if (self = [super init]) { + _delegateQueue = [[NSOperationQueue alloc] init]; + _timeout = timeout; + _converter = converter; + _proxyDict = proxyDict; + _sessionArray = [NSMutableArray array]; + + _lock = [[NSLock alloc] init]; + } + return self; +} + +- (instancetype)init { + return [self initWithProxy:nil timeout:60 urlConverter:nil]; +} + +- (void)sendRequest:(NSMutableURLRequest *)request + withIdentifier:(NSString *)identifier + withCompleteBlock:(QNCompleteBlock)completeBlock + withProgressBlock:(QNInternalProgressBlock)progressBlock + withCancelBlock:(QNCancelBlock)cancelBlock + withAccess:(NSString *)access { + + NSString *domain = request.URL.host; + NSString *u = request.URL.absoluteString; + NSURL *url = request.URL; + if (_converter != nil) { + url = [[NSURL alloc] initWithString:_converter(u)]; + request.URL = url; + domain = url.host; + } + + request.qn_domain = request.URL.host; + [request setTimeoutInterval:_timeout]; + [request setValue:[[QNUserAgent sharedInstance] getUserAgent:access] forHTTPHeaderField:@"User-Agent"]; + [request setValue:nil forHTTPHeaderField:@"Accept-Language"]; + + QNSessionDelegateHandler *delegate = [[QNSessionDelegateHandler alloc] init]; + NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + configuration.connectionProxyDictionary = _proxyDict ? _proxyDict : nil; + + __block NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:_delegateQueue]; + [_sessionArray addObject:@{@"identifier":identifier,@"session":session}]; + + delegate.cancelBlock = cancelBlock; + delegate.progressBlock = progressBlock ? progressBlock : ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) { + }; + delegate.completeBlock = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + [self finishSession:session]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + QNResponseInfo *info = [[QNResponseInfo alloc] initWithResponseInfoHost:request.qn_domain response:httpResponse body:data error:error]; + completeBlock(info, info.responseDictionary); + }; + + NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request]; + [uploadTask resume]; +} + +- (void)multipartPost:(NSString *)url + withData:(NSData *)data + withParams:(NSDictionary *)params + withFileName:(NSString *)key + withMimeType:(NSString *)mime + withIdentifier:(NSString *)identifier + withCompleteBlock:(QNCompleteBlock)completeBlock + withProgressBlock:(QNInternalProgressBlock)progressBlock + withCancelBlock:(QNCancelBlock)cancelBlock + withAccess:(NSString *)access { + NSURL *URL = [[NSURL alloc] initWithString:url]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30]; + request.HTTPMethod = @"POST"; + NSString *boundary = @"werghnvt54wef654rjuhgb56trtg34tweuyrgf"; + request.allHTTPHeaderFields = @{ + @"Content-Type" : [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] + }; + NSMutableData *postData = [[NSMutableData alloc] init]; + for (NSString *paramsKey in params) { + NSString *pair = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n", boundary, paramsKey]; + [postData appendData:[pair dataUsingEncoding:NSUTF8StringEncoding]]; + + id value = [params objectForKey:paramsKey]; + if ([value isKindOfClass:[NSString class]]) { + [postData appendData:[value dataUsingEncoding:NSUTF8StringEncoding]]; + } else if ([value isKindOfClass:[NSData class]]) { + [postData appendData:value]; + } + [postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + } + NSString *filePair = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\nContent-Type:%@\r\n\r\n", boundary, @"file", key, mime]; + [postData appendData:[filePair dataUsingEncoding:NSUTF8StringEncoding]]; + [postData appendData:data]; + [postData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + request.HTTPBody = postData; + [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)postData.length] forHTTPHeaderField:@"Content-Length"]; + + [self sendRequest:request withIdentifier:identifier withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:cancelBlock + withAccess:access]; +} + +- (void)post:(NSString *)url + withData:(NSData *)data + withParams:(NSDictionary *)params + withHeaders:(NSDictionary *)headers +withIdentifier:(NSString *)identifier + 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]; + identifier = !identifier ? [[NSUUID UUID] UUIDString] : identifier; + QNAsyncRun(^{ + [self sendRequest:request + withIdentifier:identifier + withCompleteBlock:completeBlock + withProgressBlock:progressBlock + withCancelBlock:cancelBlock + withAccess:access]; + }); +} + +- (void)get:(NSString *)url + withHeaders:(NSDictionary *)headers + withCompleteBlock:(QNCompleteBlock)completeBlock { + QNAsyncRun(^{ + NSURL *URL = [NSURL URLWithString:url]; + +// NSString *domain = URL.host; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + request.qn_domain = URL.host; + QNSessionDelegateHandler *delegate = [[QNSessionDelegateHandler alloc] init]; + NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + __block NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:self.delegateQueue]; + NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request]; + delegate.cancelBlock = nil; + delegate.progressBlock = nil; + delegate.completeBlock = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + [self finishSession:session]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + QNResponseInfo *info = [[QNResponseInfo alloc] initWithResponseInfoHost:request.qn_domain response:httpResponse body:data error:error]; + completeBlock(info, info.responseDictionary); + }; + [dataTask resume]; + }); +} + +- (void)finishSession:(NSURLSession *)session { + [_lock lock]; + for (int i = 0; i < _sessionArray.count; i++) { + NSDictionary *sessionInfo = _sessionArray[i]; + if (sessionInfo[@"session"] == session) { + [session finishTasksAndInvalidate]; + [_sessionArray removeObject:sessionInfo]; + break; + } + } + [_lock unlock]; +} + +- (void)invalidateSessionWithIdentifier:(NSString *)identifier { + [_lock lock]; + for (int i = 0; i < _sessionArray.count; i++) { + NSDictionary *sessionInfo = _sessionArray[i]; + if ([sessionInfo[@"identifier"] isEqualToString:identifier]) { + NSURLSession *session = sessionInfo[@"session"]; + [session invalidateAndCancel]; + [_sessionArray removeObject:sessionInfo]; + break; + } + } + [_lock unlock]; +} + +@end + +#endif diff --git a/Pods/Qiniu/QiniuSDK/Collect/QNReportConfig.h b/Pods/Qiniu/QiniuSDK/Collect/QNReportConfig.h new file mode 100644 index 0000000..1cbd2c8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Collect/QNReportConfig.h @@ -0,0 +1,60 @@ +// +// QNReportConfig.h +// QiniuSDK +// +// Created by 杨森 on 2020/7/14. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNReportConfig : NSObject + +- (id)init __attribute__((unavailable("Use sharedInstance: instead."))); ++ (instancetype)sharedInstance; + +/** + * 是否开启sdk上传信息搜集 默认为YES + */ +@property (nonatomic, assign, getter=isReportEnable) BOOL reportEnable; + +/** + * 每次上传时间间隔 单位:分钟 默认为0.5分钟 + */ +@property (nonatomic, assign) double interval; + +/** + * 记录文件大于 uploadThreshold 会触发上传,单位:字节 默认为16 * 1024 + */ +@property (nonatomic, assign) uint64_t uploadThreshold; + +/** + * 记录文件最大值 要大于 uploadThreshold 单位:字节 默认为20 * 1024 * 1024 + */ +@property (nonatomic, assign) uint64_t maxRecordFileSize; + +/** + * 记录文件所在文件夹目录 默认为:.../沙盒/Library/Caches/com.qiniu.report + */ +@property (nonatomic, copy) NSString *recordDirectory; + +/** + * 信息上报服务器地址 + */ +@property (nonatomic, copy, readonly) NSString *serverURL; + +/** + * 信息上报服务器地址 host + */ +@property (nonatomic, copy, readonly) NSString *serverHost; + +/** + * 信息上报请求超时时间 单位:秒 默认为10秒 + */ +@property (nonatomic, assign, readonly) NSTimeInterval timeoutInterval; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Collect/QNReportConfig.m b/Pods/Qiniu/QiniuSDK/Collect/QNReportConfig.m new file mode 100644 index 0000000..3e834f8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Collect/QNReportConfig.m @@ -0,0 +1,42 @@ +// +// QNReportConfig.m +// QiniuSDK +// +// Created by 杨森 on 2020/7/14. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNReportConfig.h" +#import "QNConfig.h" +#import "QNUtils.h" + +@implementation QNReportConfig + ++ (instancetype)sharedInstance { + + static QNReportConfig *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _reportEnable = YES; + _interval = 0.5; + _serverHost = kQNUpLogHost; + _recordDirectory = [NSString stringWithFormat:@"%@/report", [QNUtils sdkCacheDirectory]]; + _maxRecordFileSize = 20 * 1024 * 1024; + _uploadThreshold = 16 * 1024; + _timeoutInterval = 10; + } + return self; +} + +- (NSString *)serverURL { + return [NSString stringWithFormat:@"https://%@/log/4?compressed=gzip", _serverHost]; +} +@end diff --git a/Pods/Qiniu/QiniuSDK/Collect/QNReportItem.h b/Pods/Qiniu/QiniuSDK/Collect/QNReportItem.h new file mode 100644 index 0000000..8da3b5d --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Collect/QNReportItem.h @@ -0,0 +1,143 @@ +// +// QNReportItem.h +// QiniuSDK +// +// Created by yangsen on 2020/5/12. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUploadInfoReporter.h" +#import "QNResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNReportItem : NSObject + ++ (instancetype)item; + +/// 设置打点日志字段 +/// @param value log value +/// @param key log key +- (void)setReportValue:(id _Nullable)value forKey:(NSString * _Nullable)key; + +/// 移除打点日志字段 +/// @param key log key +- (void)removeReportValueForKey:(NSString * _Nullable)key; + +@end + + +@interface QNUploadInfoReporter(ReportItem) + +- (void)reportItem:(QNReportItem *)item token:(NSString *)token; + +@end + + +@interface QNResponseInfo(Report) + +@property(nonatomic, assign, readonly)NSNumber *requestReportStatusCode; +@property(nonatomic, copy, readonly)NSString *requestReportErrorType; + +@property(nonatomic, copy, readonly)NSString *qualityResult; + +@end + + + +//MARK:-- 日志类型 +extern NSString *const QNReportLogTypeRequest; +extern NSString *const QNReportLogTypeBlock; +extern NSString *const QNReportLogTypeQuality; + +//MARK:-- 请求信息打点⽇志 +extern NSString *const QNReportRequestKeyLogType; +extern NSString *const QNReportRequestKeyUpTime; +extern NSString *const QNReportRequestKeyStatusCode; +extern NSString *const QNReportRequestKeyRequestId; +extern NSString *const QNReportRequestKeyHost; +extern NSString *const QNReportRequestKeyHttpVersion; +extern NSString *const QNReportRequestKeyRemoteIp; +extern NSString *const QNReportRequestKeyPort; +extern NSString *const QNReportRequestKeyTargetBucket; +extern NSString *const QNReportRequestKeyTargetKey; +extern NSString *const QNReportRequestKeyTotalElapsedTime; +extern NSString *const QNReportRequestKeyDnsElapsedTime; +extern NSString *const QNReportRequestKeyConnectElapsedTime; +extern NSString *const QNReportRequestKeyTLSConnectElapsedTime; +extern NSString *const QNReportRequestKeyRequestElapsedTime; +extern NSString *const QNReportRequestKeyWaitElapsedTime; +extern NSString *const QNReportRequestKeyResponseElapsedTime; +extern NSString *const QNReportRequestKeyFileOffset; +extern NSString *const QNReportRequestKeyBytesSent; +extern NSString *const QNReportRequestKeyBytesTotal; +extern NSString *const QNReportRequestKeyPid; +extern NSString *const QNReportRequestKeyTid; +extern NSString *const QNReportRequestKeyTargetRegionId; +extern NSString *const QNReportRequestKeyCurrentRegionId; +extern NSString *const QNReportRequestKeyErrorType; +extern NSString *const QNReportRequestKeyErrorDescription; +extern NSString *const QNReportRequestKeyUpType; +extern NSString *const QNReportRequestKeyOsName; +extern NSString *const QNReportRequestKeyOsVersion; +extern NSString *const QNReportRequestKeySDKName; +extern NSString *const QNReportRequestKeySDKVersion; +extern NSString *const QNReportRequestKeyClientTime; +extern NSString *const QNReportRequestKeyHttpClient; +extern NSString *const QNReportRequestKeyNetworkType; +extern NSString *const QNReportRequestKeySignalStrength; +extern NSString *const QNReportRequestKeyPrefetchedDnsSource; +extern NSString *const QNReportRequestKeyDnsSource; +extern NSString *const QNReportRequestKeyDnsErrorMessage; +extern NSString *const QNReportRequestKeyPrefetchedBefore; +extern NSString *const QNReportRequestKeyPrefetchedErrorMessage; +extern NSString *const QNReportRequestKeyNetworkMeasuring; +extern NSString *const QNReportRequestKeyPerceptiveSpeed; +extern NSString *const QNReportRequestKeyHijacking; + +//MARK:-- 分块上传统计⽇志 +extern NSString *const QNReportBlockKeyLogType; +extern NSString *const QNReportBlockKeyUpTime; +extern NSString *const QNReportBlockKeyTargetBucket; +extern NSString *const QNReportBlockKeyTargetKey; +extern NSString *const QNReportBlockKeyTargetRegionId; +extern NSString *const QNReportBlockKeyCurrentRegionId; +extern NSString *const QNReportBlockKeyTotalElapsedTime; +extern NSString *const QNReportBlockKeyBytesSent; +extern NSString *const QNReportBlockKeyRecoveredFrom; +extern NSString *const QNReportBlockKeyFileSize; +extern NSString *const QNReportBlockKeyPid; +extern NSString *const QNReportBlockKeyTid; +extern NSString *const QNReportBlockKeyUpApiVersion; +extern NSString *const QNReportBlockKeyClientTime; +extern NSString *const QNReportBlockKeyOsName; +extern NSString *const QNReportBlockKeyOsVersion; +extern NSString *const QNReportBlockKeySDKName; +extern NSString *const QNReportBlockKeySDKVersion; +extern NSString *const QNReportBlockKeyPerceptiveSpeed; +extern NSString *const QNReportBlockKeyHijacking; + +//MARK:-- 上传质量统计 +extern NSString *const QNReportQualityKeyLogType; +extern NSString *const QNReportQualityKeyUpType; +extern NSString *const QNReportQualityKeyUpTime; +extern NSString *const QNReportQualityKeyResult; +extern NSString *const QNReportQualityKeyTargetBucket; +extern NSString *const QNReportQualityKeyTargetKey; +extern NSString *const QNReportQualityKeyTotalElapsedTime; +extern NSString *const QNReportQualityKeyUcQueryElapsedTime; +extern NSString *const QNReportQualityKeyRequestsCount; +extern NSString *const QNReportQualityKeyRegionsCount; +extern NSString *const QNReportQualityKeyBytesSent; +extern NSString *const QNReportQualityKeyFileSize; +extern NSString *const QNReportQualityKeyCloudType; +extern NSString *const QNReportQualityKeyErrorType; +extern NSString *const QNReportQualityKeyErrorDescription; +extern NSString *const QNReportQualityKeyOsName; +extern NSString *const QNReportQualityKeyOsVersion; +extern NSString *const QNReportQualityKeySDKName; +extern NSString *const QNReportQualityKeySDKVersion; +extern NSString *const QNReportQualityKeyPerceptiveSpeed; +extern NSString *const QNReportQualityKeyHijacking; + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Collect/QNReportItem.m b/Pods/Qiniu/QiniuSDK/Collect/QNReportItem.m new file mode 100644 index 0000000..2f22383 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Collect/QNReportItem.m @@ -0,0 +1,257 @@ +// +// QNReportItem.m +// QiniuSDK +// +// Created by yangsen on 2020/5/12. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNReportItem.h" +#import "QNAsyncRun.h" +#import "QNLogUtil.h" + +@interface QNReportItem() + +@property(nonatomic, strong)NSMutableDictionary *keyValues; + +@end +@implementation QNReportItem + ++ (instancetype)item{ + QNReportItem *item = [[QNReportItem alloc] init]; + return item; +} + +- (instancetype)init{ + if (self = [super init]) { + [self initData]; + } + return self; +} + +- (void)initData{ + _keyValues = [NSMutableDictionary dictionary]; +} + +- (void)setReportValue:(id _Nullable)value forKey:(NSString * _Nullable)key{ + if (!value || !key || ![key isKindOfClass:[NSString class]]) { + return; + } + if ([value isKindOfClass:[NSString class]] && [(NSString *)value length] > 1024) { + value = [(NSString *)value substringToIndex:1024]; + } + [self.keyValues setValue:value forKey:key]; +} + +- (void)removeReportValueForKey:(NSString * _Nullable)key{ + if (!key) { + return; + } + [self.keyValues removeObjectForKey:key]; +} + + +- (NSString *)toJson{ + + NSString *jsonString = @"{}"; + if (!self.keyValues || self.keyValues.count == 0) { + return jsonString; + } + + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self.keyValues + options:NSJSONWritingFragmentsAllowed + error:nil]; + if (!jsonData) { + return jsonString; + } + + jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + return jsonString; +} + +@end + +@implementation QNUploadInfoReporter(ReportItem) + +- (void)reportItem:(QNReportItem *)item token:(NSString *)token{ + NSString *itemJsonString = [item toJson]; + QNLogInfo(@"up log:%@", itemJsonString); + if (itemJsonString && ![itemJsonString isEqualToString:@"{}"]) { + [kQNReporter report:itemJsonString token:token]; + } +} + +@end + +@implementation QNResponseInfo(Report) + +- (NSNumber *)requestReportStatusCode{ + return @(self.statusCode); +} + +- (NSString *)requestReportErrorType{ + NSString *errorType = nil; + if (self.statusCode == -1){ + errorType = @"network_error"; + } else if (self.statusCode == kQNLocalIOError){ + errorType = @"local_io_error"; + } else if (self.statusCode == 100){ + errorType = @"protocol_error"; + } else if (self.statusCode > 199 && self.statusCode < 300) { +// NSURLErrorFailingURLErrorKey + } else if (self.statusCode > 299){ + errorType = @"response_error"; + } else if (self.statusCode == -1003){ + errorType = @"unknown_host"; + } else if (self.statusCode == -1009){ + errorType = @"network_slow"; + } else if (self.statusCode == -1001){ + errorType = @"timeout"; + } else if (self.statusCode == -1004){ + errorType = @"cannot_connect_to_host"; + } else if (self.statusCode == -1005 || self.statusCode == -1021){ + errorType = @"transmission_error"; + } else if ((self.statusCode <= -1200 && self.statusCode >= -1206) || self.statusCode == -2000 || self.statusCode == -9807){ + errorType = @"ssl_error"; + } else if (self.statusCode == -1015 || self.statusCode == -1016 || self.statusCode == -1017){ + errorType = @"parse_error"; + } else if (self.statusCode == -1007 || self.statusCode == -1010 || self.statusCode == kQNMaliciousResponseError){ + errorType = @"malicious_response"; + } else if (self.statusCode == kQNUnexpectedSysCallError + || (self.statusCode > -1130 && self.statusCode <= -1010)){ + errorType = @"unexpected_syscall_error"; + } else if (self.statusCode == kQNRequestCancelled + || self.statusCode == NSURLErrorCancelled){ + errorType = @"user_canceled"; + } else { + errorType = @"unknown_error"; + } + return errorType; +} + +- (NSString *)qualityResult{ + + NSString *result = nil; + + if (self.statusCode > 199 && self.statusCode < 300) { + result = @"ok"; + } else if (self.statusCode > 399 && + (self.statusCode < 500 || self.statusCode == 573 || self.statusCode == 579 || + self.statusCode == 608 || self.statusCode == 612 || self.statusCode == 614 || self.statusCode == 630 || self.statusCode == 631 || + self.statusCode == 701)) { + result = @"bad_request"; + } else if (self.statusCode == kQNZeroDataSize){ + result = @"zero_size_file"; + } else if (self.statusCode == kQNFileError){ + result = @"invalid_file"; + } else if (self.statusCode == kQNInvalidToken + || self.statusCode == kQNInvalidArgument){ + result = @"invalid_args"; + } + + if (result == nil) { + result = [self requestReportErrorType]; + } + + return result; +} + +@end + + +//MARK:-- 日志类型 +NSString * const QNReportLogTypeRequest = @"request"; +NSString * const QNReportLogTypeBlock = @"block"; +NSString * const QNReportLogTypeQuality = @"quality"; + + +//MARK:-- 请求信息打点⽇志 +NSString * const QNReportRequestKeyLogType = @"log_type"; +NSString * const QNReportRequestKeyUpTime = @"up_time"; +NSString * const QNReportRequestKeyStatusCode = @"status_code"; +NSString * const QNReportRequestKeyRequestId = @"req_id"; +NSString * const QNReportRequestKeyHost = @"host"; +NSString * const QNReportRequestKeyHttpVersion = @"http_version"; +NSString * const QNReportRequestKeyRemoteIp = @"remote_ip"; +NSString * const QNReportRequestKeyPort = @"port"; +NSString * const QNReportRequestKeyTargetBucket = @"target_bucket"; +NSString * const QNReportRequestKeyTargetKey = @"target_key"; +NSString * const QNReportRequestKeyTotalElapsedTime = @"total_elapsed_time"; +NSString * const QNReportRequestKeyDnsElapsedTime = @"dns_elapsed_time"; +NSString * const QNReportRequestKeyConnectElapsedTime = @"connect_elapsed_time"; +NSString * const QNReportRequestKeyTLSConnectElapsedTime = @"tls_connect_elapsed_time"; +NSString * const QNReportRequestKeyRequestElapsedTime = @"request_elapsed_time"; +NSString * const QNReportRequestKeyWaitElapsedTime = @"wait_elapsed_time"; +NSString * const QNReportRequestKeyResponseElapsedTime = @"response_elapsed_time"; +NSString * const QNReportRequestKeyFileOffset = @"file_offset"; +NSString * const QNReportRequestKeyBytesSent = @"bytes_sent"; +NSString * const QNReportRequestKeyBytesTotal = @"bytes_total"; +NSString * const QNReportRequestKeyPid = @"pid"; +NSString * const QNReportRequestKeyTid = @"tid"; +NSString * const QNReportRequestKeyTargetRegionId = @"target_region_id"; +NSString * const QNReportRequestKeyCurrentRegionId = @"current_region_id"; +NSString * const QNReportRequestKeyErrorType = @"error_type"; +NSString * const QNReportRequestKeyErrorDescription = @"error_description"; +NSString * const QNReportRequestKeyUpType = @"up_type"; +NSString * const QNReportRequestKeyOsName = @"os_name"; +NSString * const QNReportRequestKeyOsVersion = @"os_version"; +NSString * const QNReportRequestKeySDKName = @"sdk_name"; +NSString * const QNReportRequestKeySDKVersion = @"sdk_version"; +NSString * const QNReportRequestKeyClientTime = @"client_time"; +NSString * const QNReportRequestKeyHttpClient = @"http_client"; +NSString * const QNReportRequestKeyNetworkType = @"network_type"; +NSString * const QNReportRequestKeySignalStrength = @"signal_strength"; +NSString * const QNReportRequestKeyPrefetchedDnsSource = @"prefetched_dns_source"; +NSString * const QNReportRequestKeyDnsSource = @"dns_source"; +NSString * const QNReportRequestKeyDnsErrorMessage = @"dns_error_message"; +NSString * const QNReportRequestKeyPrefetchedBefore = @"prefetched_before"; +NSString * const QNReportRequestKeyPrefetchedErrorMessage = @"prefetched_error_message"; +NSString * const QNReportRequestKeyNetworkMeasuring = @"network_measuring"; +NSString * const QNReportRequestKeyPerceptiveSpeed = @"perceptive_speed"; +NSString * const QNReportRequestKeyHijacking = @"hijacking"; + +//MARK:-- 分块上传统计⽇志 +NSString * const QNReportBlockKeyLogType = @"log_type"; +NSString * const QNReportBlockKeyUpTime = @"up_time"; +NSString * const QNReportBlockKeyTargetBucket = @"target_bucket"; +NSString * const QNReportBlockKeyTargetKey = @"target_key"; +NSString * const QNReportBlockKeyTargetRegionId = @"target_region_id"; +NSString * const QNReportBlockKeyCurrentRegionId = @"current_region_id"; +NSString * const QNReportBlockKeyTotalElapsedTime = @"total_elapsed_time"; +NSString * const QNReportBlockKeyBytesSent = @"bytes_sent"; +NSString * const QNReportBlockKeyRecoveredFrom = @"recovered_from"; +NSString * const QNReportBlockKeyFileSize = @"file_size"; +NSString * const QNReportBlockKeyPid = @"pid"; +NSString * const QNReportBlockKeyTid = @"tid"; +NSString * const QNReportBlockKeyUpApiVersion = @"up_api_version"; +NSString * const QNReportBlockKeyClientTime = @"client_time"; +NSString * const QNReportBlockKeyOsName = @"os_name"; +NSString * const QNReportBlockKeyOsVersion = @"os_version"; +NSString * const QNReportBlockKeySDKName = @"sdk_name"; +NSString * const QNReportBlockKeySDKVersion = @"sdk_version"; +NSString * const QNReportBlockKeyPerceptiveSpeed = @"perceptive_speed"; +NSString * const QNReportBlockKeyHijacking = @"hijacking"; + + +//MARK:-- 上传质量统计 +NSString * const QNReportQualityKeyLogType = @"log_type"; +NSString * const QNReportQualityKeyUpType = @"up_type"; +NSString * const QNReportQualityKeyUpTime = @"up_time"; +NSString * const QNReportQualityKeyResult = @"result"; +NSString * const QNReportQualityKeyTargetBucket = @"target_bucket"; +NSString * const QNReportQualityKeyTargetKey = @"target_key"; +NSString * const QNReportQualityKeyTotalElapsedTime = @"total_elapsed_time"; +NSString * const QNReportQualityKeyUcQueryElapsedTime = @"uc_query_elapsed_time"; +NSString * const QNReportQualityKeyRequestsCount = @"requests_count"; +NSString * const QNReportQualityKeyRegionsCount = @"regions_count"; +NSString * const QNReportQualityKeyBytesSent = @"bytes_sent"; +NSString * const QNReportQualityKeyFileSize = @"file_size"; +NSString * const QNReportQualityKeyCloudType = @"cloud_type"; +NSString * const QNReportQualityKeyErrorType = @"error_type"; +NSString * const QNReportQualityKeyErrorDescription = @"error_description"; +NSString * const QNReportQualityKeyOsName = @"os_name"; +NSString * const QNReportQualityKeyOsVersion = @"os_version"; +NSString * const QNReportQualityKeySDKName = @"sdk_name"; +NSString * const QNReportQualityKeySDKVersion = @"sdk_version"; +NSString * const QNReportQualityKeyPerceptiveSpeed = @"perceptive_speed"; +NSString * const QNReportQualityKeyHijacking = @"hijacking"; diff --git a/Pods/Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.h b/Pods/Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.h new file mode 100644 index 0000000..d769170 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.h @@ -0,0 +1,36 @@ +// +// QNUploadInfoReporter.h +// QiniuSDK +// +// Created by WorkSpace_Sun on 2019/6/24. +// Copyright © 2019 Qiniu. All rights reserved. +// + +#import +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#endif + + +#define kQNReporter [QNUploadInfoReporter sharedInstance] +@interface QNUploadInfoReporter : NSObject + +- (id)init __attribute__((unavailable("Use sharedInstance: instead."))); ++ (instancetype)sharedInstance; + +/** +* 上报统计信息 +* +* @param jsonString 需要记录的json字符串 +* @param token 上传凭证 +* +*/ +- (void)report:(NSString *)jsonString token:(NSString *)token; + +/** + * 清空统计信息 + */ +- (void)clean; + +@end + diff --git a/Pods/Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.m b/Pods/Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.m new file mode 100644 index 0000000..f37960f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Collect/QNUploadInfoReporter.m @@ -0,0 +1,242 @@ +// +// QNUploadInfoReporter.m +// QiniuSDK +// +// Created by WorkSpace_Sun on 2019/6/24. +// Copyright © 2019 Qiniu. All rights reserved. +// +#import "QNDefine.h" +#import "QNZoneInfo.h" +#import "QNUploadInfoReporter.h" +#import "QNResponseInfo.h" +#import "QNUtils.h" +#import "QNFile.h" +#import "QNUpToken.h" +#import "QNUserAgent.h" +#import "QNAsyncRun.h" +#import "QNVersion.h" +#import "QNReportConfig.h" +#import "NSData+QNGZip.h" +#import "QNTransactionManager.h" +#import "QNRequestTransaction.h" + +#define kQNUplogDelayReportTransactionName @"com.qiniu.uplog" + +@interface QNUploadInfoReporter () + +@property (nonatomic, strong) QNReportConfig *config; +@property (nonatomic, assign) NSTimeInterval lastReportTime; +@property (nonatomic, strong) NSString *recorderFilePath; +@property (nonatomic, strong) NSString *recorderTempFilePath; +@property (nonatomic, copy) NSString *X_Log_Client_Id; + +@property (nonatomic, strong) QNRequestTransaction *transaction; +@property (nonatomic, assign) BOOL isReporting; + +@property (nonatomic, strong) dispatch_queue_t recordQueue; +@property (nonatomic, strong) dispatch_semaphore_t semaphore; +@end + +@implementation QNUploadInfoReporter + ++ (instancetype)sharedInstance { + + static QNUploadInfoReporter *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + + self = [super init]; + if (self) { + _config = [QNReportConfig sharedInstance]; + _lastReportTime = 0; + _recorderFilePath = [NSString stringWithFormat:@"%@/%@", _config.recordDirectory, @"qiniu.log"]; + _recorderTempFilePath = [NSString stringWithFormat:@"%@/%@", _config.recordDirectory, @"qiniuTemp.log"]; + _recordQueue = dispatch_queue_create("com.qiniu.reporter", DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (void)clean { + [self cleanRecorderFile]; + [self cleanTempRecorderFile]; +} + +- (void)cleanRecorderFile { + NSFileManager *manager = [NSFileManager defaultManager]; + if ([manager fileExistsAtPath:_recorderFilePath]) { + NSError *error = nil; + [manager removeItemAtPath:_recorderFilePath error:&error]; + if (error) { + NSLog(@"remove recorder file failed: %@", error); + return; + } + } +} + +- (void)cleanTempRecorderFile { + NSFileManager *manager = [NSFileManager defaultManager]; + if ([manager fileExistsAtPath:_recorderTempFilePath]) { + NSError *error = nil; + [manager removeItemAtPath:_recorderTempFilePath error:&error]; + if (error) { + NSLog(@"remove recorder temp file failed: %@", error); + return; + } + } +} + +- (BOOL)checkReportAvailable { + if (!_config.isReportEnable) { + return NO; + } + if (_config.maxRecordFileSize <= _config.uploadThreshold) { + NSLog(@"maxRecordFileSize must be larger than uploadThreshold"); + return NO; + } + return YES; +} + +- (void)report:(NSString *)jsonString token:(NSString *)token { + + if (![self checkReportAvailable] || !jsonString || !token || token.length == 0) { + return; + } + + // 串行队列处理文件读写 + dispatch_async(self.recordQueue, ^{ + [kQNReporter saveReportJsonString:jsonString]; + [kQNReporter reportToServerIfNeeded:token]; + }); +} + +- (void)saveReportJsonString:(NSString *)jsonString { + NSString *finalRecordInfo = [jsonString stringByAppendingString:@"\n"]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:self.recorderFilePath]) { + // 如果recordFile不存在,创建文件并写入首行,首次不上传 + [finalRecordInfo writeToFile:_recorderFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; + } else { + NSDictionary *recorderFileAttr = [fileManager attributesOfItemAtPath:self.recorderFilePath error:nil]; + if ([recorderFileAttr fileSize] > self.config.maxRecordFileSize) { + return; + } + + NSFileHandle *fileHandler = nil; + @try { + // 上传信息写入recorder文件 + fileHandler = [NSFileHandle fileHandleForUpdatingAtPath:_recorderFilePath]; + [fileHandler seekToEndOfFile]; + [fileHandler writeData: [finalRecordInfo dataUsingEncoding:NSUTF8StringEncoding]]; + } @catch (NSException *exception) { + NSLog(@"NSFileHandle cannot write data: %@", exception.description); + } @finally { + [fileHandler closeFile]; + } + } +} + +- (void)reportToServerIfNeeded:(NSString *)tokenString { + BOOL needToReport = NO; + long currentTime = [[NSDate date] timeIntervalSince1970]; + long interval = self.config.interval * 10; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSDictionary *recorderFileAttr = [fileManager attributesOfItemAtPath:self.recorderFilePath error:nil]; + if ([fileManager fileExistsAtPath:self.recorderTempFilePath]) { + needToReport = YES; + } else if ((self.lastReportTime == 0 || (currentTime - self.lastReportTime) >= interval || [recorderFileAttr fileSize] > self.config.uploadThreshold) && + ([fileManager moveItemAtPath:self.recorderFilePath toPath:self.recorderTempFilePath error:nil])) { + needToReport = YES; + } + + if (needToReport && !self.isReporting) { + [self reportToServer:tokenString]; + } else { + // 有未上传日志存在,则 interval 时间后再次重试一次 + if (![fileManager fileExistsAtPath:self.recorderFilePath] || [recorderFileAttr fileSize] == 0) { + return; + } + + NSArray *transactionList = [kQNTransactionManager transactionsForName:kQNUplogDelayReportTransactionName]; + if (transactionList != nil && transactionList.count > 1) { + return; + } + + if (transactionList != nil && transactionList.count == 1) { + QNTransaction *transaction = transactionList.firstObject; + if (transaction != nil && !transaction.isExecuting) { + return; + } + } + + QNTransaction *transaction = [QNTransaction transaction:kQNUplogDelayReportTransactionName after:interval action:^{ + [kQNReporter reportToServerIfNeeded:tokenString]; + }]; + [kQNTransactionManager addTransaction:transaction]; + } +} + + +- (void)reportToServer:(NSString *)tokenString { + if (tokenString == nil) { + return; + } + QNUpToken *token = [QNUpToken parse:tokenString]; + if (!token.isValid) { + return; + } + + NSData *logData = [self getLogData]; + if (logData == nil) { + return; + } + + self.isReporting = YES; + logData = [NSData qn_gZip:logData]; + QNRequestTransaction *transaction = [self createUploadRequestTransaction:token]; + [transaction reportLog:logData logClientId:self.X_Log_Client_Id complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + if (responseInfo.isOK) { + self.lastReportTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970]; + if (!self.X_Log_Client_Id) { + self.X_Log_Client_Id = responseInfo.responseHeader[@"x-log-client-id"]; + } + [self cleanTempRecorderFile]; + } else { + NSLog(@"upload info report failed: %@", responseInfo); + } + + self.isReporting = NO; + [self destroyUploadRequestTransaction:transaction]; + }]; +} + +- (NSData *)getLogData { + return [NSData dataWithContentsOfFile:_recorderTempFilePath]; +} + +- (QNRequestTransaction *)createUploadRequestTransaction:(QNUpToken *)token{ + if (self.config.serverURL) { + + } + NSArray *hosts = nil; + if (self.config.serverHost) { + hosts = @[self.config.serverHost]; + } + QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithHosts:hosts + regionId:QNZoneInfoEmptyRegionId + token:token]; + self.transaction = transaction; + return transaction; +} + +- (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction{ + self.transaction = nil; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Common/QNAutoZone.h b/Pods/Qiniu/QiniuSDK/Common/QNAutoZone.h new file mode 100644 index 0000000..65979a1 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNAutoZone.h @@ -0,0 +1,27 @@ +// +// QNAutoZone.h +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNZone.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNFixedZone; +@interface QNAutoZone : QNZone + ++ (instancetype)zoneWithUcHosts:(NSArray *)ucHosts; + ++ (void)clearCache; + +/** + * 当 查询失败时,会使用 zones 进行上传,默认不配置。 + */ +- (void)setDefaultZones:(NSArray *)zones; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Common/QNAutoZone.m b/Pods/Qiniu/QiniuSDK/Common/QNAutoZone.m new file mode 100644 index 0000000..8aca7f1 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNAutoZone.m @@ -0,0 +1,254 @@ +// +// QNAutoZone.m +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNDefine.h" +#import "QNCache.h" +#import "QNUtils.h" +#import "QNAutoZone.h" +#import "QNConfig.h" +#import "QNRequestTransaction.h" +#import "QNZoneInfo.h" +#import "QNUpToken.h" +#import "QNUploadOption.h" +#import "QNConfiguration.h" +#import "QNResponseInfo.h" +#import "QNFixedZone.h" +#import "QNSingleFlight.h" +#import "QNFileRecorder.h" +#import "QNUrlSafeBase64.h" +#import "QNUploadRequestMetrics.h" + +@interface QNUCQuerySingleFlightValue : NSObject + +@property(nonatomic, strong) QNResponseInfo *responseInfo; +@property(nonatomic, strong) NSDictionary *response; +@property(nonatomic, strong) QNUploadRegionRequestMetrics *metrics; + +@end + +@implementation QNUCQuerySingleFlightValue +@end + +@interface QNAutoZone () + +@property(nonatomic, strong) NSArray *ucHosts; +@property(nonatomic, strong) QNFixedZone *defaultZone; +// 已经查询到的区域信息 +@property(nonatomic, strong) NSMutableDictionary *zonesDic; +@property(nonatomic, strong) NSMutableArray *transactions; + +@end + +@implementation QNAutoZone + ++ (QNSingleFlight *)UCQuerySingleFlight { + static QNSingleFlight *singleFlight = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + singleFlight = [[QNSingleFlight alloc] init]; + }); + return singleFlight; +} + ++ (instancetype)zoneWithUcHosts:(NSArray *)ucHosts { + QNAutoZone *zone = [[self alloc] init]; + zone.ucHosts = [ucHosts copy]; + return zone; +} + ++ (QNCache *)zoneShareCache { + static QNCache *queryCache; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + QNCacheOption *option = [[QNCacheOption alloc] init]; + option.version = @"v2"; + queryCache = [QNCache cache:[QNZonesInfo class] option:option]; + }); + return queryCache; +} + ++ (void)clearCache { + [[QNAutoZone zoneShareCache] clearMemoryCache]; + [[QNAutoZone zoneShareCache] clearDiskCache]; +} + +- (instancetype)init { + if (self = [super init]) { + _zonesDic = [NSMutableDictionary dictionary]; + _transactions = [NSMutableArray array]; + } + return self; +} + +- (void)setDefaultZones:(NSArray *)zones { + self.defaultZone = [QNFixedZone combineZones:zones]; +} + +- (QNZonesInfo *)getZonesInfoWithToken:(QNUpToken *_Nullable)token { + + if (token == nil) return nil; + NSString *cacheKey = [self makeCacheKey:[QNConfiguration defaultConfiguration] akAndBucket:token.index]; + QNZonesInfo *zonesInfo = nil; + @synchronized (self) { + zonesInfo = self.zonesDic[cacheKey]; + } + zonesInfo = [zonesInfo copy]; + return zonesInfo; +} + +- (void)setZonesInfo:(QNZonesInfo *)info forKey:(NSString *)key { + if (info == nil) { + return; + } + + @synchronized (self) { + self.zonesDic[key] = info; + } +} + +- (void)preQuery:(QNUpToken *)token on:(QNPrequeryReturn)ret { + [self query:[QNConfiguration defaultConfiguration] token:token on:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, QNZonesInfo * _Nullable zonesInfo) { + if (!ret) { + return; + } + + if (responseInfo.isOK) { + ret(0, responseInfo, metrics); + } else { + ret(responseInfo.statusCode, responseInfo, metrics); + } + }]; +} + +- (void)query:(QNConfiguration *)config token:(QNUpToken *)token on:(QNQueryReturn)ret { + if (token == nil || ![token isValid]) { + ret([QNResponseInfo responseInfoWithInvalidToken:@"invalid token"], nil, nil); + return; + } + + QNUploadRegionRequestMetrics *cacheMetrics = [QNUploadRegionRequestMetrics emptyMetrics]; + [cacheMetrics start]; + + + NSString *cacheKey = [self makeCacheKey:config akAndBucket:token.index]; + QNZonesInfo *zonesInfo = [[QNAutoZone zoneShareCache] cacheForKey:cacheKey]; + + // 临时的 zonesInfo 仅能使用一次 + if (zonesInfo != nil && zonesInfo.isValid && !zonesInfo.isTemporary) { + [cacheMetrics end]; + [self setZonesInfo:zonesInfo forKey:cacheKey]; + ret([QNResponseInfo successResponse], cacheMetrics, zonesInfo); + return; + } + + kQNWeakSelf; + QNSingleFlight *singleFlight = [QNAutoZone UCQuerySingleFlight]; + [singleFlight perform:token.index action:^(QNSingleFlightComplete _Nonnull complete) { + kQNStrongSelf; + QNRequestTransaction *transaction = [self createUploadRequestTransaction:config token:token]; + + kQNWeakSelf; + kQNWeakObj(transaction); + [transaction queryUploadHosts:^(QNResponseInfo *_Nullable responseInfo, QNUploadRegionRequestMetrics *_Nullable metrics, NSDictionary *_Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + + QNUCQuerySingleFlightValue *value = [[QNUCQuerySingleFlightValue alloc] init]; + value.responseInfo = responseInfo; + value.response = response; + value.metrics = metrics; + complete(value, nil); + + [self destroyUploadRequestTransaction:transaction]; + }]; + + } complete:^(id _Nullable value, NSError *_Nullable error) { + kQNStrongSelf; + + QNResponseInfo *responseInfo = [(QNUCQuerySingleFlightValue *) value responseInfo]; + NSDictionary *response = [(QNUCQuerySingleFlightValue *) value response]; + QNUploadRegionRequestMetrics *metrics = [(QNUCQuerySingleFlightValue *) value metrics]; + + if (responseInfo && responseInfo.isOK) { + QNZonesInfo *zonesInfo = [QNZonesInfo infoWithDictionary:response]; + if ([zonesInfo isValid]) { + [self setZonesInfo:zonesInfo forKey:cacheKey]; + [[QNAutoZone zoneShareCache] cache:zonesInfo forKey:cacheKey atomically:false]; + ret(responseInfo, metrics, zonesInfo); + } else { + responseInfo = [QNResponseInfo errorResponseInfo:NSURLErrorCannotDecodeRawData errorDesc:[NSString stringWithFormat:@"origin response:%@", responseInfo]]; + ret(responseInfo, metrics, nil); + } + } else { + if (self.defaultZone != nil) { + // 备用只能用一次 + QNZonesInfo *info = [self.defaultZone getZonesInfoWithToken:token]; + [self setZonesInfo:info forKey:cacheKey]; + responseInfo = [QNResponseInfo successResponseWithDesc:[NSString stringWithFormat:@"origin response:%@", responseInfo]]; + ret(responseInfo, metrics, info); + } else if (zonesInfo != nil) { + // 缓存有,但是失效也可使用 + [self setZonesInfo:zonesInfo forKey:cacheKey]; + responseInfo = [QNResponseInfo successResponseWithDesc:[NSString stringWithFormat:@"origin response:%@", responseInfo]]; + ret(responseInfo, metrics, zonesInfo); + } else { + ret(responseInfo, metrics, nil); + } + } + }]; +} + +- (QNRequestTransaction *)createUploadRequestTransaction:(QNConfiguration *)config token:(QNUpToken *)token { + if (config == nil) { + config = [QNConfiguration defaultConfiguration]; + } + + NSArray *hosts = nil; + if (self.ucHosts && self.ucHosts.count > 0) { + hosts = [self.ucHosts copy]; + } else { + hosts = kQNPreQueryHosts; + } + QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithConfig:config + uploadOption:[QNUploadOption defaultOptions] + hosts:hosts + regionId:QNZoneInfoEmptyRegionId + key:@"" + token:token]; + @synchronized (self) { + [self.transactions addObject:transaction]; + } + return transaction; +} + +- (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction { + if (transaction) { + @synchronized (self) { + [self.transactions removeObject:transaction]; + } + } +} + +- (NSString *)makeCacheKey:(QNConfiguration *)config akAndBucket:(NSString *)akAndBucket { + NSString *key = akAndBucket; + if (config != nil) { + key = [NSString stringWithFormat:@"%@:%d",key, config.accelerateUploading]; + } + + NSString *hosts = @""; + for (NSString *host in self.ucHosts) { + if (!host) { + continue; + } + hosts = [NSString stringWithFormat:@"%@:%@", hosts, host]; + } + NSString *cacheKey = [NSString stringWithFormat:@"%@:%@", hosts, key]; + return [QNUrlSafeBase64 encodeString:cacheKey]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Common/QNConfig.h b/Pods/Qiniu/QiniuSDK/Common/QNConfig.h new file mode 100644 index 0000000..bed8269 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNConfig.h @@ -0,0 +1,18 @@ +// +// QNConfig.h +// QiniuSDK +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +//MARK: -- 内部布置 尽量不要修改 +#define kQNPreQueryHost00 @"uc.qiniuapi.com" +#define kQNPreQueryHost01 @"kodo-config.qiniuapi.com" +#define kQNPreQueryHost02 @"uc.qbox.me" +#define kQNPreQueryHost03 @"api.qiniu.com" +#define kQNPreQueryHosts @[kQNPreQueryHost00, kQNPreQueryHost01, kQNPreQueryHost02] + +#define kQNUpLogHost @"uplog.qbox.me" diff --git a/Pods/Qiniu/QiniuSDK/Common/QNErrorCode.h b/Pods/Qiniu/QiniuSDK/Common/QNErrorCode.h new file mode 100644 index 0000000..593e468 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNErrorCode.h @@ -0,0 +1,68 @@ +// +// QNErrorCode.h +// QiniuSDK +// +// Created by yangsen on 2020/10/21. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +/** + * StatusCode >= 100 见:https://developer.qiniu.com/kodo/3928/error-responses + * 除上述链接及下面定义外的状态码依据 iOS 标准库定义 + */ + +/** + * 中途取消的状态码 + */ +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; + +/** + * 本地 I/O 错误 + */ +extern const int kQNLocalIOError; + +/** + * ⽤户劫持错误 错误 + */ +extern const int kQNMaliciousResponseError; + +/** + * 没有可用的Host 错误【废弃】 + */ +extern const int kQNNoUsableHostError NS_UNAVAILABLE; + +/** + * SDK 内部错误 + */ +extern const int kQNSDKInteriorError; + +/** + * 非预期的系统调用 错误 + */ +extern const int kQNUnexpectedSysCallError; diff --git a/Pods/Qiniu/QiniuSDK/Common/QNErrorCode.m b/Pods/Qiniu/QiniuSDK/Common/QNErrorCode.m new file mode 100644 index 0000000..dc72b85 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNErrorCode.m @@ -0,0 +1,25 @@ +// +// QNErrorCode.m +// QiniuSDK +// +// Created by yangsen on 2020/10/21. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNErrorCode.h" + +const int kQNUnexpectedSysCallError = -10; +const int kQNNoUsableHostError = -9; +const int kQNSDKInteriorError = -9; +const int kQNMaliciousResponseError = -8; +const int kQNLocalIOError = -7; +const int kQNZeroDataSize = -6; +const int kQNInvalidToken = -5; +const int kQNFileError = -4; +const int kQNInvalidArgument = -3; +const int kQNRequestCancelled = -2; +const int kQNNetworkError = -1; + + + + diff --git a/Pods/Qiniu/QiniuSDK/Common/QNFixedZone.h b/Pods/Qiniu/QiniuSDK/Common/QNFixedZone.h new file mode 100644 index 0000000..a2114af --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNFixedZone.h @@ -0,0 +1,112 @@ +// +// QNFixZone.h +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNZone.h" +#import "QNDefine.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNFixedZone : QNZone + +/** + * zone 0 华东 + * + * @return 实例 + */ ++ (instancetype)zone0 kQNDeprecated("use createWithRegionId instead"); + +/** + * zoneCnEast2 华东-浙江2 + * + * @return 实例 + */ ++ (instancetype)zoneCnEast2 kQNDeprecated("use createWithRegionId instead"); + +/** + * zone 1 华北 + * + * @return 实例 + */ ++ (instancetype)zone1 kQNDeprecated("use createWithRegionId instead"); + +/** + * zone 2 华南 + * + * @return 实例 + */ ++ (instancetype)zone2 kQNDeprecated("use createWithRegionId instead"); + +/** + * zone Na0 北美 + * + * @return 实例 + */ ++ (instancetype)zoneNa0 kQNDeprecated("use createWithRegionId instead"); + +/** + * zone As0 新加坡 + * + * @return 实例 + */ ++ (instancetype)zoneAs0 kQNDeprecated("use createWithRegionId instead"); + +/** + * Zone初始化方法 + * + * @param upList 默认上传服务器地址列表 + * @return Zone实例 + */ +- (instancetype)initWithUpDomainList:(NSArray *)upList; + + +/** + * Zone初始化方法 + * + * @param accUpList 加速上传服务器地址列表 + * @param upList 默认上传服务器地址列表 + * @param oldUpList 支持 SNI 的上传服务器地址列表 + * @param regionId 区域 ID + * @return Zone实例 + */ +- (instancetype)initWithAccUpDomainList:(NSArray *)accUpList + upList:(NSArray *)upList + oldUpList:(NSArray *)oldUpList + regionId:(NSString *)regionId; + +/** + * Zone初始化方法 + * + * @param upList 默认上传服务器地址列表 + * + * @return Zone实例 + */ ++ (instancetype)createWithHost:(NSArray *)upList; + +/** + * Zone初始化方法 + * regionId 参考链接:https://developer.qiniu.com/kodo/1671/region-endpoint-fq + * + * @param regionId 根据区域 ID 创建 Zone + * + * @return Zone 实例 + */ ++ (instancetype)createWithRegionId:(NSString *)regionId; + +/** + * 获取本地所有固定zone信息 + */ ++ (QNFixedZone *)localsZoneInfo DEPRECATED_ATTRIBUTE; + +/** + * 合并区域 + */ ++ (QNFixedZone *)combineZones:(NSArray *)zones; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Common/QNFixedZone.m b/Pods/Qiniu/QiniuSDK/Common/QNFixedZone.m new file mode 100644 index 0000000..426f41f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNFixedZone.m @@ -0,0 +1,199 @@ +// +// QNFixZone.m +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNFixedZone.h" +#import "QNZoneInfo.h" +#import "QNResponseInfo.h" + +@interface QNFixedZone () + +@property (nonatomic, strong) QNZonesInfo *zonesInfo; + +@end + +@implementation QNFixedZone + ++ (instancetype)zone0 { + static QNFixedZone *z0 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + z0 = [[QNFixedZone alloc] initWithUpDomainList:@[@"upload.qiniup.com", @"up.qiniup.com"] + oldUpList:@[@"upload.qbox.me", @"up.qbox.me"] + regionId:@"z0"]; + }); + return z0; +} + ++ (instancetype)zoneCnEast2 { + static QNFixedZone *zoneCnEast2 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + zoneCnEast2 = [[QNFixedZone alloc] initWithUpDomainList:@[@"upload-cn-east-2.qiniup.com", @"up-cn-east-2.qiniup.com"] + oldUpList:nil + regionId:@"cn-east-2"]; + }); + return zoneCnEast2; +} + ++ (instancetype)zone1 { + static QNFixedZone *z1 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + z1 = [[QNFixedZone alloc] initWithUpDomainList:@[@"upload-z1.qiniup.com", @"up-z1.qiniup.com"] + oldUpList:@[@"upload-z1.qbox.me", @"up-z1.qbox.me"] + regionId:@"z1"]; + }); + return z1; +} + ++ (instancetype)zone2 { + static QNFixedZone *z2 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + z2 = [[QNFixedZone alloc] initWithUpDomainList:@[@"upload-z2.qiniup.com", @"up-z2.qiniup.com"] + oldUpList:@[@"upload-z2.qbox.me", @"up-z2.qbox.me"] + regionId:@"z2"]; + }); + return z2; +} + ++ (instancetype)zoneNa0 { + static QNFixedZone *zNa0 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + zNa0 = [[QNFixedZone alloc] initWithUpDomainList:@[@"upload-na0.qiniup.com", @"up-na0.qiniup.com"] + oldUpList:@[@"upload-na0.qbox.me", @"up-na0.qbox.me"] + regionId:@"na0"]; + }); + return zNa0; +} + ++ (instancetype)zoneAs0 { + static QNFixedZone *zAs0 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + zAs0 = [[QNFixedZone alloc] initWithUpDomainList:@[@"upload-as0.qiniup.com", @"up-as0.qiniup.com"] + oldUpList:@[@"upload-as0.qbox.me", @"up-as0.qbox.me"] + regionId:@"as0"];; + }); + return zAs0; +} + ++ (QNFixedZone *)localsZoneInfo{ + + NSArray *zones = @[[QNFixedZone zone0], + [QNFixedZone zone1], + [QNFixedZone zone2], + [QNFixedZone zoneCnEast2], + [QNFixedZone zoneNa0], + [QNFixedZone zoneAs0]]; + QNFixedZone *zone = [self combineZones:zones]; + if (zone) { + [zone.zonesInfo toTemporary]; + } + return zone; +} + ++ (QNFixedZone *)combineZones:(NSArray *)zones { + if (zones == nil || zones.count == 0) { + return nil; + } + + NSMutableArray *zoneInfoArray = [NSMutableArray array]; + for (QNFixedZone *zone in zones) { + if (zone.zonesInfo.zonesInfo) { + [zoneInfoArray addObjectsFromArray:zone.zonesInfo.zonesInfo]; + } + } + + QNFixedZone *fixedZone = [[QNFixedZone alloc] init]; + fixedZone.zonesInfo = [[QNZonesInfo alloc] initWithZonesInfo:[zoneInfoArray copy]]; + [fixedZone.zonesInfo toTemporary]; + return fixedZone; +} + ++ (instancetype)createWithHost:(NSArray *)upList { + return [[QNFixedZone alloc] initWithUpDomainList:upList oldUpList:nil regionId:nil]; +} + ++ (instancetype)createWithRegionId:(NSString *)regionId { + NSArray *upList = @[ + [NSString stringWithFormat:@"upload-%@.qiniup.com", regionId], + [NSString stringWithFormat:@"up-%@.qiniup.com", regionId], + ]; + return [[QNFixedZone alloc] initWithUpDomainList:upList oldUpList:nil regionId:regionId]; +} + +- (QNZonesInfo *)createZonesInfo:(NSArray *)upDomains + regionId:(NSString *)regionId { + return [self createZonesInfo:upDomains oldUpDomains:nil regionId:regionId]; +} + +- (QNZonesInfo *)createZonesInfo:(NSArray *)upDomains + oldUpDomains:(NSArray *)oldUpDomains + regionId:(NSString *)regionId { + return [self createZonesInfo:nil domains:upDomains oldDomains:oldUpDomains regionId:regionId]; +} + +- (QNZonesInfo *)createZonesInfo:(NSArray *)accDomains + domains:(NSArray *)domains + oldDomains:(NSArray *)oldDomains + regionId:(NSString *)regionId { + if ((!accDomains || accDomains.count == 0) && (!domains || domains.count == 0)) { + return nil; + } + + QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoWithAccHosts:accDomains + mainHosts:domains + oldHosts:oldDomains + regionId:regionId]; + QNZonesInfo *zonesInfo = [[QNZonesInfo alloc] initWithZonesInfo:@[zoneInfo]]; + return zonesInfo; +} + +- (instancetype)initWithUpDomainList:(NSArray *)upList { + if (self = [super init]) { + self.zonesInfo = [self createZonesInfo:upList regionId:nil]; + } + return self; +} +- (instancetype)initWithUpDomainList:(NSArray *)upList + regionId:(NSString *)regionId { + if (self = [super init]) { + self.zonesInfo = [self createZonesInfo:upList regionId:regionId]; + } + return self; +} +- (instancetype)initWithUpDomainList:(NSArray *)upList + oldUpList:(NSArray *)oldUpList + regionId:(NSString *)regionId { + if (self = [super init]) { + self.zonesInfo = [self createZonesInfo:upList oldUpDomains:oldUpList regionId:regionId]; + } + return self; +} +- (instancetype)initWithAccUpDomainList:(NSArray *)accUpList + upList:(NSArray *)upList + oldUpList:(NSArray *)oldUpList + regionId:(NSString *)regionId { + if (self = [super init]) { + self.zonesInfo = [self createZonesInfo:accUpList domains:upList oldDomains:oldUpList regionId:regionId]; + } + return self; +} + +- (QNZonesInfo *)getZonesInfoWithToken:(QNUpToken *)token { + return self.zonesInfo; +} + +- (void)query:(QNConfiguration * _Nullable)config token:(QNUpToken * _Nullable)token on:(QNQueryReturn _Nullable)ret { + ret([QNResponseInfo successResponse], nil, self.zonesInfo); +} + + +@end diff --git a/Pods/Qiniu/QiniuSDK/Common/QNZone.h b/Pods/Qiniu/QiniuSDK/Common/QNZone.h new file mode 100644 index 0000000..f8c4e7e --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNZone.h @@ -0,0 +1,38 @@ +// +// QNZone.h +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class QNConfiguration, QNResponseInfo, QNUpToken, QNZonesInfo, QNUploadRegionRequestMetrics; + +typedef void (^QNPrequeryReturn)(int code, QNResponseInfo * _Nullable httpResponseInfo, QNUploadRegionRequestMetrics * _Nullable metrics); +typedef void (^QNQueryReturn)(QNResponseInfo * _Nullable httpResponseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, QNZonesInfo * _Nullable zonesInfo); + +@interface QNZone : NSObject + +/// 根据token查询相关 Zone 信息【内部使用】 +/// @param token token 信息 +/// @param ret 查询回调 +- (void)preQuery:(QNUpToken * _Nullable)token on:(QNPrequeryReturn _Nullable)ret; + +/// 根据token获取ZonesInfo 【内部使用】 +/// @param token token信息 +- (QNZonesInfo *)getZonesInfoWithToken:(QNUpToken * _Nullable)token; + + +/// 根据token查询相关 Zone 信息【内部使用】 +/// @param config 配置信息 +/// @param token token 信息 +/// @param ret 查询回调 +- (void)query:(QNConfiguration * _Nullable)config token:(QNUpToken * _Nullable)token on:(QNQueryReturn _Nullable)ret; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Common/QNZone.m b/Pods/Qiniu/QiniuSDK/Common/QNZone.m new file mode 100644 index 0000000..1e35364 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNZone.m @@ -0,0 +1,30 @@ +// +// QNZone.m +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNZone.h" +#import "QNUpToken.h" +#import "QNZoneInfo.h" +#import "QNConfiguration.h" +#import "QNResponseInfo.h" + +@implementation QNZone + +- (QNZonesInfo *)getZonesInfoWithToken:(QNUpToken *)token { + return nil; +} + +- (void)preQuery:(QNUpToken *)token + on:(QNPrequeryReturn)ret { + ret(0, nil, nil); +} + +- (void)query:(QNConfiguration * _Nullable)config token:(QNUpToken * _Nullable)token on:(QNQueryReturn _Nullable)ret { + ret([QNResponseInfo responseInfoWithSDKInteriorError:@"impl query"], nil, nil); +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Common/QNZoneInfo.h b/Pods/Qiniu/QiniuSDK/Common/QNZoneInfo.h new file mode 100644 index 0000000..f680301 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNZoneInfo.h @@ -0,0 +1,68 @@ +// +// QNZoneInfo.h +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNCache.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const QNZoneInfoSDKDefaultIOHost; +extern NSString *const QNZoneInfoEmptyRegionId; + +@interface QNZoneInfo : NSObject + +@property(nonatomic, assign, readonly)long ttl; +@property(nonatomic, assign, readonly)BOOL http3Enabled; +@property(nonatomic, strong, readonly)NSArray *domains; +@property(nonatomic, strong, readonly)NSArray *acc_domains; +@property(nonatomic, strong, readonly)NSArray *old_domains; + +@property(nonatomic, copy, readonly)NSString *regionId; +@property(nonatomic, strong, readonly)NSArray *allHosts; +@property(nonatomic, strong, readonly)NSDictionary *detailInfo; + ++ (QNZoneInfo *)zoneInfoWithMainHosts:(NSArray *)mainHosts + regionId:(NSString * _Nullable)regionId; + + ++ (QNZoneInfo *)zoneInfoWithMainHosts:(NSArray *)mainHosts + oldHosts:(NSArray * _Nullable)oldHosts + regionId:(NSString * _Nullable)regionId; + ++ (QNZoneInfo *)zoneInfoWithAccHosts:(NSArray *)accHosts + mainHosts:(NSArray *)mainHosts + oldHosts:(NSArray * _Nullable)oldHosts + regionId:(NSString * _Nullable)regionId; + +/// 根据键值对构造对象 【内部使用】 +/// @param detailInfo 键值对信息 ++ (QNZoneInfo *)zoneInfoFromDictionary:(NSDictionary *)detailInfo; + +- (BOOL)isValid; + +@end + +@interface QNZonesInfo : NSObject + +@property (nonatomic, strong, readonly) NSDate *buildDate; +@property (nonatomic, assign, readonly) BOOL isTemporary; +@property (nonatomic, assign, readonly) BOOL isValid; +@property (nonatomic, strong, readonly) NSArray *zonesInfo; + +/// 根据键值对构造对象 【内部使用】 +/// @param dictionary 键值对信息 ++ (instancetype)infoWithDictionary:(NSDictionary *)dictionary; + +- (instancetype)initWithZonesInfo:(NSArray *)zonesInfo; + +// 转成临时 zones, 临时 Zones,不建议长期使用 +- (void)toTemporary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Common/QNZoneInfo.m b/Pods/Qiniu/QiniuSDK/Common/QNZoneInfo.m new file mode 100644 index 0000000..9c0c100 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Common/QNZoneInfo.m @@ -0,0 +1,250 @@ +// +// QNZoneInfo.m +// QiniuSDK +// +// Created by yangsen on 2020/4/16. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNZoneInfo.h" +#import "QNUtils.h" + +NSString * const QNZoneInfoSDKDefaultIOHost = @"default_io_host"; +NSString * const QNZoneInfoEmptyRegionId = @"none"; + +@interface QNZoneInfo() + +@property(nonatomic, strong) NSDate *buildDate; + +@property(nonatomic, copy) NSString *regionId; +@property(nonatomic, assign) long ttl; +@property(nonatomic, assign) BOOL http3Enabled; +@property(nonatomic, strong) NSArray *domains; +@property(nonatomic, strong) NSArray *acc_domains; +@property(nonatomic, strong) NSArray *old_domains; + +@property(nonatomic, strong) NSArray *allHosts; +@property(nonatomic, strong) NSDictionary *detailInfo; + +@end +@implementation QNZoneInfo + ++ (QNZoneInfo *)zoneInfoWithMainHosts:(NSArray *)mainHosts + regionId:(NSString * _Nullable)regionId{ + return [self zoneInfoWithMainHosts:mainHosts oldHosts:nil regionId:regionId]; +} + ++ (QNZoneInfo *)zoneInfoWithMainHosts:(NSArray *)mainHosts + oldHosts:(NSArray * _Nullable)oldHosts + regionId:(NSString * _Nullable)regionId{ + + if (!mainHosts || ![mainHosts isKindOfClass:[NSArray class]] || mainHosts.count == 0) { + return nil; + } + + if (mainHosts && ![mainHosts isKindOfClass:[NSArray class]]) { + mainHosts = nil; + } + + QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoFromDictionary:@{@"ttl" : @(-1), + @"region" : regionId ?: QNZoneInfoEmptyRegionId, + @"up" : @{@"domains" : mainHosts ?: @[], + @"old" : oldHosts ?: @[]}, + }]; + return zoneInfo; +} + ++ (QNZoneInfo *)zoneInfoWithAccHosts:(NSArray *)accHosts + mainHosts:(NSArray *)mainHosts + oldHosts:(NSArray * _Nullable)oldHosts + regionId:(NSString * _Nullable)regionId { + if ((!accHosts || ![accHosts isKindOfClass:[NSArray class]] || accHosts.count == 0) && + (!mainHosts || ![mainHosts isKindOfClass:[NSArray class]] || mainHosts.count == 0)) { + return nil; + } + + if (accHosts && ![accHosts isKindOfClass:[NSArray class]]) { + accHosts = nil; + } + + if (mainHosts && ![mainHosts isKindOfClass:[NSArray class]]) { + mainHosts = nil; + } + + QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoFromDictionary:@{@"ttl" : @(-1), + @"region" : regionId ?: QNZoneInfoEmptyRegionId, + @"up" : @{@"acc_domains" : accHosts ?: @[], + @"domains" : mainHosts ?: @[], + @"old" : oldHosts ?: @[]}, + }]; + return zoneInfo; +} + ++ (QNZoneInfo *)zoneInfoFromDictionary:(NSDictionary *)detail { + if (![detail isKindOfClass:[NSDictionary class]]) { + return nil; + } + + NSMutableDictionary *detailInfo = [detail mutableCopy]; + if (detailInfo[@"timestamp"] == nil) { + detailInfo[@"timestamp"] = @([QNUtils currentTimestamp]/1000); + } + long timestamp = [detailInfo[@"timestamp"] longValue]; + + NSString *regionId = [detailInfo objectForKey:@"region"]; + if (regionId == nil) { + regionId = QNZoneInfoEmptyRegionId; + } + long ttl = [[detailInfo objectForKey:@"ttl"] longValue]; + BOOL http3Enabled = false; + if ([detailInfo[@"features"] isKindOfClass:[NSDictionary class]] && + [detailInfo[@"features"][@"http3"] isKindOfClass:[NSDictionary class]]) { + http3Enabled = [detailInfo[@"features"][@"http3"][@"enabled"] boolValue]; + } + NSDictionary *up = [detailInfo objectForKey:@"up"]; + NSArray *acc_domains = [up objectForKey:@"acc_domains"]; + NSArray *domains = [up objectForKey:@"domains"]; + NSArray *old_domains = [up objectForKey:@"old"]; + + NSMutableArray *allHosts = [NSMutableArray array]; + QNZoneInfo *zoneInfo = [[QNZoneInfo alloc] init:ttl regionId:regionId]; + zoneInfo.buildDate = [NSDate dateWithTimeIntervalSince1970:timestamp]; + zoneInfo.http3Enabled = http3Enabled; + if ([acc_domains isKindOfClass:[NSArray class]]) { + zoneInfo.acc_domains = acc_domains; + [allHosts addObjectsFromArray:domains]; + } + if ([domains isKindOfClass:[NSArray class]]) { + zoneInfo.domains = domains; + [allHosts addObjectsFromArray:domains]; + } + if ([old_domains isKindOfClass:[NSArray class]]) { + zoneInfo.old_domains = old_domains; + [allHosts addObjectsFromArray:old_domains]; + } + zoneInfo.allHosts = [allHosts copy]; + + zoneInfo.detailInfo = [detailInfo copy]; + + return zoneInfo; +} + +- (instancetype)init:(long)ttl + regionId:(NSString *)regionId { + if (self = [super init]) { + _ttl = ttl; + _buildDate = [NSDate date]; + _regionId = regionId; + } + return self; +} + +- (BOOL)isValid{ + if (self.allHosts == nil || self.allHosts.count == 0) { + return false; + } + + if (self.ttl < 0) { + return true; + } + + NSDate *currentDate = [NSDate date]; + return self.ttl > [currentDate timeIntervalSinceDate:self.buildDate]; +} + +- (id)copyWithZone:(NSZone *)zone { + QNZoneInfo *zoneInfo = [[QNZoneInfo allocWithZone:zone] init]; + zoneInfo.ttl = self.ttl; + zoneInfo.buildDate = self.buildDate; + zoneInfo.http3Enabled = self.http3Enabled; + zoneInfo.regionId = self.regionId; + zoneInfo.domains = [self.domains copy]; + zoneInfo.old_domains = [self.old_domains copy]; + zoneInfo.allHosts = [self.allHosts copy]; + zoneInfo.detailInfo = [self.detailInfo copy]; + return zoneInfo; +} + + +@end + +@interface QNZonesInfo() +@property (nonatomic, strong) NSDate *buildDate; +@property (nonatomic, assign) BOOL isTemporary; +@property (nonatomic, strong) NSArray *zonesInfo; +@property (nonatomic, strong) NSDictionary *detailInfo; +@end +@implementation QNZonesInfo + ++ (instancetype)infoWithDictionary:(NSDictionary *)dictionary { + return [[self alloc] initWithDictionary:dictionary]; +} + +- (nonnull id)initWithDictionary:(nullable NSDictionary *)dictionary { + NSMutableArray *zonesInfo = [NSMutableArray array]; + NSArray *hosts = dictionary[@"hosts"]; + if ([hosts isKindOfClass:[NSArray class]]) { + for (NSInteger i = 0; i < hosts.count; i++) { + QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoFromDictionary:hosts[i]]; + if (zoneInfo && [zoneInfo allHosts].count > 0) { + [zonesInfo addObject:zoneInfo]; + } + } + } + + return [self initWithZonesInfo:zonesInfo]; +} + +- (instancetype)initWithZonesInfo:(NSArray *)zonesInfo{ + self = [super init]; + if (self) { + _buildDate = [NSDate date]; + _zonesInfo = zonesInfo; + NSMutableArray *zoneInfos = [NSMutableArray array]; + if (zonesInfo != nil) { + for (NSInteger i = 0; i < zonesInfo.count; i++) { + if (zonesInfo[i].detailInfo != nil) { + [zoneInfos addObject:zonesInfo[i].detailInfo]; + } + } + } + self.detailInfo = @{@"hosts": [zoneInfos copy]}; + } + return self; +} + +- (void)toTemporary { + _isTemporary = true; +} + +- (BOOL)isValid { + if ([self.zonesInfo count] == 0) { + return false; + } + + BOOL valid = true; + for (QNZoneInfo *info in self.zonesInfo) { + if (![info isValid]) { + valid = false; + break; + } + } + return valid; +} + +- (id)copyWithZone:(NSZone *)zone { + NSMutableArray *zonesInfoArray = [NSMutableArray array]; + for (QNZoneInfo *info in self.zonesInfo) { + [zonesInfoArray addObject:[info copy]]; + } + QNZonesInfo *zonesInfo = [[QNZonesInfo allocWithZone:zone] init]; + zonesInfo.zonesInfo = [zonesInfoArray copy]; + zonesInfo.isTemporary = self.isTemporary; + return zonesInfo; +} + +- (nullable NSDictionary *)toDictionary { + return [self.detailInfo copy]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.h b/Pods/Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.h new file mode 100644 index 0000000..88ef0ff --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.h @@ -0,0 +1,22 @@ +// +// QNConnectChecker.h +// QiniuSDK_Mac +// +// Created by yangsen on 2021/1/8. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadRequestMetrics.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNConnectChecker : NSObject + ++ (QNUploadSingleRequestMetrics *)check; + ++ (BOOL)isConnected:(QNUploadSingleRequestMetrics *)metrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.m b/Pods/Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.m new file mode 100644 index 0000000..d0ccf89 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ConnectCheck/QNConnectChecker.m @@ -0,0 +1,152 @@ +// +// QNConnectChecker.m +// QiniuSDK_Mac +// +// Created by yangsen on 2021/1/8. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNDefine.h" +#import "QNLogUtil.h" +#import "QNConfiguration.h" +#import "QNSingleFlight.h" +#import "QNConnectChecker.h" +#import "QNUploadSystemClient.h" + +@interface QNConnectChecker() + +@end +@implementation QNConnectChecker + ++ (QNSingleFlight *)singleFlight { + static QNSingleFlight *singleFlight = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + singleFlight = [[QNSingleFlight alloc] init]; + }); + return singleFlight; +} + ++ (dispatch_queue_t)checkQueue { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.qiniu.NetworkCheckQueue", DISPATCH_QUEUE_CONCURRENT); + }); + return queue; +} + ++ (BOOL)isConnected:(QNUploadSingleRequestMetrics *)metrics { + return metrics && ((NSHTTPURLResponse *)metrics.response).statusCode > 99; +} + ++ (QNUploadSingleRequestMetrics *)check { + __block QNUploadSingleRequestMetrics *metrics = nil; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [self check:^(QNUploadSingleRequestMetrics *metricsP) { + metrics = metricsP; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return metrics; +} + ++ (void)check:(void (^)(QNUploadSingleRequestMetrics *))complete { + QNSingleFlight *singleFlight = [self singleFlight]; + + kQNWeakSelf; + [singleFlight perform:@"connect_check" action:^(QNSingleFlightComplete _Nonnull singleFlightComplete) { + kQNStrongSelf; + + [self checkAllHosts:^(QNUploadSingleRequestMetrics *metrics) { + singleFlightComplete(metrics, nil); + }]; + + } complete:^(id _Nullable value, NSError * _Nullable error) { + if (complete) { + complete(value); + } + }]; +} + + ++ (void)checkAllHosts:(void (^)(QNUploadSingleRequestMetrics *metrics))complete { + + __block int completeCount = 0; + __block BOOL isCompleted = false; + kQNWeakSelf; + NSArray *allHosts = [kQNGlobalConfiguration.connectCheckURLStrings copy]; + if (allHosts.count == 0) { + QNUploadSingleRequestMetrics *metrics = [QNUploadSingleRequestMetrics emptyMetrics]; + [metrics start]; + [metrics end]; + metrics.error = [NSError errorWithDomain:@"com.qiniu.NetworkCheck" code:NSURLErrorUnsupportedURL userInfo:@{@"user_info":@"check host is empty"}]; + complete(metrics); + return; + } + + for (NSString *host in allHosts) { + [self checkHost:host complete:^(QNUploadSingleRequestMetrics *metrics) { + kQNStrongSelf; + + BOOL isHostConnected = [self isConnected:metrics]; + @synchronized (self) { + completeCount += 1; + } + if (isHostConnected || completeCount == allHosts.count) { + @synchronized (self) { + if (isCompleted) { + QNLogInfo(@"== check all hosts has completed totalCount:%d completeCount:%d", allHosts.count, completeCount); + return; + } else { + QNLogInfo(@"== check all hosts completed totalCount:%d completeCount:%d", allHosts.count, completeCount); + isCompleted = true; + } + } + complete(metrics); + } else { + QNLogInfo(@"== check all hosts not completed totalCount:%d completeCount:%d", allHosts.count, completeCount); + } + }]; + } +} + ++ (void)checkHost:(NSString *)host complete:(void (^)(QNUploadSingleRequestMetrics *metrics))complete { + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + request.URL = [NSURL URLWithString:host]; + request.HTTPMethod = @"HEAD"; + request.timeoutInterval = kQNGlobalConfiguration.connectCheckTimeout; + + __block BOOL hasCallback = false; + + QNUploadSingleRequestMetrics *timeoutMetric = [QNUploadSingleRequestMetrics emptyMetrics]; + [timeoutMetric start]; + + QNUploadSystemClient *client = [[QNUploadSystemClient alloc] init]; + [client request:request server:nil connectionProxy:nil progress:nil complete:^(NSURLResponse *response, QNUploadSingleRequestMetrics * metrics, NSData * _Nullable data, NSError * error) { + @synchronized (self) { + if (hasCallback) { + return; + } + hasCallback = true; + } + QNLogInfo(@"== checkHost:%@ responseInfo:%@", host, response); + complete(metrics); + }]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * kQNGlobalConfiguration.connectCheckTimeout), [self checkQueue], ^{ + @synchronized (self) { + if (hasCallback) { + return; + } + hasCallback = true; + } + [client cancel]; + [timeoutMetric end]; + timeoutMetric.error = [NSError errorWithDomain:@"com.qiniu.NetworkCheck" code:NSURLErrorTimedOut userInfo:nil]; + complete(timeoutMetric); + }); +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDns.h b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDns.h new file mode 100644 index 0000000..b501079 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDns.h @@ -0,0 +1,41 @@ +// +// QNDns.h +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol QNIDnsNetworkAddress + +/// 域名 +@property(nonatomic, copy, readonly)NSString *hostValue; + +/// 地址IP信息 +@property(nonatomic, copy, readonly)NSString *ipValue; + +/// ip有效时间 单位:秒 +@property(nonatomic, strong, readonly)NSNumber *ttlValue; + +/// ip预取来源, 自定义dns返回 @"customized" +@property(nonatomic, copy, readonly)NSString *sourceValue; + +/// 解析到host时的时间戳 单位:秒 +@property(nonatomic, strong, readonly)NSNumber *timestampValue; + +@end + + +@protocol QNDnsDelegate + +/// 根据host获取解析结果 +/// @param host 域名 +- (NSArray < id > *)query:(NSString *)host; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.h b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.h new file mode 100644 index 0000000..c33fba3 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.h @@ -0,0 +1,29 @@ +// +// QNDnsCacheFile.h +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import +#import "QNRecorderDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDnsCacheFile : NSObject + +/// DNS解析信息本地缓存路径 +@property(nonatomic, copy, readonly)NSString *directory; + +/// 构造方法 路径不存在,或进行创建,创建失败返回为nil +/// @param directory 路径 +/// @param error 构造错误时,会有值 ++ (instancetype _Nullable)dnsCacheFile:(NSString *)directory + error:(NSError **)error; + +- (void)clearCache:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.m b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.m new file mode 100644 index 0000000..9c8aecf --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheFile.m @@ -0,0 +1,91 @@ +// +// QNDnsCacheFile.m +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNDnsCacheFile.h" + +@interface QNDnsCacheFile() + +@property(nonatomic, copy)NSString *directory; + +@end +@implementation QNDnsCacheFile + ++ (instancetype)dnsCacheFile:(NSString *)directory + error:(NSError **)error{ + NSError *err = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:&err]; + if (err != nil) { + if (error != nil) *error = err; + return nil; + } + + QNDnsCacheFile *f = [[QNDnsCacheFile alloc] init]; + f.directory = directory; + return f; +} + +- (NSError *)set:(NSString *)key data:(NSData *)value { + @synchronized (self) { + NSError *error; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *filePath = [self pathOfKey:key]; + if ([fileManager fileExistsAtPath:filePath]) { + [fileManager removeItemAtPath:filePath error:&error]; + } + [fileManager createFileAtPath:filePath contents:value attributes:nil]; + return error; + } +} + +- (NSData *)get:(NSString *)key { + return [NSData dataWithContentsOfFile:[self pathOfKey:key]]; +} + +- (NSError *)del:(NSString *)key { + @synchronized (self) { + NSError *error = nil; + NSString *path = [self pathOfKey:key]; + if (path) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + [fileManager removeItemAtPath:path error:&error]; + } + return error; + } +} + +- (void)clearCache:(NSError *__autoreleasing _Nullable *)error { + @synchronized (self) { + NSError *err; + NSFileManager *fileManager = [NSFileManager defaultManager]; + [fileManager removeItemAtPath:self.directory error:&err]; + if (err != nil) { + if (error != nil) *error = err; + return; + } + + [fileManager createDirectoryAtPath:self.directory withIntermediateDirectories:YES attributes:nil error:&err]; + if (error != nil) { + *error = err; + } + } +} + +- (NSString *)getFileName{ + return @"dnsCache"; +} + +- (NSString *)pathOfKey:(NSString *)key { + return [QNDnsCacheFile pathJoin:key path:_directory]; +} + ++ (NSString *)pathJoin:(NSString *)key + path:(NSString *)path { + return [[NSString alloc] initWithFormat:@"%@/%@", path, key]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.h b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.h new file mode 100644 index 0000000..aa53603 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.h @@ -0,0 +1,41 @@ +// +// QNDnsCacheKey.h +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNDnsCacheInfo : NSObject + +/// 缓存时间戳 +@property(nonatomic, copy, readonly)NSString *currentTime; +/// 缓存时本地IP +@property(nonatomic, copy, readonly)NSString *localIp; +/// 缓存信息 +@property(nonatomic, copy, readonly)NSDictionary *info; + +//MARK: -- 构造方法 +/// 根据json构造对象 +/// @param jsonData json数据 ++ (instancetype)dnsCacheInfo:(NSData *)jsonData; + +/// 根据属性构造对象 +/// @param currentTime 缓存时间戳 +/// @param localIp 缓存时本地IP +/// @param info 缓存信息 ++ (instancetype)dnsCacheInfo:(NSString *)currentTime + localIp:(NSString *)localIp + info:(NSDictionary *)info; + + +/// 转化Json数据 +- (NSData *)jsonData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.m b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.m new file mode 100644 index 0000000..59cedd5 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsCacheInfo.m @@ -0,0 +1,58 @@ +// +// QNDnsCacheKey.m +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNDnsCacheInfo.h" + +@interface QNDnsCacheInfo() +/// 缓存时间戳 +@property(nonatomic, copy)NSString *currentTime; +/// 缓存时本地IP +@property(nonatomic, copy)NSString *localIp; +/// 缓存信息 +@property(nonatomic, copy)NSDictionary *info; +@end +@implementation QNDnsCacheInfo + ++ (instancetype)dnsCacheInfo:(NSData *)jsonData{ + NSDictionary *info = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil]; + if (!info || info.count == 0 || + (!info[@"currentTime"] && !info[@"localIp"] && !info[@"info"])) { + return nil; + } + return [QNDnsCacheInfo dnsCacheInfo:info[@"currentTime"] + localIp:info[@"localIp"] + info:info[@"info"]];; +} + ++ (instancetype)dnsCacheInfo:(NSString *)currentTime + localIp:(NSString *)localIp + info:(NSDictionary *)info{ + + QNDnsCacheInfo *cacheInfo = [[QNDnsCacheInfo alloc] init]; + cacheInfo.currentTime = currentTime; + cacheInfo.localIp = localIp; + cacheInfo.info = info; + return cacheInfo; +} + +- (NSData *)jsonData{ + NSMutableDictionary *cacheInfo = [NSMutableDictionary dictionary]; + if (self.currentTime) { + cacheInfo[@"currentTime"] = self.currentTime; + } + if (self.localIp) { + cacheInfo[@"localIp"] = self.localIp; + } + if (self.info) { + cacheInfo[@"info"] = self.info; + } + return [NSJSONSerialization dataWithJSONObject:cacheInfo options:NSJSONWritingPrettyPrinted error:nil]; +} + + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.h b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.h new file mode 100644 index 0000000..26b5e73 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.h @@ -0,0 +1,66 @@ +// +// QNDnsPrefetch.h +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNDns.h" +#import "QNUpToken.h" +#import "QNConfiguration.h" +#import "QNTransactionManager.h" + +NS_ASSUME_NONNULL_BEGIN + +#define kQNDnsPrefetch [QNDnsPrefetch shared] +@interface QNDnsPrefetch : NSObject + +/// 最近一次预取错误信息 +@property(nonatomic, copy, readonly)NSString *lastPrefetchedErrorMessage; + ++ (instancetype)shared; + +/// 根据host从缓存中读取DNS信息 +/// @param host 域名 +- (NSArray > *)getInetAddressByHost:(NSString *)host; + +/// 通过安全的方式预取 dns +- (NSString *)prefetchHostBySafeDns:(NSString *)host error:(NSError **)error; + +- (void)clearDnsCache:(NSError **)error; + +@end + + + +@interface QNTransactionManager(Dns) + +/// 添加加载本地dns事务 +- (void)addDnsLocalLoadTransaction; + +/// 添加检测并预取dns事务 如果未开启DNS 或 事务队列中存在token对应的事务未处理,则返回NO +/// @param currentZone 当前区域 +/// @param token token信息 +- (BOOL)addDnsCheckAndPrefetchTransaction:(QNZone *)currentZone token:(QNUpToken *)token; +- (BOOL)addDnsCheckAndPrefetchTransaction:(QNConfiguration *)config zone:(QNZone *)currentZone token:(QNUpToken *)token; + +/// 设置定时事务:检测已缓存DNS有效情况事务 无效会重新预取 +- (void)setDnsCheckWhetherCachedValidTransactionAction; + +@end + +#define kQNDnsSourceDoh @"doh" +#define kQNDnsSourceUdp @"dns" +#define kQNDnsSourceDnspod @"dnspod" +#define kQNDnsSourceSystem @"system" +#define kQNDnsSourceCustom @"customized" +#define kQNDnsSourceNone @"none" + +BOOL kQNIsDnsSourceDoh(NSString * _Nullable source); +BOOL kQNIsDnsSourceUdp(NSString * _Nullable source); +BOOL kQNIsDnsSourceDnsPod(NSString * _Nullable source); +BOOL kQNIsDnsSourceSystem(NSString * _Nullable source); +BOOL kQNIsDnsSourceCustom(NSString * _Nullable source); + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.m b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.m new file mode 100644 index 0000000..fb0fc49 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNDnsPrefetch.m @@ -0,0 +1,874 @@ +// +// QNDnsPrefetch.m +// QnDNS +// +// Created by yangsen on 2020/3/26. +// Copyright © 2020 com.qiniu. All rights reserved. +// + + +#import "QNDnsPrefetch.h" +#import "QNInetAddress.h" +#import "QNDnsCacheInfo.h" +#import "QNZoneInfo.h" + +#import "QNDefine.h" +#import "QNConfig.h" +#import "QNDnsCacheFile.h" +#import "QNUtils.h" +#import "QNAsyncRun.h" +#import "QNFixedZone.h" +#import "QNAutoZone.h" +#import + + +//MARK: -- 缓存模型 +@interface QNDnsNetworkAddress : NSObject + +@property(nonatomic, copy)NSString *hostValue; +@property(nonatomic, copy)NSString *ipValue; +@property(nonatomic, strong)NSNumber *ttlValue; +@property(nonatomic, copy)NSString *sourceValue; +@property(nonatomic, strong)NSNumber *timestampValue; + +/// 构造方法 addressData为json String / Dictionary / Data / 遵循 QNIDnsNetworkAddress的实例 ++ (instancetype)inetAddress:(id)addressInfo; + +/// 是否有效,根据时间戳判断 +- (BOOL)isValid; + +/// 对象转json +- (NSString *)toJsonInfo; + +/// 对象转字典 +- (NSDictionary *)toDictionary; + +@end +@implementation QNDnsNetworkAddress + ++ (instancetype)inetAddress:(id)addressInfo{ + + NSDictionary *addressDic = nil; + if ([addressInfo isKindOfClass:[NSDictionary class]]) { + addressDic = (NSDictionary *)addressInfo; + } else if ([addressInfo isKindOfClass:[NSString class]]){ + NSData *data = [(NSString *)addressInfo dataUsingEncoding:NSUTF8StringEncoding]; + addressDic = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } else if ([addressInfo isKindOfClass:[NSData class]]) { + addressDic = [NSJSONSerialization JSONObjectWithData:(NSData *)addressInfo + options:NSJSONReadingMutableLeaves + error:nil]; + } else if ([addressInfo conformsToProtocol:@protocol(QNIDnsNetworkAddress)]){ + id address = (id )addressInfo; + NSMutableDictionary *dic = [NSMutableDictionary dictionary]; + if ([address respondsToSelector:@selector(hostValue)] && [address hostValue]) { + dic[@"hostValue"] = [address hostValue]; + } + if ([address respondsToSelector:@selector(ipValue)] && [address ipValue]) { + dic[@"ipValue"] = [address ipValue]; + } + if ([address respondsToSelector:@selector(ttlValue)] && [address ttlValue]) { + dic[@"ttlValue"] = [address ttlValue]; + } + if ([address respondsToSelector:@selector(sourceValue)] && [address sourceValue]) { + dic[@"sourceValue"] = [address sourceValue]; + } else { + dic[@"sourceValue"] = kQNDnsSourceCustom; + } + if ([address respondsToSelector:@selector(timestampValue)] && [address timestampValue]) { + dic[@"timestampValue"] = [address timestampValue]; + } + addressDic = [dic copy]; + } + + if (addressDic) { + QNDnsNetworkAddress *address = [[QNDnsNetworkAddress alloc] init]; + [address setValuesForKeysWithDictionary:addressDic]; + return address; + } else { + return nil; + } +} + +/// 过了 ttl 时间则需要刷新 +- (BOOL)needRefresh{ + if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) { + return NO; + } + NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; + return currentTimestamp > (self.timestampValue.doubleValue + self.ttlValue.doubleValue); +} + +/// 只要在最大 ttl 时间内,即为有效 +- (BOOL)isValid{ + if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) { + return NO; + } + NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; + return currentTimestamp < (self.timestampValue.doubleValue + kQNGlobalConfiguration.dnsCacheMaxTTL); +} + +- (NSString *)toJsonInfo{ + NSString *defaultString = @"{}"; + NSDictionary *infoDic = [self toDictionary]; + if (!infoDic) { + return defaultString; + } + + NSData *infoData = [NSJSONSerialization dataWithJSONObject:infoDic + options:NSJSONWritingPrettyPrinted + error:nil]; + if (!infoData) { + return defaultString; + } + + NSString *infoStr = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding]; + if (!infoStr) { + return defaultString; + } else { + return infoStr; + } +} + +- (NSDictionary *)toDictionary{ + return [self dictionaryWithValuesForKeys:@[@"ipValue", @"hostValue", @"ttlValue", @"sourceValue", @"timestampValue"]]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key{} + +@end + + +//MARK: -- HappyDNS 适配 +@interface QNRecord(DNS) +@end +@implementation QNRecord(DNS) +- (NSString *)hostValue{ + return nil; +} +- (NSString *)ipValue{ + return self.value; +} +- (NSNumber *)ttlValue{ + return @(self.ttl); +} +- (NSNumber *)timestampValue{ + return @(self.timeStamp); +} +- (NSString *)sourceValue{ + if (self.source == QNRecordSourceSystem) { + return kQNDnsSourceSystem; + } else if (self.source == QNRecordSourceDoh) { + return [NSString stringWithFormat:@"%@<%@>", kQNDnsSourceDoh, self.server]; + } else if (self.source == QNRecordSourceUdp) { + return [NSString stringWithFormat:@"%@<%@>", kQNDnsSourceUdp, self.server]; + } else if (self.source == QNRecordSourceDnspodEnterprise) { + return kQNDnsSourceDnspod; + } else if (self.ipValue == nil || self.ipValue.length == 0) { + return kQNDnsSourceNone; + } else { + return kQNDnsSourceCustom; + } +} +@end + +@interface QNInternalDns : NSObject +@property(nonatomic, strong)id dns; +@property(nonatomic, strong)id resolver; +@end +@implementation QNInternalDns ++ (instancetype)dnsWithDns:(id)dns { + QNInternalDns *interDns = [[QNInternalDns alloc] init]; + interDns.dns = dns; + return interDns; +} ++ (instancetype)dnsWithResolver:(id)resolver { + QNInternalDns *interDns = [[QNInternalDns alloc] init]; + interDns.resolver = resolver; + return interDns; +} +- (NSArray < id > *)query:(NSString *)host error:(NSError **)error { + if (self.dns && [self.dns respondsToSelector:@selector(query:)]) { + return [self.dns query:host]; + } else if (self.resolver) { + NSArray * records = [self.resolver query:[[QNDomain alloc] init:host] networkInfo:nil error:error]; + return [self filterRecords:records]; + } + return nil; +} +- (NSArray *)filterRecords:(NSArray *)records { + NSMutableArray *newRecords = [NSMutableArray array]; + for (QNRecord *record in records) { + if (record.type == kQNTypeA || record.type == kQNTypeAAAA) { + [newRecords addObject:record]; + } + } + return [newRecords copy]; +} +@end + + +//MARK: -- DNS Prefetcher +@interface QNDnsPrefetch() + +// dns 预解析超时,默认3s +@property(nonatomic, assign)int dnsPrefetchTimeout; + +// 最近一次预取错误信息 +@property(nonatomic, copy)NSString *lastPrefetchedErrorMessage; +/// 是否正在预取,正在预取会直接取消新的预取操作请求 +@property(atomic, assign)BOOL isPrefetching; +/// 获取AutoZone时的同步锁 +@property(nonatomic, strong)dispatch_semaphore_t getAutoZoneSemaphore; +/// DNS信息本地缓存key +@property(nonatomic, strong)QNDnsCacheInfo *dnsCacheInfo; +// 用户定制 dns +@property(nonatomic, strong)QNInternalDns *customDns; +// 系统 dns +@property(nonatomic, strong)QNInternalDns *systemDns; +/// prefetch hosts +@property(nonatomic, strong)NSMutableSet *prefetchHosts; +/// 缓存DNS解析结果 +/// 线程安全:内部方法均是在同一线程执行,读写不必加锁,对外开放接口读操作 需要和内部写操作枷锁 +@property(nonatomic, strong)NSMutableDictionary *> *addressDictionary; +@property(nonatomic, strong)QNDnsCacheFile *diskCache; + +@end + +@implementation QNDnsPrefetch + ++ (instancetype)shared{ + static QNDnsPrefetch *prefetcher = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + prefetcher = [[QNDnsPrefetch alloc] init]; + }); + return prefetcher; +} + +- (instancetype)init{ + if (self = [super init]) { + _isPrefetching = NO; + _dnsPrefetchTimeout = 3; + } + return self; +} + +//MARK: -- uploadManager初始化时,加载本地缓存到内存 +/// 同步本地预取缓存 如果存在且满足使用返回false,反之为true +- (BOOL)recoverCache{ + id recorder = nil; + + NSError *error; + recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir + error:&error]; + if (error) { + return YES; + } + + NSData *data = [recorder get:[QNIP local]]; + if (!data) { + return YES; + } + + QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:data]; + if (!cacheInfo) { + return YES; + } + + NSString *localIp = [QNIP local]; + + if (!localIp || localIp.length == 0 || ![cacheInfo.localIp isEqualToString:localIp]) { + return YES; + } + + [self setDnsCacheInfo:cacheInfo]; + + return [self recoverDnsCache:cacheInfo.info]; +} +/// 本地缓存读取失败后,加载本地域名,预取DNS解析信息 +- (void)localFetch{ + if ([self prepareToPreFetch] == NO) { + return; + } + NSArray *hosts = [self getLocalPreHost]; + @synchronized (self) { + [self.prefetchHosts addObjectsFromArray:hosts]; + } + [self preFetchHosts:hosts]; + [self recorderDnsCache]; + [self endPreFetch]; +} +//MARK: -- 检测并预取 +/// 根据token检测Dns缓存信息时效,无效则预取。 完成预取操作返回YES,反之返回NO +- (void)checkAndPrefetchDnsIfNeed:(QNConfiguration *)config zone:(QNZone *)currentZone token:(QNUpToken *)token{ + if ([self prepareToPreFetch] == NO) { + return; + } + NSArray *hosts = [self getCurrentZoneHosts:config zone:currentZone token:token]; + if (hosts == nil) { + return; + } + + @synchronized (self) { + [self.prefetchHosts addObjectsFromArray:hosts]; + } + [self preFetchHosts:hosts]; + [self recorderDnsCache]; + [self endPreFetch]; +} +/// 检测已预取dns是否还有效,无效则重新预取 +- (void)checkWhetherCachedDnsValid{ + if ([self prepareToPreFetch] == NO) { + return; + } + NSArray *hosts = nil; + @synchronized (self) { + hosts = [self.prefetchHosts allObjects]; + } + [self preFetchHosts:hosts]; + [self recorderDnsCache]; + [self endPreFetch]; +} + +//MARK: -- 读取缓存的DNS信息 +/// 根据host从缓存中读取DNS信息 +- (NSArray > *)getInetAddressByHost:(NSString *)host{ + + if ([self isDnsOpen] == NO) { + return nil; + } + + [self clearDnsCacheIfNeeded]; + + NSArray *addressList = nil; + @synchronized (self) { + addressList = self.addressDictionary[host]; + } + + if (addressList && addressList.count > 0 && [addressList.firstObject isValid]) { + return addressList; + } else { + return nil; + } +} + +- (void)invalidNetworkAddressOfHost:(NSString *)host { + if (host == nil || host.length == 0) { + return; + } + @synchronized (self) { + [self.addressDictionary removeObjectForKey:host]; + } +} + +- (void)clearDnsCache:(NSError *__autoreleasing _Nullable *)error { + [self clearDnsMemoryCache]; + [self clearDnsDiskCache:error]; +} + +//MARK: -- +//MARK: -- 根据dns预取 +- (NSString *)prefetchHostBySafeDns:(NSString *)host error:(NSError * __autoreleasing *)error { + if (host == nil) { + return nil; + } + + [self invalidNetworkAddressOfHost:host]; + + NSError *err = nil; + NSArray *nextFetchHosts = @[host]; + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.customDns error:&err]; + if (nextFetchHosts.count == 0) { + return [self getInetAddressByHost:host].firstObject.sourceValue; + } + + if (!kQNGlobalConfiguration.dohEnable) { + if (error != nil && err) { + *error = err; + } + return nil; + } + + if (kQNGlobalConfiguration.dohIpv4Servers && [kQNGlobalConfiguration.dohIpv4Servers count] > 0) { + QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout]; + QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver]; + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:&err]; + if (nextFetchHosts.count == 0) { + return [self getInetAddressByHost:host].firstObject.sourceValue; + } + if (error != nil && err) { + *error = err; + } + } + + if ([QNIP isIpV6FullySupported] && kQNGlobalConfiguration.dohIpv6Servers && [kQNGlobalConfiguration.dohIpv6Servers count] > 0) { + QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout]; + QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver]; + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:&err]; + if (error != nil && err) { + *error = err; + } + } + + if (nextFetchHosts.count == 0) { + return [self getInetAddressByHost:host].firstObject.sourceValue; + } else { + return nil; + } +} + +- (BOOL)prepareToPreFetch { + if ([self isDnsOpen] == NO) { + return NO; + } + + self.lastPrefetchedErrorMessage = nil; + + if (self.isPrefetching == YES) { + return NO; + } + + [self clearDnsCacheIfNeeded]; + + self.isPrefetching = YES; + return YES; +} + +- (void)endPreFetch{ + self.isPrefetching = NO; +} + +- (void)preFetchHosts:(NSArray *)fetchHosts { + NSError *err = nil; + [self preFetchHosts:fetchHosts error:&err]; + self.lastPrefetchedErrorMessage = err.description; +} + +- (void)preFetchHosts:(NSArray *)fetchHosts error:(NSError **)error { + NSArray *nextFetchHosts = fetchHosts; + + // 定制 + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.customDns error:error]; + if (nextFetchHosts.count == 0) { + return; + } + + // 系统 + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.systemDns error:error]; + if (nextFetchHosts.count == 0) { + return; + } + + // doh + if (kQNGlobalConfiguration.dohEnable) { + if (kQNGlobalConfiguration.dohIpv4Servers && [kQNGlobalConfiguration.dohIpv4Servers count] > 0) { + QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout]; + QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver]; + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:error]; + if (nextFetchHosts.count == 0) { + return; + } + } + + if ([QNIP isIpV6FullySupported] && kQNGlobalConfiguration.dohIpv6Servers && [kQNGlobalConfiguration.dohIpv6Servers count] > 0) { + QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout]; + QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver]; + nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:error]; + if (nextFetchHosts.count == 0) { + return; + } + } + } + + // udp + if (kQNGlobalConfiguration.udpDnsEnable) { + if (kQNGlobalConfiguration.udpDnsIpv4Servers && [kQNGlobalConfiguration.udpDnsIpv4Servers count] > 0) { + QNDnsUdpResolver *udpDnsResolver = [QNDnsUdpResolver resolverWithServerIPs:kQNGlobalConfiguration.udpDnsIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout]; + QNInternalDns *udpDns = [QNInternalDns dnsWithResolver:udpDnsResolver]; + [self preFetchHosts:nextFetchHosts dns:udpDns error:error]; + } + + if ([QNIP isIpV6FullySupported] && kQNGlobalConfiguration.udpDnsIpv6Servers && [kQNGlobalConfiguration.udpDnsIpv6Servers count] > 0) { + QNDnsUdpResolver *udpDnsResolver = [QNDnsUdpResolver resolverWithServerIPs:kQNGlobalConfiguration.udpDnsIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout]; + QNInternalDns *udpDns = [QNInternalDns dnsWithResolver:udpDnsResolver]; + [self preFetchHosts:nextFetchHosts dns:udpDns error:error]; + } + } +} + +- (NSArray *)preFetchHosts:(NSArray *)preHosts dns:(QNInternalDns *)dns error:(NSError **)error { + + if (!preHosts || preHosts.count == 0) { + return nil; + } + + if (!dns) { + return [preHosts copy]; + } + + int dnsRepreHostNum = kQNGlobalConfiguration.dnsRepreHostNum; + NSMutableArray *failHosts = [NSMutableArray array]; + for (NSString *host in preHosts) { + int rePreNum = 0; + BOOL isSuccess = NO; + + while (rePreNum < dnsRepreHostNum) { + if ([self preFetchHost:host dns:dns error:error]) { + isSuccess = YES; + break; + } + rePreNum += 1; + } + + if (!isSuccess) { + [failHosts addObject:host]; + } + } + return [failHosts copy]; +} + +- (BOOL)preFetchHost:(NSString *)preHost dns:(QNInternalDns *)dns error:(NSError **)error { + + if (!preHost || preHost.length == 0) { + return NO; + } + + NSDictionary *addressDictionary = nil; + @synchronized (self) { + addressDictionary = [self.addressDictionary copy]; + } + NSArray* preAddressList = addressDictionary[preHost]; + if (preAddressList && ![preAddressList.firstObject needRefresh]) { + return YES; + } + + NSArray > * addressList = [dns query:preHost error:error]; + if (addressList && addressList.count > 0) { + NSMutableArray *addressListP = [NSMutableArray array]; + for (id inetAddress in addressList) { + QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:inetAddress]; + if (address) { + address.hostValue = preHost; + if (!address.ttlValue) { + address.ttlValue = @(kQNDefaultDnsCacheTime); + } + if (!address.timestampValue) { + address.timestampValue = @([[NSDate date] timeIntervalSince1970]); + } + [addressListP addObject:address]; + } + } + addressListP = [addressListP copy]; + @synchronized (self) { + self.addressDictionary[preHost] = addressListP; + } + return YES; + } else { + return NO; + } +} + +//MARK: -- 加载和存储缓存信息 +- (BOOL)recoverDnsCache:(NSDictionary *)dataDic{ + if (dataDic == nil) { + return NO; + } + + NSMutableDictionary *records = [NSMutableDictionary dictionary]; + for (NSString *key in dataDic.allKeys) { + NSArray *ips = dataDic[key]; + if ([ips isKindOfClass:[NSArray class]]) { + + NSMutableArray * addressList = [NSMutableArray array]; + + for (NSDictionary *ipInfo in ips) { + if ([ipInfo isKindOfClass:[NSDictionary class]]) { + QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:ipInfo]; + if (address) { + [addressList addObject:address]; + } + } + } + + if (addressList.count > 0) { + records[key] = [addressList copy]; + } + } + } + @synchronized (self) { + [self.addressDictionary setValuesForKeysWithDictionary:records]; + } + return NO; +} + +- (BOOL)recorderDnsCache{ + NSTimeInterval currentTime = [QNUtils currentTimestamp]; + NSString *localIp = [QNIP local]; + + if (localIp == nil || localIp.length == 0) { + return NO; + } + + NSError *error; + id recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir + error:&error]; + if (error) { + return NO; + } + + NSDictionary *addressDictionary = nil; + @synchronized (self) { + addressDictionary = [self.addressDictionary copy]; + } + NSMutableDictionary *addressInfo = [NSMutableDictionary dictionary]; + for (NSString *key in addressDictionary.allKeys) { + + NSArray *addressModelList = addressDictionary[key]; + NSMutableArray * addressDicList = [NSMutableArray array]; + + for (QNDnsNetworkAddress *ipInfo in addressModelList) { + NSDictionary *addressDic = [ipInfo toDictionary]; + if (addressDic) { + [addressDicList addObject:addressDic]; + } + } + + if (addressDicList.count > 0) { + addressInfo[key] = addressDicList; + } + } + + QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:[NSString stringWithFormat:@"%.0lf",currentTime] + localIp:localIp + info:addressInfo]; + + NSData *cacheData = [cacheInfo jsonData]; + if (!cacheData) { + return NO; + } + [self setDnsCacheInfo:cacheInfo]; + [recorder set:localIp data:cacheData]; + return true; +} + +- (void)clearDnsCacheIfNeeded{ + NSString *localIp = [QNIP local]; + if (localIp == nil || (self.dnsCacheInfo && ![localIp isEqualToString:self.dnsCacheInfo.localIp])) { + [self clearDnsMemoryCache]; + } +} + +- (void)clearDnsMemoryCache { + @synchronized (self) { + [self.addressDictionary removeAllObjects]; + } +} + +- (void)clearDnsDiskCache:(NSError **)error { + [self.diskCache clearCache:error]; +} + + +//MARK: -- 获取预取hosts +- (NSArray *)getLocalPreHost{ + NSMutableArray *localHosts = [NSMutableArray array]; + [localHosts addObject:kQNUpLogHost]; + return [localHosts copy]; +} + +- (NSArray *)getCurrentZoneHosts:(QNConfiguration *)config + zone:(QNZone *)currentZone + token:(QNUpToken *)token{ + if (!currentZone || !token || !token.token) { + return nil; + } + + __block QNZonesInfo *zonesInfo = nil; + [currentZone query:config token:token on:^(QNResponseInfo * _Nullable httpResponseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, QNZonesInfo * _Nullable info) { + zonesInfo = info; + dispatch_semaphore_signal(self.semaphore); + }]; + dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); + + if (zonesInfo == nil) { + return nil; + } + + QNZonesInfo *autoZonesInfo = [currentZone getZonesInfoWithToken:token]; + NSMutableArray *autoHosts = [NSMutableArray array]; + NSArray *zoneInfoList = autoZonesInfo.zonesInfo; + for (QNZoneInfo *info in zoneInfoList) { + if (info.allHosts) { + [autoHosts addObjectsFromArray:info.allHosts]; + } + } + return [autoHosts copy]; +} + + +//MARK: -- +- (BOOL)isDnsOpen{ + return [kQNGlobalConfiguration isDnsOpen]; +} + +- (QNDnsCacheInfo *)dnsCacheInfo{ + if (_dnsCacheInfo == nil) { + _dnsCacheInfo = [[QNDnsCacheInfo alloc] init]; + } + return _dnsCacheInfo; +} +- (NSMutableDictionary *> *)addressDictionary{ + if (_addressDictionary == nil) { + _addressDictionary = [NSMutableDictionary dictionary]; + } + return _addressDictionary; +} + +- (dispatch_semaphore_t)semaphore{ + if (_getAutoZoneSemaphore == NULL) { + _getAutoZoneSemaphore = dispatch_semaphore_create(0); + } + return _getAutoZoneSemaphore; +} + +- (QNDnsCacheFile *)diskCache { + if (!_diskCache) { + NSError *error; + QNDnsCacheFile *cache = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir error:&error]; + if (!error) { + _diskCache = cache; + } + } + return _diskCache; +} + +- (QNInternalDns *)customDns { + if (_customDns == nil && kQNGlobalConfiguration.dns) { + _customDns = [QNInternalDns dnsWithDns:kQNGlobalConfiguration.dns]; + } + return _customDns; +} + +- (QNInternalDns *)systemDns { + if (_systemDns == nil) { + _systemDns = [QNInternalDns dnsWithResolver:[[QNResolver alloc] initWithAddress:nil timeout:self.dnsPrefetchTimeout]]; + } + return _systemDns; +} + +- (NSMutableSet *)prefetchHosts { + if (!_prefetchHosts) { + _prefetchHosts = [NSMutableSet set]; + } + return _prefetchHosts; +} + +@end + + +//MARK: -- DNS 事务 +@implementation QNTransactionManager(Dns) +#define kQNLoadLocalDnsTransactionName @"QNLoadLocalDnsTransaction" +#define kQNDnsCheckAndPrefetchTransactionName @"QNDnsCheckAndPrefetchTransactionName" + +- (void)addDnsLocalLoadTransaction{ + + if ([kQNDnsPrefetch isDnsOpen] == NO) { + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + + QNTransaction *transaction = [QNTransaction transaction:kQNLoadLocalDnsTransactionName after:0 action:^{ + + [kQNDnsPrefetch recoverCache]; + [kQNDnsPrefetch localFetch]; + }]; + [[QNTransactionManager shared] addTransaction:transaction]; + [self setDnsCheckWhetherCachedValidTransactionAction]; + }); +} + +- (BOOL)addDnsCheckAndPrefetchTransaction:(QNZone *)currentZone token:(QNUpToken *)token { + return [self addDnsCheckAndPrefetchTransaction:[QNConfiguration defaultConfiguration] zone:currentZone token:token]; +} + +- (BOOL)addDnsCheckAndPrefetchTransaction:(QNConfiguration *)config zone:(QNZone *)currentZone token:(QNUpToken *)token { + + if (!token) { + return NO; + } + + if ([kQNDnsPrefetch isDnsOpen] == NO) { + return NO; + } + + BOOL ret = NO; + @synchronized (kQNDnsPrefetch) { + + QNTransactionManager *transactionManager = [QNTransactionManager shared]; + + if (![transactionManager existTransactionsForName:token.token]) { + QNTransaction *transaction = [QNTransaction transaction:token.token after:0 action:^{ + + [kQNDnsPrefetch checkAndPrefetchDnsIfNeed:config zone:currentZone token:token]; + }]; + [transactionManager addTransaction:transaction]; + + ret = YES; + } + } + return ret; +} + +- (void)setDnsCheckWhetherCachedValidTransactionAction{ + + if ([kQNDnsPrefetch isDnsOpen] == NO) { + return; + } + + @synchronized (kQNDnsPrefetch) { + + QNTransactionManager *transactionManager = [QNTransactionManager shared]; + QNTransaction *transaction = [transactionManager transactionsForName:kQNDnsCheckAndPrefetchTransactionName].firstObject; + + if (!transaction) { + + QNTransaction *transaction = [QNTransaction timeTransaction:kQNDnsCheckAndPrefetchTransactionName + after:10 + interval:120 + action:^{ + [kQNDnsPrefetch checkWhetherCachedDnsValid]; + }]; + [transactionManager addTransaction:transaction]; + } else { + [transactionManager performTransaction:transaction]; + } + } +} + +@end + +BOOL kQNIsDnsSourceDoh(NSString * _Nullable source) { + return [source containsString:kQNDnsSourceDoh]; +} + +BOOL kQNIsDnsSourceUdp(NSString * _Nullable source) { + return [source containsString:kQNDnsSourceUdp]; +} + +BOOL kQNIsDnsSourceDnsPod(NSString * _Nullable source) { + return [source containsString:kQNDnsSourceDnspod]; +} + +BOOL kQNIsDnsSourceSystem(NSString * _Nullable source) { + return [source containsString:kQNDnsSourceSystem]; +} + +BOOL kQNIsDnsSourceCustom(NSString * _Nullable source) { + return [source containsString:kQNDnsSourceCustom]; +} diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNInetAddress.h b/Pods/Qiniu/QiniuSDK/Http/Dns/QNInetAddress.h new file mode 100644 index 0000000..e78c1c4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNInetAddress.h @@ -0,0 +1,37 @@ +// +// QNInetAddress.h +// QiniuSDK +// +// Created by 杨森 on 2020/7/27. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNDns.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNInetAddress : NSObject + +@property(nonatomic, copy)NSString *hostValue; +@property(nonatomic, copy)NSString *ipValue; +@property(nonatomic, strong)NSNumber *ttlValue; +@property(nonatomic, strong)NSNumber *timestampValue; +@property(nonatomic, copy)NSString *sourceValue; + + +/// 构造方法 addressData为json +/// @param addressInfo 地址信息,类型可能为String / Dictionary / Data / 遵循 QNInetAddressDelegate的实例 ++ (instancetype)inetAddress:(id)addressInfo; + +/// 是否有效,根据时间戳判断 +- (BOOL)isValid; + +/// 对象转json +- (NSString *)toJsonInfo; + +/// 对象转字典 +- (NSDictionary *)toDictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Dns/QNInetAddress.m b/Pods/Qiniu/QiniuSDK/Http/Dns/QNInetAddress.m new file mode 100644 index 0000000..55707ae --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Dns/QNInetAddress.m @@ -0,0 +1,95 @@ +// +// QNInetAddress.m +// QiniuSDK +// +// Created by 杨森 on 2020/7/27. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNInetAddress.h" + +@interface QNInetAddress() +@end +@implementation QNInetAddress ++ (instancetype)inetAddress:(id)addressInfo{ + + NSDictionary *addressDic = nil; + if ([addressInfo isKindOfClass:[NSDictionary class]]) { + addressDic = (NSDictionary *)addressInfo; + } else if ([addressInfo isKindOfClass:[NSString class]]){ + NSData *data = [(NSString *)addressInfo dataUsingEncoding:NSUTF8StringEncoding]; + addressDic = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } else if ([addressInfo isKindOfClass:[NSData class]]) { + addressDic = [NSJSONSerialization JSONObjectWithData:(NSData *)addressInfo + options:NSJSONReadingMutableLeaves + error:nil]; + } else if ([addressInfo conformsToProtocol:@protocol(QNIDnsNetworkAddress)]){ + id address = (id )addressInfo; + NSMutableDictionary *dic = [NSMutableDictionary dictionary]; + if ([address respondsToSelector:@selector(hostValue)] && [address hostValue]) { + dic[@"hostValue"] = [address hostValue]; + } + if ([address respondsToSelector:@selector(ipValue)] && [address ipValue]) { + dic[@"ipValue"] = [address ipValue]; + } + if ([address respondsToSelector:@selector(ttlValue)] && [address ttlValue]) { + dic[@"ttlValue"] = [address ttlValue]; + } + if ([address respondsToSelector:@selector(timestampValue)] && [address timestampValue]) { + dic[@"timestampValue"] = [address timestampValue]; + } + addressDic = [dic copy]; + } + + if (addressDic) { + QNInetAddress *address = [[QNInetAddress alloc] init]; + [address setValuesForKeysWithDictionary:addressDic]; + return address; + } else { + return nil; + } +} + +- (BOOL)isValid{ + if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) { + return NO; + } + NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; + if (currentTimestamp > self.timestampValue.doubleValue + self.ttlValue.doubleValue) { + return NO; + } else { + return YES; + } +} + +- (NSString *)toJsonInfo{ + NSString *defaultString = @"{}"; + NSDictionary *infoDic = [self toDictionary]; + if (!infoDic) { + return defaultString; + } + + NSData *infoData = [NSJSONSerialization dataWithJSONObject:infoDic + options:NSJSONWritingPrettyPrinted + error:nil]; + if (!infoData) { + return defaultString; + } + + NSString *infoStr = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding]; + if (!infoStr) { + return defaultString; + } else { + return infoStr; + } +} + +- (NSDictionary *)toDictionary{ + return [self dictionaryWithValuesForKeys:@[@"ipValue", @"hostValue", @"ttlValue", @"timestampValue"]]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key{} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.h b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.h new file mode 100644 index 0000000..cf8e44a --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.h @@ -0,0 +1,37 @@ +// +// QNNetworkStatusManager.h +// QiniuSDK +// +// Created by yangsen on 2020/11/17. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNNetworkStatus : NSObject + +/// 网速 单位:kb/s 默认:200kb/s +@property(nonatomic, assign, readonly)int speed; + +@end + + +#define kQNNetworkStatusManager [QNNetworkStatusManager sharedInstance] +@interface QNNetworkStatusManager : NSObject + + ++ (instancetype)sharedInstance; + ++ (NSString *)getNetworkStatusType:(NSString *)host + ip:(NSString *)ip; + +- (QNNetworkStatus *)getNetworkStatus:(NSString *)type; + +- (void)updateNetworkStatus:(NSString *)type + speed:(int)speed; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.m b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.m new file mode 100644 index 0000000..c4b056f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNNetworkStatusManager.m @@ -0,0 +1,93 @@ +// +// QNNetworkStatusManager.m +// QiniuSDK +// +// Created by yangsen on 2020/11/17. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUtils.h" +#import "QNCache.h" +#import "QNAsyncRun.h" +#import "QNFileRecorder.h" +#import "QNRecorderDelegate.h" +#import "QNNetworkStatusManager.h" + +@interface QNNetworkStatus() +@property(nonatomic, assign)int speed; +@end +@implementation QNNetworkStatus +- (instancetype)init{ + if (self = [super init]) { + _speed = 200; + } + return self; +} + +- (nonnull id)initWithDictionary:(nullable NSDictionary *)dictionary { + QNNetworkStatus *status = [[QNNetworkStatus alloc] init]; + status.speed = [dictionary[@"speed"] intValue]; + return status; +} + +- (NSDictionary *)toDictionary{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + [dictionary setObject:@(self.speed) forKey:@"speed"]; + return dictionary; +} + ++ (QNNetworkStatus *)statusFromDictionary:(NSDictionary *)dictionary{ + QNNetworkStatus *status = [[QNNetworkStatus alloc] init]; + status.speed = [dictionary[@"speed"] intValue]; + return status; +} +@end + + +@interface QNNetworkStatusManager() + +@property(nonatomic, strong)QNCache *cache; + +@end +@implementation QNNetworkStatusManager + ++ (instancetype)sharedInstance{ + static QNNetworkStatusManager *manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[QNNetworkStatusManager alloc] init]; + [manager initData]; + }); + return manager; +} + +- (void)initData{ + QNCacheOption *option = [[QNCacheOption alloc] init]; + option.version = @"v1.0.2"; + option.flushCount = 10; + self.cache = [QNCache cache:[QNNetworkStatus class] option:option]; +} + ++ (NSString *)getNetworkStatusType:(NSString *)host + ip:(NSString *)ip { + return [QNUtils getIpType:ip host:host]; +} + +- (QNNetworkStatus *)getNetworkStatus:(NSString *)type{ + if (type == nil || type.length == 0) { + return nil; + } + return [self.cache cacheForKey:type]; +} + +- (void)updateNetworkStatus:(NSString *)type speed:(int)speed{ + if (type == nil || type.length == 0) { + return; + } + + QNNetworkStatus *status = [[QNNetworkStatus alloc] init]; + status.speed = speed; + [self.cache cache:status forKey:type atomically:false]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.h b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.h new file mode 100644 index 0000000..ab96523 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.h @@ -0,0 +1,24 @@ +// +// QNUploadServerNetworkStatus.h +// QiniuSDK +// +// Created by yangsen on 2020/11/17. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +#import "QNUploadServer.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadServerNetworkStatus : NSObject + ++ (QNUploadServer *)getBetterNetworkServer:(QNUploadServer *)serverA + serverB:(QNUploadServer *)serverB; + ++ (BOOL)isServerNetworkBetter:(QNUploadServer *)serverA + thanServerB:(QNUploadServer *)serverB; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.m b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.m new file mode 100644 index 0000000..667ebb8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/NetworkStatus/QNUploadServerNetworkStatus.m @@ -0,0 +1,40 @@ +// +// QNUploadServerNetworkStatus.m +// QiniuSDK +// +// Created by yangsen on 2020/11/17. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUtils.h" +#import "QNNetworkStatusManager.h" +#import "QNUploadServerNetworkStatus.h" + +@implementation QNUploadServerNetworkStatus + ++ (QNUploadServer *)getBetterNetworkServer:(QNUploadServer *)serverA serverB:(QNUploadServer *)serverB { + return [self isServerNetworkBetter:serverA thanServerB:serverB] ? serverA : serverB; +} + ++ (BOOL)isServerNetworkBetter:(QNUploadServer *)serverA thanServerB:(QNUploadServer *)serverB { + if (serverA == nil) { + return NO; + } else if (serverB == nil) { + return YES; + } + + NSString *serverTypeA = [QNNetworkStatusManager getNetworkStatusType:serverA.host ip:serverA.ip]; + NSString *serverTypeB = [QNNetworkStatusManager getNetworkStatusType:serverB.host ip:serverB.ip]; + if (serverTypeA == nil) { + return NO; + } else if (serverTypeB == nil) { + return YES; + } + + QNNetworkStatus *serverStatusA = [kQNNetworkStatusManager getNetworkStatus:serverTypeA]; + QNNetworkStatus *serverStatusB = [kQNNetworkStatusManager getNetworkStatus:serverTypeB]; + + return serverStatusB.speed < serverStatusA.speed; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/QNResponseInfo.h b/Pods/Qiniu/QiniuSDK/Http/QNResponseInfo.h new file mode 100755 index 0000000..f021ee7 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/QNResponseInfo.h @@ -0,0 +1,85 @@ +// +// QNResponseInfo.h +// QiniuSDK +// +// Created by bailong on 14/10/2. +// Copyright (c) 2014年 Qiniu. All rights reserved. +// + +#import "QNErrorCode.h" + +/** + * 上传完成后返回的状态信息 + */ +@interface QNResponseInfo : NSObject + +/// 状态码,具体见 QNErrorCode.h +@property (readonly) int statusCode; +/// response 信息 +@property (nonatomic, copy, readonly) NSDictionary *responseDictionary; +/// response 头信息 +@property (nonatomic, copy, readonly) NSDictionary *responseHeader; +/// response message +@property (nonatomic, copy, readonly) NSString *message; +/// 七牛服务器生成的请求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; +/// 客户端id +@property (nonatomic, readonly) NSString *id; +/// 时间戳 +@property (readonly) UInt64 timeStamp; +/// 是否取消 +@property (nonatomic, readonly, getter=isCancelled) BOOL canceled; +/// 成功的请求 +@property (nonatomic, readonly, getter=isOK) BOOL ok; +/// 是否网络错误 +@property (nonatomic, readonly, getter=isConnectionBroken) BOOL broken; +/// 是否TLS错误 +@property (nonatomic, readonly) BOOL isTlsError; +/// 是否可以再次重试,当遇到权限等怎么重试都不可能成功的问题时,返回NO +@property (nonatomic, readonly) BOOL couldRetry; +/// 单个host是否可以再次重试 +@property (nonatomic, readonly) BOOL couldHostRetry; +/// 单个Region是否可以再次重试 +@property (nonatomic, readonly) BOOL couldRegionRetry; +/// 当前host是否可达 +@property (nonatomic, readonly) BOOL canConnectToHost; +/// 当前host是否可用 +@property (nonatomic, readonly) BOOL isHostUnavailable; +/// 在断点续上传过程中,ctx 信息已过期。 +@property (nonatomic, readonly) BOOL isCtxExpiedError; +/// 是否是加速配置错误 +@property (nonatomic, readonly) BOOL isTransferAccelerationConfigureError; +/// 是否为 七牛响应 +@property (nonatomic, readonly, getter=isNotQiniu) BOOL notQiniu; + +//MARK:-- 构造函数 【内部使用】 ++ (instancetype)successResponse; ++ (instancetype)successResponseWithDesc:(NSString *)desc; ++ (instancetype)cancelResponse; ++ (instancetype)responseInfoWithNetworkError:(NSString *)desc; ++ (instancetype)responseInfoWithInvalidArgument:(NSString *)desc; ++ (instancetype)responseInfoWithInvalidToken:(NSString *)desc; ++ (instancetype)responseInfoWithFileError:(NSError *)error; ++ (instancetype)responseInfoOfZeroData:(NSString *)path; ++ (instancetype)responseInfoWithLocalIOError:(NSString *)desc; ++ (instancetype)responseInfoWithMaliciousResponseError:(NSString *)desc; +// 使用responseInfoWithSDKInteriorError替代 ++ (instancetype)responseInfoWithNoUsableHostError:(NSString *)desc NS_UNAVAILABLE; ++ (instancetype)responseInfoWithSDKInteriorError:(NSString *)desc; ++ (instancetype)responseInfoWithUnexpectedSysCallError:(NSString *)desc; + ++ (instancetype)errorResponseInfo:(int)errorType + errorDesc:(NSString *)errorDesc; +- (instancetype)initWithResponseInfoHost:(NSString *)host + response:(NSHTTPURLResponse *)response + body:(NSData *)body + error:(NSError *)error; +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/QNResponseInfo.m b/Pods/Qiniu/QiniuSDK/Http/QNResponseInfo.m new file mode 100755 index 0000000..e334122 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/QNResponseInfo.m @@ -0,0 +1,341 @@ +// +// QNResponseInfo.m +// QiniuSDK +// +// Created by bailong on 14/10/2. +// Copyright (c) 2014年 Qiniu. All rights reserved. +// +#import "QNErrorCode.h" +#import "QNResponseInfo.h" +#import "QNUserAgent.h" +#import "QNUtils.h" + +static NSString *kQNErrorDomain = @"qiniu.com"; + +@interface QNResponseInfo () + +@property (assign) int statusCode; +@property (nonatomic, copy) NSString *message; +@property (nonatomic, copy) NSString *reqId; +@property (nonatomic, copy) NSString *xlog; +@property (nonatomic, copy) NSString *xvia; +@property (nonatomic, copy) NSError *error; +@property (nonatomic, copy) NSString *host; +@property (nonatomic, copy) NSString *id; +@property (assign) UInt64 timeStamp; + +@end + +@implementation QNResponseInfo ++ (instancetype)successResponse{ + return [QNResponseInfo successResponseWithDesc:@"inter:ok"]; +} + ++ (instancetype)successResponseWithDesc:(NSString *)desc { + QNResponseInfo *responseInfo = [[QNResponseInfo alloc] init]; + responseInfo.statusCode = 200; + responseInfo.message = desc; + responseInfo.xlog = @"inter:xlog"; + responseInfo.reqId = @"inter:reqid"; + return responseInfo; +} + ++ (instancetype)cancelResponse { + return [QNResponseInfo errorResponseInfo:kQNRequestCancelled + errorDesc:@"cancelled by user"]; +} + ++ (instancetype)responseInfoWithNetworkError:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNNetworkError + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithInvalidArgument:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNInvalidArgument + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithInvalidToken:(NSString *)desc { + return [QNResponseInfo errorResponseInfo:kQNInvalidToken + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithFileError:(NSError *)error { + return [QNResponseInfo errorResponseInfo:kQNFileError + errorDesc:nil + 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 errorResponseInfo:kQNZeroDataSize + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithLocalIOError:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNLocalIOError + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithMaliciousResponseError:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNMaliciousResponseError + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithNoUsableHostError:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNSDKInteriorError + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithSDKInteriorError:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNSDKInteriorError + errorDesc:desc]; +} + ++ (instancetype)responseInfoWithUnexpectedSysCallError:(NSString *)desc{ + return [QNResponseInfo errorResponseInfo:kQNUnexpectedSysCallError + errorDesc:desc]; +} + ++ (instancetype)errorResponseInfo:(int)errorType + errorDesc:(NSString *)errorDesc{ + return [self errorResponseInfo:errorType errorDesc:errorDesc error:nil]; +} + ++ (instancetype)errorResponseInfo:(int)errorType + errorDesc:(NSString *)errorDesc + error:(NSError *)error{ + QNResponseInfo *response = [[QNResponseInfo alloc] init]; + response.statusCode = errorType; + response.message = errorDesc; + if (error) { + response.error = error; + } else { + NSError *error = [[NSError alloc] initWithDomain:kQNErrorDomain + code:errorType + userInfo:@{ @"error" : response.message ?: @"error" }]; + response.error = error; + } + + return response; +} + +- (instancetype)initWithResponseInfoHost:(NSString *)host + response:(NSHTTPURLResponse *)response + body:(NSData *)body + error:(NSError *)error { + + self = [super init]; + if (self) { + + _host = host; + _timeStamp = [[NSDate date] timeIntervalSince1970]; + + if (response) { + + int statusCode = (int)[response statusCode]; + NSDictionary *headers = [response allHeaderFields]; + _responseHeader = [headers copy]; + _statusCode = statusCode; + _reqId = headers[@"x-reqid"]; + _xlog = headers[@"x-log"]; + _xvia = headers[@"x-via"] ?: headers[@"x-px"] ?: headers[@"fw-via"]; + if (_statusCode == 200 && _reqId == nil && _xlog == nil) { + _statusCode = kQNMaliciousResponseError; + _message = @"this is a malicious response"; + _responseDictionary = nil; + _error = [[NSError alloc] initWithDomain:kQNErrorDomain code:_statusCode userInfo:@{@"error" : _message}]; + } else if (error) { + _error = error; + _statusCode = (int)error.code; + _message = [NSString stringWithFormat:@"%@", error]; + _responseDictionary = nil; + } else { + NSMutableDictionary *errorUserInfo = [@{@"errorHost" : host ?: @""} mutableCopy]; + if (!body) { + _message = @"no response data"; + _error = nil; + _responseDictionary = nil; + } else { + NSError *tmp = nil; + NSDictionary *responseInfo = nil; + responseInfo = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp]; + if (tmp){ + _message = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]; + _error = nil; + _responseDictionary = nil; + } else if (statusCode >= 200 && statusCode < 300) { + _error = nil; + _message = @"ok"; + _responseDictionary = responseInfo; + } else { + NSString *errorString = responseInfo[@"error"]; + if (errorString) { + [errorUserInfo setDictionary:@{@"error" : errorString}]; + _message = errorString; + _error = [[NSError alloc] initWithDomain:kQNErrorDomain code:statusCode userInfo:errorUserInfo]; + } else { + _message = errorString; + _error = nil; + } + + _responseDictionary = responseInfo; + } + } + } + } else if (error) { + _error = error; + _statusCode = (int)error.code; + _message = [NSString stringWithFormat:@"%@", error]; + _responseDictionary = nil; + } else { + _statusCode = kQNUnexpectedSysCallError; + _message = @"no response"; + } + } + return self; +} + +- (BOOL)isCancelled { + return _statusCode == kQNRequestCancelled || _statusCode == -999; +} + +- (BOOL)isTlsError{ + if (_statusCode == NSURLErrorServerCertificateHasBadDate + || _statusCode == NSURLErrorClientCertificateRejected + || _statusCode == NSURLErrorClientCertificateRequired) { + return true; + } else { + return false; + } +} + +- (BOOL)isQiniu { + // reqId is nill means the server is not qiniu + return ![self isNotQiniu]; +} + +- (BOOL)isNotQiniu { + // reqId is nill means the server is not qiniu + return (_statusCode == kQNMaliciousResponseError) || (_statusCode > 0 && _reqId == nil && _xlog == nil); +} + +- (BOOL)isOK { + return (_statusCode >= 200 && _statusCode < 300) && _error == nil && (_reqId != nil || _xlog != nil); +} + +- (BOOL)couldRetry { + if (![self isQiniu]) { + return YES; + } + + if ([self isCtxExpiedError]) { + return YES; + } + + if ([self isTransferAccelerationConfigureError]) { + return YES; + } + + if (self.isCancelled + || _statusCode == 100 + || (_statusCode > 300 && _statusCode < 400) + || (_statusCode > 400 && _statusCode < 500 && _statusCode != 406) + || _statusCode == 501 || _statusCode == 573 + || _statusCode == 608 || _statusCode == 612 || _statusCode == 614 || _statusCode == 616 + || _statusCode == 619 || _statusCode == 630 || _statusCode == 631 || _statusCode == 640 + || (_statusCode != kQNLocalIOError && _statusCode != kQNUnexpectedSysCallError && _statusCode < -1 && _statusCode > -1000)) { + return NO; + } else { + return YES; + } +} + +- (BOOL)couldRegionRetry{ + if (![self isQiniu]) { + return YES; + } + + if ([self isTransferAccelerationConfigureError]) { + return YES; + } + + if (self.isCancelled + || _statusCode == 100 + || (_statusCode > 300 && _statusCode < 500 && _statusCode != 406) + || _statusCode == 501 || _statusCode == 573 || _statusCode == 579 + || _statusCode == 608 || _statusCode == 612 || _statusCode == 614 || _statusCode == 616 + || _statusCode == 619 || _statusCode == 630 || _statusCode == 631 || _statusCode == 640 + || _statusCode == 701 + || (_statusCode != kQNLocalIOError && _statusCode != kQNUnexpectedSysCallError && _statusCode < -1 && _statusCode > -1000)) { + return NO; + } else { + return YES; + } +} + +- (BOOL)couldHostRetry{ + if (![self isQiniu]) { + return YES; + } + + if ([self isTransferAccelerationConfigureError]) { + return NO; + } + + if (self.isCancelled + || _statusCode == 100 + || (_statusCode > 300 && _statusCode < 500 && _statusCode != 406) + || _statusCode == 501 || _statusCode == 502 || _statusCode == 503 + || _statusCode == 571 || _statusCode == 573 || _statusCode == 579 || _statusCode == 599 + || _statusCode == 608 || _statusCode == 612 || _statusCode == 614 || _statusCode == 616 + || _statusCode == 619 || _statusCode == 630 || _statusCode == 631 || _statusCode == 640 + || _statusCode == 701 + || (_statusCode != kQNLocalIOError && _statusCode != kQNUnexpectedSysCallError && _statusCode < -1 && _statusCode > -1000)) { + return NO; + } else { + return YES; + } +} + +- (BOOL)canConnectToHost{ + if (_statusCode > 99 || self.isCancelled) { + return true; + } else { + return false; + } +} + +- (BOOL)isHostUnavailable{ + // 基本不可恢复,注:会影响下次请求,范围太大可能会造成大量的timeout + if ([self isTransferAccelerationConfigureError] || + _statusCode == 502 || _statusCode == 503 || _statusCode == 504 || _statusCode == 599) { + return true; + } else { + return false; + } +} + +- (BOOL)isCtxExpiedError { + return _statusCode == 701 || (_statusCode == 612 && [_message containsString:@"no such uploadId"]); +} + +- (BOOL)isTransferAccelerationConfigureError { + NSString *errorDesc = [NSString stringWithFormat:@"%@", self.error]; + return [errorDesc containsString:@"transfer acceleration is not configured on this bucket"]; +} + +- (BOOL)isConnectionBroken { + return _statusCode == kQNNetworkError || _statusCode == NSURLErrorNotConnectedToInternet; +} + +- (NSString *)description { + 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]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.h b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.h new file mode 100644 index 0000000..1b3b96e --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.h @@ -0,0 +1,128 @@ +// +// QNUploadRequestMetrics.h +// QiniuSDK +// +// Created by yangsen on 2020/4/29. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +#import "QNUploadRegionInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadMetrics : NSObject + +@property (nonatomic, nullable, strong, readonly) NSDate *startDate; +@property (nonatomic, nullable, strong, readonly) NSDate *endDate; +@property (nonatomic, nullable, strong, readonly) NSNumber *totalElapsedTime; + +//MARK:-- 构造 ++ (instancetype)emptyMetrics; + +- (void)start; +- (void)end; + +@end + + +#define kQNMetricsRequestHijacked @"forsure" +#define kQNMetricsRequestMaybeHijacked @"maybe" + +@interface QNUploadSingleRequestMetrics : QNUploadMetrics + +// 请求的 httpVersion +@property (nonatomic, copy)NSString *httpVersion; + +// 请求是否劫持 +@property (nonatomic, copy)NSString *hijacked; +@property (nonatomic, assign, readonly)BOOL isForsureHijacked; +@property (nonatomic, assign, readonly)BOOL isMaybeHijacked; +@property (nonatomic, copy) NSString *syncDnsSource; +@property (nonatomic, strong) NSError *syncDnsError; + +// 只有进行网络检测才会有 connectCheckMetrics +@property (nonatomic, nullable , strong) QNUploadSingleRequestMetrics *connectCheckMetrics; + +// 错误信息 +@property (nonatomic, nullable , strong) NSError *error; + +@property (nonatomic, nullable, copy) NSURLRequest *request; +@property (nonatomic, nullable, copy) NSURLResponse *response; + +@property (nonatomic, nullable, copy) NSDate *domainLookupStartDate; +@property (nonatomic, nullable, copy) NSDate *domainLookupEndDate; +@property (nonatomic, nullable, strong, readonly) NSNumber *totalDnsTime; + +@property (nonatomic, nullable, copy) NSDate *connectStartDate; +@property (nonatomic, nullable, copy) NSDate *connectEndDate; +@property (nonatomic, nullable, strong, readonly) NSNumber *totalConnectTime; + +@property (nonatomic, nullable, copy) NSDate *secureConnectionStartDate; +@property (nonatomic, nullable, copy) NSDate *secureConnectionEndDate; +@property (nonatomic, nullable, strong, readonly) NSNumber *totalSecureConnectTime; + +@property (nonatomic, nullable, copy) NSDate *requestStartDate; +@property (nonatomic, nullable, copy) NSDate *requestEndDate; +@property (nonatomic, nullable, strong, readonly) NSNumber *totalRequestTime; + +@property (nonatomic, nullable, strong, readonly) NSNumber *totalWaitTime; + +@property (nonatomic, nullable, copy) NSDate *responseStartDate; +@property (nonatomic, nullable, copy) NSDate *responseEndDate; +@property (nonatomic, nullable, strong, readonly) NSNumber *totalResponseTime; + +@property (nonatomic, assign) int64_t countOfRequestHeaderBytesSent; +@property (nonatomic, assign) int64_t countOfRequestBodyBytesSent; + +@property (nonatomic, assign) int64_t countOfResponseHeaderBytesReceived; +@property (nonatomic, assign) int64_t countOfResponseBodyBytesReceived; + +@property (nonatomic, nullable, copy) NSString *localAddress; +@property (nonatomic, nullable, copy) NSNumber *localPort; +@property (nonatomic, nullable, copy) NSString *remoteAddress; +@property (nonatomic, nullable, copy) NSNumber *remotePort; + +@property (nonatomic, strong, readonly) NSNumber *totalBytes; +@property (nonatomic, strong, readonly) NSNumber *bytesSend; +@property (nonatomic, strong, readonly) NSNumber *perceptiveSpeed; + + +@end + + +@interface QNUploadRegionRequestMetrics : QNUploadMetrics + +@property (nonatomic, strong, readonly) NSNumber *requestCount; +@property (nonatomic, strong, readonly) NSNumber *bytesSend; +@property (nonatomic, strong, readonly) id region; +@property (nonatomic, strong, readonly) QNUploadSingleRequestMetrics *lastMetrics; +@property (nonatomic, copy, readonly) NSArray *metricsList; + +//MARK:-- 构造 +- (instancetype)initWithRegion:(id )region; + +- (void)addMetricsList:(NSArray *)metricsList; +- (void)addMetrics:(QNUploadRegionRequestMetrics*)metrics; + +@end + + +@interface QNUploadTaskMetrics : QNUploadMetrics + +@property (nonatomic, copy, readonly) NSString *upType; +@property (nonatomic, strong, readonly) NSNumber *requestCount; +@property (nonatomic, strong, readonly) NSNumber *bytesSend; +@property (nonatomic, strong, readonly) NSNumber *regionCount; +@property (nonatomic, strong, readonly) QNUploadRegionRequestMetrics *lastMetrics; + +@property (nonatomic, strong) QNUploadRegionRequestMetrics *ucQueryMetrics; +@property (nonatomic, strong) NSArray> *regions; + ++ (instancetype)taskMetrics:(NSString *)upType; + +- (void)addMetrics:(QNUploadRegionRequestMetrics *)metrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.m b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.m new file mode 100644 index 0000000..fd2bfac --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestMetrics.m @@ -0,0 +1,351 @@ +// +// QNUploadRequestMetrics.m +// QiniuSDK +// +// Created by yangsen on 2020/4/29. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUtils.h" +#import "QNUploadRequestMetrics.h" +#import "NSURLRequest+QNRequest.h" +#import "QNZoneInfo.h" + +@interface QNUploadMetrics() + +@property (nullable, strong) NSDate *startDate; +@property (nullable, strong) NSDate *endDate; + +@end +@implementation QNUploadMetrics +//MARK:-- 构造 ++ (instancetype)emptyMetrics { + return [[self alloc] init]; +} + +- (NSNumber *)totalElapsedTime{ + return [QNUtils dateDuration:self.startDate endDate:self.endDate]; +} + +- (void)start { + self.startDate = [NSDate date]; +} + +- (void)end { + self.endDate = [NSDate date]; +} +@end + +@interface QNUploadSingleRequestMetrics() +@property (nonatomic, assign) int64_t countOfRequestHeaderBytes; +@property (nonatomic, assign) int64_t countOfRequestBodyBytes; +@end +@implementation QNUploadSingleRequestMetrics + ++ (instancetype)emptyMetrics{ + QNUploadSingleRequestMetrics *metrics = [[QNUploadSingleRequestMetrics alloc] init]; + return metrics; +} + +- (instancetype)init{ + if (self = [super init]) { + [self initData]; + } + return self; +} + +- (void)initData{ + _countOfRequestHeaderBytesSent = 0; + _countOfRequestBodyBytesSent = 0; + _countOfResponseHeaderBytesReceived = 0; + _countOfResponseBodyBytesReceived = 0; +} + +- (void)setRequest:(NSURLRequest *)request{ + NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:request.URL + cachePolicy:request.cachePolicy + timeoutInterval:request.timeoutInterval]; + newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields; + + self.countOfRequestHeaderBytes = [NSString stringWithFormat:@"%@", request.allHTTPHeaderFields].length; + self.countOfRequestBodyBytes = [request.qn_getHttpBody length]; + _totalBytes = @(self.countOfRequestHeaderBytes + self.countOfRequestBodyBytes); + _request = [newRequest copy]; +} + +- (void)setResponse:(NSURLResponse *)response { + if ([response isKindOfClass:[NSHTTPURLResponse class]] && + [(NSHTTPURLResponse *)response statusCode] >= 200 && + [(NSHTTPURLResponse *)response statusCode] < 300) { + _countOfRequestHeaderBytesSent = _countOfRequestHeaderBytes; + _countOfRequestBodyBytesSent = _countOfRequestBodyBytes; + } + if (_countOfResponseBodyBytesReceived <= 0) { + _countOfResponseBodyBytesReceived = response.expectedContentLength; + } + if (_countOfResponseHeaderBytesReceived <= 0 && [response isKindOfClass:[NSHTTPURLResponse class]]) { + _countOfResponseHeaderBytesReceived = [NSString stringWithFormat:@"%@", [(NSHTTPURLResponse *)response allHeaderFields]].length; + } + _response = [response copy]; +} + +- (BOOL)isForsureHijacked { + return [self.hijacked isEqualToString:kQNMetricsRequestHijacked]; +} + +- (BOOL)isMaybeHijacked { + return [self.hijacked isEqualToString:kQNMetricsRequestMaybeHijacked]; +} + +- (NSNumber *)totalElapsedTime{ + return [self timeFromStartDate:self.startDate + toEndDate:self.endDate]; +} + +- (NSNumber *)totalDnsTime{ + return [self timeFromStartDate:self.domainLookupStartDate + toEndDate:self.domainLookupEndDate]; +} + +- (NSNumber *)totalConnectTime{ + return [self timeFromStartDate:self.connectStartDate + toEndDate:self.connectEndDate]; +} + +- (NSNumber *)totalSecureConnectTime{ + return [self timeFromStartDate:self.secureConnectionStartDate + toEndDate:self.secureConnectionEndDate]; +} + +- (NSNumber *)totalRequestTime{ + return [self timeFromStartDate:self.requestStartDate + toEndDate:self.requestEndDate]; +} + +- (NSNumber *)totalWaitTime{ + return [self timeFromStartDate:self.requestEndDate + toEndDate:self.responseStartDate]; +} + +- (NSNumber *)totalResponseTime{ + return [self timeFromStartDate:self.responseStartDate + toEndDate:self.responseEndDate]; +} + +- (NSNumber *)bytesSend{ + int64_t totalBytes = [self totalBytes].integerValue; + int64_t senderBytes = self.countOfRequestBodyBytesSent + self.countOfRequestHeaderBytesSent; + int64_t bytes = MIN(totalBytes, senderBytes); + return @(bytes); +} + +- (NSNumber *)timeFromStartDate:(NSDate *)startDate toEndDate:(NSDate *)endDate{ + return [QNUtils dateDuration:startDate endDate:endDate]; +} + +- (NSNumber *)perceptiveSpeed { + int64_t size = self.bytesSend.longLongValue + _countOfResponseHeaderBytesReceived + _countOfResponseBodyBytesReceived; + if (size == 0 || self.totalElapsedTime == nil) { + return nil; + } + + return [QNUtils calculateSpeed:size totalTime:self.totalElapsedTime.longLongValue]; +} + +@end + + +@interface QNUploadRegionRequestMetrics() + +@property (nonatomic, strong) id region; +@property (nonatomic, copy) NSMutableArray *metricsListInter; + +@end +@implementation QNUploadRegionRequestMetrics + ++ (instancetype)emptyMetrics{ + QNUploadRegionRequestMetrics *metrics = [[QNUploadRegionRequestMetrics alloc] init]; + return metrics; +} + +- (instancetype)initWithRegion:(id)region{ + if (self = [super init]) { + _region = region; + _metricsListInter = [NSMutableArray array]; + } + return self; +} + +- (QNUploadSingleRequestMetrics *)lastMetrics { + @synchronized (self) { + return self.metricsListInter.lastObject; + } +} + +- (NSNumber *)requestCount{ + if (self.metricsList) { + return @(self.metricsList.count); + } else { + return @(0); + } +} + +- (NSNumber *)bytesSend{ + if (self.metricsList) { + long long bytes = 0; + for (QNUploadSingleRequestMetrics *metrics in self.metricsList) { + bytes += metrics.bytesSend.longLongValue; + } + return @(bytes); + } else { + return @(0); + } +} + +- (void)addMetricsList:(NSArray *)metricsList{ + @synchronized (self) { + [_metricsListInter addObjectsFromArray:metricsList]; + } +} + +- (void)addMetrics:(QNUploadRegionRequestMetrics*)metrics{ + if ([metrics.region.zoneInfo.regionId isEqualToString:self.region.zoneInfo.regionId]) { + @synchronized (self) { + [_metricsListInter addObjectsFromArray:metrics.metricsListInter]; + } + } +} + +- (NSArray *)metricsList{ + @synchronized (self) { + return [_metricsListInter copy]; + } +} + +@end + + +@interface QNUploadTaskMetrics() + +@property (nonatomic, copy) NSString *upType; +@property (nonatomic, copy) NSMutableArray *metricsKeys; +@property (nonatomic, strong) NSMutableDictionary *metricsInfo; + +@end +@implementation QNUploadTaskMetrics + ++ (instancetype)emptyMetrics{ + QNUploadTaskMetrics *metrics = [[QNUploadTaskMetrics alloc] init]; + return metrics; +} + ++ (instancetype)taskMetrics:(NSString *)upType { + QNUploadTaskMetrics *metrics = [self emptyMetrics]; + metrics.upType = upType; + return metrics; +} + +- (instancetype)init{ + if (self = [super init]) { + _metricsKeys = [NSMutableArray array]; + _metricsInfo = [NSMutableDictionary dictionary]; + } + return self; +} + +- (QNUploadRegionRequestMetrics *)lastMetrics { + if (self.metricsKeys.count < 1) { + return nil; + } + + @synchronized (self) { + NSString *key = self.metricsKeys.lastObject; + if (key == nil) { + return nil; + } + return self.metricsInfo[key]; + } +} +- (NSNumber *)totalElapsedTime{ + NSDictionary *metricsInfo = [self syncCopyMetricsInfo]; + if (metricsInfo) { + double time = 0; + for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) { + time += metrics.totalElapsedTime.doubleValue; + } + return time > 0 ? @(time) : nil; + } else { + return nil; + } +} + +- (NSNumber *)requestCount{ + NSDictionary *metricsInfo = [self syncCopyMetricsInfo]; + if (metricsInfo) { + NSInteger count = 0; + for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) { + count += metrics.requestCount.integerValue; + } + return @(count); + } else { + return @(0); + } +} + +- (NSNumber *)bytesSend{ + NSDictionary *metricsInfo = [self syncCopyMetricsInfo]; + if (metricsInfo) { + long long bytes = 0; + for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) { + bytes += metrics.bytesSend.longLongValue; + } + return @(bytes); + } else { + return @(0); + } +} + +- (NSNumber *)regionCount{ + NSDictionary *metricsInfo = [self syncCopyMetricsInfo]; + if (metricsInfo) { + int count = 0; + for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) { + if (![metrics.region.zoneInfo.regionId isEqualToString:QNZoneInfoEmptyRegionId]) { + count += 1; + } + } + return @(count); + } else { + return @(0); + } +} + +- (void)setUcQueryMetrics:(QNUploadRegionRequestMetrics *)ucQueryMetrics { + _ucQueryMetrics = ucQueryMetrics; + [self addMetrics:ucQueryMetrics]; +} + +- (void)addMetrics:(QNUploadRegionRequestMetrics *)metrics{ + NSString *regionId = metrics.region.zoneInfo.regionId; + if (!regionId) { + return; + } + @synchronized (self) { + QNUploadRegionRequestMetrics *metricsOld = self.metricsInfo[regionId]; + if (metricsOld) { + [metricsOld addMetrics:metrics]; + } else { + [self.metricsKeys addObject:regionId]; + self.metricsInfo[regionId] = metrics; + } + } +} + +- (NSDictionary *)syncCopyMetricsInfo { + @synchronized (self) { + return [_metricsInfo copy]; + } +} + + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestState.h b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestState.h new file mode 100644 index 0000000..433a42b --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestState.h @@ -0,0 +1,25 @@ +// +// QNUploadRequestState.h +// QiniuSDK_Mac +// +// Created by yangsen on 2020/11/17. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadRequestState : NSObject + +// old server 不验证tls sni +@property(nonatomic, assign)BOOL isUseOldServer; + +// 用户是否取消 +@property(nonatomic, assign)BOOL isUserCancel; + +- (instancetype)copy; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestState.m b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestState.m new file mode 100644 index 0000000..f7b0bc6 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/QNUploadRequestState.m @@ -0,0 +1,32 @@ +// +// QNUploadRequestState.m +// QiniuSDK_Mac +// +// Created by yangsen on 2020/11/17. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNIUploadServer.h" +#import "QNUploadRequestState.h" + +@implementation QNUploadRequestState +- (instancetype)init{ + if (self = [super init]) { + [self initData]; + } + return self; +} + +- (void)initData{ + _isUserCancel = NO; + _isUseOldServer = NO; +} + +- (instancetype)copy { + QNUploadRequestState *state = [[QNUploadRequestState alloc] init]; + state.isUserCancel = self.isUserCancel; + state.isUseOldServer = self.isUseOldServer; + return state; +} + +@end diff --git a/msext/QiniuSDK/Http/QNUserAgent.h b/Pods/Qiniu/QiniuSDK/Http/QNUserAgent.h old mode 100755 new mode 100644 similarity index 85% rename from msext/QiniuSDK/Http/QNUserAgent.h rename to Pods/Qiniu/QiniuSDK/Http/QNUserAgent.h index be92fb3..e606d98 --- a/msext/QiniuSDK/Http/QNUserAgent.h +++ b/Pods/Qiniu/QiniuSDK/Http/QNUserAgent.h @@ -13,6 +13,7 @@ * */ +#define kQNUserAgent [QNUserAgent sharedInstance] @interface QNUserAgent : NSObject /** @@ -27,6 +28,7 @@ /** * UserAgent + AK 字串 + * @param access access信息 */ - (NSString *)getUserAgent:(NSString *)access; diff --git a/msext/QiniuSDK/Http/QNUserAgent.m b/Pods/Qiniu/QiniuSDK/Http/QNUserAgent.m old mode 100755 new mode 100644 similarity index 77% rename from msext/QiniuSDK/Http/QNUserAgent.m rename to Pods/Qiniu/QiniuSDK/Http/QNUserAgent.m index dc45597..e011c4b --- a/msext/QiniuSDK/Http/QNUserAgent.m +++ b/Pods/Qiniu/QiniuSDK/Http/QNUserAgent.m @@ -15,7 +15,7 @@ #endif #import "QNUserAgent.h" -#import "QNVersion.h" +#import "QNUtils.h" static NSString *qn_clientId(void) { #if __IPHONE_OS_VERSION_MIN_REQUIRED @@ -32,10 +32,15 @@ static NSString *qn_clientId(void) { } static NSString *qn_userAgent(NSString *id, NSString *ak) { + NSString *addition = @""; +#if DEBUG + addition = @"_Debug"; +#endif + #if __IPHONE_OS_VERSION_MIN_REQUIRED - return [NSString stringWithFormat:@"QiniuObject-C/%@ (%@; iOS %@; %@; %@)", kQiniuVersion, [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], id, ak]; + return [NSString stringWithFormat:@"QiniuObject-C%@/%@ (%@; iOS %@; %@; %@)", addition, [QNUtils sdkVersion], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], id, ak]; #else - return [NSString stringWithFormat:@"QiniuObject-C/%@ (Mac OS X %@; %@; %@)", kQiniuVersion, [[NSProcessInfo processInfo] operatingSystemVersionString], id, ak]; + return [NSString stringWithFormat:@"QiniuObject-C%@/%@ (Mac OS X %@; %@; %@)", addition, [QNUtils sdkVersion], [[NSProcessInfo processInfo] operatingSystemVersionString], id, ak]; #endif } diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h new file mode 100644 index 0000000..4dbf5c4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h @@ -0,0 +1,50 @@ +// +// NSURLRequest+QNRequest.h +// AppTest +// +// Created by yangsen on 2020/4/8. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSURLRequest(QNRequest) + +/// 请求id【内部使用】 +/// 只有通过设置qn_domain才会有效 +@property(nonatomic, strong, nullable, readonly)NSString *qn_identifier; + +/// 请求domain【内部使用】 +/// 只有通过NSMutableURLRequest设置才会有效 +@property(nonatomic, strong, nullable, readonly)NSString *qn_domain; + +/// 请求ip【内部使用】 +/// 只有通过NSMutableURLRequest设置才会有效 +@property(nonatomic, strong, nullable, readonly)NSString *qn_ip; + +/// 请求头信息 去除七牛内部标记占位 +@property(nonatomic, strong, nullable, readonly)NSDictionary *qn_allHTTPHeaderFields; + ++ (instancetype)qn_requestWithURL:(NSURL *)url; + +/// 获取请求体 +- (NSData *)qn_getHttpBody; + +- (BOOL)qn_isHttps; + +@end + + +@interface NSMutableURLRequest(QNRequest) + +/// 请求domain【内部使用】 +@property(nonatomic, strong, nullable)NSString *qn_domain; +/// 请求ip【内部使用】 +@property(nonatomic, strong, nullable)NSString *qn_ip; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.m b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.m new file mode 100644 index 0000000..9358a66 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.m @@ -0,0 +1,123 @@ +// +// NSURLRequest+QNRequest.m +// AppTest +// +// Created by yangsen on 2020/4/8. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import +#import "NSURLRequest+QNRequest.h" + + +@implementation NSURLRequest(QNRequest) + +#define kQNURLRequestHostKey @"Host" +#define kQNURLRequestIPKey @"QNURLRequestIP" +#define kQNURLRequestIdentifierKey @"QNURLRequestIdentifier" + +- (NSString *)qn_identifier{ + return self.allHTTPHeaderFields[kQNURLRequestIdentifierKey]; +} + +- (NSString *)qn_domain{ + NSString *host = self.allHTTPHeaderFields[kQNURLRequestHostKey]; + if (host == nil) { + host = self.URL.host; + } + return host; +} + +- (NSString *)qn_ip{ + return self.allHTTPHeaderFields[kQNURLRequestIPKey]; +} + +- (NSDictionary *)qn_allHTTPHeaderFields{ + NSDictionary *headerFields = [self.allHTTPHeaderFields copy]; + NSMutableDictionary *headerFieldsNew = [NSMutableDictionary dictionary]; + for (NSString *key in headerFields) { + if (![key isEqualToString:kQNURLRequestIdentifierKey]) { + [headerFieldsNew setObject:headerFields[key] forKey:key]; + } + } + return [headerFieldsNew copy]; +} + ++ (instancetype)qn_requestWithURL:(NSURL *)url{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request setValue:url.host forHTTPHeaderField:kQNURLRequestHostKey]; + return request; +} + + +- (NSData *)qn_getHttpBody{ + + if (self.HTTPBody || + (![self.HTTPMethod isEqualToString:@"POST"] && ![self.HTTPMethod isEqualToString:@"PUT"])) { + return self.HTTPBody; + } + + NSInteger maxLength = 1024; + uint8_t d[maxLength]; + + NSInputStream *stream = self.HTTPBodyStream; + NSMutableData *data = [NSMutableData data]; + + [stream open]; + + BOOL end = NO; + + while (!end) { + NSInteger bytesRead = [stream read:d maxLength:maxLength]; + if (bytesRead == 0) { + end = YES; + } else if (bytesRead == -1){ + end = YES; + } else if (stream.streamError == nil){ + [data appendBytes:(void *)d length:bytesRead]; + } + } + [stream close]; + return [data copy]; +} + +- (BOOL)qn_isHttps{ + if ([self.URL.absoluteString rangeOfString:@"https://"].location != NSNotFound) { + return YES; + } else { + return NO; + } +} +@end + + +@implementation NSMutableURLRequest(QNRequest) + +- (void)setQn_domain:(NSString *)qn_domain{ + if (qn_domain) { + [self addValue:qn_domain forHTTPHeaderField:kQNURLRequestHostKey]; + } else { + [self setValue:nil forHTTPHeaderField:kQNURLRequestHostKey]; + } + + NSString *identifier = [NSString stringWithFormat:@"%p-%@", &self, qn_domain]; + [self setQn_identifier:identifier]; +} + +- (void)setQn_ip:(NSString *)qn_ip{ + if (qn_ip) { + [self addValue:qn_ip forHTTPHeaderField:kQNURLRequestIPKey]; + } else { + [self setValue:nil forHTTPHeaderField:kQNURLRequestIPKey]; + } +} + +- (void)setQn_identifier:(NSString *)qn_identifier{ + if (qn_identifier) { + [self addValue:qn_identifier forHTTPHeaderField:kQNURLRequestIdentifierKey]; + } else { + [self setValue:nil forHTTPHeaderField:kQNURLRequestIdentifierKey]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h new file mode 100644 index 0000000..6becce7 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h @@ -0,0 +1,17 @@ +// +// QNCFHttpClient.h +// QiniuSDK +// +// Created by yangsen on 2021/10/11. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNRequestClient.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNCFHttpClient : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.m b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.m new file mode 100644 index 0000000..b18106f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.m @@ -0,0 +1,160 @@ +// +// QNCFHttpClient.m +// QiniuSDK +// +// Created by yangsen on 2021/10/11. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNAsyncRun.h" +#import "QNCFHttpClient.h" +#import "QNCFHttpClientInner.h" +#import "NSURLRequest+QNRequest.h" +#import "QNUploadRequestMetrics.h" +#import "QNCFHttpThreadPool.h" + +@interface QNCFHttpClient() + +@property(nonatomic, assign)BOOL hasCallBack; +@property(nonatomic, assign)NSInteger redirectCount; +@property(nonatomic, assign)NSInteger maxRedirectCount; + +@property(nonatomic, strong)NSURLRequest *request; +@property(nonatomic, strong)NSURLResponse *response; +@property(nonatomic, strong)NSDictionary *connectionProxy; +@property(nonatomic, strong)QNUploadSingleRequestMetrics *requestMetrics; +@property(nonatomic, strong)NSMutableData *responseData; +@property(nonatomic, copy)void(^progress)(long long totalBytesWritten, long long totalBytesExpectedToWrite); +@property(nonatomic, copy)QNRequestClientCompleteHandler complete; + +@property(nonatomic, strong)QNCFHttpClientInner *httpClient; +@property(nonatomic, strong)QNCFHttpThread *thread; + +@end +@implementation QNCFHttpClient + +- (NSString *)clientId { + return @"CFNetwork"; +} + +- (instancetype)init { + if (self = [super init]) { + self.redirectCount = 0; + self.maxRedirectCount = 15; + self.hasCallBack = false; + } + return self; +} + +- (void)request:(NSURLRequest *)request + server:(id )server +connectionProxy:(NSDictionary *)connectionProxy + progress:(void (^)(long long, long long))progress + complete:(QNRequestClientCompleteHandler)complete { + + self.thread = [[QNCFHttpThreadPool shared] getOneThread]; + // 有 ip 才会使用 + if (server && server.ip.length > 0 && server.host.length > 0) { + NSString *urlString = request.URL.absoluteString; + urlString = [urlString stringByReplacingOccurrencesOfString:server.host withString:server.ip]; + NSMutableURLRequest *requestNew = [request mutableCopy]; + requestNew.URL = [NSURL URLWithString:urlString]; + requestNew.qn_domain = server.host; + self.request = [requestNew copy]; + } else { + self.request = request; + } + + self.connectionProxy = connectionProxy; + self.progress = progress; + self.complete = complete; + self.requestMetrics = [QNUploadSingleRequestMetrics emptyMetrics]; + self.requestMetrics.request = self.request; + self.requestMetrics.remoteAddress = self.request.qn_ip; + self.requestMetrics.remotePort = self.request.qn_isHttps ? @443 : @80; + [self.requestMetrics start]; + + self.responseData = [NSMutableData data]; + self.httpClient = [QNCFHttpClientInner client:self.request connectionProxy:connectionProxy]; + self.httpClient.delegate = self; + [self.httpClient performSelector:@selector(main) + onThread:self.thread + withObject:nil + waitUntilDone:NO]; +} + +- (void)cancel { + if (self.thread) { + return; + } + + [self.httpClient performSelector:@selector(cancel) + onThread:self.thread + withObject:nil + waitUntilDone:NO]; +} + +- (void)completeAction:(NSError *)error { + @synchronized (self) { + if (self.hasCallBack) { + return; + } + self.hasCallBack = true; + } + self.requestMetrics.response = self.response; + [self.requestMetrics end]; + if (self.complete) { + self.complete(self.response, self.requestMetrics, self.responseData, error); + } + [[QNCFHttpThreadPool shared] subtractOperationCountOfThread:self.thread]; +} + +//MARK: -- delegate +- (void)didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{ + self.requestMetrics.countOfRequestBodyBytesSent = totalBytesSent; + if (self.progress) { + self.progress(totalBytesSent, totalBytesExpectedToSend); + } +} + +- (void)didFinish { + self.requestMetrics.responseEndDate = [NSDate date]; + [self completeAction:nil]; +} + +- (void)didLoadData:(nonnull NSData *)data { + [self.responseData appendData:data]; +} + +- (void)onError:(nonnull NSError *)error { + [self completeAction:error]; +} + +- (void)onReceiveResponse:(NSURLResponse *)response httpVersion:(NSString *)httpVersion{ + self.requestMetrics.responseStartDate = [NSDate date]; + if ([httpVersion isEqualToString:@"http/1.0"]) { + self.requestMetrics.httpVersion = @"1.0"; + } else if ([httpVersion isEqualToString:@"http/1.1"]) { + self.requestMetrics.httpVersion = @"1.1"; + } else if ([httpVersion isEqualToString:@"h2"]) { + self.requestMetrics.httpVersion = @"2"; + } else if ([httpVersion isEqualToString:@"h3"]) { + self.requestMetrics.httpVersion = @"3"; + } else { + self.requestMetrics.httpVersion = httpVersion; + } + self.response = response; +} + +- (void)redirectedToRequest:(nonnull NSURLRequest *)request redirectResponse:(nonnull NSURLResponse *)redirectResponse { + if (self.redirectCount < self.maxRedirectCount) { + self.redirectCount += 1; + [self request:request server:nil connectionProxy:self.connectionProxy progress:self.progress complete:self.complete]; + } else { + [self didFinish]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h new file mode 100644 index 0000000..1516c58 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h @@ -0,0 +1,43 @@ +// +// QNHttpClient.h +// AppTest +// +// Created by yangsen on 2020/4/7. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol QNCFHttpClientInnerDelegate + +- (void)redirectedToRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse; + +- (void)onError:(NSError *)error; + +- (void)didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend; + +- (void)onReceiveResponse:(NSURLResponse *)response httpVersion:(NSString *)httpVersion; + +- (void)didLoadData:(NSData *)data; + +- (void)didFinish; + +@end + +@interface QNCFHttpClientInner : NSOperation + +@property(nonatomic, strong, readonly)NSMutableURLRequest *request; +@property(nonatomic, strong, readonly)NSDictionary *connectionProxy; + +@property(nonatomic, weak)id delegate; + ++ (instancetype)client:(NSURLRequest *)request connectionProxy:(NSDictionary *)connectionProxy; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.m b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.m new file mode 100644 index 0000000..8a110f4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.m @@ -0,0 +1,864 @@ +// +// QNHttpClient.m +// AppTest +// +// Created by yangsen on 2020/4/7. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNErrorCode.h" +#import "QNDefine.h" +#import "QNCFHttpClientInner.h" +#import "NSURLRequest+QNRequest.h" +#import + +#define kQNCFHttpClientErrorDomain @"CFNetwork" + +@interface QNCFHttpClientInner() + +@property(nonatomic, assign)BOOL isCallFinishOrError; +@property(nonatomic, assign)BOOL isCompleted; +@property(nonatomic, strong)NSMutableURLRequest *request; +@property(nonatomic, strong)NSDictionary *connectionProxy; +@property(nonatomic, assign)BOOL isReadResponseHeader; +@property(nonatomic, assign)BOOL isReadResponseBody; +@property(nonatomic, assign)BOOL isInputStreamEvaluated; +@property(nonatomic, strong)NSInputStream *inputStream; + +// 上传进度 +@property(nonatomic, strong)NSTimer *progressTimer; // 进度定时器 +@property(nonatomic, assign)int64_t totalBytesSent; // 已上传大小 +@property(nonatomic, assign)int64_t totalBytesExpectedToSend; // 总大小 + +@end +@implementation QNCFHttpClientInner + ++ (instancetype)client:(NSURLRequest *)request connectionProxy:(nonnull NSDictionary *)connectionProxy{ + if (!request) { + return nil; + } + QNCFHttpClientInner *client = [[QNCFHttpClientInner alloc] init]; + client.connectionProxy = connectionProxy; + client.request = [request mutableCopy]; + client.isCompleted = false; + return client; +} + +- (void)main { + [self prepare]; + [self openInputStream]; + [self startProgress]; +} + +- (void)prepare { + @autoreleasepool { + self.inputStream = [self createInputStream:self.request]; + } + + NSString *host = [self.request qn_domain]; + if ([self.request qn_isHttps]) { + [self setInputStreamSNI:self.inputStream sni:host]; + } + + [self setupProgress]; +} + +- (void)releaseResource{ + [self endProgress:YES]; + [self closeInputStream]; +} + +- (void)cancel { + [self releaseResource]; + [self delegate_onError:[self createError:NSURLErrorCancelled errorDescription:@"user cancel"]]; +} + +//MARK: -- request -> stream +- (NSInputStream *)createInputStream:(NSURLRequest *)urlRequest{ + + CFReadStreamRef readStream = NULL; + @autoreleasepool { + CFStringRef urlString = (__bridge CFStringRef) [urlRequest.URL absoluteString]; + CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, + urlString, + NULL); + CFStringRef httpMethod = (__bridge CFStringRef) urlRequest.HTTPMethod; + CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, + httpMethod, + url, + kCFHTTPVersion1_1); + CFRelease(url); + + NSDictionary *headFieldInfo = self.request.qn_allHTTPHeaderFields; + for (NSString *headerField in headFieldInfo) { + CFStringRef headerFieldP = (__bridge CFStringRef)headerField; + CFStringRef headerFieldValueP = (__bridge CFStringRef)(headFieldInfo[headerField]); + CFHTTPMessageSetHeaderFieldValue(request, headerFieldP, headerFieldValueP); + } + + NSData *httpBody = [self.request qn_getHttpBody]; + if (httpBody) { + CFDataRef bodyData = (__bridge CFDataRef) httpBody; + CFHTTPMessageSetBody(request, bodyData); + } + + readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request); + CFRelease(request); + } + + @autoreleasepool { + if (self.connectionProxy) { + for (NSString *key in self.connectionProxy.allKeys) { + NSObject *value = self.connectionProxy[key]; + if (key.length > 0) { + CFReadStreamSetProperty(readStream, (__bridge CFTypeRef _Null_unspecified)key, (__bridge CFTypeRef _Null_unspecified)(value)); + } + } + } + } + return (__bridge_transfer NSInputStream *) readStream; +} + +- (void)setInputStreamSNI:(NSInputStream *)inputStream sni:(NSString *)sni{ + if (!sni || sni.length == 0) { + return; + } + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings setObject:NSStreamSocketSecurityLevelNegotiatedSSL + forKey:NSStreamSocketSecurityLevelKey]; + [settings setObject:sni + forKey:(NSString *)kCFStreamSSLPeerName]; + [inputStream setProperty:settings forKey:(NSString *)CFBridgingRelease(kCFStreamPropertySSLSettings)]; +} + + +//MARK: -- stream action +- (void)openInputStream{ + [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + self.inputStream.delegate = self; + [self.inputStream open]; +} + +- (void)closeInputStream { + @synchronized (self) { + if (self.inputStream) { + [self.inputStream close]; + [self.inputStream setDelegate:nil]; + [self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + self.inputStream = nil; + } + } +} + +- (BOOL)shouldEvaluateInputStreamServerTrust{ + if (![self.request qn_isHttps] || self.isInputStreamEvaluated) { + return NO; + } else { + return YES; + } +} + +- (void)inputStreamGetAndNotifyHttpResponse{ + @synchronized (self) { + if (self.isReadResponseHeader) { + return; + } + self.isReadResponseHeader = YES; + } + + + CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream; + CFHTTPMessageRef httpMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); + + CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(httpMessage); + NSDictionary *headInfo = (__bridge_transfer NSDictionary *)headerFields; + + CFStringRef httpVersion = CFHTTPMessageCopyVersion(httpMessage); + NSString *httpVersionInfo = (__bridge_transfer NSString *)httpVersion; + + CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(httpMessage); + + if (![self isHttpRedirectStatusCode:statusCode]) { + NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:statusCode HTTPVersion:httpVersionInfo headerFields:headInfo]; + [self delegate_onReceiveResponse:response httpVersion:httpVersionInfo]; + } + + CFRelease(httpMessage); +} + +- (void)inputStreamGetAndNotifyHttpData{ + @synchronized (self) { + if (self.isReadResponseBody) { + return; + } + self.isReadResponseBody = YES; + } + + UInt8 buffer[16 * 1024]; + UInt8 *buf = NULL; + NSUInteger length = 0; + + if (![self.inputStream getBuffer:&buf length:&length]) { + NSInteger amount = [self.inputStream read:buffer maxLength:sizeof(buffer)]; + buf = buffer; + length = amount; + } + + NSData *data = [[NSData alloc] initWithBytes:buf length:length]; + [self delegate_didLoadData:data]; +} + +- (BOOL)isInputStreamHttpResponseHeaderComplete{ + CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream; + CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); + BOOL isComplete = CFHTTPMessageIsHeaderComplete(responseMessage); + CFRelease(responseMessage); + return isComplete; +} + +- (BOOL)shouldInputStreamRedirect{ + CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream; + CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); + CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(responseMessage); + CFRelease(responseMessage); + return [self isHttpRedirectStatusCode:statusCode]; +} + +- (BOOL)isHttpRedirectStatusCode:(NSInteger)code{ + if (code == 301 || code == 302 || code == 303 || code == 307) { + return YES; + } else { + return NO; + } +} + +- (void)inputStreamRedirect{ + CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream; + CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); + + CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(responseMessage); + NSDictionary *headInfo = (__bridge_transfer NSDictionary *)headerFields; + + NSString *urlString = headInfo[@"Location"]; + if (!urlString) { + urlString = headInfo[@"location"]; + } + if (!urlString) { + return; + } + + CFStringRef httpVersion = CFHTTPMessageCopyVersion(responseMessage); + NSString *httpVersionString = (__bridge_transfer NSString *)httpVersion; + + CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(responseMessage); + + NSDictionary *requestHeader = self.request.allHTTPHeaderFields; + if (statusCode == 303) { + NSMutableDictionary *header = [NSMutableDictionary dictionary]; + if (requestHeader[@"User-Agent"]) { + header[@"User-Agent"] = requestHeader[@"User-Agent"]; + } + if (requestHeader[@"Accept"]) { + header[@"Accept"] = requestHeader[@"Accept"]; + } + requestHeader = [header copy]; + } + + NSURL *url = [NSURL URLWithString:urlString]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.HTTPMethod = @"GET"; + [request setAllHTTPHeaderFields:requestHeader]; + NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL + statusCode:statusCode + HTTPVersion:httpVersionString + headerFields:headInfo]; + + [self releaseResource]; + [self delegate_redirectedToRequest:request redirectResponse:response]; + + CFRelease(responseMessage); +} + +//MARK: -- NSStreamDelegate +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{ + @autoreleasepool { + switch (eventCode) { + case NSStreamEventHasBytesAvailable:{ + if (![self isInputStreamHttpResponseHeaderComplete]) { + break; + } + + [self inputStreamGetAndNotifyHttpResponse]; + [self inputStreamGetAndNotifyHttpData]; + } + break; + case NSStreamEventHasSpaceAvailable: + break; + case NSStreamEventErrorOccurred:{ + [self releaseResource]; + [self endProgress: YES]; + [self delegate_onError:[self translateCFNetworkErrorIntoUrlError:[aStream streamError]]]; + } + break; + case NSStreamEventEndEncountered:{ + if ([self shouldInputStreamRedirect]) { + [self inputStreamRedirect]; + } else { + + [self inputStreamGetAndNotifyHttpResponse]; + [self inputStreamGetAndNotifyHttpData]; + + [self releaseResource]; + [self endProgress: NO]; + [self delegate_didFinish]; + } + } + break; + default: + break; + } + } +} + +//MARK: -- progress and timer action +- (void)setupProgress{ + self.totalBytesExpectedToSend = [self.request.qn_getHttpBody length]; +} + +- (void)startProgress{ + [self createTimer]; +} + +- (void)endProgress:(BOOL)hasError{ + + [self invalidateTimer]; + + if (!hasError) { + [self delegate_didSendBodyData:self.totalBytesExpectedToSend - self.totalBytesSent + totalBytesSent:self.totalBytesExpectedToSend + totalBytesExpectedToSend:self.totalBytesExpectedToSend]; + } +} + +- (void)createTimer{ + + if (_progressTimer) { + [self invalidateTimer]; + } + + kQNWeakSelf; + NSTimer *timer = [NSTimer timerWithTimeInterval:0.3 + target:weak_self + selector:@selector(timerAction) + userInfo:nil + repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + + [self timerAction]; + _progressTimer = timer; +} + +- (void)invalidateTimer{ + [self.progressTimer invalidate]; + self.progressTimer = nil; +} + +- (void)timerAction{ + long long totalBytesSent = [(NSNumber *)CFBridgingRelease(CFReadStreamCopyProperty((CFReadStreamRef)[self inputStream], kCFStreamPropertyHTTPRequestBytesWrittenCount)) longLongValue]; + long long bytesSent = totalBytesSent - self.totalBytesSent; + self.totalBytesSent = totalBytesSent; + if (bytesSent > 0 && self.totalBytesSent <= self.totalBytesSent) { + [self delegate_didSendBodyData:bytesSent + totalBytesSent:self.totalBytesSent + totalBytesExpectedToSend:self.totalBytesExpectedToSend]; + } +} + +- (NSError *)translateCFNetworkErrorIntoUrlError:(NSError *)cfError{ + if (cfError == nil) { + return nil; + } + + NSInteger errorCode = kQNNetworkError; + NSString *errorInfo = [NSString stringWithFormat:@"cf client:[%ld] %@", (long)cfError.code, cfError.localizedDescription]; + switch (cfError.code) { + case ENOENT: /* No such file or directory */ + errorCode = NSFileNoSuchFileError; + break; + case EIO: /* Input/output error */ + errorCode = kQNLocalIOError; + break; + case E2BIG: /* Argument list too long */ + break; + case ENOEXEC: /* Exec format error */ + errorCode = kQNLocalIOError; + break; + case EBADF: /* Bad file descriptor */ + errorCode = kQNLocalIOError; + break; + case ECHILD: /* No child processes */ + errorCode = kQNUnexpectedSysCallError; + break; + case EDEADLK: /* Resource deadlock avoided */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENOMEM: /* Cannot allocate memory */ + errorCode = kQNUnexpectedSysCallError; + break; + case EACCES: /* Permission denied */ + errorCode = NSURLErrorNoPermissionsToReadFile; + break; + case EFAULT: /* Bad address */ + errorCode = NSURLErrorBadURL; + break; + case EBUSY: /* Device / Resource busy */ + errorCode = kQNUnexpectedSysCallError; + break; + case EEXIST: /* File exists */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENODEV: /* Operation not supported by device */ + errorCode = kQNUnexpectedSysCallError; + break; + case EISDIR: /* Is a directory */ + errorCode = NSURLErrorFileIsDirectory; + break; + case ENOTDIR: /* Not a directory */ + errorCode = kQNUnexpectedSysCallError; + break; + case EINVAL: /* Invalid argument */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENFILE: /* Too many open files in system */ + errorCode = kQNUnexpectedSysCallError; + break; + case EMFILE: /* Too many open files */ + errorCode = kQNUnexpectedSysCallError; + break; + case EFBIG: /* File too large */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENOSPC: /* No space left on device */ + errorCode = kQNUnexpectedSysCallError; + break; + case ESPIPE: /* Illegal seek */ + errorCode = kQNUnexpectedSysCallError; + break; + case EMLINK: /* Too many links */ + errorCode = kQNUnexpectedSysCallError; + break; + case EPIPE: /* Broken pipe */ + errorCode = kQNUnexpectedSysCallError; + break; + case EDOM: /* Numerical argument out of domain */ + errorCode = kQNUnexpectedSysCallError; + break; + case ERANGE: /* Result too large */ + errorCode = kQNUnexpectedSysCallError; + break; + case EAGAIN: /* Resource temporarily unavailable */ + break; + case ENOTSOCK: /* Socket operation on non-socket */ + break; + case EDESTADDRREQ: /* Destination address required */ + errorCode = NSURLErrorBadURL; + break; + case EMSGSIZE: /* Message too long */ + break; + case EPROTOTYPE: /* Protocol wrong type for socket */ + break; + case ENOPROTOOPT: /* Protocol not available */ + break; + case EPROTONOSUPPORT: /* Protocol not supported */ + break; + case ENOTSUP: /* Operation not supported */ + break; + case EPFNOSUPPORT: /* Protocol family not supported */ + break; + case EAFNOSUPPORT: /* Address family not supported by protocol family */ + break; + case EADDRINUSE: /* Address already in use */ + break; + case EADDRNOTAVAIL: /* Can't assign requested address */ + break; + case ENETDOWN: /* Network is down */ + errorCode = NSURLErrorCannotConnectToHost; + break; + case ENETUNREACH: /* Network is unreachable */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case ENETRESET: /* Network dropped connection on reset */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case ECONNABORTED: /* Software caused connection abort */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case ECONNRESET: /* Connection reset by peer */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case ENOBUFS: /* No buffer space available */ + errorCode = kQNUnexpectedSysCallError; + break; + case EISCONN: /* Socket is already connected */ + break; + case ENOTCONN: /* Socket is not connected */ + errorCode = NSURLErrorCannotConnectToHost; + break; + case ESHUTDOWN: /* Can't send after socket shutdown */ + break; + case ETOOMANYREFS: /* Too many references: can't splice */ + break; + case ETIMEDOUT: /* Operation timed out */ + errorCode = NSURLErrorTimedOut; + break; + case ECONNREFUSED: /* Connection refused */ + errorCode = NSURLErrorCannotConnectToHost; + break; + case ELOOP: /* Too many levels of symbolic links */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENAMETOOLONG: /* File name too long */ + break; + case EHOSTDOWN: /* Host is down */ + break; + case EHOSTUNREACH: /* No route to host */ + break; + case ENOTEMPTY: /* Directory not empty */ + break; + case EPROCLIM: /* Too many processes */ + errorCode = kQNUnexpectedSysCallError; + break; + case EUSERS: /* Too many users */ + errorCode = kQNUnexpectedSysCallError; + break; + case EDQUOT: /* Disc quota exceeded */ + errorCode = kQNUnexpectedSysCallError; + break; + case ESTALE: /* Stale NFS file handle */ + errorCode = kQNUnexpectedSysCallError; + break; + case EREMOTE: /* Too many levels of remote in path */ + break; + case EBADRPC: /* RPC struct is bad */ + errorCode = kQNUnexpectedSysCallError; + break; + case ERPCMISMATCH: /* RPC version wrong */ + errorCode = kQNUnexpectedSysCallError; + break; + case EPROGUNAVAIL: /* RPC prog. not avail */ + errorCode = kQNUnexpectedSysCallError; + break; + case EPROGMISMATCH: /* Program version wrong */ + errorCode = kQNUnexpectedSysCallError; + break; + case EPROCUNAVAIL: /* Bad procedure for program */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENOLCK: /* No locks available */ + errorCode = kQNUnexpectedSysCallError; + break; + case ENOSYS: /* Function not implemented */ + errorCode = kQNUnexpectedSysCallError; + break; + case EFTYPE: /* Inappropriate file type or format */ + break; + case EAUTH: /* Authentication error */ + break; + case ENEEDAUTH: /* Need authenticator */ + break; + case EPWROFF: /* Device power is off */ + errorCode = kQNUnexpectedSysCallError; + break; + case EDEVERR: /* Device error, e.g. paper out */ + errorCode = kQNUnexpectedSysCallError; + break; + case EOVERFLOW: /* Value too large to be stored in data type */ + errorCode = kQNUnexpectedSysCallError; + break; + case EBADEXEC: /* Bad executable */ + errorCode = kQNUnexpectedSysCallError; + break; + case EBADARCH: /* Bad CPU type in executable */ + errorCode = kQNUnexpectedSysCallError; + break; + case ESHLIBVERS: /* Shared library version mismatch */ + errorCode = kQNUnexpectedSysCallError; + break; + case EBADMACHO: /* Malformed Macho file */ + errorCode = kQNUnexpectedSysCallError; + break; + case ECANCELED: /* Operation canceled */ + errorCode = NSURLErrorCancelled; + break; + case EIDRM: /* Identifier removed */ + break; + case ENOMSG: /* No message of desired type */ + break; + case EILSEQ: /* Illegal byte sequence */ + break; + case ENOATTR: /* Attribute not found */ + break; + case EBADMSG: /* Bad message */ + break; + case EMULTIHOP: /* Reserved */ + break; + case ENODATA: /* No message available on STREAM */ + break; + case ENOLINK: /* Reserved */ + break; + case ENOSR: /* No STREAM resources */ + break; + case ENOSTR: /* Not a STREAM */ + break; + case EPROTO: /* Protocol error */ + break; + case ETIME: /* STREAM ioctl timeout */ + errorCode = NSURLErrorTimedOut; + break; + case EOPNOTSUPP: /* Operation not supported on socket */ + break; + case ENOPOLICY: /* No such policy registered */ + break; + case ENOTRECOVERABLE: /* State not recoverable */ + break; + case EOWNERDEAD: /* Previous owner died */ + errorCode = kQNUnexpectedSysCallError; + break; + case EQFULL: /* Interface output queue is full */ + break; + case -9800: /* SSL protocol error */ + errorCode = NSURLErrorSecureConnectionFailed; + break; + case -9801: /* Cipher Suite negotiation failure */ + errorCode = NSURLErrorSecureConnectionFailed; + break; + case -9802: /* Fatal alert */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9803: /* I/O would block (not fatal) */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9804: /* attempt to restore an unknown session */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9805: /* connection closed gracefully */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case -9806: /* connection closed via error */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case -9807: /* invalid certificate chain */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9808: /* bad certificate format */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9809: /* underlying cryptographic error */ + errorCode = NSURLErrorSecureConnectionFailed; + break; + case -9810: /* Internal error */ + errorCode = NSURLErrorNotConnectedToInternet; + break; + case -9811: /* module attach failure */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9812: /* valid cert chain, untrusted root */ + errorCode = NSURLErrorServerCertificateHasUnknownRoot; + break; + case -9813: /* cert chain not verified by root */ + errorCode = NSURLErrorServerCertificateHasUnknownRoot; + break; + case -9814: /* chain had an expired cert */ + errorCode = NSURLErrorServerCertificateHasBadDate; + break; + case -9815: /* chain had a cert not yet valid */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9816: /* server closed session with no notification */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case -9817: /* insufficient buffer provided */ + errorCode = NSURLErrorCannotDecodeRawData; + break; + case -9818: /* bad SSLCipherSuite */ + errorCode = NSURLErrorClientCertificateRejected; + break; + case -9819: /* unexpected message received */ + errorCode = NSURLErrorNotConnectedToInternet; + break; + case -9820: /* bad MAC */ + errorCode = NSURLErrorNotConnectedToInternet; + break; + case -9821: /* decryption failed */ + errorCode = NSURLErrorNotConnectedToInternet; + break; + case -9822: /* record overflow */ + errorCode = NSURLErrorDataLengthExceedsMaximum; + break; + case -9823: /* decompression failure */ + errorCode = NSURLErrorDownloadDecodingFailedMidStream; + break; + case -9824: /* handshake failure */ + errorCode = NSURLErrorClientCertificateRejected; + break; + case -9825: /* misc. bad certificate */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9826: /* bad unsupported cert format */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9827: /* certificate revoked */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9828: /* certificate expired */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9829: /* unknown certificate */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9830: /* illegal parameter */ + errorCode = NSURLErrorCannotDecodeRawData; + break; + case -9831: /* unknown Cert Authority */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9832: /* access denied */ + errorCode = NSURLErrorClientCertificateRejected; + break; + case -9833: /* decoding error */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9834: /* decryption error */ + errorCode = NSURLErrorCannotDecodeRawData; + break; + case -9835: /* export restriction */ + errorCode = NSURLErrorCannotConnectToHost; + break; + case -9836: /* bad protocol version */ + errorCode = NSURLErrorCannotConnectToHost; + break; + case -9837: /* insufficient security */ + errorCode = NSURLErrorClientCertificateRejected; + break; + case -9838: /* internal error */ + errorCode = NSURLErrorTimedOut; + break; + case -9839: /* user canceled */ + errorCode = NSURLErrorCancelled; + break; + case -9840: /* no renegotiation allowed */ + errorCode = NSURLErrorCannotConnectToHost; + break; + case -9841: /* peer cert is valid, or was ignored if verification disabled */ + errorCode = NSURLErrorServerCertificateNotYetValid; + break; + case -9842: /* server has requested a client cert */ + errorCode = NSURLErrorClientCertificateRejected; + break; + case -9843: /* peer host name mismatch */ + errorCode = NSURLErrorNotConnectedToInternet; + break; + case -9844: /* peer dropped connection before responding */ + errorCode = NSURLErrorNetworkConnectionLost; + break; + case -9845: /* decryption failure */ + errorCode = NSURLErrorCannotDecodeRawData; + break; + case -9846: /* bad MAC */ + errorCode = NSURLErrorNotConnectedToInternet; + break; + case -9847: /* record overflow */ + errorCode = NSURLErrorDataLengthExceedsMaximum; + break; + case -9848: /* configuration error */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9849: /* unexpected (skipped) record in DTLS */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9850: /* weak ephemeral dh key */ + errorCode = kQNUnexpectedSysCallError; + break; + case -9851: /* SNI */ + errorCode = NSURLErrorClientCertificateRejected; + break; + default: + break; + } + + return [NSError errorWithDomain:NSURLErrorDomain code:errorCode userInfo:@{@"UserInfo" : errorInfo ?: @""}]; +} + + +//MARK: -- delegate action +- (void)delegate_redirectedToRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse{ + if ([self.delegate respondsToSelector:@selector(redirectedToRequest:redirectResponse:)]) { + [self.delegate redirectedToRequest:request redirectResponse:redirectResponse]; + } +} + +- (void)delegate_onError:(NSError *)error{ + @synchronized (self) { + if (self.isCallFinishOrError) { + return; + } + self.isCallFinishOrError = YES; + } + + if ([self.delegate respondsToSelector:@selector(onError:)]) { + [self.delegate onError:error]; + } +} + +- (void)delegate_didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{ + if ([self.delegate respondsToSelector:@selector(didSendBodyData: + totalBytesSent: + totalBytesExpectedToSend:)]) { + [self.delegate didSendBodyData:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend]; + } +} +- (void)delegate_onReceiveResponse:(NSURLResponse *)response httpVersion:(NSString *)httpVersion{ + if ([self.delegate respondsToSelector:@selector(onReceiveResponse:httpVersion:)]) { + [self.delegate onReceiveResponse:response httpVersion:httpVersion]; + } +} + +- (void)delegate_didLoadData:(NSData *)data{ + if ([self.delegate respondsToSelector:@selector(didLoadData:)]) { + [self.delegate didLoadData:data]; + } +} + +- (void)delegate_didFinish{ + @synchronized (self) { + if (self.isCallFinishOrError) { + return; + } + self.isCallFinishOrError = YES; + } + + if ([self.delegate respondsToSelector:@selector(didFinish)]) { + [self.delegate didFinish]; + } +} + + +// MARK: error +- (NSError *)createError:(NSInteger)errorCode errorDescription:(NSString *)errorDescription { + if (errorDescription) { + return [NSError errorWithDomain:kQNCFHttpClientErrorDomain + code:errorCode + userInfo:@{@"userInfo":errorDescription}]; + } else { + return [NSError errorWithDomain:kQNCFHttpClientErrorDomain + code:NSURLErrorSecureConnectionFailed + userInfo:nil]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h new file mode 100644 index 0000000..bdae309 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h @@ -0,0 +1,31 @@ +// +// QNCFHttpThreadPool.h +// Qiniu +// +// Created by yangsen on 2021/10/13. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNCFHttpThread : NSThread + +@property(nonatomic, assign, readonly)NSInteger operationCount; + +@end + + +@interface QNCFHttpThreadPool : NSObject + +@property(nonatomic, assign, readonly)NSInteger maxOperationPerThread; + ++ (instancetype)shared; + +- (QNCFHttpThread *)getOneThread; +- (void)addOperationCountOfThread:(QNCFHttpThread *)thread; +- (void)subtractOperationCountOfThread:(QNCFHttpThread *)thread; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.m b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.m new file mode 100644 index 0000000..615548c --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.m @@ -0,0 +1,128 @@ +// +// QNCFHttpThreadPool.m +// Qiniu +// +// Created by yangsen on 2021/10/13. +// + +#import "QNCFHttpThreadPool.h" +#import "QNTransactionManager.h" + +@interface QNCFHttpThread() +@property(nonatomic, assign)BOOL isCompleted; +@property(nonatomic, assign)NSInteger operationCount; +@property(nonatomic, strong)NSDate *deadline; +@end +@implementation QNCFHttpThread ++ (instancetype)thread { + return [[QNCFHttpThread alloc] init];; +} + +- (instancetype)init { + if (self = [super init]) { + self.isCompleted = NO; + self.operationCount = 0; + } + return self; +} + +- (void)main { + @autoreleasepool { + [super main]; + + while (!self.isCompleted) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; + } + } +} + +- (void)cancel { + self.isCompleted = YES; +} + +@end + +@interface QNCFHttpThreadPool() +// 单位:秒 +@property(nonatomic, assign)NSInteger threadLiveTime; +@property(nonatomic, assign)NSInteger maxOperationPerThread; +@property(nonatomic, strong)NSMutableArray *pool; +@end +@implementation QNCFHttpThreadPool + ++ (instancetype)shared { + static QNCFHttpThreadPool *pool = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + pool = [[QNCFHttpThreadPool alloc] init]; + pool.threadLiveTime = 60; + pool.maxOperationPerThread = 1; + pool.pool = [NSMutableArray array]; + [pool addThreadLiveChecker]; + }); + return pool; +} + +- (void)addThreadLiveChecker { + QNTransaction *transaction = [QNTransaction timeTransaction:@"CFHttpThreadPool" after:0 interval:1 action:^{ + [[QNCFHttpThreadPool shared] checkThreadLive]; + }]; + [kQNTransactionManager addTransaction:transaction]; +} + +- (void)checkThreadLive { + @synchronized (self) { + NSArray *pool = [self.pool copy]; + for (QNCFHttpThread *thread in pool) { + if (thread.operationCount < 1 && thread.deadline && [thread.deadline timeIntervalSinceNow] < 0) { + [self.pool removeObject:thread]; + [thread cancel]; + } + } + } +} + +- (QNCFHttpThread *)getOneThread { + QNCFHttpThread *thread = nil; + @synchronized (self) { + for (QNCFHttpThread *t in self.pool) { + if (t.operationCount < self.maxOperationPerThread) { + thread = t; + break; + } + } + if (thread == nil) { + thread = [QNCFHttpThread thread]; + thread.name = [NSString stringWithFormat:@"com.qiniu.cfclient.%lu", (unsigned long)self.pool.count]; + [thread start]; + [self.pool addObject:thread]; + } + thread.operationCount += 1; + thread.deadline = nil; + } + return thread; +} + +- (void)addOperationCountOfThread:(QNCFHttpThread *)thread { + if (thread == nil) { + return; + } + @synchronized (self) { + thread.operationCount += 1; + thread.deadline = nil; + } +} + +- (void)subtractOperationCountOfThread:(QNCFHttpThread *)thread { + if (thread == nil) { + return; + } + @synchronized (self) { + thread.operationCount -= 1; + if (thread.operationCount < 1) { + thread.deadline = [NSDate dateWithTimeIntervalSinceNow:self.threadLiveTime]; + } + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.h b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.h new file mode 100644 index 0000000..35fb4c4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.h @@ -0,0 +1,17 @@ +// +// QNUploadSystemClient.h +// QiniuSDK_Mac +// +// Created by yangsen on 2020/5/6. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNRequestClient.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadSystemClient : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.m b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.m new file mode 100644 index 0000000..6582a04 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/HttpClient/QNUploadSystemClient.m @@ -0,0 +1,202 @@ +// +// QNUploadSystemClient.m +// QiniuSDK_Mac +// +// Created by yangsen on 2020/5/6. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUploadSystemClient.h" +#import "QNUserAgent.h" +#import "NSURLRequest+QNRequest.h" + +@interface QNUploadSystemClient() + +@property(nonatomic, strong)NSURLRequest *request; +@property(nonatomic, strong)QNUploadSingleRequestMetrics *requestMetrics; +@property(nonatomic, strong)NSURLSessionDataTask *uploadTask; +@property(nonatomic, strong)NSMutableData *responseData; +@property(nonatomic, copy)void(^progress)(long long totalBytesWritten, long long totalBytesExpectedToWrite); +@property(nonatomic, copy)QNRequestClientCompleteHandler complete; + +@end +@implementation QNUploadSystemClient + +- (NSString *)clientId { + return @"NSURLSession"; +} + +- (void)request:(NSURLRequest *)request + server:(id )server +connectionProxy:(NSDictionary *)connectionProxy + progress:(void (^)(long long, long long))progress + complete:(QNRequestClientCompleteHandler)complete { + + // 非 https 方可使用 IP + if (!request.qn_isHttps && server && server.ip.length > 0 && server.host.length > 0) { + NSString *urlString = request.URL.absoluteString; + urlString = [urlString stringByReplacingOccurrencesOfString:server.host withString:server.ip]; + NSMutableURLRequest *requestNew = [request mutableCopy]; + requestNew.URL = [NSURL URLWithString:urlString]; + requestNew.qn_domain = server.host; + self.request = [requestNew copy]; + } else { + self.request = request; + } + + self.requestMetrics = [QNUploadSingleRequestMetrics emptyMetrics]; + self.requestMetrics.remoteAddress = self.request.qn_isHttps ? nil : server.ip; + self.requestMetrics.remotePort = self.request.qn_isHttps ? @443 : @80; + [self.requestMetrics start]; + + self.responseData = [NSMutableData data]; + self.progress = progress; + self.complete = complete; + + NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + if (connectionProxy) { + configuration.connectionProxyDictionary = connectionProxy; + } + NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration + delegate:self + delegateQueue:nil]; + NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:self.request]; + [uploadTask resume]; + + self.uploadTask = uploadTask; +} + +- (void)cancel{ + [self.uploadTask cancel]; +} + +//MARK:-- NSURLSessionDelegate +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + [self.responseData appendData:data]; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error { + [self.requestMetrics end]; + self.requestMetrics.request = task.currentRequest; + self.requestMetrics.response = task.response; + self.requestMetrics.error = error; + self.complete(task.response, self.requestMetrics,self.responseData, error); + + [session finishTasksAndInvalidate]; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(ios(10.0)) { + NSURLSessionTaskTransactionMetrics *transactionMetrics = metrics.transactionMetrics.lastObject; + + self.requestMetrics.domainLookupStartDate = transactionMetrics.domainLookupStartDate; + self.requestMetrics.domainLookupEndDate = transactionMetrics.domainLookupEndDate; + self.requestMetrics.connectStartDate = transactionMetrics.connectStartDate; + self.requestMetrics.secureConnectionStartDate = transactionMetrics.secureConnectionStartDate; + self.requestMetrics.secureConnectionEndDate = transactionMetrics.secureConnectionEndDate; + self.requestMetrics.connectEndDate = transactionMetrics.connectEndDate; + + self.requestMetrics.requestStartDate = transactionMetrics.requestStartDate; + self.requestMetrics.requestEndDate = transactionMetrics.requestEndDate; + self.requestMetrics.responseStartDate = transactionMetrics.responseStartDate; + self.requestMetrics.responseEndDate = transactionMetrics.responseEndDate; + + if ([transactionMetrics.networkProtocolName isEqualToString:@"http/1.0"]) { + self.requestMetrics.httpVersion = @"1.0"; + } else if ([transactionMetrics.networkProtocolName isEqualToString:@"http/1.1"]) { + self.requestMetrics.httpVersion = @"1.1"; + } else if ([transactionMetrics.networkProtocolName isEqualToString:@"h2"]) { + self.requestMetrics.httpVersion = @"2"; + } else if ([transactionMetrics.networkProtocolName isEqualToString:@"h3"]) { + self.requestMetrics.httpVersion = @"3"; + } else { + self.requestMetrics.httpVersion = transactionMetrics.networkProtocolName; + } + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + if (@available(iOS 13.0, macOS 10.15, *)) { + if (transactionMetrics.remoteAddress) { + self.requestMetrics.remoteAddress = transactionMetrics.remoteAddress; + self.requestMetrics.remotePort = transactionMetrics.remotePort; + } + if (transactionMetrics.countOfRequestHeaderBytesSent > 0) { + self.requestMetrics.countOfRequestHeaderBytesSent = transactionMetrics.countOfRequestHeaderBytesSent; + } + if (transactionMetrics.countOfResponseHeaderBytesReceived > 0) { + self.requestMetrics.countOfResponseHeaderBytesReceived = transactionMetrics.countOfResponseHeaderBytesReceived; + } + if (transactionMetrics.countOfResponseBodyBytesReceived > 0) { + self.requestMetrics.countOfResponseBodyBytesReceived = transactionMetrics.countOfResponseBodyBytesReceived; + } + } +#endif + +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + + self.requestMetrics.countOfRequestBodyBytesSent = totalBytesSent; + if (self.progress) { + self.progress(totalBytesSent, totalBytesExpectedToSend); + } +} + +/* +- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust + forDomain:(NSString *)domain { + + NSMutableArray *policies = [NSMutableArray array]; + if (domain) { + [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; + } else { + [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()]; + } + + SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); + + if (@available(iOS 13.0, macOS 10.14, *)) { + CFErrorRef error = NULL; + BOOL ret = SecTrustEvaluateWithError(serverTrust, &error); + return ret && (error == nil); + } else { + SecTrustResultType result; + SecTrustEvaluate(serverTrust, &result); + return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler { + if (!challenge) { + return; + } + NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; + NSURLCredential *credential = nil; + + NSString* host = [[self.request allHTTPHeaderFields] objectForKey:@"host"]; + if (!host) { + host = self.request.URL.host; + } + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) { + disposition = NSURLSessionAuthChallengeUseCredential; + credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + } else { + disposition = NSURLSessionAuthChallengePerformDefaultHandling; + } + } else { + disposition = NSURLSessionAuthChallengePerformDefaultHandling; + } + + completionHandler(disposition,credential); +} +*/ +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.h new file mode 100644 index 0000000..48f2c57 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.h @@ -0,0 +1,56 @@ +// +// QNHttpRequest.h +// QiniuSDK +// +// Created by yangsen on 2020/4/29. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +#import "QNHttpSingleRequest.h" +#import "QNUploadRegionInfo.h" + +NS_ASSUME_NONNULL_BEGIN + + +@class QNUploadRequestState, QNResponseInfo, QNConfiguration, QNUploadOption, QNUpToken, QNUploadRegionRequestMetrics; + +typedef void(^QNRegionRequestCompleteHandler)(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response); + +@interface QNHttpRegionRequest : NSObject + +@property(nonatomic, strong, readonly)QNConfiguration *config; +@property(nonatomic, strong, readonly)QNUploadOption *uploadOption; + + +- (instancetype)initWithConfig:(QNConfiguration *)config + uploadOption:(QNUploadOption *)uploadOption + token:(QNUpToken *)token + region:(id )region + requestInfo:(QNUploadRequestInfo *)requestInfo + requestState:(QNUploadRequestState *)requestState; + + +- (void)get:(NSString * _Nullable)action + headers:(NSDictionary * _Nullable)headers +shouldRetry:(BOOL(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))shouldRetry + complete:(QNRegionRequestCompleteHandler)complete; + +- (void)post:(NSString * _Nullable)action + headers:(NSDictionary * _Nullable)headers + body:(NSData * _Nullable)body + shouldRetry:(BOOL(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))shouldRetry + progress:(void(^_Nullable)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNRegionRequestCompleteHandler)complete; + + +- (void)put:(NSString *)action + headers:(NSDictionary * _Nullable)headers + body:(NSData * _Nullable)body +shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNRegionRequestCompleteHandler)complete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.m b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.m new file mode 100644 index 0000000..fee44fb --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpRegionRequest.m @@ -0,0 +1,216 @@ +// +// 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 "QNUrlUtils.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 currentServer; +@property(nonatomic, strong)id region; + +@end +@implementation QNHttpRegionRequest + +- (instancetype)initWithConfig:(QNConfiguration *)config + uploadOption:(QNUploadOption *)uploadOption + token:(QNUpToken *)token + region:(id )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 )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; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + NSString *urlString = [NSString stringWithFormat:@"%@%@", [QNUrlUtils setHostScheme:serverHost useHttps:self.config.useHttps], 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 * _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 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 )getNextServer:(QNResponseInfo *)responseInfo{ + + if (responseInfo.isTlsError) { + self.requestState.isUseOldServer = YES; + } + + return [self.region getNextServer:[self.requestState copy] responseInfo:responseInfo freezeServer:self.currentServer]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.h new file mode 100644 index 0000000..6d1aa00 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.h @@ -0,0 +1,42 @@ +// +// QNHttpRequest+SingleRequestRetry.h +// QiniuSDK +// +// Created by yangsen on 2020/4/29. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +#import "QNUploadRequestInfo.h" +#import "QNIUploadServer.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNUploadRequestState, QNResponseInfo, QNConfiguration, QNUploadOption, QNUpToken, QNUploadSingleRequestMetrics; + +typedef void(^QNSingleRequestCompleteHandler)(QNResponseInfo * _Nullable responseInfo, NSArray * _Nullable metrics, NSDictionary * _Nullable response); + +@interface QNHttpSingleRequest : NSObject + +- (instancetype)initWithConfig:(QNConfiguration *)config + uploadOption:(QNUploadOption *)uploadOption + token:(QNUpToken *)token + requestInfo:(QNUploadRequestInfo *)requestInfo + requestState:(QNUploadRequestState *)requestState; + + +/// 网络请求 +/// @param request 请求内容 +/// @param server server信息,目前仅用于日志统计 +/// @param shouldRetry 判断是否需要重试的block +/// @param progress 上传进度回调 +/// @param complete 上传完成回调 +- (void)request:(NSURLRequest *)request + server:(id )server + shouldRetry:(BOOL(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))shouldRetry + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNSingleRequestCompleteHandler)complete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.m b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.m new file mode 100644 index 0000000..40b5ee2 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNHttpSingleRequest.m @@ -0,0 +1,323 @@ +// +// QNHttpRequest+SingleRequestRetry.m +// QiniuSDK +// +// Created by yangsen on 2020/4/29. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNDefine.h" +#import "QNAsyncRun.h" +#import "QNVersion.h" +#import "QNUtils.h" +#import "QNLogUtil.h" +#import "QNHttpSingleRequest.h" +#import "QNConfiguration.h" +#import "QNUploadOption.h" +#import "QNUpToken.h" +#import "QNResponseInfo.h" +#import "QNNetworkStatusManager.h" +#import "QNRequestClient.h" +#import "QNUploadRequestState.h" + +#import "QNConnectChecker.h" +#import "QNDnsPrefetch.h" + +#import "QNReportItem.h" + +#import "QNCFHttpClient.h" +#import "QNUploadSystemClient.h" +#import "NSURLRequest+QNRequest.h" + + + +@interface QNHttpSingleRequest() + +@property(nonatomic, assign)int currentRetryTime; +@property(nonatomic, strong)QNConfiguration *config; +@property(nonatomic, strong)QNUploadOption *uploadOption; +@property(nonatomic, strong)QNUpToken *token; +@property(nonatomic, strong)QNUploadRequestInfo *requestInfo; +@property(nonatomic, strong)QNUploadRequestState *requestState; + +@property(nonatomic, strong)NSMutableArray *requestMetricsList; + +@property(nonatomic, strong)id client; + +@end +@implementation QNHttpSingleRequest + +- (instancetype)initWithConfig:(QNConfiguration *)config + uploadOption:(QNUploadOption *)uploadOption + token:(QNUpToken *)token + requestInfo:(QNUploadRequestInfo *)requestInfo + requestState:(QNUploadRequestState *)requestState{ + if (self = [super init]) { + _config = config; + _uploadOption = uploadOption; + _token = token; + _requestInfo = requestInfo; + _requestState = requestState; + _currentRetryTime = 0; + } + return self; +} + +- (void)request:(NSURLRequest *)request + server:(id )server + shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNSingleRequestCompleteHandler)complete{ + + _currentRetryTime = 0; + _requestMetricsList = [NSMutableArray array]; + [self retryRequest:request server:server shouldRetry:shouldRetry progress:progress complete:complete]; +} + +- (void)retryRequest:(NSURLRequest *)request + server:(id )server + shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNSingleRequestCompleteHandler)complete{ + + if (kQNIsHttp3(server.httpVersion)) { + self.client = [[QNUploadSystemClient alloc] init]; + } else { + if ([self shouldUseCFClient:request server:server]) { + self.client = [[QNCFHttpClient alloc] init]; + } else { + self.client = [[QNUploadSystemClient alloc] init]; + } + } + + kQNWeakSelf; + BOOL (^checkCancelHandler)(void) = ^{ + kQNStrongSelf; + + BOOL isCancelled = self.requestState.isUserCancel; + if (!isCancelled && self.uploadOption.cancellationSignal) { + isCancelled = self.uploadOption.cancellationSignal(); + } + return isCancelled; + }; + + QNLogInfo(@"key:%@ retry:%d url:%@", self.requestInfo.key, self.currentRetryTime, request.URL); + + [self.client request:request server:server connectionProxy:self.config.proxy progress:^(long long totalBytesWritten, long long totalBytesExpectedToWrite) { + kQNStrongSelf; + + if (progress) { + progress(totalBytesWritten, totalBytesExpectedToWrite); + } + + if (checkCancelHandler()) { + self.requestState.isUserCancel = YES; + [self.client cancel]; + } + } complete:^(NSURLResponse *response, QNUploadSingleRequestMetrics *metrics, NSData * responseData, NSError * error) { + kQNStrongSelf; + + if (metrics) { + [self.requestMetricsList addObject:metrics]; + } + + QNResponseInfo *responseInfo = nil; + if (checkCancelHandler()) { + responseInfo = [QNResponseInfo cancelResponse]; + [self reportRequest:responseInfo server:server requestMetrics:metrics]; + [self complete:responseInfo server:server response:nil requestMetrics:metrics complete:complete]; + return; + } + + NSDictionary *responseDic = nil; + if (responseData) { + responseDic = [NSJSONSerialization JSONObjectWithData:responseData + options:NSJSONReadingMutableLeaves + error:nil]; + } + + responseInfo = [[QNResponseInfo alloc] initWithResponseInfoHost:request.qn_domain + response:(NSHTTPURLResponse *)response + body:responseData + error:error]; + BOOL isSafeDnsSource = kQNIsDnsSourceCustom(server.source) || kQNIsDnsSourceDoh(server.source) || kQNIsDnsSourceDnsPod(server.source); + BOOL hijacked = responseInfo.isNotQiniu && !isSafeDnsSource; + if (hijacked) { + metrics.hijacked = kQNMetricsRequestHijacked; + NSError *err = nil; + metrics.syncDnsSource = [kQNDnsPrefetch prefetchHostBySafeDns:server.host error:&err]; + metrics.syncDnsError = err; + } + + if (!hijacked && [self shouldCheckConnect:responseInfo]) { + // 网络状态检测 + QNUploadSingleRequestMetrics *connectCheckMetrics = [QNConnectChecker check]; + metrics.connectCheckMetrics = connectCheckMetrics; + if (![QNConnectChecker isConnected:connectCheckMetrics]) { + NSString *message = [NSString stringWithFormat:@"check origin statusCode:%d error:%@", responseInfo.statusCode, responseInfo.error]; + responseInfo = [QNResponseInfo errorResponseInfo:NSURLErrorNotConnectedToInternet errorDesc:message]; + } else if (!isSafeDnsSource) { + metrics.hijacked = kQNMetricsRequestMaybeHijacked; + NSError *err = nil; + [kQNDnsPrefetch prefetchHostBySafeDns:server.host error:&err]; + metrics.syncDnsError = err; + } + } + + [self reportRequest:responseInfo server:server requestMetrics:metrics]; + + QNLogInfo(@"key:%@ response:%@", self.requestInfo.key, responseInfo); + if (shouldRetry(responseInfo, responseDic) + && self.currentRetryTime < self.config.retryMax + && responseInfo.couldHostRetry) { + self.currentRetryTime += 1; + QNAsyncRunAfter(self.config.retryInterval, kQNBackgroundQueue, ^{ + [self retryRequest:request server:server shouldRetry:shouldRetry progress:progress complete:complete]; + }); + } else { + [self complete:responseInfo server:server response:responseDic requestMetrics:metrics complete:complete]; + } + }]; + +} + +- (BOOL)shouldCheckConnect:(QNResponseInfo *)responseInfo { + if (!kQNGlobalConfiguration.connectCheckEnable || [kQNGlobalConfiguration.connectCheckURLStrings count] == 0) { + return NO; + } + + return responseInfo.statusCode == kQNNetworkError || + responseInfo.statusCode == kQNUnexpectedSysCallError || // CF 内部部分错误码 归结到了调用错误 + responseInfo.statusCode == NSURLErrorTimedOut /* NSURLErrorTimedOut */ || + responseInfo.statusCode == -1003 /* NSURLErrorCannotFindHost */ || + responseInfo.statusCode == -1004 /* NSURLErrorCannotConnectToHost */ || + responseInfo.statusCode == -1005 /* NSURLErrorNetworkConnectionLost */ || + responseInfo.statusCode == -1006 /* NSURLErrorDNSLookupFailed */ || + responseInfo.statusCode == -1009 /* NSURLErrorNotConnectedToInternet */ || + responseInfo.statusCode == -1200 /* NSURLErrorSecureConnectionFailed */ || + responseInfo.statusCode == -1204 /* NSURLErrorServerCertificateNotYetValid */ || + responseInfo.statusCode == -1205 /* NSURLErrorClientCertificateRejected */; +} + +- (void)complete:(QNResponseInfo *)responseInfo + server:(id)server + response:(NSDictionary *)response + requestMetrics:(QNUploadSingleRequestMetrics *)requestMetrics + complete:(QNSingleRequestCompleteHandler)complete { + [self updateHostNetworkStatus:responseInfo server:server requestMetrics:requestMetrics]; + if (complete) { + complete(responseInfo, [self.requestMetricsList copy], response); + } +} + +- (BOOL)shouldUseCFClient:(NSURLRequest *)request server:(id )server { + if (request.qn_isHttps && server.host.length > 0 && server.ip.length > 0) { + return YES; + } else { + return NO; + } +} + +//MARK:-- 统计网络状态 +- (void)updateHostNetworkStatus:(QNResponseInfo *)responseInfo + server:(id )server + requestMetrics:(QNUploadSingleRequestMetrics *)requestMetrics{ + long long bytes = requestMetrics.bytesSend.longLongValue; + if (requestMetrics.startDate && requestMetrics.endDate && bytes >= 1024 * 1024) { + double duration = [requestMetrics.endDate timeIntervalSinceDate:requestMetrics.startDate] * 1000; + NSNumber *speed = [QNUtils calculateSpeed:bytes totalTime:duration]; + if (speed) { + NSString *type = [QNNetworkStatusManager getNetworkStatusType:server.host ip:server.ip]; + [kQNNetworkStatusManager updateNetworkStatus:type speed:(int)(speed.longValue / 1000)]; + } + } +} + +//MARK:-- 统计quality日志 +- (void)reportRequest:(QNResponseInfo *)info + server:(id )server + requestMetrics:(QNUploadSingleRequestMetrics *)requestMetrics { + + if (! [self.requestInfo shouldReportRequestLog]) { + return; + } + + QNUploadSingleRequestMetrics *requestMetricsP = requestMetrics ?: [QNUploadSingleRequestMetrics emptyMetrics]; + + NSInteger currentTimestamp = [QNUtils currentTimestamp]; + QNReportItem *item = [QNReportItem item]; + [item setReportValue:QNReportLogTypeRequest forKey:QNReportRequestKeyLogType]; + [item setReportValue:@(currentTimestamp/1000) forKey:QNReportRequestKeyUpTime]; + [item setReportValue:info.requestReportStatusCode forKey:QNReportRequestKeyStatusCode]; + [item setReportValue:info.reqId forKey:QNReportRequestKeyRequestId]; + [item setReportValue:requestMetricsP.request.qn_domain forKey:QNReportRequestKeyHost]; + [item setReportValue:requestMetricsP.remoteAddress forKey:QNReportRequestKeyRemoteIp]; + [item setReportValue:requestMetricsP.remotePort forKey:QNReportRequestKeyPort]; + [item setReportValue:self.requestInfo.bucket forKey:QNReportRequestKeyTargetBucket]; + [item setReportValue:self.requestInfo.key forKey:QNReportRequestKeyTargetKey]; + [item setReportValue:requestMetricsP.totalElapsedTime forKey:QNReportRequestKeyTotalElapsedTime]; + [item setReportValue:requestMetricsP.totalDnsTime forKey:QNReportRequestKeyDnsElapsedTime]; + [item setReportValue:requestMetricsP.totalConnectTime forKey:QNReportRequestKeyConnectElapsedTime]; + [item setReportValue:requestMetricsP.totalSecureConnectTime forKey:QNReportRequestKeyTLSConnectElapsedTime]; + [item setReportValue:requestMetricsP.totalRequestTime forKey:QNReportRequestKeyRequestElapsedTime]; + [item setReportValue:requestMetricsP.totalWaitTime forKey:QNReportRequestKeyWaitElapsedTime]; + [item setReportValue:requestMetricsP.totalWaitTime forKey:QNReportRequestKeyResponseElapsedTime]; + [item setReportValue:requestMetricsP.totalResponseTime forKey:QNReportRequestKeyResponseElapsedTime]; + [item setReportValue:self.requestInfo.fileOffset forKey:QNReportRequestKeyFileOffset]; + [item setReportValue:requestMetricsP.bytesSend forKey:QNReportRequestKeyBytesSent]; + [item setReportValue:requestMetricsP.totalBytes forKey:QNReportRequestKeyBytesTotal]; + [item setReportValue:@([QNUtils getCurrentProcessID]) forKey:QNReportRequestKeyPid]; + [item setReportValue:@([QNUtils getCurrentThreadID]) forKey:QNReportRequestKeyTid]; + [item setReportValue:self.requestInfo.targetRegionId forKey:QNReportRequestKeyTargetRegionId]; + [item setReportValue:self.requestInfo.currentRegionId forKey:QNReportRequestKeyCurrentRegionId]; + [item setReportValue:info.requestReportErrorType forKey:QNReportRequestKeyErrorType]; + NSString *errorDesc = info.requestReportErrorType ? info.message : nil; + [item setReportValue:errorDesc forKey:QNReportRequestKeyErrorDescription]; + [item setReportValue:self.requestInfo.requestType forKey:QNReportRequestKeyUpType]; + [item setReportValue:[QNUtils systemName] forKey:QNReportRequestKeyOsName]; + [item setReportValue:[QNUtils systemVersion] forKey:QNReportRequestKeyOsVersion]; + [item setReportValue:[QNUtils sdkLanguage] forKey:QNReportRequestKeySDKName]; + [item setReportValue:[QNUtils sdkVersion] forKey:QNReportRequestKeySDKVersion]; + [item setReportValue:@([QNUtils currentTimestamp]) forKey:QNReportRequestKeyClientTime]; + [item setReportValue:[QNUtils getCurrentNetworkType] forKey:QNReportRequestKeyNetworkType]; + [item setReportValue:[QNUtils getCurrentSignalStrength] forKey:QNReportRequestKeySignalStrength]; + + [item setReportValue:server.source forKey:QNReportRequestKeyPrefetchedDnsSource]; + if (server.ipPrefetchedTime) { + NSInteger prefetchTime = currentTimestamp/1000 - [server.ipPrefetchedTime integerValue]; + [item setReportValue:@(prefetchTime) forKey:QNReportRequestKeyPrefetchedBefore]; + } + [item setReportValue:kQNDnsPrefetch.lastPrefetchedErrorMessage forKey:QNReportRequestKeyPrefetchedErrorMessage]; + + [item setReportValue:requestMetricsP.httpVersion forKey:QNReportRequestKeyHttpVersion]; + + if (!kQNGlobalConfiguration.connectCheckEnable) { + [item setReportValue:@"disable" forKey:QNReportRequestKeyNetworkMeasuring]; + } else if (requestMetricsP.connectCheckMetrics) { + QNUploadSingleRequestMetrics *metrics = requestMetricsP.connectCheckMetrics; + NSString *connectCheckDuration = [NSString stringWithFormat:@"%.2lf", [metrics.totalElapsedTime doubleValue]]; + NSString *connectCheckStatusCode = @""; + if (metrics.response) { + connectCheckStatusCode = [NSString stringWithFormat:@"%ld", (long)((NSHTTPURLResponse *)metrics.response).statusCode]; + } else if (metrics.error) { + connectCheckStatusCode = [NSString stringWithFormat:@"%ld", (long)metrics.error.code]; + } + NSString *networkMeasuring = [NSString stringWithFormat:@"duration:%@ status_code:%@",connectCheckDuration, connectCheckStatusCode]; + [item setReportValue:networkMeasuring forKey:QNReportRequestKeyNetworkMeasuring]; + } + // 劫持标记 + [item setReportValue:requestMetricsP.hijacked forKey:QNReportRequestKeyHijacking]; + [item setReportValue:requestMetricsP.syncDnsSource forKey:QNReportRequestKeyDnsSource]; + [item setReportValue:[requestMetricsP.syncDnsError description] forKey:QNReportRequestKeyDnsErrorMessage]; + + // 成功统计速度 + if (info.isOK) { + [item setReportValue:requestMetricsP.perceptiveSpeed forKey:QNReportRequestKeyPerceptiveSpeed]; + } + + [item setReportValue:self.client.clientId forKey:QNReportRequestKeyHttpClient]; + + [kQNReporter reportItem:item token:self.token.token]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNIUploadServer.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNIUploadServer.h new file mode 100644 index 0000000..3306618 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNIUploadServer.h @@ -0,0 +1,28 @@ +// +// QNIUploadServer.h +// QiniuSDK +// +// Created by yangsen on 2020/7/3. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +@protocol QNUploadServer + +@property(nonatomic, copy, nullable, readonly)NSString *httpVersion; +@property(nonatomic, copy, nullable, readonly)NSString *serverId; +@property(nonatomic, copy, nullable, readonly)NSString *ip; +@property(nonatomic, copy, nullable, readonly)NSString *host; +@property(nonatomic, copy, nullable, readonly)NSString *source; +@property(nonatomic,strong, nullable, readonly)NSNumber *ipPrefetchedTime; + +@end + +#define kQNHttpVersion1 @"http_version_1" +#define kQNHttpVersion2 @"http_version_2" +#define kQNHttpVersion3 @"http_version_3" + +BOOL kQNIsHttp3(NSString * _Nullable httpVersion); +BOOL kQNIsHttp2(NSString * _Nullable httpVersion); + diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNIUploadServer.m b/Pods/Qiniu/QiniuSDK/Http/Request/QNIUploadServer.m new file mode 100644 index 0000000..1f0aca4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNIUploadServer.m @@ -0,0 +1,17 @@ +// +// QNIUploadServer.m +// QiniuSDK +// +// Created by yangsen on 2021/2/4. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNIUploadServer.h" + +BOOL kQNIsHttp3(NSString * _Nullable httpVersion) { + return [httpVersion isEqualToString:kQNHttpVersion3]; +} + +BOOL kQNIsHttp2(NSString * _Nullable httpVersion) { + return [httpVersion isEqualToString:kQNHttpVersion2]; +} diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestClient.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestClient.h new file mode 100644 index 0000000..0b9322f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestClient.h @@ -0,0 +1,30 @@ +// +// QNRequestClient.h +// QiniuSDK +// +// Created by yangsen on 2020/4/29. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUploadRequestMetrics.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^QNRequestClientCompleteHandler)(NSURLResponse * _Nullable, QNUploadSingleRequestMetrics * _Nullable, NSData * _Nullable, NSError * _Nullable); + +@protocol QNRequestClient + +// client 标识 +@property(nonatomic, copy, readonly)NSString *clientId; + +- (void)request:(NSURLRequest *)request + server:(_Nullable id )server +connectionProxy:(NSDictionary * _Nullable)connectionProxy + progress:(void(^ _Nullable)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(_Nullable QNRequestClientCompleteHandler)complete; + +- (void)cancel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.h new file mode 100644 index 0000000..d6ac2f0 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.h @@ -0,0 +1,102 @@ +// +// QNRequestTransaction.h +// QiniuSDK +// +// Created by yangsen on 2020/4/30. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +#import "QNUploadRegionInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNUpToken, QNConfiguration, QNUploadOption, QNResponseInfo, QNUploadRegionRequestMetrics; + +typedef void(^QNRequestTransactionCompleteHandler)(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response); + +// 单个对象只能执行一个事务,多个事务需要创建多个事务对象完成 +@interface QNRequestTransaction : NSObject + +//MARK:-- 构造方法 +- (instancetype)initWithHosts:(NSArray *)hosts + regionId:(NSString * _Nullable)regionId + token:(QNUpToken *)token; + +//MARK:-- upload事务构造方法 选择 +- (instancetype)initWithConfig:(QNConfiguration *)config + uploadOption:(QNUploadOption *)uploadOption + targetRegion:(id )targetRegion + currentRegion:(id )currentRegion + key:(NSString * _Nullable)key + token:(QNUpToken *)token; +- (instancetype)initWithConfig:(QNConfiguration *)config + uploadOption:(QNUploadOption *)uploadOption + hosts:(NSArray *)hosts + regionId:(NSString * _Nullable)regionId + key:(NSString * _Nullable)key + token:(QNUpToken *)token; + +- (void)queryUploadHosts:(QNRequestTransactionCompleteHandler)complete; + +- (void)uploadFormData:(NSData *)data + fileName:(NSString *)fileName + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNRequestTransactionCompleteHandler)complete; + +- (void)makeBlock:(long long)blockOffset + blockSize:(long long)blockSize + firstChunkData:(NSData *)firstChunkData + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNRequestTransactionCompleteHandler)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; + +- (void)makeFile:(long long)fileSize + fileName:(NSString *)fileName + blockContexts:(NSArray *)blockContexts + complete:(QNRequestTransactionCompleteHandler)complete; + + +- (void)initPart:(QNRequestTransactionCompleteHandler)complete; + +- (void)uploadPart:(NSString *)uploadId + partIndex:(NSInteger)partIndex + partData:(NSData *)partData + progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress + complete:(QNRequestTransactionCompleteHandler)complete; + +/** + * partInfoArray + * |_ NSDictionary : { "etag": "", "partNumber": } + */ +- (void)completeParts:(NSString *)fileName + uploadId:(NSString *)uploadId + partInfoArray:(NSArray *)partInfoArray + complete:(QNRequestTransactionCompleteHandler)complete; + +/** + * 上传日志 + */ +- (void)reportLog:(NSData *)logData + logClientId:(NSString *)logClientId + complete:(QNRequestTransactionCompleteHandler)complete; + +/** + * 获取服务端配置 + */ +- (void)serverConfig:(QNRequestTransactionCompleteHandler)complete; + +/** + * 获取服务端针对某个用户的配置 + */ +- (void)serverUserConfig:(QNRequestTransactionCompleteHandler)complete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.m b/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.m new file mode 100644 index 0000000..bc2b287 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNRequestTransaction.m @@ -0,0 +1,545 @@ +// +// 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 *)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 *)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 )targetRegion + currentRegion:(id )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 *)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 *)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 diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRegionInfo.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRegionInfo.h new file mode 100644 index 0000000..2187b46 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRegionInfo.h @@ -0,0 +1,30 @@ +// +// QNUploadRegion.h +// QiniuSDK_Mac +// +// Created by yangsen on 2020/4/30. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNIUploadServer.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNZoneInfo, QNUploadRequestState, QNResponseInfo; + +@protocol QNUploadRegion + +@property(nonatomic, assign, readonly)BOOL isValid; +@property(nonatomic, strong, nullable, readonly)QNZoneInfo *zoneInfo; + +- (void)setupRegionData:(QNZoneInfo * _Nullable)zoneInfo; + +- (id _Nullable)getNextServer:(QNUploadRequestState *)requestState + responseInfo:(QNResponseInfo *)responseInfo + freezeServer:(id _Nullable)freezeServer; + +- (void)updateIpListFormHost:(NSString *)host; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.h b/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.h new file mode 100644 index 0000000..8a3a8d5 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.h @@ -0,0 +1,45 @@ +// +// QNUploadRequestInfo.h +// QiniuSDK_Mac +// +// Created by yangsen on 2020/5/13. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadRequestInfo : NSObject + +/// 当前请求的类型 +@property(nonatomic, copy, nullable)NSString *requestType; + +/// 上传的bucket +@property(nonatomic, copy, nullable)NSString *bucket; +/// 上传的key +@property(nonatomic, copy, nullable)NSString *key; +/// 上传数据的偏移量 +@property(nonatomic, strong, nullable)NSNumber *fileOffset; +/// 上传的目标region +@property(nonatomic, copy, nullable)NSString *targetRegionId; +/// 当前上传的region +@property(nonatomic, copy, nullable)NSString *currentRegionId; + +- (BOOL)shouldReportRequestLog; + +@end + +extern NSString *const QNUploadRequestTypeUCQuery; +extern NSString *const QNUploadRequestTypeForm; +extern NSString *const QNUploadRequestTypeMkblk; +extern NSString *const QNUploadRequestTypeBput; +extern NSString *const QNUploadRequestTypeMkfile; +extern NSString *const QNUploadRequestTypeInitParts; +extern NSString *const QNUploadRequestTypeUploadPart; +extern NSString *const QNUploadRequestTypeCompletePart; +extern NSString *const QNUploadRequestTypeServerConfig; +extern NSString *const QNUploadRequestTypeServerUserConfig; +extern NSString *const QNUploadRequestTypeUpLog; + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.m b/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.m new file mode 100644 index 0000000..1c081cf --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/Request/QNUploadRequestInfo.m @@ -0,0 +1,29 @@ +// +// QNUploadRequestInfo.m +// QiniuSDK_Mac +// +// Created by yangsen on 2020/5/13. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUploadRequestInfo.h" + +@implementation QNUploadRequestInfo + +- (BOOL)shouldReportRequestLog{ + return ![self.requestType isEqualToString:QNUploadRequestTypeUpLog]; +} + +@end + +NSString * const QNUploadRequestTypeUCQuery = @"uc_query"; +NSString * const QNUploadRequestTypeForm = @"form"; +NSString * const QNUploadRequestTypeMkblk = @"mkblk"; +NSString * const QNUploadRequestTypeBput = @"bput"; +NSString * const QNUploadRequestTypeMkfile = @"mkfile"; +NSString * const QNUploadRequestTypeInitParts = @"init_parts"; +NSString * const QNUploadRequestTypeUploadPart = @"upload_part"; +NSString * const QNUploadRequestTypeCompletePart = @"complete_part"; +NSString * const QNUploadRequestTypeServerConfig = @"server_config"; +NSString * const QNUploadRequestTypeServerUserConfig = @"server_user_config"; +NSString * const QNUploadRequestTypeUpLog = @"uplog"; diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.h b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.h new file mode 100644 index 0000000..8e8c5d0 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.h @@ -0,0 +1,21 @@ +// +// QNUploadServerDomainResolver.h +// AppTest +// +// Created by yangsen on 2020/4/23. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNUploadRegionInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNConfiguration; + +@interface QNUploadDomainRegion : NSObject + +- (instancetype)initWithConfig:(QNConfiguration *)config; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.m b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.m new file mode 100644 index 0000000..daf72f1 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.m @@ -0,0 +1,444 @@ +// +// QNUploadServerDomainResolver.m +// AppTest +// +// Created by yangsen on 2020/4/23. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNUploadRequestState.h" +#import "QNUploadDomainRegion.h" +#import "QNResponseInfo.h" +#import "QNUploadServer.h" +#import "QNZoneInfo.h" +#import "QNUploadServerFreezeUtil.h" +#import "QNUploadServerFreezeManager.h" +#import "QNDnsPrefetch.h" +#import "QNLogUtil.h" +#import "QNUtils.h" +#import "QNDefine.h" +#import "QNUploadServerNetworkStatus.h" + +@interface QNUploadIpGroup : NSObject +@property(nonatomic, assign)int ipIndex; +@property(nonatomic, copy, readonly)NSString *groupType; +@property(nonatomic, strong, readonly)NSArray > *ipList; +@end +@implementation QNUploadIpGroup +- (instancetype)initWithGroupType:(NSString *)groupType + ipList:(NSArray > *)ipList{ + if (self = [super init]) { + _groupType = groupType; + _ipList = ipList; + _ipIndex = -1; + } + return self; +} +- (id )getServerIP{ + if (!self.ipList || self.ipList.count == 0) { + return nil; + } else { + if (_ipIndex < 0 || _ipIndex > (self.ipList.count - 1)) { + _ipIndex = arc4random()%self.ipList.count; + } + return self.ipList[_ipIndex]; + } +} +@end + +@interface QNUploadServerDomain: NSObject +@property(nonatomic, copy)NSString *host; +@property(nonatomic, strong)NSArray *ipGroupList; +@end +@implementation QNUploadServerDomain + ++ (QNUploadServerDomain *)domain:(NSString *)host{ + QNUploadServerDomain *domain = [[QNUploadServerDomain alloc] init]; + domain.host = host; + return domain; +} + +- (QNUploadServer *)getServerWithCondition:(BOOL(^)(NSString *host, QNUploadServer *server, QNUploadServer *filterServer))condition { + + @synchronized (self) { + if (!self.ipGroupList || self.ipGroupList.count == 0) { + [self createIpGroupList]; + } + } + + QNUploadServer *server = nil; + + // Host解析出IP时: + if (self.ipGroupList && self.ipGroupList.count > 0) { + for (QNUploadIpGroup *ipGroup in self.ipGroupList) { + + id inetAddress = [ipGroup getServerIP]; + QNUploadServer *filterServer = [QNUploadServer server:self.host + ip:inetAddress.ipValue + source:inetAddress.sourceValue + ipPrefetchedTime:inetAddress.timestampValue]; + if (condition == nil || condition(self.host, server, filterServer)) { + server = filterServer; + } + + if (condition == nil) { + break; + } + } + return server; + } + + // Host未解析出IP时: + QNUploadServer *hostServer = [QNUploadServer server:self.host + ip:nil + source:nil + ipPrefetchedTime:nil]; + if (condition == nil || condition(self.host, nil, hostServer)) { + // 未解析时,没有可比性,直接返回自身,自身即为最优 + server = hostServer; + } + + return server; +} + +- (QNUploadServer *)getOneServer{ + if (!self.host || self.host.length == 0) { + return nil; + } + if (self.ipGroupList && self.ipGroupList.count > 0) { + NSInteger index = arc4random()%self.ipGroupList.count; + QNUploadIpGroup *ipGroup = self.ipGroupList[index]; + id inetAddress = [ipGroup getServerIP]; + QNUploadServer *server = [QNUploadServer server:self.host ip:inetAddress.ipValue source:inetAddress.sourceValue ipPrefetchedTime:inetAddress.timestampValue];; + return server; + } else { + return [QNUploadServer server:self.host ip:nil source:nil ipPrefetchedTime:nil]; + } +} + +- (void)clearIpGroupList { + @synchronized (self) { + self.ipGroupList = nil; + } +} + +- (void)createIpGroupList { + + @synchronized (self) { + if (self.ipGroupList && self.ipGroupList.count > 0) { + return; + } + + // get address List of host + NSArray *inetAddresses = [kQNDnsPrefetch getInetAddressByHost:self.host]; + if (!inetAddresses || inetAddresses.count == 0) { + return; + } + + // address List to ipList of group & check ip network + NSMutableDictionary *ipGroupInfos = [NSMutableDictionary dictionary]; + for (id inetAddress in inetAddresses) { + NSString *ipValue = inetAddress.ipValue; + NSString *groupType = [QNUtils getIpType:ipValue host:self.host]; + if (groupType) { + NSMutableArray *ipList = ipGroupInfos[groupType] ?: [NSMutableArray array]; + [ipList addObject:inetAddress]; + ipGroupInfos[groupType] = ipList; + } + } + + // ipList of group to ipGroup List + NSMutableArray *ipGroupList = [NSMutableArray array]; + for (NSString *groupType in ipGroupInfos.allKeys) { + NSArray *ipList = ipGroupInfos[groupType]; + QNUploadIpGroup *ipGroup = [[QNUploadIpGroup alloc] initWithGroupType:groupType ipList:ipList]; + [ipGroupList addObject:ipGroup]; + } + + self.ipGroupList = ipGroupList; + } +} + +@end + + +@interface QNUploadDomainRegion() + +// 是否支持http3 +@property(nonatomic, assign)BOOL http3Enabled; + +// 是否冻结过Host,PS:如果没有冻结过 Host,则当前 Region 上传也就不会有错误信息,可能会返回-9,所以必须要再进行一次尝试 +@property(atomic , assign)BOOL hasFreezeHost; +@property(atomic , assign)BOOL isAllFrozen; +@property(atomic , assign)BOOL enableAccelerateUpload; +// 局部http2冻结管理对象 +@property(nonatomic, strong)QNUploadServerFreezeManager *partialHttp2Freezer; +@property(nonatomic, strong)QNUploadServerFreezeManager *partialHttp3Freezer; +@property(nonatomic, strong)NSArray *accDomainHostList; +@property(nonatomic, strong)NSDictionary *accDomainDictionary; +@property(nonatomic, strong)NSArray *domainHostList; +@property(nonatomic, strong)NSDictionary *domainDictionary; +@property(nonatomic, strong)NSArray *oldDomainHostList; +@property(nonatomic, strong)NSDictionary *oldDomainDictionary; + +@property(nonatomic, strong, nullable)QNZoneInfo *zoneInfo; +@end +@implementation QNUploadDomainRegion + +- (instancetype)initWithConfig:(QNConfiguration *)config { + if (self = [super init]) { + if (config) { + self.enableAccelerateUpload = config.accelerateUploading; + } + } + return self; +} + +- (BOOL)isValid{ + return !self.isAllFrozen && + ((self.enableAccelerateUpload && self.accDomainHostList > 0) || + self.domainHostList.count > 0 || self.oldDomainHostList.count > 0); +} + +- (void)setupRegionData:(QNZoneInfo *)zoneInfo{ + _zoneInfo = zoneInfo; + + self.isAllFrozen = NO; + self.hasFreezeHost = NO; + self.http3Enabled = zoneInfo.http3Enabled; + // 暂时屏蔽 + self.http3Enabled = false; + + NSMutableArray *serverGroups = [NSMutableArray array]; + NSMutableArray *accDomainHostList = [NSMutableArray array]; + if (zoneInfo.acc_domains) { + [serverGroups addObjectsFromArray:zoneInfo.acc_domains]; + [accDomainHostList addObjectsFromArray:zoneInfo.acc_domains]; + } + self.accDomainHostList = accDomainHostList; + self.accDomainDictionary = [self createDomainDictionary:serverGroups]; + + + [serverGroups removeAllObjects]; + NSMutableArray *domainHostList = [NSMutableArray array]; + if (zoneInfo.domains) { + [serverGroups addObjectsFromArray:zoneInfo.domains]; + [domainHostList addObjectsFromArray:zoneInfo.domains]; + } + self.domainHostList = domainHostList; + self.domainDictionary = [self createDomainDictionary:serverGroups]; + + [serverGroups removeAllObjects]; + NSMutableArray *oldDomainHostList = [NSMutableArray array]; + if (zoneInfo.old_domains) { + [serverGroups addObjectsFromArray:zoneInfo.old_domains]; + [oldDomainHostList addObjectsFromArray:zoneInfo.old_domains]; + } + self.oldDomainHostList = oldDomainHostList; + self.oldDomainDictionary = [self createDomainDictionary:serverGroups]; + + QNLogInfo(@"region :%@",domainHostList); + QNLogInfo(@"region old:%@",oldDomainHostList); +} + +- (NSDictionary *)createDomainDictionary:(NSArray *)hosts{ + NSMutableDictionary *domainDictionary = [NSMutableDictionary dictionary]; + + for (NSString *host in hosts) { + QNUploadServerDomain *domain = [QNUploadServerDomain domain:host]; + [domainDictionary setObject:domain forKey:host]; + } + return [domainDictionary copy]; +} + +- (void)updateIpListFormHost:(NSString *)host { + if (host == nil) { + return; + } + + [self.domainDictionary[host] clearIpGroupList]; + [self.oldDomainDictionary[host] clearIpGroupList]; +} + +- (id _Nullable)getNextServer:(QNUploadRequestState *)requestState + responseInfo:(QNResponseInfo *)responseInfo + freezeServer:(id _Nullable)freezeServer{ + if (self.isAllFrozen) { + return nil; + } + + [self freezeServerIfNeed:responseInfo freezeServer:freezeServer]; + + BOOL accelerate = YES; + @synchronized (self) { + if (self.enableAccelerateUpload && responseInfo.isTransferAccelerationConfigureError) { + self.enableAccelerateUpload = NO; + } + accelerate = self.enableAccelerateUpload; + } + + NSMutableArray *hostList = [NSMutableArray array]; + NSMutableDictionary *domainInfo = [NSMutableDictionary dictionary]; + if (requestState.isUseOldServer) { + if (self.oldDomainHostList.count > 0 && self.oldDomainDictionary.count > 0) { + [hostList addObjectsFromArray:self.oldDomainHostList]; + [domainInfo addEntriesFromDictionary:self.oldDomainDictionary]; + } + } else { + + // 优先使用 acc + if (accelerate && + self.accDomainHostList.count > 0 && + self.accDomainDictionary.count > 0) { + [hostList addObjectsFromArray:self.accDomainHostList]; + [domainInfo addEntriesFromDictionary:self.accDomainDictionary]; + } + + if (self.domainHostList.count > 0 && + self.domainDictionary.count > 0){ + [hostList addObjectsFromArray:self.domainHostList]; + [domainInfo addEntriesFromDictionary:self.domainDictionary]; + } + } + + if (hostList.count == 0 || domainInfo.count == 0) { + return nil; + } + + + QNUploadServer *server = nil; + // 1. 优先使用http3 + if (self.http3Enabled) { + for (NSString *host in hostList) { + QNUploadServer *domainServer = [domainInfo[host] getServerWithCondition:^BOOL(NSString *host, QNUploadServer *serverP, QNUploadServer *filterServer) { + + // 1.1 剔除冻结对象 + NSString *frozenType = QNUploadFrozenType(host, filterServer.ip); + BOOL isFrozen = [QNUploadServerFreezeUtil isType:frozenType + frozenByFreezeManagers:@[self.partialHttp3Freezer, kQNUploadGlobalHttp3Freezer]]; + if (isFrozen) { + return NO; + } + + // 1.2 挑选网络状态最优 + return [QNUploadServerNetworkStatus isServerNetworkBetter:filterServer thanServerB:serverP]; + }]; + server = [QNUploadServerNetworkStatus getBetterNetworkServer:server serverB:domainServer]; + + if (server) { + break; + } + } + + if (server) { + server.httpVersion = kQNHttpVersion3; + return server; + } + } + + + // 2. 挑选http2 + for (NSString *host in hostList) { + kQNWeakSelf; + QNUploadServer *domainServer = [domainInfo[host] getServerWithCondition:^BOOL(NSString *host, QNUploadServer *serverP, QNUploadServer *filterServer) { + kQNStrongSelf; + + // 2.1 剔除冻结对象 + NSString *frozenType = QNUploadFrozenType(host, filterServer.ip); + BOOL isFrozen = [QNUploadServerFreezeUtil isType:frozenType + frozenByFreezeManagers:@[self.partialHttp2Freezer, kQNUploadGlobalHttp2Freezer]]; + if (isFrozen) { + return NO; + } + + // 2.2 挑选网络状态最优 + return [QNUploadServerNetworkStatus isServerNetworkBetter:filterServer thanServerB:serverP]; + }]; + server = [QNUploadServerNetworkStatus getBetterNetworkServer:server serverB:domainServer]; + + if (server) { + break; + } + } + + // 3. 无可用 server 且未冻结过 Host 则随机获取一个 + if (server == nil && !self.hasFreezeHost && hostList.count > 0) { + NSInteger index = arc4random()%hostList.count; + NSString *host = hostList[index]; + server = [domainInfo[host] getOneServer]; + [self unfreezeServer:server]; + } + + if (server == nil) { + self.isAllFrozen = YES; + } + + server.httpVersion = kQNHttpVersion2; + + QNLogInfo(@"get server host:%@ ip:%@", server.host, server.ip); + return server; +} + +- (void)freezeServerIfNeed:(QNResponseInfo *)responseInfo + freezeServer:(QNUploadServer *)freezeServer { + + if (freezeServer == nil || freezeServer.serverId == nil || responseInfo == nil) { + return; + } + + NSString *frozenType = QNUploadFrozenType(freezeServer.host, freezeServer.ip); + // 1. http3 冻结 + if (kQNIsHttp3(freezeServer.httpVersion)) { + if (responseInfo.isNotQiniu) { + self.hasFreezeHost = YES; + [self.partialHttp3Freezer freezeType:frozenType frozenTime:kQNGlobalConfiguration.partialHostFrozenTime]; + } + + if (!responseInfo.canConnectToHost || responseInfo.isHostUnavailable) { + self.hasFreezeHost = YES; + [kQNUploadGlobalHttp3Freezer freezeType:frozenType frozenTime:kQNUploadHttp3FrozenTime]; + } + return; + } + + // 2. http2 冻结 + // 2.1 无法连接到Host || Host不可用, 局部冻结 + if (responseInfo.isNotQiniu || !responseInfo.canConnectToHost || responseInfo.isHostUnavailable) { + QNLogInfo(@"partial freeze server host:%@ ip:%@", freezeServer.host, freezeServer.ip); + self.hasFreezeHost = YES; + [self.partialHttp2Freezer freezeType:frozenType frozenTime:kQNGlobalConfiguration.partialHostFrozenTime]; + } + + // 2.2 Host不可用,全局冻结 + if (responseInfo.isHostUnavailable) { + QNLogInfo(@"global freeze server host:%@ ip:%@", freezeServer.host, freezeServer.ip); + self.hasFreezeHost = YES; + [kQNUploadGlobalHttp2Freezer freezeType:frozenType frozenTime:kQNGlobalConfiguration.globalHostFrozenTime]; + } +} + +/// 仅仅解封局部的 +- (void)unfreezeServer:(QNUploadServer *)freezeServer { + if (freezeServer == nil) { + return; + } + + NSString *frozenType = QNUploadFrozenType(freezeServer.host, freezeServer.ip); + [self.partialHttp2Freezer unfreezeType:frozenType]; +} + +- (QNUploadServerFreezeManager *)partialHttp2Freezer{ + if (!_partialHttp2Freezer) { + _partialHttp2Freezer = [[QNUploadServerFreezeManager alloc] init]; + } + return _partialHttp2Freezer; +} + +- (QNUploadServerFreezeManager *)partialHttp3Freezer{ + if (!_partialHttp3Freezer) { + _partialHttp3Freezer = [[QNUploadServerFreezeManager alloc] init]; + } + return _partialHttp3Freezer; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.h b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.h new file mode 100644 index 0000000..f092ccb --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.h @@ -0,0 +1,29 @@ +// +// QNUploadServer.h +// AppTest +// +// Created by yangsen on 2020/4/23. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNUploadRegionInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadServer : NSObject + +@property(nonatomic, copy)NSString *httpVersion; + +/// 上传server构造方法 +/// @param host host +/// @param ip host对应的IP +/// @param source ip查询来源,@"system",@"httpdns", @"none", @"customized" 自定义请使用@"customized" +/// @param ipPrefetchedTime 根据host获取IP的时间戳 ++ (instancetype)server:(NSString * _Nullable)host + ip:(NSString * _Nullable)ip + source:(NSString * _Nullable)source + ipPrefetchedTime:(NSNumber * _Nullable)ipPrefetchedTime; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.m b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.m new file mode 100644 index 0000000..59d2b09 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServer.m @@ -0,0 +1,39 @@ +// +// QNUploadServer.m +// AppTest +// +// Created by yangsen on 2020/4/23. +// Copyright © 2020 com.qiniu. All rights reserved. +// + +#import "QNUploadServer.h" + +@interface QNUploadServer() + +@property(nonatomic, copy)NSString *ip; +@property(nonatomic, copy)NSString *host; +@property(nonatomic, copy)NSString *source; +@property(nonatomic,strong)NSNumber *ipPrefetchedTime; + +@end +@implementation QNUploadServer +@synthesize httpVersion; + ++ (instancetype)server:(NSString *)host + ip:(NSString *)ip + source:(NSString *)source + ipPrefetchedTime:(NSNumber *)ipPrefetchedTime{ + QNUploadServer *server = [[QNUploadServer alloc] init]; + server.ip = ip; + server.host = host; + server.source = source ?: @"none"; + server.httpVersion = kQNHttpVersion2; + server.ipPrefetchedTime = ipPrefetchedTime; + return server; +} + +- (NSString *)serverId { + return [self.host copy]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.h b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.h new file mode 100644 index 0000000..d6f9daa --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.h @@ -0,0 +1,30 @@ +// +// QNUploadServerFreezeManager.h +// QiniuSDK +// +// Created by yangsen on 2020/6/2. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadServerFreezeManager : NSObject + +/// 查询host是否被冻结 +/// @param type 冻结Key +- (BOOL)isTypeFrozen:(NSString * _Nullable)type; + +/// 冻结host +/// @param type 冻结Key +/// @param frozenTime 冻结时间 +- (void)freezeType:(NSString * _Nullable)type frozenTime:(NSInteger)frozenTime; + +/// 解冻host +/// @param type 冻结Key +- (void)unfreezeType:(NSString * _Nullable)type; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.m b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.m new file mode 100644 index 0000000..ec2470d --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeManager.m @@ -0,0 +1,97 @@ +// +// QNUploadServerFreezeManager.m +// QiniuSDK +// +// Created by yangsen on 2020/6/2. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNConfiguration.h" +#import "QNUploadServerFreezeManager.h" + +@interface QNUploadServerFreezeItem : NSObject +@property(nonatomic, copy)NSString *type; +@property(nonatomic, strong)NSDate *freezeDate; +@end +@implementation QNUploadServerFreezeItem ++ (instancetype)item:(NSString *)type{ + QNUploadServerFreezeItem *item = [[QNUploadServerFreezeItem alloc] init]; + item.type = type; + return item; +} +- (BOOL)isFrozenByDate:(NSDate *)date{ + BOOL isFrozen = YES; + @synchronized (self) { + if (!self.freezeDate || [self.freezeDate timeIntervalSinceDate:date] < 0){ + isFrozen = NO; + } + } + return isFrozen; +} +- (void)freeze:(NSInteger)frozenTime{ + @synchronized (self) { + self.freezeDate = [NSDate dateWithTimeIntervalSinceNow:frozenTime]; + } +} +@end + +@interface QNUploadServerFreezeManager() + +@property(nonatomic, strong)NSMutableDictionary *freezeInfo; + +@end +@implementation QNUploadServerFreezeManager + +- (instancetype)init{ + if (self = [super init]) { + _freezeInfo = [NSMutableDictionary dictionary]; + } + return self; +} + +- (BOOL)isTypeFrozen:(NSString * _Nullable)type { + if (!type || type.length == 0) { + return true; + } + + BOOL isFrozen = true; + QNUploadServerFreezeItem *item = nil; + @synchronized (self) { + item = self.freezeInfo[type]; + } + + if (!item || ![item isFrozenByDate:[NSDate date]]) { + isFrozen = false; + } + + return isFrozen; +} + +- (void)freezeType:(NSString * _Nullable)type frozenTime:(NSInteger)frozenTime { + if (!type || type.length == 0) { + return; + } + + QNUploadServerFreezeItem *item = nil; + @synchronized (self) { + item = self.freezeInfo[type]; + if (!item) { + item = [QNUploadServerFreezeItem item:type]; + self.freezeInfo[type] = item; + } + } + + [item freeze:frozenTime]; +} + +- (void)unfreezeType:(NSString * _Nullable)type { + if (!type || type.length == 0) { + return; + } + + @synchronized (self) { + [self.freezeInfo removeObjectForKey:type]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.h b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.h new file mode 100644 index 0000000..f3ba587 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.h @@ -0,0 +1,31 @@ +// +// QNUploadServerFreezeUtil.h +// QiniuSDK +// +// Created by yangsen on 2021/2/4. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadServerFreezeManager.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +#define kQNUploadHttp3FrozenTime (3600 * 24) +#define QNUploadFrozenType(HOST, IP) ([QNUploadServerFreezeUtil getFrozenType:HOST ip:IP]) + +#define kQNUploadGlobalHttp3Freezer [QNUploadServerFreezeUtil sharedHttp3Freezer] +#define kQNUploadGlobalHttp2Freezer [QNUploadServerFreezeUtil sharedHttp2Freezer] + +@interface QNUploadServerFreezeUtil : NSObject + ++ (QNUploadServerFreezeManager *)sharedHttp2Freezer; ++ (QNUploadServerFreezeManager *)sharedHttp3Freezer; + ++ (BOOL)isType:(NSString *)type frozenByFreezeManagers:(NSArray *)freezeManagerList; + ++ (NSString *)getFrozenType:(NSString *)host ip:(NSString *)ip; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.m b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.m new file mode 100644 index 0000000..44e11a2 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadServerFreezeUtil.m @@ -0,0 +1,55 @@ +// +// QNUploadServerFreezeUtil.m +// QiniuSDK +// +// Created by yangsen on 2021/2/4. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUtils.h" +#import "QNUploadServerFreezeUtil.h" + +@implementation QNUploadServerFreezeUtil + ++ (QNUploadServerFreezeManager *)sharedHttp2Freezer { + static QNUploadServerFreezeManager *manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[QNUploadServerFreezeManager alloc] init]; + }); + return manager; +} + ++ (QNUploadServerFreezeManager *)sharedHttp3Freezer { + static QNUploadServerFreezeManager *manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[QNUploadServerFreezeManager alloc] init]; + }); + return manager; +} + ++ (BOOL)isType:(NSString *)type frozenByFreezeManagers:(NSArray *)freezeManagerList{ + if (!type || type.length == 0) { + return YES; + } + if (!freezeManagerList || freezeManagerList.count == 0) { + return NO; + } + + BOOL isFrozen = NO; + for (QNUploadServerFreezeManager *freezeManager in freezeManagerList) { + isFrozen = [freezeManager isTypeFrozen:type]; + if (isFrozen) { + break; + } + } + return isFrozen; +} + ++ (NSString *)getFrozenType:(NSString *)host ip:(NSString *)ip { + NSString *ipType = [QNUtils getIpType:ip host:host]; + return [NSString stringWithFormat:@"%@-%@", host, ipType]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/PrivacyInfo.xcprivacy b/Pods/Qiniu/QiniuSDK/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..9b24084 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/PrivacyInfo.xcprivacy @@ -0,0 +1,36 @@ + + + + + NSPrivacyTracking + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + diff --git a/msext/QiniuSDK/QiniuSDK.h b/Pods/Qiniu/QiniuSDK/QiniuSDK.h old mode 100755 new mode 100644 similarity index 57% rename from msext/QiniuSDK/QiniuSDK.h rename to Pods/Qiniu/QiniuSDK/QiniuSDK.h index d9f2e6d..5f2ccfc --- a/msext/QiniuSDK/QiniuSDK.h +++ b/Pods/Qiniu/QiniuSDK/QiniuSDK.h @@ -8,9 +8,19 @@ #import +#import "QNErrorCode.h" +#import "QNDns.h" +#import "QNZone.h" +#import "QNFixedZone.h" +#import "QNAutoZone.h" +#import "QNLogUtil.h" #import "QNConfiguration.h" +#import "QNServerConfigMonitor.h" +#import "QNRecorderDelegate.h" #import "QNFileRecorder.h" #import "QNResponseInfo.h" #import "QNUploadManager.h" #import "QNUploadOption.h" #import "QNUrlSafeBase64.h" +#import "QNReportConfig.h" +#import "QNPipeline.h" diff --git a/msext/QiniuSDK/Recorder/QNFileRecorder.h b/Pods/Qiniu/QiniuSDK/Recorder/QNFileRecorder.h similarity index 94% rename from msext/QiniuSDK/Recorder/QNFileRecorder.h rename to Pods/Qiniu/QiniuSDK/Recorder/QNFileRecorder.h index 30bae0e..3c93397 100755 --- a/msext/QiniuSDK/Recorder/QNFileRecorder.h +++ b/Pods/Qiniu/QiniuSDK/Recorder/QNFileRecorder.h @@ -49,4 +49,7 @@ directory:(NSString *)dir encodeKey:(BOOL)encode; +// 删除所有修改时间在 date 之前的缓存 +- (NSError *)deleteAll; + @end diff --git a/msext/QiniuSDK/Recorder/QNFileRecorder.m b/Pods/Qiniu/QiniuSDK/Recorder/QNFileRecorder.m old mode 100755 new mode 100644 similarity index 79% rename from msext/QiniuSDK/Recorder/QNFileRecorder.m rename to Pods/Qiniu/QiniuSDK/Recorder/QNFileRecorder.m index 09ffb67..2de994f --- a/msext/QiniuSDK/Recorder/QNFileRecorder.m +++ b/Pods/Qiniu/QiniuSDK/Recorder/QNFileRecorder.m @@ -81,6 +81,31 @@ return error; } +- (NSError *)deleteAll { + NSString *filePath = self.directory; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + BOOL isDir = NO; + BOOL existed = [fileManager fileExistsAtPath:filePath isDirectory:&isDir]; + if ( !(isDir == YES && existed == YES) ) { + return nil; + } + + //文件夹 + NSError *error; + [fileManager removeItemAtPath:filePath error:&error]; + if (error != nil) { + return error; + } + + [fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:&error]; + return error; +} + +- (NSString *)getFileName{ + return nil; +} + + (void)removeKey:(NSString *)key directory:(NSString *)dir encodeKey:(BOOL)encode { @@ -90,6 +115,9 @@ NSError *error; NSString *path = [QNFileRecorder pathJoin:key path:dir]; [[NSFileManager defaultManager] removeItemAtPath:path error:&error]; + if (error) { + NSLog(@"%s,%@", __func__, error); + } } - (NSString *)description { diff --git a/msext/QiniuSDK/Recorder/QNRecorderDelegate.h b/Pods/Qiniu/QiniuSDK/Recorder/QNRecorderDelegate.h similarity index 95% rename from msext/QiniuSDK/Recorder/QNRecorderDelegate.h rename to Pods/Qiniu/QiniuSDK/Recorder/QNRecorderDelegate.h index b308730..5f00e36 100755 --- a/msext/QiniuSDK/Recorder/QNRecorderDelegate.h +++ b/Pods/Qiniu/QiniuSDK/Recorder/QNRecorderDelegate.h @@ -52,4 +52,9 @@ typedef NSString * (^QNRecorderKeyGenerator)(NSString *uploadKey, NSString *file */ - (NSError *)del:(NSString *)key; +/** + * 缓存文件名称 + */ +- (NSString *)getFileName; + @end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.h b/Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.h new file mode 100644 index 0000000..46e7371 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.h @@ -0,0 +1,126 @@ +// +// QNBaseUpload.h +// QiniuSDK +// +// Created by WorkSpace_Sun on 2020/4/19. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import +#import "QNConfiguration.h" +#import "QNCrc32.h" +#import "QNRecorderDelegate.h" +#import "QNUpToken.h" +#import "QNUrlSafeBase64.h" +#import "QNAsyncRun.h" +#import "QNUploadManager.h" +#import "QNUploadOption.h" +#import "QNZone.h" +#import "QNUploadSource.h" +#import "QNUploadRequestMetrics.h" + +extern NSString *const QNUploadUpTypeForm; +extern NSString *const QNUploadUpTypeResumableV1; +extern NSString *const QNUploadUpTypeResumableV2; + +typedef void (^QNUpTaskCompletionHandler)(QNResponseInfo *info, NSString *key, QNUploadTaskMetrics *metrics, NSDictionary *resp); + +@interface QNBaseUpload : NSObject + +@property (nonatomic, copy, readonly) NSString *upType; +@property (nonatomic, copy, readonly) NSString *key; +@property (nonatomic, copy, readonly) NSString *fileName; +@property (nonatomic, strong, readonly) NSData *data; +@property (nonatomic, strong, readonly) id uploadSource; +@property (nonatomic, strong, readonly) QNUpToken *token; +@property (nonatomic, strong, readonly) QNUploadOption *option; +@property (nonatomic, strong, readonly) QNConfiguration *config; +@property (nonatomic, strong, readonly) id recorder; +@property (nonatomic, copy, readonly) NSString *recorderKey; +@property (nonatomic, strong, readonly) QNUpTaskCompletionHandler completionHandler; + +@property (nonatomic, strong, readonly) QNUploadRegionRequestMetrics *currentRegionRequestMetrics; +@property (nonatomic, strong, readonly) QNUploadTaskMetrics *metrics; + + +//MARK:-- 构造函数 + +/// file构造函数 +/// @param uploadSource 文件源 +/// @param key 上传key +/// @param token 上传token +/// @param option 上传option +/// @param config 上传config +/// @param recorder 断点续传记录信息 +/// @param recorderKey 断电上传信息保存的key值,需确保唯一性 +/// @param completionHandler 上传完成回调 +- (instancetype)initWithSource:(id)uploadSource + key:(NSString *)key + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + recorder:(id)recorder + recorderKey:(NSString *)recorderKey + completionHandler:(QNUpTaskCompletionHandler)completionHandler; + +/// data 构造函数 +/// @param data 上传data流 +/// @param key 上传key +/// @param fileName 上传fileName +/// @param token 上传token +/// @param option 上传option +/// @param config 上传config +/// @param completionHandler 上传完成回调 +- (instancetype)initWithData:(NSData *)data + key:(NSString *)key + fileName:(NSString *)fileName + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + completionHandler:(QNUpTaskCompletionHandler)completionHandler; + +/// 初始化数据 +- (void)initData; + +//MARK: -- 上传 + +/// 开始上传流程 +- (void)run; + +/// 准备上传 +- (int)prepareToUpload; + +/// 重新加载上传数据 +- (BOOL)reloadUploadInfo; + +/// 开始上传 +- (void)startToUpload; + +/// 切换区域 +- (BOOL)switchRegionAndUpload; +// 根据错误信息进行切换region并上传,return:是否切换region并上传 +- (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo; + +/// 上传结束调用回调方法,在上传结束时调用,该方法内部会调用回调,已通知上层上传结束 +/// @param info 上传返回信息 +/// @param response 上传字典信息 +- (void)complete:(QNResponseInfo *)info + response:(NSDictionary *)response; + +//MARK: -- 机房管理 + +/// 在区域列表头部插入一个区域 +- (void)insertRegionAtFirst:(id )region; +/// 切换区域 +- (BOOL)switchRegion; +/// 获取目标区域 +- (id )getTargetRegion; +/// 获取当前区域 +- (id )getCurrentRegion; + +//MARK: -- upLog + +// 一个上传流程可能会发起多个上传操作(如:上传多个分片),每个上传操作均是以一个Region的host做重试操作 +- (void)addRegionRequestMetricsOfOneFlow:(QNUploadRegionRequestMetrics *)metrics; + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.m b/Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.m new file mode 100644 index 0000000..8d8ef1a --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.m @@ -0,0 +1,295 @@ +// +// QNBaseUpload.m +// QiniuSDK +// +// Created by WorkSpace_Sun on 2020/4/19. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNAutoZone.h" +#import "QNZoneInfo.h" +#import "QNResponseInfo.h" +#import "QNDefine.h" +#import "QNBaseUpload.h" +#import "QNUploadDomainRegion.h" + +NSString *const QNUploadUpTypeForm = @"form"; +NSString *const QNUploadUpTypeResumableV1 = @"resumable_v1"; +NSString *const QNUploadUpTypeResumableV2 = @"resumable_v2"; + +@interface QNBaseUpload () + +@property (nonatomic, strong) QNBaseUpload *strongSelf; + +@property (nonatomic, copy) NSString *key; +@property (nonatomic, copy) NSString *fileName; +@property (nonatomic, strong) NSData *data; +@property (nonatomic, strong) id uploadSource; +@property (nonatomic, strong) QNUpToken *token; +@property (nonatomic, copy) NSString *identifier; +@property (nonatomic, strong) QNUploadOption *option; +@property (nonatomic, strong) QNConfiguration *config; +@property (nonatomic, strong) id recorder; +@property (nonatomic, copy) NSString *recorderKey; +@property (nonatomic, strong) QNUpTaskCompletionHandler completionHandler; + +@property (nonatomic, assign)NSInteger currentRegionIndex; +@property (nonatomic, strong)NSMutableArray > *regions; + +@property (nonatomic, strong)QNUploadRegionRequestMetrics *currentRegionRequestMetrics; +@property (nonatomic, strong) QNUploadTaskMetrics *metrics; + +@end + +@implementation QNBaseUpload + +- (instancetype)initWithSource:(id)uploadSource + key:(NSString *)key + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + recorder:(id)recorder + recorderKey:(NSString *)recorderKey + completionHandler:(QNUpTaskCompletionHandler)completionHandler{ + return [self initWithSource:uploadSource data:nil fileName:[uploadSource getFileName] key:key token:token option:option configuration:config recorder:recorder recorderKey:recorderKey completionHandler:completionHandler]; +} + +- (instancetype)initWithData:(NSData *)data + key:(NSString *)key + fileName:(NSString *)fileName + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + completionHandler:(QNUpTaskCompletionHandler)completionHandler{ + return [self initWithSource:nil data:data fileName:fileName key:key token:token option:option configuration:config recorder:nil recorderKey:nil completionHandler:completionHandler]; +} + +- (instancetype)initWithSource:(id)uploadSource + data:(NSData *)data + fileName:(NSString *)fileName + key:(NSString *)key + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + recorder:(id)recorder + recorderKey:(NSString *)recorderKey + completionHandler:(QNUpTaskCompletionHandler)completionHandler{ + if (self = [super init]) { + _uploadSource = uploadSource; + _data = data; + _fileName = fileName ?: @"?"; + _key = key; + _token = token; + _config = config; + _option = option ?: [QNUploadOption defaultOptions]; + _recorder = recorder; + _recorderKey = recorderKey; + _completionHandler = completionHandler; + [self initData]; + } + return self; +} + +- (instancetype)init{ + if (self = [super init]) { + [self initData]; + } + return self; +} + +- (void)initData{ + _strongSelf = self; + _currentRegionIndex = 0; +} + +- (void)run { + [self.metrics start]; + + kQNWeakSelf; + [_config.zone query:self.config token:self.token on:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, QNZonesInfo * _Nullable zonesInfo) { + + kQNStrongSelf; + self.metrics.ucQueryMetrics = metrics; + + if (responseInfo != nil && responseInfo.isOK && zonesInfo) { + if (![self setupRegions:zonesInfo]) { + responseInfo = [QNResponseInfo responseInfoWithInvalidArgument:[NSString stringWithFormat:@"setup regions host fail, origin response:%@", responseInfo]]; + [self complete:responseInfo response:responseInfo.responseDictionary]; + return; + } + + int prepareCode = [self prepareToUpload]; + if (prepareCode == 0) { + [self startToUpload]; + } else { + QNResponseInfo *responseInfoP = [QNResponseInfo errorResponseInfo:prepareCode errorDesc:nil]; + [self complete:responseInfoP response:responseInfoP.responseDictionary]; + } + } else { + if (responseInfo == nil) { + // responseInfo 一定会有值 + responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"can't get regions"]; + } + + [self complete:responseInfo response:responseInfo.responseDictionary]; + } + }]; +} + +- (BOOL)reloadUploadInfo { + return YES; +} + +- (int)prepareToUpload{ + return 0; +} + +- (void)startToUpload{ + self.currentRegionRequestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:[self getCurrentRegion]]; + [self.currentRegionRequestMetrics start]; +} + +// 内部不再调用 +- (BOOL)switchRegionAndUpload{ + if (self.currentRegionRequestMetrics) { + [self.currentRegionRequestMetrics end]; + [self.metrics addMetrics:self.currentRegionRequestMetrics]; + self.currentRegionRequestMetrics = nil; + } + + BOOL isSwitched = [self switchRegion]; + if (isSwitched) { + [self startToUpload]; + } + return isSwitched; +} + +// 根据错误信息进行切换region并上传,return:是否切换region并上传 +- (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo { + if (errorResponseInfo.statusCode == 400 && [errorResponseInfo.message containsString:@"incorrect region"]) { + [QNAutoZone clearCache]; + } + + if (!errorResponseInfo || errorResponseInfo.isOK || // 不存在 || 成功 不需要重试 + ![errorResponseInfo couldRetry] || ![self.config allowBackupHost]) { // 不能重试 + return false; + } + + if (self.currentRegionRequestMetrics) { + [self.currentRegionRequestMetrics end]; + [self.metrics addMetrics:self.currentRegionRequestMetrics]; + self.currentRegionRequestMetrics = nil; + } + + // 重新加载上传数据,上传记录 & Resource index 归零 + if (![self reloadUploadInfo]) { + return false; + } + + // 切换区域,当为 context 过期错误不需要切换区域 + if (!errorResponseInfo.isCtxExpiedError && ![self switchRegion]) { + // 非 context 过期错误,但是切换 region 失败 + return false; + } + + [self startToUpload]; + + return true; +} + +- (void)complete:(QNResponseInfo *)info + response:(NSDictionary *)response{ + + [self.metrics end]; + [self.currentRegionRequestMetrics end]; + + if (self.currentRegionRequestMetrics) { + [self.metrics addMetrics:self.currentRegionRequestMetrics]; + } + if (self.completionHandler) { + self.completionHandler(info, _key, _metrics, response); + } + self.strongSelf = nil; +} + +//MARK:-- region +- (BOOL)setupRegions:(QNZonesInfo *)zonesInfo{ + if (zonesInfo == nil || zonesInfo.zonesInfo == nil || zonesInfo.zonesInfo.count == 0) { + return NO; + } + + NSMutableArray *defaultRegions = [NSMutableArray array]; + NSArray *zoneInfos = zonesInfo.zonesInfo; + for (QNZoneInfo *zoneInfo in zoneInfos) { + QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] initWithConfig:self.config]; + [region setupRegionData:zoneInfo]; + if (region.isValid) { + [defaultRegions addObject:region]; + } + } + self.regions = defaultRegions; + self.metrics.regions = defaultRegions; + return defaultRegions.count > 0; +} + +- (void)insertRegionAtFirst:(id )region{ + BOOL hasRegion = NO; + for (id regionP in self.regions) { + if ([regionP.zoneInfo.regionId isEqualToString:region.zoneInfo.regionId]) { + hasRegion = YES; + break; + } + } + if (!hasRegion) { + [self.regions insertObject:region atIndex:0]; + } +} + +- (BOOL)switchRegion{ + BOOL ret = NO; + @synchronized (self) { + NSInteger regionIndex = _currentRegionIndex + 1; + if (regionIndex < self.regions.count) { + _currentRegionIndex = regionIndex; + ret = YES; + } + } + return ret; +} + +- (id )getTargetRegion{ + return self.regions.firstObject; +} + +- (id )getCurrentRegion{ + id region = nil; + @synchronized (self) { + if (self.currentRegionIndex < self.regions.count) { + region = self.regions[self.currentRegionIndex]; + } + } + return region; +} + +- (void)addRegionRequestMetricsOfOneFlow:(QNUploadRegionRequestMetrics *)metrics{ + if (metrics == nil) { + return; + } + + @synchronized (self) { + if (self.currentRegionRequestMetrics == nil) { + self.currentRegionRequestMetrics = metrics; + return; + } + } + + [self.currentRegionRequestMetrics addMetrics:metrics]; +} + +- (QNUploadTaskMetrics *)metrics { + if (_metrics == nil) { + _metrics = [QNUploadTaskMetrics taskMetrics:self.upType]; + } + return _metrics; +} +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h b/Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h new file mode 100644 index 0000000..d92c620 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h @@ -0,0 +1,14 @@ +// +// QNConcurrentResumeUpload.h +// QiniuSDK +// +// Created by WorkSpace_Sun on 2019/7/15. +// Copyright © 2019 Qiniu. All rights reserved. +// +/// 并发分片上传 + +#import "QNPartsUpload.h" + +@interface QNConcurrentResumeUpload : QNPartsUpload + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.m b/Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.m new file mode 100644 index 0000000..5304699 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.m @@ -0,0 +1,43 @@ +// +// QNConcurrentResumeUpload.m +// QiniuSDK +// +// Created by WorkSpace_Sun on 2019/7/15. +// Copyright © 2019 Qiniu. All rights reserved. +// + +#import "QNLogUtil.h" +#import "QNConcurrentResumeUpload.h" + +@interface QNConcurrentResumeUpload() + +@property(nonatomic, strong) dispatch_group_t uploadGroup; +@property(nonatomic, strong) dispatch_queue_t uploadQueue; + +@end + +@implementation QNConcurrentResumeUpload + +- (int)prepareToUpload{ + self.uploadGroup = dispatch_group_create(); + self.uploadQueue = dispatch_queue_create("com.qiniu.concurrentUpload", DISPATCH_QUEUE_SERIAL); + return [super prepareToUpload]; +} + +- (void)uploadRestData:(dispatch_block_t)completeHandler { + QNLogInfo(@"key:%@ 并发分片", self.key); + + for (int i = 0; i < self.config.concurrentTaskCount; i++) { + dispatch_group_enter(self.uploadGroup); + dispatch_group_async(self.uploadGroup, self.uploadQueue, ^{ + [super performUploadRestData:^{ + dispatch_group_leave(self.uploadGroup); + }]; + }); + } + dispatch_group_notify(self.uploadGroup, self.uploadQueue, ^{ + completeHandler(); + }); +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.h b/Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.h new file mode 100644 index 0000000..e5cb7f9 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.h @@ -0,0 +1,346 @@ +// +// QNConfiguration.h +// QiniuSDK +// +// Created by bailong on 15/5/21. +// Copyright (c) 2015年 Qiniu. All rights reserved. +// + +#import +#import "QNRecorderDelegate.h" +#import "QNDns.h" + +/** + * 断点上传时的分块大小 + */ +extern const UInt32 kQNBlockSize; + +/** + * DNS默认缓存时间 + */ +extern const UInt32 kQNDefaultDnsCacheTime; + +/** + * 转换为用户需要的url + * + * @param url 上传url + * + * @return 根据上传url算出代理url + */ +typedef NSString * (^QNUrlConvert)(NSString *url); + +typedef NS_ENUM(NSInteger, QNResumeUploadVersion){ + QNResumeUploadVersionV1, // 分片v1 + QNResumeUploadVersionV2 // 分片v2 +}; + +@class QNConfigurationBuilder; +@class QNZone; +@class QNReportConfig; + +/** + * Builder block + * + * @param builder builder实例 + */ +typedef void (^QNConfigurationBuilderBlock)(QNConfigurationBuilder *builder); + +@interface QNConfiguration : NSObject + +/** + * 存储区域 + */ +@property (copy, nonatomic, readonly) QNZone *zone; + +/** + * 断点上传时的分片大小 + */ +@property (readonly) UInt32 chunkSize; + +/** + * 如果大于此值就使用断点上传,否则使用form上传 + */ +@property (readonly) UInt32 putThreshold; + +/** + * 上传失败时每个上传域名的重试次数,默认重试1次 + */ +@property (readonly) UInt32 retryMax; + +/** + * 重试前等待时长,默认0.5s + */ +@property (readonly) NSTimeInterval retryInterval; + +/** + * 单个请求超时时间 单位 秒 + * 注:每个文件上传肯能存在多个操作,当每个操作失败时,可能存在多个请求重试。 + */ +@property (readonly) UInt32 timeoutInterval; + +/** + * 是否使用 https,默认为 YES + */ +@property (nonatomic, assign, readonly) BOOL useHttps; + +/** + * 单个文件是否开启并发分片上传,默认为NO + * 单个文件大小大于4M时,会采用分片上传,每个分片会已单独的请求进行上传操作,多个上传操作可以使用并发, + * 也可以采用串行,采用并发时,可以设置并发的个数(对concurrentTaskCount进行设置)。 + */ +@property (nonatomic, assign, readonly) BOOL useConcurrentResumeUpload; + +/** + * 分片上传版本 + */ +@property (nonatomic, assign, readonly) QNResumeUploadVersion resumeUploadVersion; + +/** + * 并发分片上传的并发任务个数,在concurrentResumeUpload为YES时有效,默认为3个 + */ +@property (nonatomic, assign, readonly) UInt32 concurrentTaskCount; + +/** + * 重试时是否允许使用备用上传域名,默认为YES + */ +@property (nonatomic, assign) BOOL allowBackupHost; + +/** + * 是否允许使用加速域名,默认为 false + */ +@property (nonatomic, assign, readonly) BOOL accelerateUploading; + +/** + * 持久化记录接口,可以实现将记录持久化到文件,数据库等 + */ +@property (nonatomic, readonly) id recorder; + +/** + * 为持久化上传记录,根据上传的key以及文件名 生成持久化的记录key + */ +@property (nonatomic, readonly) QNRecorderKeyGenerator recorderKeyGen; + +/** + * 上传请求代理配置信息 + */ +@property (nonatomic, readonly) NSDictionary *proxy; + +/** + * 上传URL转换,使url转换为用户需要的url + */ +@property (nonatomic, readonly) QNUrlConvert converter; + +/** + * 默认配置 + */ ++ (instancetype)defaultConfiguration; + +/** + * 使用 QNConfigurationBuilder 进行配置 + * @param block 配置block + */ ++ (instancetype)build:(QNConfigurationBuilderBlock)block; + +@end + + +#define kQNGlobalConfiguration [QNGlobalConfiguration shared] +@interface QNGlobalConfiguration : NSObject + +/** + * 是否开启dns预解析 默认开启 + */ +@property(nonatomic, assign)BOOL isDnsOpen; + +/** + * dns 预取失败后 会进行重新预取 dnsRepreHostNum为最多尝试次数 + */ +@property(nonatomic, assign)UInt32 dnsRepreHostNum; + +/** + * dns 预取超时,单位:秒 默认:2 + */ +@property(nonatomic, assign)int dnsResolveTimeout; + +/** + * dns 预取, ip 默认有效时间 单位:秒 默认:120 + * 只有在 dns 预取未返回 ttl 时使用 + */ +@property(nonatomic, assign)UInt32 dnsCacheTime; + +/** + * dns预取缓存最大有效时间 单位:秒 默认 1800 + * 当 dns 缓存 ip 过期并未刷新时,只要在 dnsCacheMaxTTL 时间内仍有效。 + */ +@property(nonatomic, assign)UInt32 dnsCacheMaxTTL; + +/** + * 自定义DNS解析客户端host + */ +@property(nonatomic, strong) id dns; + +/** + * dns解析结果本地缓存路径 + */ +@property(nonatomic, copy, readonly)NSString *dnsCacheDir; + +/** + * 是否使用 udp 方式进行 Dns 预取,默认开启 + */ +@property(nonatomic, assign)BOOL udpDnsEnable; + +/** + * 使用 udp 进行 Dns 预取时的 server ipv4 数组;当对某个 Host 使用 udp 进行 Dns 预取时,会使用 udpDnsIps 进行并发预取 + * 当 udpDnsEnable 开启时,使用 udp 进行 Dns 预取方式才会生效 + * 默认 + */ +@property(nonatomic, copy) NSArray *udpDnsIpv4Servers; + +/** + * 使用 udp 进行 Dns 预取时的 server ipv6 数组;当对某个 Host 使用 udp 进行 Dns 预取时,会使用 udpDnsIps 进行并发预取 + * 当 udpDnsEnable 开启时,使用 udp 进行 Dns 预取方式才会生效 + * 默认:nil + */ +@property(nonatomic, copy) NSArray *udpDnsIpv6Servers; + +/** + * 是否使用 doh 预取,默认开启 + */ +@property(nonatomic, assign)BOOL dohEnable; + +/** + * 使用 doh 预取时的 server 数组;当对某个 Host 使用 Doh 预取时,会使用 dohServers 进行并发预取 + * 当 dohEnable 开启时,doh 预取才会生效 + * 注意:如果使用 ip,需保证服务证书与 IP 绑定,避免 sni 问题 + */ +@property(nonatomic, copy) NSArray *dohIpv4Servers; + +/** + * 使用 doh 预取时的 server 数组;当对某个 Host 使用 Doh 预取时,会使用 dohServers 进行并发预取 + * 当 dohEnable 开启时,doh 预取才会生效 + * 默认:nil + * 注意:如果使用 ip,需保证服务证书与 IP 绑定,避免 sni 问题 + */ +@property(nonatomic, copy) NSArray *dohIpv6Servers; + +/** + * Host全局冻结时间 单位:秒 默认:60 推荐范围:[30 ~ 120] + * 当某个Host的上传失败后并且可能短时间无法恢复,会冻结该Host + */ +@property(nonatomic, assign)UInt32 globalHostFrozenTime; + +/** + * Host局部冻结时间,只会影响当前上传操作 单位:秒 默认:5*60 推荐范围:[60 ~ 10*60] + * 当某个Host的上传失败后并且短时间可能会恢复,会局部冻结该Host + */ +@property(nonatomic, assign)UInt32 partialHostFrozenTime; + +/** + * 网络连接状态检测使用的connectCheckURLStrings,网络链接状态检测可能会影响重试机制,启动网络连接状态检测有助于提高上传可用性。 + * 当请求的 Response 为网络异常时,并发对 connectCheckURLStrings 中 URLString 进行 HEAD 请求,以此检测当前网络状态的链接状态,其中任意一个 URLString 链接成功则认为当前网络状态链接良好; + * 当 connectCheckURLStrings 为 nil 或者 空数组时则弃用检测功能。 + */ +@property(nonatomic, copy)NSArray *connectCheckURLStrings; + +/** + * 是否开启网络连接状态检测,默认:开启 + */ +@property(nonatomic, assign)BOOL connectCheckEnable; + +/** + * 网络连接状态检测HEAD请求超时,默认:2s + */ +@property(nonatomic, assign)NSTimeInterval connectCheckTimeout; + + ++ (instancetype)shared; + +@end + + +@interface QNConfigurationBuilder : NSObject + +/** + * 默认上传服务器地址 + */ +@property (nonatomic, strong) QNZone *zone; + +/** + * 断点上传时的分片大小 + * 分片 v1 最小为 1024,即 1K,建议用户配置 >= 512K + * 分片 v2 最小为 1024 * 1024,即 1M + */ +@property (assign) UInt32 chunkSize; + +/** + * 如果大于此值就使用断点上传,否则使用form上传 + */ +@property (assign) UInt32 putThreshold; + +/** + * 上传失败时每个上传域名的重试次数,默认重试1次 + */ +@property (assign) UInt32 retryMax; + +/** + * 重试前等待时长,默认0.5s + */ +@property (assign) NSTimeInterval retryInterval; + +/** + * 超时时间 单位 秒 + */ +@property (assign) UInt32 timeoutInterval; + +/** + * 是否使用 https,默认为 YES + */ +@property (nonatomic, assign) BOOL useHttps; + +/** + * 重试时是否允许使用备用上传域名,默认为YES + */ +@property (nonatomic, assign) BOOL allowBackupHost; + +/** + * 是否允许使用加速域名,默认为 false + */ +@property (nonatomic, assign) BOOL accelerateUploading; + + +/** + * 是否开启并发分片上传,默认为NO + */ +@property (nonatomic, assign) BOOL useConcurrentResumeUpload; + +/** + * 分片上传版本 + */ +@property (nonatomic, assign) QNResumeUploadVersion resumeUploadVersion; + +/** + * 并发分片上传的并发任务个数,在concurrentResumeUpload为YES时有效,默认为3个 + */ +@property (nonatomic, assign) UInt32 concurrentTaskCount; + +/** + * 持久化记录接口,可以实现将记录持久化到文件,数据库等 + */ +@property (nonatomic, strong) id recorder; + +/** + * 为持久化上传记录,根据上传的key以及文件名 生成持久化的记录key + */ +@property (nonatomic, strong) QNRecorderKeyGenerator recorderKeyGen; + +/** + * 上传请求代理配置信息 + */ +@property (nonatomic, strong) NSDictionary *proxy; + +/** + * 上传URL转换,使url转换为用户需要的url + */ +@property (nonatomic, strong) QNUrlConvert converter; + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.m b/Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.m new file mode 100644 index 0000000..7262a62 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.m @@ -0,0 +1,293 @@ +// +// QNConfiguration.m +// QiniuSDK +// +// Created by bailong on 15/5/21. +// Copyright (c) 2015年 Qiniu. All rights reserved. +// + +#import "QNConfiguration.h" +#import "QNResponseInfo.h" +#import "QNUpToken.h" +#import "QNReportConfig.h" +#import "QNAutoZone.h" +#import "QN_GTM_Base64.h" + +const UInt32 kQNBlockSize = 4 * 1024 * 1024; +const UInt32 kQNDefaultDnsCacheTime = 2 * 60; + + +@implementation QNConfiguration + ++ (instancetype)defaultConfiguration{ + QNConfigurationBuilder *builder = [[QNConfigurationBuilder alloc] init]; + return [[QNConfiguration alloc] initWithBuilder:builder]; +} + ++ (instancetype)build:(QNConfigurationBuilderBlock)block { + QNConfigurationBuilder *builder = [[QNConfigurationBuilder alloc] init]; + block(builder); + return [[QNConfiguration alloc] initWithBuilder:builder]; +} + +- (instancetype)initWithBuilder:(QNConfigurationBuilder *)builder { + if (self = [super init]) { + _useConcurrentResumeUpload = builder.useConcurrentResumeUpload; + _resumeUploadVersion = builder.resumeUploadVersion; + _concurrentTaskCount = builder.concurrentTaskCount; + + _chunkSize = builder.chunkSize; + if (builder.resumeUploadVersion == QNResumeUploadVersionV1) { + if (_chunkSize < 1024) { + _chunkSize = 1024; + } + } else if (builder.resumeUploadVersion == QNResumeUploadVersionV2) { + if (_chunkSize < 1024 * 1024) { + _chunkSize = 1024 * 1024; + } + } + + _putThreshold = builder.putThreshold; + _retryMax = builder.retryMax; + _retryInterval = builder.retryInterval; + _timeoutInterval = builder.timeoutInterval; + + _recorder = builder.recorder; + _recorderKeyGen = builder.recorderKeyGen; + + _proxy = builder.proxy; + + _converter = builder.converter; + + _zone = builder.zone; + + _useHttps = builder.useHttps; + + _allowBackupHost = builder.allowBackupHost; + _accelerateUploading = builder.accelerateUploading; + + } + return self; +} + +@end + + +@interface QNGlobalConfiguration(){ + NSArray *_defaultDohIpv4Servers; + NSArray *_defaultDohIpv6Servers; + NSArray *_defaultUdpDnsIpv4Servers; + NSArray *_defaultUdpDnsIpv6Servers; + NSArray *_defaultConnectCheckUrls; +} + +@property(nonatomic, strong)NSArray *defaultDohIpv4Servers; +@property(nonatomic, strong)NSArray *defaultDohIpv6Servers; +@property(nonatomic, strong)NSArray *defaultUdpDnsIpv4Servers; +@property(nonatomic, strong)NSArray *defaultUdpDnsIpv6Servers; +@property(nonatomic, strong)NSArray *defaultConnectCheckUrls; +@end +@implementation QNGlobalConfiguration ++ (instancetype)shared{ + static QNGlobalConfiguration *config = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + config = [[QNGlobalConfiguration alloc] init]; + [config setupData]; + }); + return config; +} +- (void)setupData{ + _isDnsOpen = YES; + _dnsResolveTimeout = 2; + _dnsCacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/Dns"]; + _dnsRepreHostNum = 2; + _dnsCacheTime = kQNDefaultDnsCacheTime; + _dnsCacheMaxTTL = 10*60; + + _dohEnable = true; + _defaultDohIpv4Servers = [self parseBase64Array:@"WyJodHRwczovLzIyMy42LjYuNi9kbnMtcXVlcnkiLCAiaHR0cHM6Ly84LjguOC44L2Rucy1xdWVyeSJd"]; + + _udpDnsEnable = true; + _defaultUdpDnsIpv4Servers = [self parseBase64Array:@"WyIyMjMuNS41LjUiLCAiMTE0LjExNC4xMTQuMTE0IiwgIjEuMS4xLjEiLCAiOC44LjguOCJd"]; + + _globalHostFrozenTime = 60; + _partialHostFrozenTime = 5*60; + + _connectCheckEnable = YES; + _connectCheckTimeout = 2; + _defaultConnectCheckUrls = [self parseBase64Array:@"WyJodHRwczovL3d3dy5xaW5pdS5jb20iLCAiaHR0cHM6Ly93d3cuYmFpZHUuY29tIiwgImh0dHBzOi8vd3d3Lmdvb2dsZS5jb20iXQ=="]; + _connectCheckURLStrings = nil; +} + +- (NSArray *)parseBase64Array:(NSString *)data { + NSData *jsonData = [QN_GTM_Base64 decodeData:[data dataUsingEncoding:NSUTF8StringEncoding]]; + NSArray *ret = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil]; + if (ret && [ret isKindOfClass:[NSArray class]]) { + return ret; + } + return nil; +} + +- (BOOL)isDohEnable { + return _dohEnable && (self.dohIpv4Servers.count > 0 || self.dohIpv6Servers.count > 0) ; +} + +- (NSArray *)dohIpv4Servers { + if (_dohIpv4Servers) { + return _dohIpv4Servers; + } else { + return self.defaultDohIpv4Servers; + } +} + +- (NSArray *)dohIpv6Servers { + if (_dohIpv6Servers) { + return _dohIpv6Servers; + } else { + return self.defaultDohIpv6Servers; + } +} + +- (NSArray *)udpDnsIpv4Servers { + if (_udpDnsIpv4Servers) { + return _udpDnsIpv4Servers; + } else { + return self.defaultUdpDnsIpv4Servers; + } +} + +- (NSArray *)udpDnsIpv6Servers { + if (_udpDnsIpv6Servers) { + return _udpDnsIpv6Servers; + } else { + return self.defaultUdpDnsIpv6Servers; + } +} + +- (BOOL)isUdpDnsEnable { + return _udpDnsEnable && (self.udpDnsIpv4Servers.count > 0 || self.udpDnsIpv6Servers.count > 0) ; +} + +- (NSArray *)connectCheckURLStrings { + if (_connectCheckURLStrings) { + return _connectCheckURLStrings; + } else { + return self.defaultConnectCheckUrls; + } +} + +- (NSArray *)defaultDohIpv4Servers { + NSArray *arr = nil; + @synchronized (self) { + if (_defaultDohIpv4Servers) { + arr = [_defaultDohIpv4Servers copy]; + } + } + return arr; +} + +- (void)setDefaultDohIpv4Servers:(NSArray *)defaultDohIpv4Servers { + @synchronized (self) { + _defaultDohIpv4Servers = defaultDohIpv4Servers; + } +} + +- (NSArray *)defaultDohIpv6Servers { + NSArray *arr = nil; + @synchronized (self) { + if (_defaultDohIpv6Servers) { + arr = [_defaultDohIpv6Servers copy]; + } + } + return arr; +} + +- (void)setDefaultDohIpv6Servers:(NSArray *)defaultDohIpv6Servers { + @synchronized (self) { + _defaultDohIpv6Servers = defaultDohIpv6Servers; + } +} + + +- (NSArray *)defaultUdpDnsIpv4Servers { + NSArray *arr = nil; + @synchronized (self) { + if (_defaultUdpDnsIpv4Servers) { + arr = [_defaultUdpDnsIpv4Servers copy]; + } + } + return arr; +} + +- (void)setDefaultUdpDnsIpv4Servers:(NSArray *)defaultUdpDnsIpv4Servers { + @synchronized (self) { + _defaultUdpDnsIpv4Servers = defaultUdpDnsIpv4Servers; + } +} + + +- (NSArray *)defaultUdpDnsIpv6Servers { + NSArray *arr = nil; + @synchronized (self) { + if (_defaultUdpDnsIpv6Servers) { + arr = [_defaultUdpDnsIpv6Servers copy]; + } + } + return arr; +} + +- (void)setDefaultUdpDnsIpv6Servers:(NSArray *)defaultUdpDnsIpv6Servers { + @synchronized (self) { + _defaultUdpDnsIpv6Servers = defaultUdpDnsIpv6Servers; + } +} + +- (NSArray *)defaultConnectCheckUrls { + NSArray *arr = nil; + @synchronized (self) { + if (_defaultConnectCheckUrls) { + arr = [_defaultConnectCheckUrls copy]; + } + } + return arr; +} + +- (void)setDefaultConnectCheckUrls:(NSArray *)defaultConnectCheckUrls { + @synchronized (self) { + _defaultConnectCheckUrls = defaultConnectCheckUrls; + } +} + + +@end + +@implementation QNConfigurationBuilder + +- (instancetype)init { + if (self = [super init]) { + _zone = [[QNAutoZone alloc] init]; + _chunkSize = 2 * 1024 * 1024; + _putThreshold = 4 * 1024 * 1024; + _retryMax = 1; + _timeoutInterval = 90; + _retryInterval = 0.5; + + _recorder = nil; + _recorderKeyGen = nil; + + _proxy = nil; + _converter = nil; + + _useHttps = YES; + _allowBackupHost = YES; + _accelerateUploading = NO; + _useConcurrentResumeUpload = NO; + _resumeUploadVersion = QNResumeUploadVersionV1; + _concurrentTaskCount = 3; + } + return self; +} + +@end + diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.h b/Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.h new file mode 100755 index 0000000..f75c91e --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.h @@ -0,0 +1,13 @@ +// +// QNFormUpload.h +// QiniuSDK +// +// Created by bailong on 15/1/4. +// Copyright (c) 2015年 Qiniu. All rights reserved. +// + +#import "QNBaseUpload.h" + +@interface QNFormUpload : QNBaseUpload + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.m b/Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.m new file mode 100644 index 0000000..a06a298 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.m @@ -0,0 +1,73 @@ +// +// QNFormUpload.m +// QiniuSDK +// +// Created by bailong on 15/1/4. +// Copyright (c) 2015年 Qiniu. All rights reserved. +// +#import "QNDefine.h" +#import "QNLogUtil.h" +#import "QNFormUpload.h" +#import "QNResponseInfo.h" +#import "QNUpProgress.h" +#import "QNRequestTransaction.h" + +@interface QNFormUpload () + +@property(nonatomic, strong)QNUpProgress *progress; + +@property(nonatomic, strong)QNRequestTransaction *uploadTransaction; + +@end + +@implementation QNFormUpload + +- (void)startToUpload { + [super startToUpload]; + + QNLogInfo(@"key:%@ form上传", self.key); + + self.uploadTransaction = [[QNRequestTransaction alloc] initWithConfig:self.config + uploadOption:self.option + targetRegion:[self getTargetRegion] + currentRegion:[self getCurrentRegion] + key:self.key + token:self.token]; + + kQNWeakSelf; + void(^progressHandler)(long long totalBytesWritten, long long totalBytesExpectedToWrite) = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite){ + kQNStrongSelf; + [self.progress progress:self.key uploadBytes:totalBytesWritten totalBytes:totalBytesExpectedToWrite]; + }; + + [self.uploadTransaction uploadFormData:self.data + fileName:self.fileName + progress:progressHandler + complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + + [self addRegionRequestMetricsOfOneFlow:metrics]; + + if (!responseInfo.isOK) { + if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) { + [self complete:responseInfo response:response]; + } + return; + } + + [self.progress notifyDone:self.key totalBytes:self.data.length]; + [self complete:responseInfo response:response]; + }]; +} + +- (QNUpProgress *)progress { + if (_progress == nil) { + _progress = [QNUpProgress progress:self.option.progressHandler byteProgress:self.option.byteProgressHandler]; + } + return _progress; +} + +- (NSString *)upType { + return QNUploadUpTypeForm; +} +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.h b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.h new file mode 100644 index 0000000..dd18b06 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.h @@ -0,0 +1,24 @@ +// +// QNPartsUpload.h +// QiniuSDK_Mac +// +// Created by yangsen on 2020/5/7. +// Copyright © 2020 Qiniu. All rights reserved. +// +/// 分片上传,默认为串行 + +#import "QNBaseUpload.h" +#import "QNUploadInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@class QNRequestTransaction; +@interface QNPartsUpload : QNBaseUpload + +/// 上传剩余的数据,此方法整合上传流程,上传操作为performUploadRestData,默认串行上传 +- (void)uploadRestData:(dispatch_block_t)completeHandler; +- (void)performUploadRestData:(dispatch_block_t)completeHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.m b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.m new file mode 100644 index 0000000..23aed73 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.m @@ -0,0 +1,324 @@ +// +// QNPartsUpload.m +// QiniuSDK_Mac +// +// Created by yangsen on 2020/5/7. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNDefine.h" +#import "QNUtils.h" +#import "QNLogUtil.h" +#import "QNPartsUpload.h" +#import "QNZoneInfo.h" +#import "QNReportItem.h" +#import "QNRequestTransaction.h" +#import "QNPartsUploadPerformerV1.h" +#import "QNPartsUploadPerformerV2.h" + +#define kQNRecordFileInfoKey @"recordFileInfo" +#define kQNRecordZoneInfoKey @"recordZoneInfo" + + +@interface QNPartsUpload() + +@property(nonatomic, strong)QNPartsUploadPerformer *uploadPerformer; + +@property( atomic, strong)QNResponseInfo *uploadDataErrorResponseInfo; +@property( atomic, strong)NSDictionary *uploadDataErrorResponse; + +@end +@implementation QNPartsUpload + +- (void)initData { + [super initData]; + // 根据文件从本地恢复上传信息,如果没有则重新构建上传信息 + if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) { + QNLogInfo(@"key:%@ 分片V1", self.key); + self.uploadPerformer = [[QNPartsUploadPerformerV1 alloc] initWithSource:self.uploadSource + fileName:self.fileName + key:self.key + token:self.token + option:self.option + configuration:self.config + recorderKey:self.recorderKey]; + } else { + QNLogInfo(@"key:%@ 分片V2", self.key); + self.uploadPerformer = [[QNPartsUploadPerformerV2 alloc] initWithSource:self.uploadSource + fileName:self.fileName + key:self.key + token:self.token + option:self.option + configuration:self.config + recorderKey:self.recorderKey]; + } +} + +- (BOOL)isAllUploaded { + return [self.uploadPerformer.uploadInfo isAllUploaded]; +} + +- (void)setErrorResponseInfo:(QNResponseInfo *)responseInfo errorResponse:(NSDictionary *)response{ + if (!responseInfo) { + return; + } + if (!self.uploadDataErrorResponseInfo || responseInfo.statusCode != kQNSDKInteriorError) { + self.uploadDataErrorResponseInfo = responseInfo; + self.uploadDataErrorResponse = response ?: responseInfo.responseDictionary; + } +} + +- (int)prepareToUpload{ + int code = [super prepareToUpload]; + if (code != 0) { + return code; + } + + // 配置当前region + if (self.uploadPerformer.currentRegion && self.uploadPerformer.currentRegion.isValid) { + // currentRegion有值,为断点续传,将region插入至regionList第一处 + [self insertRegionAtFirst:self.uploadPerformer.currentRegion]; + QNLogInfo(@"key:%@ 使用缓存region", self.key); + } else { + // currentRegion无值 切换region + [self.uploadPerformer switchRegion:[self getCurrentRegion]]; + } + QNLogInfo(@"key:%@ region:%@", self.key, self.uploadPerformer.currentRegion.zoneInfo.regionId); + + if (self.uploadSource == nil) { + code = kQNLocalIOError; + } + return code; +} + +- (BOOL)switchRegion{ + BOOL isSuccess = [super switchRegion]; + if (isSuccess) { + [self.uploadPerformer switchRegion:self.getCurrentRegion]; + QNLogInfo(@"key:%@ 切换region:%@", self.key , self.uploadPerformer.currentRegion.zoneInfo.regionId); + } + return isSuccess; +} + +- (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo { + [self reportBlock]; + return [super switchRegionAndUploadIfNeededWithErrorResponse:errorResponseInfo]; +} + +- (BOOL)reloadUploadInfo { + if (![super reloadUploadInfo]) { + return NO; + } + + // 重新加载资源 + return [self.uploadPerformer couldReloadInfo] && [self.uploadPerformer reloadInfo]; +} + +- (void)startToUpload{ + [super startToUpload]; + + // 重置错误信息 + self.uploadDataErrorResponseInfo = nil; + self.uploadDataErrorResponse = nil; + + + QNLogInfo(@"key:%@ serverInit", self.key); + + // 1. 启动upload + kQNWeakSelf; + [self serverInit:^(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) { + kQNStrongSelf; + + if (!responseInfo.isOK) { + if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) { + [self complete:responseInfo response:response]; + } + return; + } + + QNLogInfo(@"key:%@ uploadRestData", self.key); + + // 2. 上传数据 + kQNWeakSelf; + [self uploadRestData:^{ + kQNStrongSelf; + + if (![self isAllUploaded]) { + if (![self switchRegionAndUploadIfNeededWithErrorResponse:self.uploadDataErrorResponseInfo]) { + [self complete:self.uploadDataErrorResponseInfo response:self.uploadDataErrorResponse]; + } + return; + } + + // 只有再读取结束再能知道文件大小,需要检测 + if ([self.uploadPerformer.uploadInfo getSourceSize] == 0) { + QNResponseInfo *responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"]; + [self complete:responseInfo response:responseInfo.responseDictionary]; + return; + } + + QNLogInfo(@"key:%@ completeUpload errorResponseInfo:%@", self.key, self.uploadDataErrorResponseInfo); + + // 3. 组装文件 + kQNWeakSelf; + [self completeUpload:^(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) { + kQNStrongSelf; + + if (!responseInfo.isOK) { + if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) { + [self complete:responseInfo response:response]; + } + return; + } + [self complete:responseInfo response:response]; + }]; + }]; + }]; +} + +- (void)uploadRestData:(dispatch_block_t)completeHandler { + QNLogInfo(@"key:%@ 串行分片", self.key); + [self performUploadRestData:completeHandler]; +} + +- (void)performUploadRestData:(dispatch_block_t)completeHandler { + if ([self isAllUploaded]) { + completeHandler(); + return; + } + + kQNWeakSelf; + [self uploadNextData:^(BOOL stop, QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) { + kQNStrongSelf; + + if (stop || !responseInfo.isOK) { + completeHandler(); + } else { + [self performUploadRestData:completeHandler]; + } + }]; +} + +//MARK:-- concurrent upload model API +- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler { + + kQNWeakSelf; + void(^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){ + kQNStrongSelf; + + if (!responseInfo.isOK) { + [self setErrorResponseInfo:responseInfo errorResponse:response]; + } + [self addRegionRequestMetricsOfOneFlow:metrics]; + completeHandler(responseInfo, response); + }; + + [self.uploadPerformer serverInit:completeHandlerP]; +} + +- (void)uploadNextData:(void(^)(BOOL stop, QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler { + + kQNWeakSelf; + void(^completeHandlerP)(BOOL, QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(BOOL stop, QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){ + kQNStrongSelf; + + if (!responseInfo.isOK) { + [self setErrorResponseInfo:responseInfo errorResponse:response]; + } + [self addRegionRequestMetricsOfOneFlow:metrics]; + completeHandler(stop, responseInfo, response); + }; + + [self.uploadPerformer uploadNextData:completeHandlerP]; +} + +- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler { + + kQNWeakSelf; + void(^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){ + kQNStrongSelf; + + if (!responseInfo.isOK) { + [self setErrorResponseInfo:responseInfo errorResponse:response]; + } + [self addRegionRequestMetricsOfOneFlow:metrics]; + completeHandler(responseInfo, response); + }; + [self.uploadPerformer completeUpload:completeHandlerP]; +} + + +- (void)complete:(QNResponseInfo *)info response:(NSDictionary *)response{ + [self.uploadSource close]; + if ([self shouldRemoveUploadInfoRecord:info]) { + [self.uploadPerformer removeUploadInfoRecord]; + } + + [super complete:info response:response]; + + [self reportBlock]; +} + +- (BOOL)shouldRemoveUploadInfoRecord:(QNResponseInfo *)info { + return info.isOK || info.statusCode == 612 || info.statusCode == 614 || info.statusCode == 701; +} + +//MARK:-- 统计block日志 +- (void)reportBlock{ + + QNUploadRegionRequestMetrics *metrics = self.currentRegionRequestMetrics ?: [QNUploadRegionRequestMetrics emptyMetrics]; + + QNReportItem *item = [QNReportItem item]; + [item setReportValue:QNReportLogTypeBlock forKey:QNReportBlockKeyLogType]; + [item setReportValue:@([[NSDate date] timeIntervalSince1970]) forKey:QNReportBlockKeyUpTime]; + [item setReportValue:self.token.bucket forKey:QNReportBlockKeyTargetBucket]; + [item setReportValue:self.key forKey:QNReportBlockKeyTargetKey]; + [item setReportValue:[self getTargetRegion].zoneInfo.regionId forKey:QNReportBlockKeyTargetRegionId]; + [item setReportValue:[self getCurrentRegion].zoneInfo.regionId forKey:QNReportBlockKeyCurrentRegionId]; + [item setReportValue:metrics.totalElapsedTime forKey:QNReportBlockKeyTotalElapsedTime]; + [item setReportValue:metrics.bytesSend forKey:QNReportBlockKeyBytesSent]; + [item setReportValue:self.uploadPerformer.recoveredFrom forKey:QNReportBlockKeyRecoveredFrom]; + [item setReportValue:@([self.uploadSource getSize]) forKey:QNReportBlockKeyFileSize]; + [item setReportValue:@([QNUtils getCurrentProcessID]) forKey:QNReportBlockKeyPid]; + [item setReportValue:@([QNUtils getCurrentThreadID]) forKey:QNReportBlockKeyTid]; + + [item setReportValue:metrics.metricsList.lastObject.hijacked forKey:QNReportBlockKeyHijacking]; + + // 统计当前 region 上传速度 文件大小 / 总耗时 + if (self.uploadDataErrorResponseInfo == nil && [self.uploadSource getSize] > 0 && [metrics totalElapsedTime] > 0) { + NSNumber *speed = [QNUtils calculateSpeed:[self.uploadSource getSize] totalTime:[metrics totalElapsedTime].longLongValue]; + [item setReportValue:speed forKey:QNReportBlockKeyPerceptiveSpeed]; + } + + if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) { + [item setReportValue:@(1) forKey:QNReportBlockKeyUpApiVersion]; + } else { + [item setReportValue:@(2) forKey:QNReportBlockKeyUpApiVersion]; + } + + [item setReportValue:[QNUtils getCurrentNetworkType] forKey:QNReportBlockKeyClientTime]; + [item setReportValue:[QNUtils systemName] forKey:QNReportBlockKeyOsName]; + [item setReportValue:[QNUtils systemVersion] forKey:QNReportBlockKeyOsVersion]; + [item setReportValue:[QNUtils sdkLanguage] forKey:QNReportBlockKeySDKName]; + [item setReportValue:[QNUtils sdkVersion] forKey:QNReportBlockKeySDKVersion]; + + [kQNReporter reportItem:item token:self.token.token]; +} + +- (NSString *)upType { + if (self.config == nil) { + return nil; + } + + NSString *sourceType = @""; + if ([self.uploadSource respondsToSelector:@selector(sourceType)]) { + sourceType = [self.uploadSource sourceType]; + } + if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) { + return [NSString stringWithFormat:@"%@<%@>",QNUploadUpTypeResumableV1, sourceType]; + } else { + return [NSString stringWithFormat:@"%@<%@>",QNUploadUpTypeResumableV2, sourceType]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h new file mode 100644 index 0000000..7c29178 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h @@ -0,0 +1,87 @@ +// +// QNPartsUploadPerformer.h +// QiniuSDK +// +// Created by yangsen on 2020/12/1. +// Copyright © 2020 Qiniu. All rights reserved. +// +/// 抽象类,不可以直接使用,需要使用子类 + +#import "QNFileDelegate.h" +#import "QNUploadSource.h" +#import "QNResponseInfo.h" +#import "QNUploadOption.h" +#import "QNConfiguration.h" +#import "QNUpToken.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol QNUploadRegion; +@class QNUploadInfo, QNRequestTransaction, QNUploadRegionRequestMetrics; + +@interface QNPartsUploadPerformer : NSObject + +@property (nonatomic, copy, readonly) NSString *key; +@property (nonatomic, copy, readonly) NSString *fileName; +@property (nonatomic, strong, readonly) id uploadSource; +@property (nonatomic, strong, readonly) QNUpToken *token; + +@property (nonatomic, strong, readonly) QNUploadOption *option; +@property (nonatomic, strong, readonly) QNConfiguration *config; +@property (nonatomic, strong, readonly) id recorder; +@property (nonatomic, copy, readonly) NSString *recorderKey; + +/// 断点续传时,起始上传偏移 +@property(nonatomic, strong, readonly)NSNumber *recoveredFrom; +@property(nonatomic, strong, readonly)id currentRegion; +@property(nonatomic, strong, readonly)QNUploadInfo *uploadInfo; + +- (instancetype)initWithSource:(id)uploadSource + fileName:(NSString *)fileName + key:(NSString *)key + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + recorderKey:(NSString *)recorderKey; + +// 是否可以重新加载资源 +- (BOOL)couldReloadInfo; + +// 重新加载资源 +- (BOOL)reloadInfo; + +- (void)switchRegion:(id )region; + +/// 通知回调当前进度 +- (void)notifyProgress:(BOOL)isCompleted; + +/// 分片信息保存本地 +- (void)recordUploadInfo; +/// 分片信息从本地移除 +- (void)removeUploadInfoRecord; + +/// 根据字典构造分片信息 【子类实现】 +- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary * _Nonnull)fileInfoDictionary; +/// 根据配置构造分片信息 【子类实现】 +- (QNUploadInfo *)getDefaultUploadInfo; + +- (QNRequestTransaction *)createUploadRequestTransaction; +- (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction; + +/// 上传前,服务端配置工作 【子类实现】 +- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler; +/// 上传文件分片 【子类实现】 +- (void)uploadNextData:(void(^)(BOOL stop, + QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler; +/// 完成上传,服务端组织文件信息 【子类实现】 +- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.m b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.m new file mode 100644 index 0000000..2fccbcb --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.m @@ -0,0 +1,237 @@ +// +// QNPartsUploadPerformer.m +// QiniuSDK +// +// Created by yangsen on 2020/12/1. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNLogUtil.h" +#import "QNAsyncRun.h" +#import "QNUpToken.h" +#import "QNZoneInfo.h" +#import "QNUploadOption.h" +#import "QNConfiguration.h" +#import "QNUploadInfo.h" +#import "QNUploadRegionInfo.h" +#import "QNRecorderDelegate.h" +#import "QNUploadDomainRegion.h" +#import "QNPartsUploadPerformer.h" +#import "QNUpProgress.h" +#import "QNRequestTransaction.h" + +#define kQNRecordFileInfoKey @"recordFileInfo" +#define kQNRecordZoneInfoKey @"recordZoneInfo" + +@interface QNPartsUploadPerformer() + +@property (nonatomic, copy) NSString *key; +@property (nonatomic, copy) NSString *fileName; +@property (nonatomic, strong) id uploadSource; +@property (nonatomic, strong) QNUpToken *token; + +@property (nonatomic, strong) QNUploadOption *option; +@property (nonatomic, strong) QNConfiguration *config; +@property (nonatomic, strong) id recorder; +@property (nonatomic, copy) NSString *recorderKey; + +@property (nonatomic, strong) NSNumber *recoveredFrom; +@property (nonatomic, strong) id targetRegion; +@property (nonatomic, strong) id currentRegion; +@property (nonatomic, strong) QNUploadInfo *uploadInfo; + +@property(nonatomic, strong) NSLock *progressLocker; +@property(nonatomic, strong) QNUpProgress *progress; +@property(nonatomic, strong) NSMutableArray *uploadTransactions; + +@end +@implementation QNPartsUploadPerformer + +- (instancetype)initWithSource:(id)uploadSource + fileName:(NSString *)fileName + key:(NSString *)key + token:(QNUpToken *)token + option:(QNUploadOption *)option + configuration:(QNConfiguration *)config + recorderKey:(NSString *)recorderKey { + if (self = [super init]) { + _uploadSource = uploadSource; + _fileName = fileName; + _key = key; + _token = token; + _option = option; + _config = config; + _recorder = config.recorder; + _recorderKey = recorderKey; + + [self initData]; + } + return self; +} + +- (void)initData { + self.uploadTransactions = [NSMutableArray array]; + + if (!self.uploadInfo) { + self.uploadInfo = [self getDefaultUploadInfo]; + } + [self recoverUploadInfoFromRecord]; +} + +- (BOOL)couldReloadInfo { + return [self.uploadInfo couldReloadSource]; +} + +- (BOOL)reloadInfo { + self.recoveredFrom = nil; + [self.uploadInfo clearUploadState]; + return [self.uploadInfo reloadSource]; +} + +- (void)switchRegion:(id )region { + self.currentRegion = region; + if (!self.targetRegion) { + self.targetRegion = region; + } +} + +- (void)notifyProgress:(BOOL)isCompleted { + if (self.uploadInfo == nil) { + return; + } + + if (isCompleted) { + [self.progress notifyDone:self.key totalBytes:[self.uploadInfo getSourceSize]]; + } else { + [self.progress progress:self.key uploadBytes:[self.uploadInfo uploadSize] totalBytes:[self.uploadInfo getSourceSize]]; + } +} + +- (void)recordUploadInfo { + + NSString *key = self.recorderKey; + if (self.recorder == nil || key == nil || key.length == 0) { + return; + } + @synchronized (self) { + NSDictionary *zoneInfo = [self.currentRegion zoneInfo].detailInfo; + NSDictionary *uploadInfo = [self.uploadInfo toDictionary]; + if (zoneInfo && uploadInfo) { + NSDictionary *info = @{kQNRecordZoneInfoKey : zoneInfo, + kQNRecordFileInfoKey : uploadInfo}; + NSData *data = [NSJSONSerialization dataWithJSONObject:info options:NSJSONWritingPrettyPrinted error:nil]; + if (data) { + [self.recorder set:key data:data]; + } + } + } + QNLogInfo(@"key:%@ recorderKey:%@ recordUploadInfo", self.key, self.recorderKey); +} + +- (void)removeUploadInfoRecord { + + self.recoveredFrom = nil; + [self.uploadInfo clearUploadState]; + [self.recorder del:self.recorderKey]; + QNLogInfo(@"key:%@ recorderKey:%@ removeUploadInfoRecord", self.key, self.recorderKey); +} + +- (void)recoverUploadInfoFromRecord { + QNLogInfo(@"key:%@ recorderKey:%@ recorder:%@ recoverUploadInfoFromRecord", self.key, self.recorderKey, self.recorder); + + NSString *key = self.recorderKey; + if (self.recorder == nil || key == nil || [key isEqualToString:@""]) { + return; + } + + NSData *data = [self.recorder get:key]; + if (data == nil) { + QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord data:nil", self.key, self.recorderKey); + return; + } + + NSError *error = nil; + NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; + if (error != nil || ![info isKindOfClass:[NSDictionary class]]) { + QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord json error", self.key, self.recorderKey); + [self.recorder del:self.key]; + return; + } + + QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoFromDictionary:info[kQNRecordZoneInfoKey]]; + QNUploadInfo *recoverUploadInfo = [self getFileInfoWithDictionary:info[kQNRecordFileInfoKey]]; + + if (zoneInfo && self.uploadInfo && [recoverUploadInfo isValid] + && [self.uploadInfo isSameUploadInfo:recoverUploadInfo]) { + QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord valid", self.key, self.recorderKey); + + [recoverUploadInfo checkInfoStateAndUpdate]; + self.uploadInfo = recoverUploadInfo; + + QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] init]; + [region setupRegionData:zoneInfo]; + self.currentRegion = region; + self.targetRegion = region; + self.recoveredFrom = @([recoverUploadInfo uploadSize]); + } else { + QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord invalid", self.key, self.recorderKey); + + [self.recorder del:self.key]; + self.currentRegion = nil; + self.targetRegion = nil; + self.recoveredFrom = nil; + } +} + +- (QNRequestTransaction *)createUploadRequestTransaction { + QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithConfig:self.config + uploadOption:self.option + targetRegion:self.targetRegion + currentRegion:self.currentRegion + key:self.key + token:self.token]; + @synchronized (self) { + [self.uploadTransactions addObject:transaction]; + } + return transaction; +} + +- (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction { + if (transaction) { + @synchronized (self) { + [self.uploadTransactions removeObject:transaction]; + } + } +} + +- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary { + return nil; +} + +- (QNUploadInfo *)getDefaultUploadInfo { + return nil; +} + +- (void)serverInit:(void (^)(QNResponseInfo * _Nullable, + QNUploadRegionRequestMetrics * _Nullable, + NSDictionary * _Nullable))completeHandler {} + +- (void)uploadNextData:(void (^)(BOOL stop, + QNResponseInfo * _Nullable, + QNUploadRegionRequestMetrics * _Nullable, + NSDictionary * _Nullable))completeHandler {} + +- (void)completeUpload:(void (^)(QNResponseInfo * _Nullable, + QNUploadRegionRequestMetrics * _Nullable, + NSDictionary * _Nullable))completeHandler {} + +- (QNUpProgress *)progress { + [self.progressLocker lock]; + if (_progress == nil) { + _progress = [QNUpProgress progress:self.option.progressHandler byteProgress:self.option.byteProgressHandler]; + } + [self.progressLocker unlock]; + return _progress; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h new file mode 100644 index 0000000..3c94fb2 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h @@ -0,0 +1,19 @@ +// +// QNPartsUploadApiV1.h +// QiniuSDK +// +// Created by yangsen on 2020/11/30. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNPartsUploadPerformer.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNPartsUploadPerformerV1 : QNPartsUploadPerformer + + + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.m b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.m new file mode 100644 index 0000000..bbe7ef3 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.m @@ -0,0 +1,188 @@ +// +// QNPartsUploadApiV1.m +// QiniuSDK +// +// Created by yangsen on 2020/11/30. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNLogUtil.h" +#import "QNDefine.h" +#import "QNRequestTransaction.h" +#import "QNUploadInfoV1.h" +#import "QNPartsUploadPerformerV1.h" + +@interface QNPartsUploadPerformerV1() +@end +@implementation QNPartsUploadPerformerV1 ++ (long long)blockSize{ + return 4 * 1024 * 1024; +} + +- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary { + return [QNUploadInfoV1 info:self.uploadSource dictionary:fileInfoDictionary]; +} + +- (QNUploadInfo *)getDefaultUploadInfo { + return [QNUploadInfoV1 info:self.uploadSource configuration:self.config]; +} + +- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + QNResponseInfo *responseInfo = [QNResponseInfo successResponse]; + completeHandler(responseInfo, nil, nil); +} + +- (void)uploadNextData:(void(^)(BOOL stop, + QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + QNUploadInfoV1 *uploadInfo = (QNUploadInfoV1 *)self.uploadInfo; + + NSError *error; + QNUploadBlock *block = nil; + QNUploadData *chunk = nil; + @synchronized (self) { + block = [uploadInfo nextUploadBlock:&error]; + chunk = [uploadInfo nextUploadData:block]; + chunk.state = QNUploadStateUploading; + } + + if (error) { + QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithLocalIOError:[NSString stringWithFormat:@"%@", error]]; + completeHandler(YES, responseInfo, nil, nil); + return; + } + + if (block == nil || chunk == nil) { + QNLogInfo(@"key:%@ no chunk left", self.key); + + QNResponseInfo *responseInfo = nil; + if (uploadInfo.getSourceSize == 0) { + responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"]; + } else { + responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"no chunk left"]; + } + completeHandler(YES, responseInfo, nil, nil); + return; + } + + if (chunk.data == nil) { + QNLogInfo(@"key:%@ chunk data is nil", self.key); + + QNResponseInfo *responseInfo = [QNResponseInfo responseInfoOfZeroData:@"chunk data is nil"];; + completeHandler(YES, responseInfo, nil, nil); + return; + } + + kQNWeakSelf; + void (^progress)(long long, long long) = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite){ + kQNStrongSelf; + chunk.uploadSize = totalBytesWritten; + [self notifyProgress:false]; + }; + + void (^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + + NSString *blockContext = response[@"ctx"]; + NSNumber *expiredAt = response[@"expired_at"]; + if (responseInfo.isOK && blockContext && expiredAt) { + block.context = blockContext; + block.expiredAt = expiredAt; + chunk.state = QNUploadStateComplete; + [self recordUploadInfo]; + [self notifyProgress:false]; + } else { + chunk.state = QNUploadStateWaitToUpload; + } + completeHandler(NO, responseInfo, metrics, response); + }; + + if ([uploadInfo isFirstData:chunk]) { + QNLogInfo(@"key:%@ makeBlock", self.key); + [self makeBlock:block firstChunk:chunk chunkData:chunk.data progress:progress completeHandler:completeHandlerP]; + } else { + QNLogInfo(@"key:%@ uploadChunk", self.key); + [self uploadChunk:block chunk:chunk chunkData:chunk.data progress:progress completeHandler:completeHandlerP]; + } +} + +- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + QNUploadInfoV1 *uploadInfo = (QNUploadInfoV1 *)self.uploadInfo; + + QNRequestTransaction *transaction = [self createUploadRequestTransaction]; + + kQNWeakSelf; + kQNWeakObj(transaction); + [transaction makeFile:[uploadInfo getSourceSize] + fileName:self.fileName + blockContexts:[uploadInfo allBlocksContexts] + complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + if (responseInfo.isOK) { + [self notifyProgress:true]; + } + completeHandler(responseInfo, metrics, response); + [self destroyUploadRequestTransaction:transaction]; + }]; +} + + +- (void)makeBlock:(QNUploadBlock *)block + firstChunk:(QNUploadData *)chunk + chunkData:(NSData *)chunkData + progress:(void(^)(long long totalBytesWritten, + long long totalBytesExpectedToWrite))progress + completeHandler:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + + QNRequestTransaction *transaction = [self createUploadRequestTransaction]; + kQNWeakSelf; + kQNWeakObj(transaction); + [transaction makeBlock:block.offset + blockSize:block.size + firstChunkData:chunkData + progress:progress + complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + + completeHandler(responseInfo, metrics, response); + [self destroyUploadRequestTransaction:transaction]; + }]; +} + + +- (void)uploadChunk:(QNUploadBlock *)block + chunk:(QNUploadData *)chunk + chunkData:(NSData *)chunkData + progress:(void(^)(long long totalBytesWritten, + long long totalBytesExpectedToWrite))progress + completeHandler:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + + QNRequestTransaction *transaction = [self createUploadRequestTransaction]; + kQNWeakSelf; + kQNWeakObj(transaction); + [transaction uploadChunk:block.context + blockOffset:block.offset + chunkData:chunkData + chunkOffset:chunk.offset + progress:progress + complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + + completeHandler(responseInfo, metrics, response); + [self destroyUploadRequestTransaction:transaction]; + }]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h new file mode 100644 index 0000000..acae537 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h @@ -0,0 +1,17 @@ +// +// QNPartsUploadApiV2.h +// QiniuSDK +// +// Created by yangsen on 2020/11/30. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNPartsUploadPerformer.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNPartsUploadPerformerV2 : QNPartsUploadPerformer + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.m b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.m new file mode 100644 index 0000000..1a865db --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.m @@ -0,0 +1,148 @@ +// +// QNPartsUploadApiV2.m +// QiniuSDK +// +// Created by yangsen on 2020/11/30. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNLogUtil.h" +#import "QNDefine.h" +#import "QNRequestTransaction.h" +#import "QNUploadInfoV2.h" +#import "QNPartsUploadPerformerV2.h" + +@interface QNPartsUploadPerformerV2() +@end +@implementation QNPartsUploadPerformerV2 + +- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary { + return [QNUploadInfoV2 info:self.uploadSource dictionary:fileInfoDictionary]; +} + +- (QNUploadInfo *)getDefaultUploadInfo { + return [QNUploadInfoV2 info:self.uploadSource configuration:self.config]; +} + +- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + + QNUploadInfoV2 *uploadInfo = (QNUploadInfoV2 *)self.uploadInfo; + if (uploadInfo && [uploadInfo isValid]) { + QNLogInfo(@"key:%@ serverInit success", self.key); + QNResponseInfo *responseInfo = [QNResponseInfo successResponse]; + completeHandler(responseInfo, nil, nil); + return; + } + + QNRequestTransaction *transaction = [self createUploadRequestTransaction]; + + kQNWeakSelf; + kQNWeakObj(transaction); + [transaction initPart:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + + NSString *uploadId = response[@"uploadId"]; + NSNumber *expireAt = response[@"expireAt"]; + if (responseInfo.isOK && uploadId && expireAt) { + uploadInfo.uploadId = uploadId; + uploadInfo.expireAt = expireAt; + [self recordUploadInfo]; + } + completeHandler(responseInfo, metrics, response); + [self destroyUploadRequestTransaction:transaction]; + }]; +} + +- (void)uploadNextData:(void(^)(BOOL stop, + QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + QNUploadInfoV2 *uploadInfo = (QNUploadInfoV2 *)self.uploadInfo; + + NSError *error = nil; + QNUploadData *data = nil; + @synchronized (self) { + data = [uploadInfo nextUploadData:&error]; + data.state = QNUploadStateUploading; + } + + if (error) { + QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithLocalIOError:[NSString stringWithFormat:@"%@", error]]; + completeHandler(YES, responseInfo, nil, nil); + return; + } + + // 上传完毕 + if (data == nil) { + QNLogInfo(@"key:%@ no data left", self.key); + + QNResponseInfo *responseInfo = nil; + if (uploadInfo.getSourceSize == 0) { + responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"]; + } else { + responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"no chunk left"]; + } + completeHandler(YES, responseInfo, nil, nil); + return; + } + + kQNWeakSelf; + void (^progress)(long long, long long) = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite){ + kQNStrongSelf; + data.uploadSize = totalBytesWritten; + [self notifyProgress:false]; + }; + + QNRequestTransaction *transaction = [self createUploadRequestTransaction]; + + kQNWeakObj(transaction); + [transaction uploadPart:uploadInfo.uploadId + partIndex:[uploadInfo getPartIndexOfData:data] + partData:data.data + progress:progress + complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + + NSString *etag = response[@"etag"]; + NSString *md5 = response[@"md5"]; + if (responseInfo.isOK && etag && md5) { + data.etag = etag; + data.state = QNUploadStateComplete; + [self recordUploadInfo]; + [self notifyProgress:false]; + } else { + data.state = QNUploadStateWaitToUpload; + } + completeHandler(NO, responseInfo, metrics, response); + [self destroyUploadRequestTransaction:transaction]; + }]; +} + +- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo, + QNUploadRegionRequestMetrics * _Nullable metrics, + NSDictionary * _Nullable response))completeHandler { + + QNUploadInfoV2 *uploadInfo = (QNUploadInfoV2 *)self.uploadInfo; + + NSArray *partInfoArray = [uploadInfo getPartInfoArray]; + QNRequestTransaction *transaction = [self createUploadRequestTransaction]; + + kQNWeakSelf; + kQNWeakObj(transaction); + [transaction completeParts:self.fileName uploadId:uploadInfo.uploadId partInfoArray:partInfoArray complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + kQNStrongSelf; + kQNStrongObj(transaction); + if (responseInfo.isOK) { + [self notifyProgress:true]; + } + completeHandler(responseInfo, metrics, response); + [self destroyUploadRequestTransaction:transaction]; + }]; +} + + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.h b/Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.h new file mode 100644 index 0000000..3157197 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.h @@ -0,0 +1,23 @@ +// +// QNUpProgress.h +// QiniuSDK +// +// Created by yangsen on 2021/5/21. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadOption.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUpProgress : NSObject + ++ (instancetype)progress:(QNUpProgressHandler)progress byteProgress:(QNUpByteProgressHandler)byteProgress; + +- (void)progress:(NSString *)key uploadBytes:(long long)uploadBytes totalBytes:(long long)totalBytes; + +- (void)notifyDone:(NSString *)key totalBytes:(long long)totalBytes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.m b/Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.m new file mode 100644 index 0000000..86b372c --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.m @@ -0,0 +1,87 @@ +// +// QNUpProgress.m +// QiniuSDK +// +// Created by yangsen on 2021/5/21. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNAsyncRun.h" +#import "QNUpProgress.h" + +@interface QNUpProgress() + +@property(nonatomic, assign)long long maxProgressUploadBytes; +@property(nonatomic, assign)long long previousUploadBytes; +@property(nonatomic, copy)QNUpProgressHandler progress; +@property(nonatomic, copy)QNUpByteProgressHandler byteProgress; + +@end +@implementation QNUpProgress + ++ (instancetype)progress:(QNUpProgressHandler)progress byteProgress:(QNUpByteProgressHandler)byteProgress { + QNUpProgress *upProgress = [[QNUpProgress alloc] init]; + upProgress.maxProgressUploadBytes = -1; + upProgress.previousUploadBytes = 0; + upProgress.progress = progress; + upProgress.byteProgress = byteProgress; + return upProgress; +} + +- (void)progress:(NSString *)key uploadBytes:(long long)uploadBytes totalBytes:(long long)totalBytes { + if ((self.progress == nil && self.byteProgress == nil) || uploadBytes < 0 || (totalBytes > 0 && uploadBytes > totalBytes)) { + return; + } + + if (totalBytes > 0) { + @synchronized (self) { + if (self.maxProgressUploadBytes < 0) { + self.maxProgressUploadBytes = totalBytes * 0.95; + } + } + + if (uploadBytes > self.maxProgressUploadBytes) { + return; + } + } + + @synchronized (self) { + if (uploadBytes > self.previousUploadBytes) { + self.previousUploadBytes = uploadBytes; + } else { + return; + } + } + + [self notify:key uploadBytes:uploadBytes totalBytes:totalBytes]; +} + +- (void)notifyDone:(NSString *)key totalBytes:(long long)totalBytes { + [self notify:key uploadBytes:totalBytes totalBytes:totalBytes]; +} + +- (void)notify:(NSString *)key uploadBytes:(long long)uploadBytes totalBytes:(long long)totalBytes { + if (self.progress == nil && self.byteProgress == nil) { + return; + } + + if (self.byteProgress) { + QNAsyncRunInMain(^{ + self.byteProgress(key, uploadBytes, totalBytes); + }); + return; + } + + if (totalBytes <= 0) { + return; + } + + if (self.progress) { + QNAsyncRunInMain(^{ + double notifyPercent = (double) uploadBytes / (double) totalBytes; + self.progress(key, notifyPercent); + }); + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUpToken.h b/Pods/Qiniu/QiniuSDK/Storage/QNUpToken.h new file mode 100644 index 0000000..9d703b2 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUpToken.h @@ -0,0 +1,33 @@ +// +// QNUpToken.h +// QiniuSDK +// +// Created by bailong on 15/6/7. +// Copyright (c) 2015年 Qiniu. All rights reserved. +// + +#import + +@interface QNUpToken : NSObject + ++ (instancetype)parse:(NSString *)token; + +@property (assign, nonatomic, readonly) long deadline; +@property (copy , nonatomic, readonly) NSString *access; +@property (copy , nonatomic, readonly) NSString *bucket; +@property (copy , nonatomic, readonly) NSString *token; + +@property (readonly) BOOL isValid; +@property (readonly) BOOL hasReturnUrl; + ++ (instancetype)getInvalidToken; + +- (NSString *)index; + +/// 是否在未来 duration 分钟内有效 +- (BOOL)isValidForDuration:(long)duration; + +/// 在是否在 date 之前有效 +- (BOOL)isValidBeforeDate:(NSDate *)date; + +@end diff --git a/msext/QiniuSDK/Storage/QNUpToken.m b/Pods/Qiniu/QiniuSDK/Storage/QNUpToken.m old mode 100755 new mode 100644 similarity index 59% rename from msext/QiniuSDK/Storage/QNUpToken.m rename to Pods/Qiniu/QiniuSDK/Storage/QNUpToken.m index 2473151..147926f --- a/msext/QiniuSDK/Storage/QNUpToken.m +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUpToken.m @@ -9,6 +9,9 @@ #import "QNUrlSafeBase64.h" #import "QNUpToken.h" +#define kQNPolicyKeyScope @"scope" +#define kQNPolicyKeyDeadline @"deadline" +#define kQNPolicyKeyReturnUrl @"returnUrl" @interface QNUpToken () - (instancetype)init:(NSDictionary *)policy token:(NSString *)token; @@ -17,12 +20,19 @@ @implementation QNUpToken ++ (instancetype)getInvalidToken { + QNUpToken *token = [[QNUpToken alloc] init]; + token->_deadline = -1; + return token; +} + - (instancetype)init:(NSDictionary *)policy token:(NSString *)token { if (self = [super init]) { _token = token; _access = [self getAccess]; _bucket = [self getBucket:policy]; - _hasReturnUrl = (policy[@"returnUrl"] != nil); + _deadline = [policy[kQNPolicyKeyDeadline] longValue]; + _hasReturnUrl = (policy[kQNPolicyKeyReturnUrl] != nil); } return self; @@ -36,8 +46,8 @@ - (NSString *)getBucket:(NSDictionary *)info { - NSString *scope = [info objectForKey:@"scope"]; - if (!scope) { + NSString *scope = [info objectForKey:kQNPolicyKeyScope]; + if (!scope || [scope isKindOfClass:[NSNull class]]) { return @""; } @@ -58,9 +68,13 @@ } NSData *data = [QNUrlSafeBase64 decodeString:array[2]]; + if (!data) { + return nil; + } + NSError *tmp = nil; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&tmp]; - if (tmp != nil || dict[@"scope"] == nil || dict[@"deadline"] == nil) { + if (tmp != nil || dict[kQNPolicyKeyScope] == nil || dict[kQNPolicyKeyDeadline] == nil) { return nil; } return [[QNUpToken alloc] init:dict token:token]; @@ -70,4 +84,20 @@ return [NSString stringWithFormat:@"%@:%@", _access, _bucket]; } +- (BOOL)isValid { + return _access && _access.length > 0 && _bucket && _bucket.length > 0; +} + +- (BOOL)isValidForDuration:(long)duration { + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:duration]; + return [self isValidBeforeDate:date]; +} + +- (BOOL)isValidBeforeDate:(NSDate *)date { + if (date == nil) { + return NO; + } + return [date timeIntervalSince1970] < self.deadline; +} + @end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.h new file mode 100644 index 0000000..63bee21 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.h @@ -0,0 +1,57 @@ +// +// QNUploadBlock.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadData.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadBlock : NSObject +// block下标 +@property(nonatomic, assign, readonly)NSInteger index; +// 当前data偏移量 +@property(nonatomic, assign, readonly)long long offset; +// 块大小 +@property(nonatomic, assign, readonly)NSInteger size; +// 需要上传的片数据 +@property(nonatomic, strong, readonly)NSArray *uploadDataList; +// block上传上下文信息 +@property(nonatomic, copy, nullable)NSString *context; +// block md5 +@property(nonatomic, copy, nullable)NSString *md5; +// 是否已完成上传【不进行离线缓存】 +@property(nonatomic, assign, readonly)BOOL isCompleted; +// 上传大小 【不进行离线缓存】 +@property(nonatomic, assign, readonly)NSInteger uploadSize; +// ctx 过期时间 +@property(nonatomic, strong, nullable)NSNumber *expiredAt; + +//MARK:-- 构造 ++ (instancetype)blockFromDictionary:(NSDictionary *)dictionary; +- (instancetype)initWithOffset:(long long)offset + blockSize:(NSInteger)blockSize + dataSize:(NSInteger)dataSize + index:(NSInteger)index; + +// 检测 block 是否有效 +- (BOOL)isValid; + +/// 获取下一个需要上传的块 +- (QNUploadData *)nextUploadDataWithoutCheckData; + +/// 检测 data 状态,处理出于上传状态的无 data 数据的情况,无 data 数据则状态调整为监测数据状态 +- (void)checkInfoStateAndUpdate; + +/// 清理上传状态 +- (void)clearUploadState; + +/// 转化字典 +- (NSDictionary *)toDictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.m new file mode 100644 index 0000000..3ef0fdf --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.m @@ -0,0 +1,175 @@ +// +// QNUploadBlock.m +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadBlock.h" + +@interface QNUploadBlock() + +@property(nonatomic, assign)long long offset; +@property(nonatomic, assign)NSInteger size; +@property(nonatomic, assign)NSInteger index; +@property(nonatomic, strong)NSArray *uploadDataList; + +@end +@implementation QNUploadBlock + ++ (instancetype)blockFromDictionary:(NSDictionary *)dictionary{ + if (![dictionary isKindOfClass:[NSDictionary class]]) { + return nil; + } + + QNUploadBlock *block = [[QNUploadBlock alloc] init]; + block.offset = [dictionary[@"offset"] longLongValue]; + block.size = [dictionary[@"size"] integerValue]; + block.index = [dictionary[@"index"] integerValue]; + block.expiredAt = dictionary[@"expired_at"]; + block.md5 = dictionary[@"md5"]; + block.context = dictionary[@"context"]; + + NSArray *uploadDataInfos = dictionary[@"uploadDataList"]; + if ([uploadDataInfos isKindOfClass:[NSArray class]]) { + + NSMutableArray *uploadDataList = [NSMutableArray array]; + for (NSDictionary *uploadDataInfo in uploadDataInfos) { + QNUploadData *data = [QNUploadData dataFromDictionary:uploadDataInfo]; + if (!data) { + return nil; + } + [uploadDataList addObject:data]; + } + block.uploadDataList = [uploadDataList copy]; + } + return block; +} + +- (instancetype)initWithOffset:(long long)offset + blockSize:(NSInteger)blockSize + dataSize:(NSInteger)dataSize + index:(NSInteger)index { + if (self = [super init]) { + _offset = offset; + _size = blockSize; + _index = index; + _uploadDataList = [self createDataList:dataSize]; + } + return self; +} + +- (BOOL)isValid { + if (!self.expiredAt || self.expiredAt.integerValue <= 0) { + // 不存在时,为新创建 block: 有效 + return true; + } + + // 存在则有效期必须为过期 + return (self.expiredAt.doubleValue - 12*3600) > [[NSDate date] timeIntervalSince1970]; +} + +- (BOOL)isCompleted{ + if (self.uploadDataList == nil) { + return true; + } + + BOOL isCompleted = true; + for (QNUploadData *data in self.uploadDataList) { + if (data.isUploaded == false) { + isCompleted = false; + break; + } + } + return isCompleted; +} + +- (NSInteger)uploadSize { + if (self.uploadDataList == nil) { + return 0; + } + + NSInteger uploadSize = 0; + for (QNUploadData *data in self.uploadDataList) { + uploadSize += data.uploadSize; + } + return uploadSize; +} + +- (NSArray *)createDataList:(long long)dataSize{ + + long long offSize = 0; + NSInteger dataIndex = 0; + NSMutableArray *datas = [NSMutableArray array]; + while (offSize < self.size) { + long long lastSize = self.size - offSize; + long long dataSizeP = MIN(lastSize, dataSize); + QNUploadData *data = [[QNUploadData alloc] initWithOffset:offSize + dataSize:dataSizeP + index:dataIndex]; + [datas addObject:data]; + offSize += dataSizeP; + dataIndex += 1; + } + return [datas copy]; +} + +- (QNUploadData *)nextUploadDataWithoutCheckData { + if (!self.uploadDataList || self.uploadDataList.count == 0) { + return nil; + } + + QNUploadData *data = nil; + for (QNUploadData *dataP in self.uploadDataList) { + if ([dataP needToUpload]) { + data = dataP; + break; + } + } + return data; +} + +- (void)clearUploadState{ + self.md5 = nil; + self.context = nil; + for (QNUploadData *data in self.uploadDataList) { + [data clearUploadState]; + } +} + +- (void)checkInfoStateAndUpdate { + for (QNUploadData *data in self.uploadDataList) { + [data checkStateAndUpdate]; + } +} + +- (NSDictionary *)toDictionary{ + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + dictionary[@"offset"] = @(self.offset); + dictionary[@"size"] = @(self.size); + dictionary[@"index"] = @(self.index); + dictionary[@"expired_at"] = self.expiredAt ?: @(0); + dictionary[@"md5"] = self.md5 ?: @""; + if (self.context) { + dictionary[@"context"] = self.context; + } + + if (self.uploadDataList) { + + NSMutableArray *uploadDataInfos = [NSMutableArray array]; + for (QNUploadData *data in self.uploadDataList) { + + NSDictionary *uploadDataInfo = [data toDictionary]; + if (uploadDataInfo) { + [uploadDataInfos addObject:uploadDataInfo]; + } + } + dictionary[@"uploadDataList"] = [uploadDataInfos copy]; + } + + return [dictionary copy]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadData.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadData.h new file mode 100644 index 0000000..c18db38 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadData.h @@ -0,0 +1,60 @@ +// +// QNUploadData.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSInteger, QNUploadState) { + QNUploadStateNeedToCheck, // 需要检测数据 + QNUploadStateWaitToUpload, // 等待上传 + QNUploadStateUploading, // 正在上传 + QNUploadStateComplete, // 上传结束 +}; + +@interface QNUploadData : NSObject + +/// 当前data偏移量 +@property(nonatomic, assign, readonly)long long offset; +/// 当前data大小 +@property(nonatomic, assign, readonly)long long size; +/// data下标 +@property(nonatomic, assign, readonly)NSInteger index; +/// data etag +@property(nonatomic, copy, nullable)NSString *etag; +/// data md5 +@property(nonatomic, copy, nullable)NSString *md5; +/// 上传状态 +@property(nonatomic, assign)QNUploadState state; +/// 上传进度 【不进行离线缓存】 +@property(nonatomic, assign)long long uploadSize; +/// 上传数据 【不进行离线缓存】 +@property(nonatomic, strong, nullable)NSData *data; + +//MARK:-- 构造 ++ (instancetype)dataFromDictionary:(NSDictionary *)dictionary; +- (instancetype)initWithOffset:(long long)offset + dataSize:(long long)dataSize + index:(NSInteger)index; + +//MARK:-- logic +/// 是否需要上传 +- (BOOL)needToUpload; +/// 是否已经上传 +- (BOOL)isUploaded; + +/// 检测 data 状态,处理出于上传状态的无 data 数据的情况,无 data 数据则状态调整为监测数据状态 +- (void)checkStateAndUpdate; + +/// 转化字典 +- (NSDictionary *)toDictionary; +/// 清除状态 +- (void)clearUploadState; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadData.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadData.m new file mode 100644 index 0000000..8d06c4a --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadData.m @@ -0,0 +1,112 @@ +// +// QNUploadData.m +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadData.h" + +@interface QNUploadData() + +@property(nonatomic, assign)long long offset; +@property(nonatomic, assign)long long size; +@property(nonatomic, assign)NSInteger index; + +@end +@implementation QNUploadData + ++ (instancetype)dataFromDictionary:(NSDictionary *)dictionary{ + if (![dictionary isKindOfClass:[NSDictionary class]]) { + return nil; + } + QNUploadData *data = [[QNUploadData alloc] init]; + data.offset = [dictionary[@"offset"] longLongValue]; + data.size = [dictionary[@"size"] longLongValue]; + data.index = [dictionary[@"index"] integerValue]; + data.etag = dictionary[@"etag"]; + data.md5 = dictionary[@"md5"]; + data.state = [dictionary[@"state"] intValue]; + return data; +} + +- (instancetype)initWithOffset:(long long)offset + dataSize:(long long)dataSize + index:(NSInteger)index { + if (self = [super init]) { + _offset = offset; + _size = dataSize; + _index = index; + _etag = @""; + _md5 = @""; + _state = QNUploadStateNeedToCheck; + } + return self; +} + +- (BOOL)needToUpload { + BOOL needToUpload = false; + switch (self.state) { + case QNUploadStateNeedToCheck: + case QNUploadStateWaitToUpload: + needToUpload = true; + break; + default: + break; + } + return needToUpload; +} + +- (BOOL)isUploaded { + return self.state == QNUploadStateComplete; +} + +- (void)setState:(QNUploadState)state { + switch (state) { + case QNUploadStateNeedToCheck: + case QNUploadStateWaitToUpload: + case QNUploadStateUploading: + self.uploadSize = 0; + self.etag = @""; + break; + default: + self.data = nil; + break; + } + _state = state; +} + +- (long long)uploadSize { + if (self.state == QNUploadStateComplete) { + return _size; + } else { + return _uploadSize; + } +} + +- (void)clearUploadState{ + self.state = QNUploadStateNeedToCheck; + self.etag = nil; + self.md5 = nil; +} + +- (void)checkStateAndUpdate { + if ((self.state == QNUploadStateWaitToUpload || self.state == QNUploadStateUploading) && self.data == nil) { + self.state = QNUploadStateNeedToCheck; + } +} + +- (NSDictionary *)toDictionary{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + dictionary[@"offset"] = @(self.offset); + dictionary[@"size"] = @(self.size); + dictionary[@"index"] = @(self.index); + dictionary[@"etag"] = self.etag ?: @""; + dictionary[@"md5"] = self.md5 ?: @""; + dictionary[@"state"] = @(self.state); + return [dictionary copy]; +} + +@end + diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.h new file mode 100644 index 0000000..d618053 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.h @@ -0,0 +1,75 @@ +// +// QNUploadInfo.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadSource.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadInfo : NSObject + +/// 构造函数 +/// @param source 上传数据源 ++ (instancetype)info:(id )source; + +/// 通过字典信息进行配置 +/// @param dictionary 配置信息 +- (void)setInfoFromDictionary:(NSDictionary *)dictionary; + +/// 信息转化为字典 +- (NSDictionary *)toDictionary; + +/// 数据源是否有效,为空则无效 +- (BOOL)hasValidResource; + +/// 是否有效,数据源是否有效 & 上传信息有效,比如断点续传时,UploadId是否有效 +- (BOOL)isValid; + +/// 是否可以重新 +- (BOOL)couldReloadSource; + +/// 重新加载数据 +- (BOOL)reloadSource; + +/// 数据源ID +- (NSString *)getSourceId; + +/// 数据源大小,未知为:-1 +- (long long)getSourceSize; + +/// 是否为同一个 UploadInfo, +/// 同一个:source 相同,上传方式相同 +/// @param info 上传信息 +- (BOOL)isSameUploadInfo:(QNUploadInfo *)info; + +/// 已上传大小 +- (long long)uploadSize; + +/// 资源是否已全部上传 +/// 子类重写 +- (BOOL)isAllUploaded; + +/// 清除上传状态信息 +/// 子类重写 +- (void)clearUploadState; + +/// 检查文件状态, 主要处理没有 data 但处于上传状态 +- (void)checkInfoStateAndUpdate; + +/// 读取数据 +/// @param dataSize 读取数据大小 +/// @param dataOffset 数据偏移量 +/// @param error 读取时的错误信息 +- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error; + +/// 关闭流 +- (void)close; + +@end + +#define kQNUploadInfoTypeKey @"infoType" +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.m new file mode 100644 index 0000000..a2c1930 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.m @@ -0,0 +1,115 @@ +// +// QNUploadInfo.m +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNErrorCode.h" +#import "QNUploadInfo.h" + +@interface QNUploadInfo() + +@property(nonatomic, copy)NSString *sourceId; +@property(nonatomic, assign)long long sourceSize; +@property(nonatomic, copy)NSString *fileName; + +@property(nonatomic, strong)id source; + +@end +@implementation QNUploadInfo + ++ (instancetype)info:(id )source { + QNUploadInfo *info = [[self alloc] init]; + info.source = source; + info.sourceSize = [source getSize]; + info.fileName = [source getFileName]; + return info; +} + +- (void)setInfoFromDictionary:(NSDictionary *)dictionary { + self.sourceSize = [dictionary[@"sourceSize"] longValue]; + self.sourceId = dictionary[@"sourceId"]; +} + +- (NSDictionary *)toDictionary { + return @{@"sourceSize" : @([self getSourceSize]), + @"sourceId" : self.sourceId ?: @""}; +} + +- (BOOL)hasValidResource { + return self.source != nil; +} + +- (BOOL)isValid { + return [self hasValidResource]; +} + +- (BOOL)couldReloadSource { + return [self.source couldReloadSource]; +} + +- (BOOL)reloadSource { + return [self.source reloadSource]; +} + +- (NSString *)getSourceId { + return [self.source getId]; +} + +- (long long)getSourceSize { + return [self.source getSize]; +} + +- (BOOL)isSameUploadInfo:(QNUploadInfo *)info { + if (info == nil || ((self.sourceId.length > 0 || info.sourceId.length > 0) && ![self.sourceId isEqualToString:info.sourceId])) { + return false; + } + + // 检测文件大小,如果能获取到文件大小的话,就进行检测 + if (info.sourceSize > kQNUnknownSourceSize && + self.sourceSize > kQNUnknownSourceSize && + info.sourceSize != self.sourceSize) { + return false; + } + + return true; +} + +- (long long)uploadSize { + return 0; +} + +- (BOOL)isAllUploaded { + return true; +} + +- (void)clearUploadState { +} + +- (void)checkInfoStateAndUpdate { +} + +- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error { + if (!self.source) { + *error = [NSError errorWithDomain:NSStreamSOCKSErrorDomain code:kQNLocalIOError userInfo:@{NSLocalizedDescriptionKey : @"file is not exist"}]; + return nil; + } + + NSData *data = nil; + @synchronized (self.source) { + data = [self.source readData:dataSize dataOffset:dataOffset error:error]; + } + if (*error == nil && data != nil && (data.length == 0 || data.length != dataSize)) { + self.sourceSize = data.length + dataOffset; + } + return data; +} + +- (void)close { + [self.source close]; +} + +@end + diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h new file mode 100644 index 0000000..df17088 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h @@ -0,0 +1,35 @@ +// +// QNUploadInfoV1.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNConfiguration.h" +#import "QNUploadData.h" +#import "QNUploadBlock.h" +#import "QNUploadInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadInfoV1 : QNUploadInfo + ++ (instancetype)info:(id )source + configuration:(QNConfiguration *)configuration; + + ++ (instancetype)info:(id )source + dictionary:(NSDictionary *)dictionary; + +- (BOOL)isFirstData:(QNUploadData *)data; + +- (QNUploadBlock *)nextUploadBlock:(NSError **)error; + +- (QNUploadData *)nextUploadData:(QNUploadBlock *)block; + +- (NSArray *)allBlocksContexts; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.m new file mode 100644 index 0000000..8016b9e --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.m @@ -0,0 +1,327 @@ +// +// QNUploadInfoV1.m +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "NSData+QNMD5.h" +#import "QNMutableArray.h" +#import "QNUploadInfoV1.h" + +#define kTypeValue @"UploadInfoV1" +#define kBlockSize (4 * 1024 * 1024) + +@interface QNUploadInfoV1() + +@property(nonatomic, assign)int dataSize; +@property(nonatomic, strong)QNMutableArray *blockList; + +@property(nonatomic, assign)BOOL isEOF; +@property(nonatomic, strong, nullable)NSError *readError; +@end +@implementation QNUploadInfoV1 + ++ (instancetype)info:(id)source + configuration:(nonnull QNConfiguration *)configuration { + + QNUploadInfoV1 *info = [QNUploadInfoV1 info:source]; + if (configuration.useConcurrentResumeUpload || configuration.chunkSize > kBlockSize) { + info.dataSize = kBlockSize; + } else { + info.dataSize = configuration.chunkSize; + } + info.blockList = [QNMutableArray array]; + return info; +} + ++ (instancetype)info:(id )source + dictionary:(NSDictionary *)dictionary { + if (dictionary == nil) { + return nil; + } + + int dataSize = [dictionary[@"dataSize"] intValue]; + NSString *type = dictionary[kQNUploadInfoTypeKey]; + NSArray *blockInfoList = dictionary[@"blockList"]; + + QNMutableArray *blockList = [QNMutableArray array]; + if ([blockInfoList isKindOfClass:[NSArray class]]) { + for (int i = 0; i < blockInfoList.count; i++) { + NSDictionary *blockInfo = blockInfoList[i]; + if ([blockInfo isKindOfClass:[NSDictionary class]]) { + QNUploadBlock *block = [QNUploadBlock blockFromDictionary:blockInfo]; + if (block == nil) { + return nil; + } + [blockList addObject:block]; + } + } + } + + QNUploadInfoV1 *info = [QNUploadInfoV1 info:source]; + [info setInfoFromDictionary:dictionary]; + info.dataSize = dataSize; + info.blockList = blockList; + + if (![type isEqualToString:kTypeValue] || ![[source getId] isEqualToString:[info getSourceId]]) { + return nil; + } else { + return info; + } +} + +- (BOOL)isFirstData:(QNUploadData *)data { + return data.index == 0; +} + +- (BOOL)isValid { + if (![super isValid]) { + return false; + } + + __block BOOL valid = true; + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + valid = [block isValid]; + if (!valid) { + *stop = true; + } + }]; + return valid; +} + +- (BOOL)reloadSource { + self.isEOF = false; + self.readError = nil; + return [super reloadSource]; +} + +- (BOOL)isSameUploadInfo:(QNUploadInfo *)info { + if (![super isSameUploadInfo:info]) { + return false; + } + + if (![info isKindOfClass:[QNUploadInfoV1 class]]) { + return false; + } + + return self.dataSize == [(QNUploadInfoV1 *)info dataSize]; +} + +- (void)clearUploadState { + if (self.blockList == nil || self.blockList.count == 0) { + return; + } + + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + [block clearUploadState]; + }]; +} + +- (void)checkInfoStateAndUpdate { + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + [block checkInfoStateAndUpdate]; + }]; +} + +- (long long)uploadSize { + if (self.blockList == nil || self.blockList.count == 0) { + return 0; + } + + __block long long uploadSize = 0; + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + uploadSize += [block uploadSize]; + }]; + return uploadSize; +} + +- (BOOL)isAllUploaded { + if (!_isEOF) { + return false; + } + + if (self.blockList == nil || self.blockList.count == 0) { + return true; + } + + __block BOOL isAllUploaded = true; + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + if (!block.isCompleted) { + isAllUploaded = false; + *stop = true; + } + }]; + return isAllUploaded; +} + +- (NSDictionary *)toDictionary { + NSMutableDictionary *dictionary = [[super toDictionary] mutableCopy]; + if (dictionary == nil) { + dictionary = [NSMutableDictionary dictionary]; + } + [dictionary setObject:kTypeValue forKey:kQNUploadInfoTypeKey]; + [dictionary setObject:@(self.dataSize) forKey:@"dataSize"]; + + if (self.blockList != nil && self.blockList.count != 0) { + NSMutableArray *blockInfoList = [NSMutableArray array]; + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + [blockInfoList addObject:[block toDictionary]]; + }]; + [dictionary setObject:[blockInfoList copy] forKey:@"blockList"]; + } + + return [dictionary copy]; +} + +- (QNUploadBlock *)nextUploadBlock:(NSError **)error { + // 从 blockList 中读取需要上传的 block + QNUploadBlock *block = [self nextUploadBlockFormBlockList]; + + // 内存的 blockList 中没有可上传的数据,则从资源中读并创建 block + if (block == nil) { + if (self.isEOF) { + return nil; + } else if (self.readError) { + *error = self.readError; + return nil; + } + + // 从资源中读取新的 block 进行上传 + long long blockOffset = 0; + if (self.blockList.count > 0) { + QNUploadBlock *lastBlock = self.blockList[self.blockList.count - 1]; + blockOffset = lastBlock.offset + (long long)(lastBlock.size); + } + + block = [[QNUploadBlock alloc] initWithOffset:blockOffset blockSize:kBlockSize dataSize:self.dataSize index:self.blockList.count]; + } + + QNUploadBlock *loadBlock = [self loadBlockData:block error:error]; + if (*error != nil) { + self.readError = *error; + return nil; + } + + if (loadBlock == nil) { + // 没有加在到 block, 也即数据源读取结束 + self.isEOF = true; + // 有多余的 block 则移除,移除中包含 block + if (self.blockList.count > block.index) { + self.blockList = [[self.blockList subarrayWithRange:NSMakeRange(0, block.index)] mutableCopy]; + } + } else { + // 加在到 block + if (loadBlock.index == self.blockList.count) { + // 新块:block index 等于 blockList size 则为新创建 block,需要加入 blockList + [self.blockList addObject:loadBlock]; + } else if (loadBlock != block) { + // 更换块:重新加在了 block, 更换信息 + [self.blockList replaceObjectAtIndex:loadBlock.index withObject:loadBlock]; + } + + // 数据源读取结束,块读取大小小于预期,读取结束 + if (loadBlock.size < kBlockSize) { + self.isEOF = true; + // 有多余的 block 则移除,移除中不包含 block + if (self.blockList.count > block.index + 1) { + self.blockList = [[self.blockList subarrayWithRange:NSMakeRange(0, block.index + 1)] mutableCopy]; + } + } + } + + return loadBlock; +} + +- (QNUploadBlock *)nextUploadBlockFormBlockList { + if (self.blockList == nil || self.blockList.count == 0) { + return nil; + } + + __block QNUploadBlock *block = nil; + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *blockP, NSUInteger idx, BOOL * _Nonnull stop) { + QNUploadData *data = [blockP nextUploadDataWithoutCheckData]; + if (data != nil) { + block = blockP; + *stop = true; + } + }]; + return block; +} + +// 加载块中的数据 +// 1. 数据块已加载,直接返回 +// 2. 数据块未加载,读块数据 +// 2.1 如果未读到数据,则已 EOF,返回 null +// 2.2 如果读到数据 +// 2.2.1 如果块数据符合预期,则当片未上传,则加载片数据 +// 2.2.2 如果块数据不符合预期,创建新块,加载片信息 +- (QNUploadBlock *)loadBlockData:(QNUploadBlock *)block error:(NSError **)error { + if (block == nil) { + return nil; + } + + // 已经加载过 block 数据 + // 没有需要上传的片 或者 有需要上传片但是已加载过片数据 + QNUploadData *nextUploadData = [block nextUploadDataWithoutCheckData]; + if (nextUploadData.state == QNUploadStateWaitToUpload && nextUploadData.data != nil) { + return block; + } + + // 未加载过 block 数据 + // 根据 block 信息加载 blockBytes + NSData *blockBytes = nil; + blockBytes = [self readData:block.size dataOffset:block.offset error:error]; + if (*error != nil) { + return nil; + } + + // 没有数据不需要上传 + if (blockBytes == nil || blockBytes.length == 0) { + return nil; + } + + NSString *md5 = [blockBytes qn_md5]; + // 判断当前 block 的数据是否和实际数据吻合,不吻合则之前 block 被抛弃,重新创建 block + if (blockBytes.length != block.size || block.md5 == nil || ![block.md5 isEqualToString:md5]) { + block = [[QNUploadBlock alloc] initWithOffset:block.offset blockSize:blockBytes.length dataSize:self.dataSize index:block.index]; + block.md5 = md5; + } + + for (QNUploadData *data in block.uploadDataList) { + if (data.state != QNUploadStateComplete) { + // 还未上传的 + data.data = [blockBytes subdataWithRange:NSMakeRange((NSUInteger)data.offset, (NSUInteger)data.size)]; + data.state = QNUploadStateWaitToUpload; + } else { + // 已经上传的 + data.state = QNUploadStateComplete; + } + } + + return block; +} + +- (QNUploadData *)nextUploadData:(QNUploadBlock *)block { + if (block == nil) { + return nil; + } + return [block nextUploadDataWithoutCheckData]; +} + +- (NSArray *)allBlocksContexts { + if (self.blockList == nil || self.blockList.count == 0) { + return nil; + } + + NSMutableArray *contexts = [NSMutableArray array]; + [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) { + if (block.context && block.context.length > 0) { + [contexts addObject:block.context]; + } + }]; + return [contexts copy]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h new file mode 100644 index 0000000..0095b3f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h @@ -0,0 +1,35 @@ +// +// QNUploadInfoV2.h +// QiniuSDK +// +// Created by yangsen on 2021/5/13. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNConfiguration.h" +#import "QNUploadData.h" +#import "QNUploadInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadInfoV2 : QNUploadInfo + +@property(nonatomic, copy, nullable)NSString *uploadId; +@property(nonatomic, strong, nullable)NSNumber *expireAt; + ++ (instancetype)info:(id )source + configuration:(QNConfiguration *)configuration; + + ++ (instancetype)info:(id )source + dictionary:(NSDictionary *)dictionary; + +- (QNUploadData *)nextUploadData:(NSError **)error; + +- (NSInteger)getPartIndexOfData:(QNUploadData *)data; + +- (NSArray *> *)getPartInfoArray; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.m new file mode 100644 index 0000000..58b76c1 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.m @@ -0,0 +1,322 @@ +// +// QNUploadInfoV2.m +// QiniuSDK +// +// Created by yangsen on 2021/5/13. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "NSData+QNMD5.h" +#import "QNMutableArray.h" +#import "QNUploadInfoV2.h" + +#define kTypeValue @"UploadInfoV2" +#define kMaxDataSize (1024 * 1024 * 1024) + +@interface QNUploadInfoV2() + +@property(nonatomic, assign)int dataSize; +@property(nonatomic, strong)QNMutableArray *dataList; + +@property(nonatomic, assign)BOOL isEOF; +@property(nonatomic, strong, nullable)NSError *readError; +@end +@implementation QNUploadInfoV2 + ++ (instancetype)info:(id)source + configuration:(nonnull QNConfiguration *)configuration { + + QNUploadInfoV2 *info = [QNUploadInfoV2 info:source]; + info.dataSize = MIN(configuration.chunkSize, kMaxDataSize); + info.dataList = [QNMutableArray array]; + return info; +} + ++ (instancetype)info:(id )source + dictionary:(NSDictionary *)dictionary { + if (dictionary == nil) { + return nil; + } + + int dataSize = [dictionary[@"dataSize"] intValue]; + NSNumber *expireAt = dictionary[@"expireAt"]; + NSString *uploadId = dictionary[@"uploadId"]; + NSString *type = dictionary[kQNUploadInfoTypeKey]; + if (expireAt == nil || ![expireAt isKindOfClass:[NSNumber class]] || + uploadId == nil || ![uploadId isKindOfClass:[NSString class]] || uploadId.length == 0) { + return nil; + } + + NSArray *dataInfoList = dictionary[@"dataList"]; + + QNMutableArray *dataList = [QNMutableArray array]; + if ([dataInfoList isKindOfClass:[NSArray class]]) { + for (int i = 0; i < dataInfoList.count; i++) { + NSDictionary *dataInfo = dataInfoList[i]; + if ([dataInfo isKindOfClass:[NSDictionary class]]) { + QNUploadData *data = [QNUploadData dataFromDictionary:dataInfo]; + if (data == nil) { + return nil; + } + [dataList addObject:data]; + } + } + } + + QNUploadInfoV2 *info = [QNUploadInfoV2 info:source]; + [info setInfoFromDictionary:dictionary]; + info.expireAt = expireAt; + info.uploadId = uploadId; + info.dataSize = dataSize; + info.dataList = dataList; + + if (![type isEqualToString:kTypeValue] || ![[source getId] isEqualToString:[info getSourceId]]) { + return nil; + } else { + return info; + } +} + +- (BOOL)isValid { + if (![super isValid]) { + return false; + } + + if (!self.expireAt || !self.uploadId || self.uploadId.length == 0) { + return false; + } + + return (self.expireAt.doubleValue - 2*3600) > [[NSDate date] timeIntervalSince1970]; +} + +- (BOOL)reloadSource { + self.isEOF = false; + self.readError = nil; + return [super reloadSource]; +} + +- (BOOL)isSameUploadInfo:(QNUploadInfo *)info { + if (![super isSameUploadInfo:info]) { + return false; + } + + if (![info isKindOfClass:[QNUploadInfoV2 class]]) { + return false; + } + + return self.dataSize == [(QNUploadInfoV2 *)info dataSize]; +} + +- (void)clearUploadState { + self.expireAt = nil; + self.uploadId = nil; + if (self.dataList == nil || self.dataList.count == 0) { + return; + } + + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) { + [data clearUploadState]; + }]; +} + +- (void)checkInfoStateAndUpdate { + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) { + [data checkStateAndUpdate]; + }]; +} + +- (long long)uploadSize { + if (self.dataList == nil || self.dataList.count == 0) { + return 0; + } + + __block long long uploadSize = 0; + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) { + uploadSize += [data uploadSize]; + }]; + return uploadSize; +} + +- (BOOL)isAllUploaded { + if (!_isEOF) { + return false; + } + + if (self.dataList == nil || self.dataList.count == 0) { + return true; + } + + __block BOOL isAllUploaded = true; + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) { + if (!data.isUploaded) { + isAllUploaded = false; + *stop = true; + } + }]; + return isAllUploaded; +} + +- (NSDictionary *)toDictionary { + NSMutableDictionary *dictionary = [[super toDictionary] mutableCopy]; + if (dictionary == nil) { + dictionary = [NSMutableDictionary dictionary]; + } + [dictionary setObject:kTypeValue forKey:kQNUploadInfoTypeKey]; + [dictionary setObject:@(self.dataSize) forKey:@"dataSize"]; + [dictionary setObject:self.expireAt ?: 0 forKey:@"expireAt"]; + [dictionary setObject:self.uploadId ?: @"" forKey:@"uploadId"]; + + if (self.dataList != nil && self.dataList.count != 0) { + NSMutableArray *blockInfoList = [NSMutableArray array]; + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) { + [blockInfoList addObject:[data toDictionary]]; + }]; + [dictionary setObject:[blockInfoList copy] forKey:@"dataList"]; + } + + return [dictionary copy]; +} + +- (NSInteger)getPartIndexOfData:(QNUploadData *)data { + return data.index + 1; +} + +- (QNUploadData *)nextUploadData:(NSError **)error { + + // 从 dataList 中读取需要上传的 data + QNUploadData *data = [self nextUploadDataFormDataList]; + + // 内存的 dataList 中没有可上传的数据,则从资源中读并创建 data + if (data == nil) { + if (self.isEOF) { + return nil; + } else if (self.readError) { + *error = self.readError; + return nil; + } + + // 从资源中读取新的 block 进行上传 + long long dataOffset = 0; + if (self.dataList.count > 0) { + QNUploadData *lastData = self.dataList[self.dataList.count - 1]; + dataOffset = lastData.offset + lastData.size; + } + + data = [[QNUploadData alloc] initWithOffset:dataOffset dataSize:self.dataSize index:self.dataList.count]; + } + + QNUploadData*loadData = [self loadData:data error:error]; + if (*error != nil) { + self.readError = *error; + return nil; + } + + if (loadData == nil) { + // 没有加在到 data, 也即数据源读取结束 + self.isEOF = true; + // 有多余的 data 则移除,移除中包含 data + if (self.dataList.count > data.index) { + self.dataList = [[self.dataList subarrayWithRange:NSMakeRange(0, data.index)] mutableCopy]; + } + } else { + // 加在到 data + if (loadData.index == self.dataList.count) { + // 新块:data index 等于 dataList size 则为新创建 block,需要加入 dataList + [self.dataList addObject:loadData]; + } else if (loadData != data) { + // 更换块:重新加在了 data, 更换信息 + [self.dataList replaceObjectAtIndex:loadData.index withObject:loadData]; + } + + // 数据源读取结束,块读取大小小于预期,读取结束 + if (loadData.size < data.size) { + self.isEOF = true; + // 有多余的 data 则移除,移除中不包含 data + if (self.dataList.count > data.index + 1) { + self.dataList = [[self.dataList subarrayWithRange:NSMakeRange(0, data.index + 1)] mutableCopy]; + } + } + } + + return loadData; +} + +- (QNUploadData *)nextUploadDataFormDataList { + if (self.dataList == nil || self.dataList.count == 0) { + return nil; + } + + __block QNUploadData *data = nil; + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *dataP, NSUInteger idx, BOOL * _Nonnull stop) { + if ([dataP needToUpload]) { + data = dataP; + *stop = true; + } + }]; + + return data; +} + +// 加载块中的数据 +// 1. 数据块已加载,直接返回 +// 2. 数据块未加载,读块数据 +// 2.1 如果未读到数据,则已 EOF,返回 null +// 2.2 如果读到数据 +// 2.2.1 如果块数据符合预期,则当片未上传,则加载片数据 +// 2.2.2 如果块数据不符合预期,创建新块,加载片信息 +- (QNUploadData *)loadData:(QNUploadData *)data error:(NSError **)error { + if (data == nil) { + return nil; + } + + // 之前已加载并验证过数据,不必在验证 + if (data.data != nil) { + return data; + } + + // 未加载过 block 数据 + // 根据 data 信息加载 dataBytes + NSData *dataBytes = [self readData:(NSInteger)data.size dataOffset:data.offset error:error]; + if (*error != nil) { + return nil; + } + + // 没有数据不需要上传 + if (dataBytes == nil || dataBytes.length == 0) { + return nil; + } + + NSString *md5 = [dataBytes qn_md5]; + // 判断当前 block 的数据是否和实际数据吻合,不吻合则之前 block 被抛弃,重新创建 block + if (dataBytes.length != data.size || data.md5 == nil || ![data.md5 isEqualToString:md5]) { + data = [[QNUploadData alloc] initWithOffset:data.offset dataSize:dataBytes.length index:data.index]; + data.md5 = md5; + } + + if (data.etag == nil || data.etag.length == 0) { + data.data = dataBytes; + data.state = QNUploadStateWaitToUpload; + } else { + data.state = QNUploadStateComplete; + } + + return data; +} + +- (NSArray *> *)getPartInfoArray { + if (self.uploadId == nil || self.uploadId.length == 0) { + return nil; + } + + NSMutableArray *infoArray = [NSMutableArray array]; + [self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) { + if (data.state == QNUploadStateComplete && data.etag != nil) { + [infoArray addObject:@{@"etag" : data.etag, + @"partNumber" : @([self getPartIndexOfData:data])}]; + } + }]; + + return [infoArray copy]; +} + +@end diff --git a/msext/QiniuSDK/Storage/QNUploadManager.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.h similarity index 76% rename from msext/QiniuSDK/Storage/QNUploadManager.h rename to Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.h index 43cda53..80f78c5 100755 --- a/msext/QiniuSDK/Storage/QNUploadManager.h +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.h @@ -13,10 +13,13 @@ @class QNResponseInfo; @class QNUploadOption; @class QNConfiguration; -@class ALAsset; @class PHAsset; @class PHAssetResource; +#if !TARGET_OS_MACCATALYST +@class ALAsset; +#endif + /** * 上传完成后的回调函数 * @@ -27,7 +30,7 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDictionary *resp); /** - 管理上传的类,可以生成一次,持续使用,不必反复创建。 + 管理上传的类,可以生成一次,持续使用,不必反复创建。 */ @interface QNUploadManager : NSObject @@ -91,6 +94,28 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDic complete:(QNUpCompletionHandler)completionHandler option:(QNUploadOption *)option; + +/** + * 上传数据流 + * + * @param inputStream 数据流 + * @param sourceId 数据 id; 用于断点续传的标识 + * @param size 流大小,主要用来计算上传进度,不能预知大小传 -1 + * @param fileName 文件名 + * @param key 上传到云存储的key,为nil时表示是由七牛生成 + * @param token 上传需要的token, 由服务器生成 + * @param completionHandler 上传完成后的回调函数 + * @param option 上传时传入的可选参数 + */ +- (void)putInputStream:(NSInputStream *)inputStream + sourceId:(NSString *)sourceId + size:(long long)size + fileName:(NSString *)fileName + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option; + /** * 上传文件 * @@ -106,10 +131,11 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDic complete:(QNUpCompletionHandler)completionHandler option:(QNUploadOption *)option; +#if !TARGET_OS_MACCATALYST /** * 上传ALAsset文件 * - * @param alasset ALAsset文件 + * @param asset ALAsset文件 * @param key 上传到云存储的key,为nil时表示是由七牛生成 * @param token 上传需要的token, 由服务器生成 * @param completionHandler 上传完成后的回调函数 @@ -119,7 +145,8 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDic key:(NSString *)key token:(NSString *)token complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option; + option:(QNUploadOption *)option API_DEPRECATED("use putPHAsset instead", ios(4.0, 9.0)) API_UNAVAILABLE(macos, tvos); +#endif /** * 上传PHAsset文件(IOS8 andLater) @@ -134,12 +161,12 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDic key:(NSString *)key token:(NSString *)token complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option; + option:(QNUploadOption *)option API_AVAILABLE(ios(9.1)) API_UNAVAILABLE(macos, tvos); /** * 上传PHAssetResource文件(IOS9.1 andLater) * - * @param asset PHAssetResource文件 + * @param assetResource PHAssetResource文件 * @param key 上传到云存储的key,为nil时表示是由七牛生成 * @param token 上传需要的token, 由服务器生成 * @param completionHandler 上传完成后的回调函数 @@ -150,6 +177,6 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDic key:(NSString *)key token:(NSString *)token complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option; + option:(QNUploadOption *)option API_AVAILABLE(ios(9)) API_UNAVAILABLE(macos, tvos); @end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.m new file mode 100644 index 0000000..bea8933 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.m @@ -0,0 +1,505 @@ +// +// QNUploader.h +// QiniuSDK +// +// Created by bailong on 14-9-28. +// Copyright (c) 2014年 Qiniu. All rights reserved. +// + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#import + +#if !TARGET_OS_MACCATALYST +#import +#import "QNALAssetFile.h" +#endif + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +#import "QNPHAssetFile.h" +#import +#endif + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 +#import "QNPHAssetResource.h" +#endif + +#else +#import +#endif + +#import "QNUploadManager.h" + +#import "QNAsyncRun.h" +#import "QNConfiguration.h" +#import "QNCrc32.h" +#import "QNFile.h" +#import "QNUtils.h" +#import "QNResponseInfo.h" + +#import "QNFormUpload.h" +#import "QNPartsUpload.h" +#import "QNConcurrentResumeUpload.h" + +#import "QNUpToken.h" +#import "QNUploadOption.h" +#import "QNReportItem.h" + +#import "QNServerConfigMonitor.h" +#import "QNDnsPrefetch.h" +#import "QNZone.h" + +#import "QNUploadSourceFile.h" +#import "QNUploadSourceStream.h" + +@interface QNUploadManager () +@property (nonatomic) QNConfiguration *config; +@end + +@implementation QNUploadManager + +- (instancetype)init { + return [self initWithConfiguration:nil]; +} + +- (instancetype)initWithRecorder:(id)recorder { + return [self initWithRecorder:recorder recorderKeyGenerator:nil]; +} + +- (instancetype)initWithRecorder:(id)recorder + recorderKeyGenerator:(QNRecorderKeyGenerator)recorderKeyGenerator { + QNConfiguration *config = [QNConfiguration build:^(QNConfigurationBuilder *builder) { + builder.recorder = recorder; + builder.recorderKeyGen = recorderKeyGenerator; + }]; + return [self initWithConfiguration:config]; +} + +- (instancetype)initWithConfiguration:(QNConfiguration *)config { + if (self = [super init]) { + if (config == nil) { + config = [QNConfiguration build:^(QNConfigurationBuilder *builder){ + }]; + } + _config = config; + [[QNTransactionManager shared] addDnsLocalLoadTransaction]; + [QNServerConfigMonitor startMonitor]; + } + return self; +} + ++ (instancetype)sharedInstanceWithConfiguration:(QNConfiguration *)config { + static QNUploadManager *sharedInstance = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] initWithConfiguration:config]; + }); + + return sharedInstance; +} + +- (void)putData:(NSData *)data + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { + + [self putData:data fileName:nil key:key token:token complete:completionHandler option:option]; +} + +- (void)putData:(NSData *)data + fileName:(NSString *)fileName + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { + + if ([QNUploadManager checkAndNotifyError:key token:token input:data complete:completionHandler]) { + return; + } + + QNUpToken *t = [QNUpToken parse:token]; + if (t == nil || ![t isValid]) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithInvalidToken:@"invalid token"]; + [QNUploadManager complete:token + key:key + source:data + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + + QNServerConfigMonitor.token = token; + [[QNTransactionManager shared] addDnsCheckAndPrefetchTransaction:self.config zone:self.config.zone token:t]; + + QNUpTaskCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, QNUploadTaskMetrics *metrics, NSDictionary *resp) { + [QNUploadManager complete:token + key:key + source:data + responseInfo:info + response:resp + taskMetrics:metrics + complete:completionHandler]; + }; + QNFormUpload *up = [[QNFormUpload alloc] initWithData:data + key:key + fileName:fileName + token:t + option:option + configuration:self.config + completionHandler:complete]; + QNAsyncRun(^{ + [up run]; + }); +} + +- (void)putInputStream:(NSInputStream *)inputStream + sourceId:(NSString *)sourceId + size:(long long)size + fileName:(NSString *)fileName + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { + + if ([QNUploadManager checkAndNotifyError:key token:token input:inputStream complete:completionHandler]) { + return; + } + + @autoreleasepool { + QNUploadSourceStream *source = [QNUploadSourceStream stream:inputStream sourceId:sourceId size:size fileName:fileName]; + [self putInternal:source key:key token:token complete:completionHandler option:option]; + } +} + +- (void)putFile:(NSString *)filePath + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { + + if ([QNUploadManager checkAndNotifyError:key token:token input:filePath complete:completionHandler]) { + return; + } + + @autoreleasepool { + NSError *error = nil; + __block QNFile *file = [[QNFile alloc] init:filePath error:&error]; + if (error) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; + [QNUploadManager complete:token + key:key + source:nil + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + [self putFileInternal:file key:key token:token complete:completionHandler option:option]; + } +} + +#if !TARGET_OS_MACCATALYST +- (void)putALAsset:(ALAsset *)asset + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { +#if __IPHONE_OS_VERSION_MIN_REQUIRED + + if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) { + return; + } + + @autoreleasepool { + NSError *error = nil; + __block QNALAssetFile *file = [[QNALAssetFile alloc] init:asset error:&error]; + if (error) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; + [QNUploadManager complete:token + key:key + source:nil + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + [self putFileInternal:file key:key token:token complete:completionHandler option:option]; + } +#endif +} +#endif + +- (void)putPHAsset:(PHAsset *)asset + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100) + + if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) { + return; + } + + @autoreleasepool { + NSError *error = nil; + __block QNPHAssetFile *file = [[QNPHAssetFile alloc] init:asset error:&error]; + if (error) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; + [QNUploadManager complete:token + key:key + source:nil + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + [self putFileInternal:file key:key token:token complete:completionHandler option:option]; + } +#endif +} + +- (void)putPHAssetResource:(PHAssetResource *)assetResource + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000) + + if ([QNUploadManager checkAndNotifyError:key token:token input:assetResource complete:completionHandler]) { + return; + } + @autoreleasepool { + NSError *error = nil; + __block QNPHAssetResource *file = [[QNPHAssetResource alloc] init:assetResource error:&error]; + if (error) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; + [QNUploadManager complete:token + key:key + source:nil + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + [self putFileInternal:file key:key token:token complete:completionHandler option:option]; + } +#endif +} + +- (void)putFileInternal:(id)file + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { + [self putInternal:[QNUploadSourceFile file:file] + key:key token:token + complete:completionHandler + option:option]; +} + +- (void)putInternal:(id)source + key:(NSString *)key + token:(NSString *)token + complete:(QNUpCompletionHandler)completionHandler + option:(QNUploadOption *)option { + + @autoreleasepool { + QNUpToken *t = [QNUpToken parse:token]; + if (t == nil || ![t isValid]) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithInvalidToken:@"invalid token"]; + [QNUploadManager complete:token + key:key + source:source + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + + + QNUpTaskCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, QNUploadTaskMetrics *metrics, NSDictionary *resp) { + [QNUploadManager complete:token + key:key + source:source + responseInfo:info + response:resp + taskMetrics:metrics + complete:completionHandler]; + }; + + QNServerConfigMonitor.token = token; + [[QNTransactionManager shared] addDnsCheckAndPrefetchTransaction:self.config zone:self.config.zone token:t]; + + long long sourceSize = [source getSize]; + if (sourceSize > 0 && sourceSize <= self.config.putThreshold) { + NSError *error; + NSData *data = [source readData:(NSInteger)sourceSize dataOffset:0 error:&error]; + [source close]; + if (error) { + QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; + [QNUploadManager complete:token + key:key + source:source + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return; + } + + [self putData:data + fileName:[source getFileName] + key:key + token:token + complete:completionHandler + option:option]; + return; + } + + NSString *recorderKey = key; + if (self.config.recorder != nil && self.config.recorderKeyGen != nil) { + recorderKey = self.config.recorderKeyGen(key, [source getId]); + } + + if (self.config.useConcurrentResumeUpload) { + QNConcurrentResumeUpload *up = [[QNConcurrentResumeUpload alloc] + initWithSource:source + key:key + token:t + option:option + configuration:self.config + recorder:self.config.recorder + recorderKey:recorderKey + completionHandler:complete]; + QNAsyncRun(^{ + [up run]; + }); + } else { + QNPartsUpload *up = [[QNPartsUpload alloc] + initWithSource:source + key:key + token:t + option:option + configuration:self.config + recorder:self.config.recorder + recorderKey:recorderKey + completionHandler:complete]; + QNAsyncRun(^{ + [up run]; + }); + } + } +} + ++ (BOOL)checkAndNotifyError:(NSString *)key + token:(NSString *)token + input:(NSObject *)input + complete:(QNUpCompletionHandler)completionHandler { + if (completionHandler == nil) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"no completionHandler" + userInfo:nil]; + return YES; + } + + QNResponseInfo *info = nil; + if (input == nil) { + info = [QNResponseInfo responseInfoOfZeroData:@"no input data"]; + } else if ([input isKindOfClass:[NSData class]] && [(NSData *)input length] == 0) { + info = [QNResponseInfo responseInfoOfZeroData:@"no input data"]; + } else if (token == nil || [token isEqual:[NSNull null]] || [token isEqualToString:@""]) { + info = [QNResponseInfo responseInfoWithInvalidToken:@"no token"]; + } + if (info != nil) { + [QNUploadManager complete:token + key:key + source:nil + responseInfo:info + response:nil + taskMetrics:nil + complete:completionHandler]; + return YES; + } else { + return NO; + } +} + ++ (void)complete:(NSString *)token + key:(NSString *)key + source:(NSObject *)source + responseInfo:(QNResponseInfo *)responseInfo + response:(NSDictionary *)response + taskMetrics:(QNUploadTaskMetrics *)taskMetrics + complete:(QNUpCompletionHandler)completionHandler { + + [QNUploadManager reportQuality:key source:source responseInfo:responseInfo taskMetrics:taskMetrics token:token]; + + QNAsyncRunInMain(^{ + if (completionHandler) { + completionHandler(responseInfo, key, response); + } + }); +} + + +//MARK:-- 统计quality日志 ++ (void)reportQuality:(NSString *)key + source:(NSObject *)source + responseInfo:(QNResponseInfo *)responseInfo + taskMetrics:(QNUploadTaskMetrics *)taskMetrics + token:(NSString *)token{ + + QNUpToken *upToken = [QNUpToken parse:token]; + QNUploadTaskMetrics *taskMetricsP = taskMetrics ?: [QNUploadTaskMetrics emptyMetrics]; + + QNReportItem *item = [QNReportItem item]; + [item setReportValue:QNReportLogTypeQuality forKey:QNReportQualityKeyLogType]; + [item setReportValue:taskMetricsP.upType forKey:QNReportQualityKeyUpType]; + [item setReportValue:@([[NSDate date] timeIntervalSince1970]) forKey:QNReportQualityKeyUpTime]; + [item setReportValue:responseInfo.qualityResult forKey:QNReportQualityKeyResult]; + [item setReportValue:upToken.bucket forKey:QNReportQualityKeyTargetBucket]; + [item setReportValue:key forKey:QNReportQualityKeyTargetKey]; + [item setReportValue:taskMetricsP.totalElapsedTime forKey:QNReportQualityKeyTotalElapsedTime]; + [item setReportValue:taskMetricsP.ucQueryMetrics.totalElapsedTime forKey:QNReportQualityKeyUcQueryElapsedTime]; + [item setReportValue:taskMetricsP.requestCount forKey:QNReportQualityKeyRequestsCount]; + [item setReportValue:taskMetricsP.regionCount forKey:QNReportQualityKeyRegionsCount]; + [item setReportValue:taskMetricsP.bytesSend forKey:QNReportQualityKeyBytesSent]; + + [item setReportValue:[QNUtils systemName] forKey:QNReportQualityKeyOsName]; + [item setReportValue:[QNUtils systemVersion] forKey:QNReportQualityKeyOsVersion]; + [item setReportValue:[QNUtils sdkLanguage] forKey:QNReportQualityKeySDKName]; + [item setReportValue:[QNUtils sdkVersion] forKey:QNReportQualityKeySDKVersion]; + + [item setReportValue:responseInfo.requestReportErrorType forKey:QNReportQualityKeyErrorType]; + NSString *errorDesc = responseInfo.requestReportErrorType ? responseInfo.message : nil; + [item setReportValue:errorDesc forKey:QNReportQualityKeyErrorDescription]; + + [item setReportValue:taskMetricsP.lastMetrics.lastMetrics.hijacked forKey:QNReportBlockKeyHijacking]; + + long long fileSize = -1; + if ([source conformsToProtocol:@protocol(QNUploadSource)]) { + fileSize = [(id )source getSize]; + } else if ([source isKindOfClass:[NSData class]]) { + fileSize = [(NSData *)source length]; + } + [item setReportValue:@(fileSize) forKey:QNReportQualityKeyFileSize]; + if (responseInfo.isOK && fileSize > 0 && taskMetrics.totalElapsedTime) { + NSNumber *speed = [QNUtils calculateSpeed:fileSize totalTime:taskMetrics.totalElapsedTime.longLongValue]; + [item setReportValue:speed forKey:QNReportQualityKeyPerceptiveSpeed]; + } + + [kQNReporter reportItem:item token:token]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.h new file mode 100755 index 0000000..f426e19 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.h @@ -0,0 +1,138 @@ +// +// QNUploadOption.h +// QiniuSDK +// +// Created by bailong on 14/10/4. +// Copyright (c) 2014年 Qiniu. All rights reserved. +// + +#import + +/** + * 上传进度回调函数 + * + * @param key 上传时指定的存储key + * @param percent 进度百分比 + */ +typedef void (^QNUpProgressHandler)(NSString *key, float percent); + +/** + * 上传进度回调函数 + * + * @param key 上传文件的保存文件名 + * @param uploadBytes 已上传大小 + * @param totalBytes 总大小;无法获取大小时为 -1 + */ +typedef void (^QNUpByteProgressHandler)(NSString *key, long long uploadBytes, long long totalBytes); + +/** + * 上传中途取消函数 + * + * @return 如果想取消,返回True, 否则返回No + */ +typedef BOOL (^QNUpCancellationSignal)(void); + +/** + * 可选参数集合,此类初始化后sdk上传使用时 不会对此进行改变;如果参数没有变化以及没有使用依赖,可以重复使用。 + */ +@interface QNUploadOption : NSObject + +/** + * 用于服务器上传回调通知的自定义参数,参数的key必须以x: 开头 eg: x:foo + */ +@property (copy, nonatomic, readonly) NSDictionary *params; + +/** + * 用于设置meta数据,参数的key必须以x-qn-meta- 开头 eg: x-qn-meta-key + */ +@property (copy, nonatomic, readonly) NSDictionary *metaDataParam; + +/** + * 指定文件的mime类型 + */ +@property (copy, nonatomic, readonly) NSString *mimeType; + +/** + * 是否进行crc校验 + */ +@property (readonly) BOOL checkCrc; + +/** + * 进度回调函数 + */ +@property (copy, readonly) QNUpProgressHandler progressHandler; + +/** + * 进度回调函数 + * 注: + * 使用此接口,progressHandler 会无效 + */ +@property (copy, readonly) QNUpByteProgressHandler byteProgressHandler; + +/** + * 中途取消函数 + */ +@property (copy, readonly) QNUpCancellationSignal cancellationSignal; + +/** + * 可选参数的初始化方法 + * + * @param mimeType mime类型 + * @param progress 进度函数 + * @param params 自定义服务器回调参数 参数的key必须以x: 开头 eg: x:foo + * @param check 是否进行crc检查 + * @param cancellation 中途取消函数 + * + * @return 可选参数类实例 + */ +- (instancetype)initWithMime:(NSString *)mimeType + progressHandler:(QNUpProgressHandler)progress + params:(NSDictionary *)params + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation; + +- (instancetype)initWithMime:(NSString *)mimeType + byteProgressHandler:(QNUpByteProgressHandler)progress + params:(NSDictionary *)params + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation; + + +/** + * 可选参数的初始化方法 + * + * @param mimeType mime类型 + * @param progress 进度函数 + * @param params 自定义服务器回调参数 参数的key必须以x: 开头 eg: x:foo + * @param metaDataParams 设置meta数据,参数的key必须以x-qn-meta- 开头 eg: x-qn-meta-key + * @param check 是否进行crc检查 + * @param cancellation 中途取消函数 + * + * @return 可选参数类实例 + */ +- (instancetype)initWithMime:(NSString *)mimeType + progressHandler:(QNUpProgressHandler)progress + params:(NSDictionary *)params + metaDataParams:(NSDictionary *)metaDataParams + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation; + +- (instancetype)initWithMime:(NSString *)mimeType + byteProgressHandler:(QNUpByteProgressHandler)progress + params:(NSDictionary *)params + metaDataParams:(NSDictionary *)metaDataParams + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation; + +- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress; + +- (instancetype)initWithByteProgressHandler:(QNUpByteProgressHandler)progress; + +/** + * 内部使用,默认的参数实例 + * + * @return 可选参数类实例 + */ ++ (instancetype)defaultOptions; + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.m new file mode 100755 index 0000000..65715a8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.m @@ -0,0 +1,134 @@ +// +// QNUploadOption.m +// QiniuSDK +// +// Created by bailong on 14/10/4. +// Copyright (c) 2014年 Qiniu. All rights reserved. +// + +#import "QNUploadOption.h" +#import "QNUploadManager.h" + +static NSString *mime(NSString *mimeType) { + if (mimeType == nil || [mimeType isEqualToString:@""]) { + return @"application/octet-stream"; + } + return mimeType; +} + +@implementation QNUploadOption + ++ (NSDictionary *)filterParam:(NSDictionary *)params { + NSMutableDictionary *ret = [NSMutableDictionary dictionary]; + if (params == nil) { + return ret; + } + + [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { + if ([key hasPrefix:@"x:"] && ![obj isEqualToString:@""]) { + ret[key] = obj; + } else { + NSLog(@"参数%@设置无效,请检查参数格式", key); + } + }]; + + return ret; +} + ++ (NSDictionary *)filterMetaDataParam:(NSDictionary *)params { + NSMutableDictionary *ret = [NSMutableDictionary dictionary]; + if (params == nil) { + return ret; + } + + [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { + if ([key hasPrefix:@"x-qn-meta-"] && ![obj isEqualToString:@""]) { + ret[key] = obj; + } else { + NSLog(@"参数%@设置无效,请检查参数格式", key); + } + }]; + + return ret; +} + + +- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress { + return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil]; +} + +- (instancetype)initWithByteProgressHandler:(QNUpByteProgressHandler)progress { + return [self initWithMime:nil byteProgressHandler:progress params:nil checkCrc:NO cancellationSignal:nil]; +} + +- (instancetype)initWithMime:(NSString *)mimeType + progressHandler:(QNUpProgressHandler)progress + params:(NSDictionary *)params + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancel { + return [self initWithMime:mimeType + progressHandler:progress + params:params + metaDataParams:nil + checkCrc:check + cancellationSignal:cancel]; +} + +- (instancetype)initWithMime:(NSString *)mimeType + byteProgressHandler:(QNUpByteProgressHandler)progress + params:(NSDictionary *)params + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation { + return [self initWithMime:mimeType + byteProgressHandler:progress + params:params + metaDataParams:nil + checkCrc:check + cancellationSignal:cancellation]; +} + +- (instancetype)initWithMime:(NSString *)mimeType + progressHandler:(QNUpProgressHandler)progress + params:(NSDictionary *)params + metaDataParams:(NSDictionary *)metaDataParams + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation{ + if (self = [super init]) { + _mimeType = mime(mimeType); + _progressHandler = progress != nil ? progress : ^(NSString *key, float percent) {}; + _params = [QNUploadOption filterParam:params]; + _metaDataParam = [QNUploadOption filterMetaDataParam:metaDataParams]; + _checkCrc = check; + _cancellationSignal = cancellation != nil ? cancellation : ^BOOL() { + return NO; + }; + } + + return self; +} + +- (instancetype)initWithMime:(NSString *)mimeType + byteProgressHandler:(QNUpByteProgressHandler)progress + params:(NSDictionary *)params + metaDataParams:(NSDictionary *)metaDataParams + checkCrc:(BOOL)check + cancellationSignal:(QNUpCancellationSignal)cancellation { + if (self = [super init]) { + _mimeType = mime(mimeType); + _byteProgressHandler = progress != nil ? progress : ^(NSString *key, long long uploadBytes, long long totalBytes) {}; + _params = [QNUploadOption filterParam:params]; + _metaDataParam = [QNUploadOption filterMetaDataParam:metaDataParams]; + _checkCrc = check; + _cancellationSignal = cancellation != nil ? cancellation : ^BOOL() { + return NO; + }; + } + + return self; +} + ++ (instancetype)defaultOptions { + return [[QNUploadOption alloc] initWithMime:nil byteProgressHandler:nil params:nil checkCrc:NO cancellationSignal:nil]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadSource.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSource.h new file mode 100644 index 0000000..eac53cc --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSource.h @@ -0,0 +1,83 @@ +// +// QNUploadSource.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol QNUploadSource + +/** + * 获取资源唯一标识 + * 作为断点续传时判断是否为同一资源的依据之一; + * 如果两个资源的 record key 和 资源唯一标识均相同则认为资源为同一资源,断点续传才会生效 + * 注: + * 同一资源的数据必须完全相同,否则上传可能会出现异常 + * + * @return 资源修改时间 + */ +- (NSString *)getId; + +/** + * 是否可以重新加载文件信息,也即是否可以重新读取信息 + * @return return + */ +- (BOOL)couldReloadSource; + +/** + * 重新加载文件信息,以便于重新读取 + * + * @return 重新加载是否成功 + */ +- (BOOL)reloadSource; + +/** + * 获取资源文件名 + * @return 资源文件名 + */ +- (NSString *)getFileName; + +/** + * 获取资源大小 + * 无法获取大小时返回 -1 + * 作用: + * 1. 验证资源是否为同一资源 + * 2. 计算上传进度 + * + * @return 资源大小 + */ +- (long long)getSize; + +/** + * 读取数据 + * 1. 返回 NSData 可能为空,但不会为 null; + * 2. 当 NSData 大小和 dataSize 不同时,则源数据已经读取结束 + * 3. 读取异常时抛出 error + * 4. 仅支持串行调用,且 dataOffset 依次递增 + * + * @param dataSize 数据大小 + * @param dataOffset 数据偏移量 + * @param error 异常时的错误信息 + * @return 数据 + */ +- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error; + +/** + * 关闭流 + */ +- (void)close; + +@optional +// 上传源类型 +- (NSString *)sourceType; + +@end + +#define kQNUnknownSourceSize (-1) + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h new file mode 100644 index 0000000..ce39124 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h @@ -0,0 +1,20 @@ +// +// QNUploadSourceFile.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNFileDelegate.h" +#import "QNUploadSource.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadSourceFile : NSObject + ++ (instancetype)file:(id )file; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.m new file mode 100644 index 0000000..ce17f0b --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.m @@ -0,0 +1,60 @@ +// +// QNUploadSourceFile.m +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadSourceFile.h" + +@interface QNUploadSourceFile() + +@property(nonatomic, strong)id file; + +@end +@implementation QNUploadSourceFile + ++ (instancetype)file:(id )file { + QNUploadSourceFile *sourceFile = [[QNUploadSourceFile alloc] init]; + sourceFile.file = file; + return sourceFile; +} + + +- (BOOL)couldReloadSource { + return self.file != nil; +} + +- (BOOL)reloadSource { + return true; +} + +- (nonnull NSString *)getId { + return [NSString stringWithFormat:@"%@_%lld", [self getFileName], [self.file modifyTime]]; +} + +- (nonnull NSString *)getFileName { + return [[self.file path] lastPathComponent]; +} + +- (long long)getSize { + return [self.file size]; +} + +- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError *__autoreleasing _Nullable *)error { + return [self.file read:dataOffset size:dataSize error:error]; +} + +- (void)close { + [self.file close]; +} + +- (NSString *)sourceType { + if ([self.file respondsToSelector:@selector(fileType)]) { + return self.file.fileType; + } else { + return @"SourceFile"; + } +} +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h new file mode 100644 index 0000000..3def8a4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h @@ -0,0 +1,22 @@ +// +// QNUploadSourceStream.h +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNUploadSource.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUploadSourceStream : NSObject + ++ (instancetype)stream:(NSInputStream * _Nonnull)stream + sourceId:(NSString * _Nullable)sourceId + size:(long long)size + fileName:(NSString * _Nullable)fileName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.m b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.m new file mode 100644 index 0000000..0f218c8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.m @@ -0,0 +1,234 @@ +// +// QNUploadSourceStream.m +// QiniuSDK +// +// Created by yangsen on 2021/5/10. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNErrorCode.h" +#import "QNUploadSourceStream.h" + +@interface QNUploadSourceStream() + +@property(nonatomic, assign)BOOL hasSize; +@property(nonatomic, assign)long long size; +@property(nonatomic, assign)long long readOffset; +@property(nonatomic, copy)NSString *sourceId; +@property(nonatomic, copy)NSString *fileName; +@property(nonatomic, strong)NSInputStream *stream; + +@end +@implementation QNUploadSourceStream + ++ (instancetype)stream:(NSInputStream * _Nonnull)stream + sourceId:(NSString * _Nullable)sourceId + size:(long long)size + fileName:(NSString * _Nullable)fileName { + QNUploadSourceStream *sourceStream = [[QNUploadSourceStream alloc] init]; + sourceStream.stream = stream; + sourceStream.sourceId = sourceId; + sourceStream.fileName = fileName; + sourceStream.size = size; + sourceStream.hasSize = size > 0; + sourceStream.readOffset = 0; + return sourceStream; +} + +- (NSString *)getId { + return self.sourceId; +} + +- (BOOL)couldReloadSource { + return false; +} + +- (BOOL)reloadSource { + return false; +} + +- (NSString *)getFileName { + return self.fileName; +} + +- (long long)getSize { + if (self.size > kQNUnknownSourceSize) { + return self.size; + } else { + return kQNUnknownSourceSize; + } +} + +- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error { + if (self.stream == nil) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"inputStream is empty"}]; + return nil; + } + + if (dataOffset < self.readOffset) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"read data error: error data offset"}]; + return nil; + } + + // 打开流 + [self openStreamIfNeeded]; + + if (dataOffset > self.readOffset) { + // 跳过多余的数据 + [self streamSkipSize:dataOffset - self.readOffset error:error]; + if (*error != nil) { + return nil; + } + self.readOffset = dataOffset; + } + + // 读取数据 + BOOL isEOF = false; + NSInteger sliceSize = 1024; + NSInteger readSize = 0; + NSMutableData *data = [NSMutableData data]; + while (readSize < dataSize) { + @autoreleasepool { + NSData *sliceData = [self readDataFromStream:sliceSize error:error]; + if (*error != nil) { + break; + } + + if (sliceData.length > 0) { + readSize += sliceData.length; + [data appendData:sliceData]; + } + + if (sliceData.length < sliceSize) { + isEOF = true; + break; + } + } + } + + + self.readOffset += readSize; + + if (*error != nil) { + return nil; + } + + if (isEOF) { + self.size = self.readOffset; + } + + return data; +} + +- (void)openStreamIfNeeded { + BOOL isOpening = true; + while (true) { + switch (self.stream.streamStatus) { + case NSStreamStatusNotOpen: + [self.stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + [self.stream open]; + continue; + case NSStreamStatusOpening: + continue; + default: + isOpening = false; + break; + } + + if (!isOpening) { + break; + } + } +} + +- (void)streamSkipSize:(long long)size error:(NSError **)error { + BOOL isEOF = false; + NSInteger sliceSize = 1024; + NSInteger readSize = 0; + while (readSize < size) { + @autoreleasepool { + NSData *sliceData = [self readDataFromStream:sliceSize error:error]; + if (*error != nil) { + break; + } + + if (sliceData.length > 0) { + readSize += sliceData.length; + } + + if (sliceData.length < sliceSize) { + isEOF = true; + break; + } + sliceData = nil; + } + } +} + +// read 之前必须先 open stream +- (NSData *)readDataFromStream:(NSInteger)dataSize error:(NSError **)error { + BOOL isEOF = false; + NSInteger readSize = 0; + NSMutableData *data = [NSMutableData data]; + uint8_t buffer[dataSize]; + while (readSize < dataSize) { + // 检查状态 + switch (self.stream.streamStatus) { + case NSStreamStatusOpen: + break; + case NSStreamStatusReading: + continue; + case NSStreamStatusWriting: + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"stream is writing"}]; + break; + case NSStreamStatusAtEnd: + isEOF = true; + break; + case NSStreamStatusClosed: + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"stream is closed"}]; + break; + case NSStreamStatusError: + *error = self.stream.streamError; + break; + default: + break; + } + if (*error != nil) { + return nil; + } + + if (isEOF) { + break; + } + + // 检查是否有数据可读 + if (!self.stream.hasBytesAvailable) { + [NSThread sleepForTimeInterval:0.05]; + continue; + } + + // 读取数据 + NSInteger maxLength = dataSize; + NSInteger length = [self.stream read:buffer maxLength:maxLength]; + *error = self.stream.streamError; + if (*error != nil) { + return nil; + } + + if (length > 0) { + readSize += length; + [data appendBytes:(const void *)buffer length:length]; + } + } + return [data copy]; +} + +- (void)close { + [self.stream close]; + [self.stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; +} + +- (NSString *)sourceType { + return [NSString stringWithFormat:@"SourceStream:%@", _hasSize?@"HasSize":@"NoSize"]; +} +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h new file mode 100644 index 0000000..d86badb --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h @@ -0,0 +1,94 @@ +// +// QNServerConfig.h +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNCache.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNServerRegionConfig : NSObject + +@property(nonatomic, assign, readonly)long clearId; +@property(nonatomic, assign, readonly)BOOL clearCache; + ++ (instancetype)config:(NSDictionary *)info; + +@end + + +@interface QNServerDnsServer : NSObject + +@property(nonatomic, assign, readonly)BOOL isOverride; +@property(nonatomic, strong, readonly)NSArray *servers; + ++ (instancetype)config:(NSDictionary *)info; + +@end + +@interface QNServerDohConfig : NSObject + +@property(nonatomic, strong, readonly)NSNumber *enable; +@property(nonatomic, strong, readonly)QNServerDnsServer *ipv4Server; +@property(nonatomic, strong, readonly)QNServerDnsServer *ipv6Server; + ++ (instancetype)config:(NSDictionary *)info; + +@end + + +@interface QNServerUdpDnsConfig : NSObject + +@property(nonatomic, strong, readonly)NSNumber *enable; +@property(nonatomic, strong, readonly)QNServerDnsServer *ipv4Server; +@property(nonatomic, strong, readonly)QNServerDnsServer *ipv6Server; + ++ (instancetype)config:(NSDictionary *)info; + +@end + + +@interface QNServerDnsConfig : NSObject + +@property(nonatomic, strong, readonly)NSNumber *enable; +@property(nonatomic, assign, readonly)long clearId; +@property(nonatomic, assign, readonly)BOOL clearCache; +@property(nonatomic, strong, readonly)QNServerUdpDnsConfig *udpConfig; +@property(nonatomic, strong, readonly)QNServerDohConfig *dohConfig; + ++ (instancetype)config:(NSDictionary *)info; + +@end + + +@interface QNConnectCheckConfig : NSObject + +@property(nonatomic, assign, readonly)BOOL isOverride; +@property(nonatomic, strong, readonly)NSNumber *enable; +@property(nonatomic, strong, readonly)NSNumber *timeoutMs; +@property(nonatomic, strong, readonly)NSArray *urls; + ++ (instancetype)config:(NSDictionary *)info; + +@end + + +@interface QNServerConfig : NSObject + +@property(nonatomic, assign, readonly)BOOL isValid; +@property(nonatomic, assign, readonly)long ttl; +@property(nonatomic, strong, readonly)QNServerRegionConfig *regionConfig; +@property(nonatomic, strong, readonly)QNServerDnsConfig *dnsConfig; +@property(nonatomic, strong, readonly)QNConnectCheckConfig *connectCheckConfig; + +@property(nonatomic, strong, readonly)NSDictionary *info; + ++ (instancetype)config:(NSDictionary *)info; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.m b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.m new file mode 100644 index 0000000..d7dffd8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.m @@ -0,0 +1,160 @@ +// +// QNServerConfig.m +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNServerConfig.h" + +@interface QNServerRegionConfig() +@property(nonatomic, assign)long clearId; +@property(nonatomic, assign)BOOL clearCache; +@end +@implementation QNServerRegionConfig ++ (instancetype)config:(NSDictionary *)info { + QNServerRegionConfig *config = [[QNServerRegionConfig alloc] init]; + config.clearId = [info[@"clear_id"] longValue]; + config.clearCache = [info[@"clear_cache"] longValue]; + return config; +} +@end + +@interface QNServerDnsServer() +@property(nonatomic, assign)BOOL isOverride; +@property(nonatomic, strong)NSArray *servers; +@end +@implementation QNServerDnsServer ++ (instancetype)config:(NSDictionary *)info { + QNServerDnsServer *config = [[QNServerDnsServer alloc] init]; + config.isOverride = [info[@"override_default"] boolValue]; + if (info[@"ips"] && [info[@"ips"] isKindOfClass:[NSArray class]]) { + config.servers = info[@"ips"]; + } else if ([info[@"urls"] isKindOfClass:[NSArray class]]){ + config.servers = info[@"urls"]; + } + return config; +} +@end + +@interface QNServerDohConfig() +@property(nonatomic, strong)NSNumber *enable; +@property(nonatomic, strong)QNServerDnsServer *ipv4Server; +@property(nonatomic, strong)QNServerDnsServer *ipv6Server; +@end +@implementation QNServerDohConfig ++ (instancetype)config:(NSDictionary *)info { + QNServerDohConfig *config = [[QNServerDohConfig alloc] init]; + config.enable = info[@"enabled"]; + config.ipv4Server = [QNServerDnsServer config:info[@"ipv4"]]; + config.ipv6Server = [QNServerDnsServer config:info[@"ipv6"]]; + return config; +} +@end + +@interface QNServerUdpDnsConfig() +@property(nonatomic, strong)NSNumber *enable; +@property(nonatomic, strong)QNServerDnsServer *ipv4Server; +@property(nonatomic, strong)QNServerDnsServer *ipv6Server; +@end +@implementation QNServerUdpDnsConfig ++ (instancetype)config:(NSDictionary *)info { + QNServerUdpDnsConfig *config = [[QNServerUdpDnsConfig alloc] init]; + config.enable = info[@"enabled"]; + config.ipv4Server = [QNServerDnsServer config:info[@"ipv4"]]; + config.ipv6Server = [QNServerDnsServer config:info[@"ipv6"]]; + return config; +} +@end + + +@interface QNServerDnsConfig() +@property(nonatomic, strong)NSNumber *enable; +@property(nonatomic, assign)long clearId; +@property(nonatomic, assign)BOOL clearCache; +@property(nonatomic, strong)QNServerUdpDnsConfig *udpConfig; +@property(nonatomic, strong)QNServerDohConfig *dohConfig; +@end +@implementation QNServerDnsConfig ++ (instancetype)config:(NSDictionary *)info { + QNServerDnsConfig *config = [[QNServerDnsConfig alloc] init]; + config.enable = info[@"enabled"]; + config.clearId = [info[@"clear_id"] longValue]; + config.clearCache = [info[@"clear_cache"] longValue]; + config.dohConfig = [QNServerDohConfig config:info[@"doh"]]; + config.udpConfig = [QNServerUdpDnsConfig config:info[@"udp"]]; + return config; +} +@end + + +@interface QNConnectCheckConfig() +@property(nonatomic, assign)BOOL isOverride; +@property(nonatomic, strong)NSNumber *enable; +@property(nonatomic, strong)NSNumber *timeoutMs; +@property(nonatomic, strong)NSArray *urls; +@end +@implementation QNConnectCheckConfig ++ (instancetype)config:(NSDictionary *)info { + QNConnectCheckConfig *config = [[QNConnectCheckConfig alloc] init]; + config.isOverride = [info[@"override_default"] boolValue]; + config.enable = info[@"enabled"]; + config.timeoutMs = info[@"timeout_ms"]; + if (info[@"urls"] && [info[@"urls"] isKindOfClass:[NSArray class]]) { + config.urls = info[@"urls"]; + } + return config; +} +@end + + +@interface QNServerConfig() +@property(nonatomic, strong)NSDictionary *info; +@property(nonatomic, assign)double timestamp; +@property(nonatomic, assign)long ttl; +@property(nonatomic, strong)QNServerRegionConfig *regionConfig; +@property(nonatomic, strong)QNServerDnsConfig *dnsConfig; +@property(nonatomic, strong)QNConnectCheckConfig *connectCheckConfig; +@end +@implementation QNServerConfig + ++ (instancetype)config:(NSDictionary *)info { + return [[QNServerConfig alloc] initWithDictionary:info]; +} + +- (nonnull id)initWithDictionary:(nullable NSDictionary *)info { + if (self = [self init]) { + if (info) { + self.ttl = [info[@"ttl"] longValue]; + self.regionConfig = [QNServerRegionConfig config:info[@"region"]]; + self.dnsConfig = [QNServerDnsConfig config:info[@"dns"]]; + self.connectCheckConfig = [QNConnectCheckConfig config:info[@"connection_check"]]; + + if (self.ttl < 10) { + self.ttl = 10; + } + + NSMutableDictionary *mutableInfo = [info mutableCopy]; + if (info[@"timestamp"] != nil) { + self.timestamp = [info[@"timestamp"] doubleValue]; + } + if (self.timestamp == 0) { + self.timestamp = [[NSDate date] timeIntervalSince1970]; + mutableInfo[@"timestamp"] = @(self.timestamp); + } + self.info = [mutableInfo copy]; + } + } + return self; +} + +- (nullable NSDictionary *)toDictionary { + return [self.info copy]; +} + +- (BOOL)isValid { + return [[NSDate date] timeIntervalSince1970] < (self.timestamp + self.ttl); +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h new file mode 100644 index 0000000..2de2d4d --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h @@ -0,0 +1,29 @@ +// +// QNServerConfigCache.h +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNServerConfig.h" +#import "QNServerUserConfig.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNServerConfigCache : NSObject + +@property(nonatomic, strong)QNServerConfig *config; +@property(nonatomic, strong)QNServerUserConfig *userConfig; + +- (QNServerConfig *)getConfigFromDisk; +- (void)saveConfigToDisk:(QNServerConfig *)config; + +- (QNServerUserConfig *)getUserConfigFromDisk; +- (void)saveUserConfigToDisk:(QNServerUserConfig *)config; + +- (void)removeConfigCache; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.m b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.m new file mode 100644 index 0000000..c9f63b0 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.m @@ -0,0 +1,65 @@ +// +// QNServerConfigCache.m +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNServerConfigCache.h" +#import "QNUtils.h" +#import "QNCache.h" + +#define kQNServerConfigDiskKey @"config" +#define kQNServerUserConfigDiskKey @"userConfig" + +@interface QNServerConfigCache(){ + QNServerConfig *_config; + QNServerUserConfig *_userConfig; +} +@property(nonatomic, strong) QNCache *configCache; +@property(nonatomic, strong) QNCache *userConfigCache; +@end +@implementation QNServerConfigCache + +- (instancetype)init { + if (self = [super init]) { + QNCacheOption *option = [[QNCacheOption alloc] init]; + option.version = @"v1.0.0"; + self.configCache = [QNCache cache:[QNServerConfig class] option:option]; + + option = [[QNCacheOption alloc] init]; + option.version = @"v1.0.0"; + self.userConfigCache = [QNCache cache:[QNServerUserConfig class] option:option]; + } + return self; +} + +//MARK: --- config +- (QNServerConfig *)getConfigFromDisk { + return [self.configCache cacheForKey:kQNServerConfigDiskKey]; +} + +- (void)saveConfigToDisk:(QNServerConfig *)config { + [self.configCache cache:config forKey:kQNServerConfigDiskKey atomically:true]; +} + +//MARK: --- user config +- (QNServerUserConfig *)getUserConfigFromDisk { + return [self.userConfigCache cacheForKey:kQNServerUserConfigDiskKey]; +} + +- (void)saveUserConfigToDisk:(QNServerUserConfig *)config { + [self.userConfigCache cache:config forKey:kQNServerUserConfigDiskKey atomically:true]; +} + +- (void)removeConfigCache { + @synchronized (self) { + [self.configCache clearMemoryCache]; + [self.configCache clearDiskCache]; + [self.userConfigCache clearMemoryCache]; + [self.userConfigCache clearDiskCache]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h new file mode 100644 index 0000000..4b11d97 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h @@ -0,0 +1,33 @@ +// +// QNServerConfiguration.h +// QiniuSDK +// +// Created by yangsen on 2021/8/25. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNServerConfigMonitor : NSObject + +@property(nonatomic, assign, class)BOOL enable; + +@property(class, nonatomic, strong)NSString *token; + +// 开始监控 ++ (void)startMonitor; + +// 停止监控 ++ (void)endMonitor; + +// 配置 token ++ (void)setToken:(NSString *)token; + +// 移除缓存 ++ (void)removeConfigCache; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.m b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.m new file mode 100644 index 0000000..ece02e8 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.m @@ -0,0 +1,237 @@ +// +// QNServerConfiguration.m +// QiniuSDK +// +// Created by yangsen on 2021/8/25. +// Copyright © 2021 Qiniu. All rights reserved. +// +#import "QNLogUtil.h" +#import "QNDefine.h" +#import "QNAutoZone.h" +#import "QNDnsPrefetch.h" +#import "QNConfiguration.h" +#import "QNServerConfigSynchronizer.h" +#import "QNServerConfigCache.h" +#import "QNServerConfigMonitor.h" +#import "QNTransactionManager.h" + +#define kQNServerConfigTransactionKey @"QNServerConfig" + +@interface QNGlobalConfiguration(DnsDefaultServer) +@property(nonatomic, strong)NSArray *defaultConnectCheckUrls; +@property(nonatomic, strong)NSArray *defaultDohIpv4Servers; +@property(nonatomic, strong)NSArray *defaultDohIpv6Servers; +@property(nonatomic, strong)NSArray *defaultUdpDnsIpv4Servers; +@property(nonatomic, strong)NSArray *defaultUdpDnsIpv6Servers; +@end +@implementation QNGlobalConfiguration(DnsDefaultServer) +@dynamic defaultConnectCheckUrls; +@dynamic defaultDohIpv4Servers; +@dynamic defaultDohIpv6Servers; +@dynamic defaultUdpDnsIpv4Servers; +@dynamic defaultUdpDnsIpv6Servers; +@end + +@interface QNServerConfigMonitor() + +@property(nonatomic, assign)BOOL enable; +@property(nonatomic, strong)QNServerConfigCache *cache; + +@end +@implementation QNServerConfigMonitor ++ (instancetype)share { + static QNServerConfigMonitor *monitor = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + monitor = [[QNServerConfigMonitor alloc] init]; + }); + return monitor; +} + +- (instancetype)init { + if (self = [super init]) { + _enable = true; + _cache = [[QNServerConfigCache alloc] init]; + } + return self; +} + ++ (BOOL)enable { + return [[QNServerConfigMonitor share] enable]; +} + ++ (void)setEnable:(BOOL)enable { + [QNServerConfigMonitor share].enable = enable; +} + ++ (NSString *)token { + return QNServerConfigSynchronizer.token; +} + +// 配置 token ++ (void)setToken:(NSString *)token { + QNServerConfigSynchronizer.token = token; +} + +// 开始监控 ++ (void)startMonitor { + if (![QNServerConfigMonitor share].enable) { + return; + } + + @synchronized (self) { + BOOL isExist = [kQNTransactionManager existTransactionsForName:kQNServerConfigTransactionKey]; + if (isExist) { + return; + } + + int interval = 120 + arc4random()%240; + QNTransaction *transaction = [QNTransaction timeTransaction:kQNServerConfigTransactionKey after:0 interval:interval action:^{ + [[QNServerConfigMonitor share] monitor]; + }]; + [kQNTransactionManager addTransaction:transaction]; + } +} + +// 停止监控 ++ (void)endMonitor { + @synchronized (self) { + NSArray *transactions = [kQNTransactionManager transactionsForName:kQNServerConfigTransactionKey]; + for (QNTransaction *transaction in transactions) { + [kQNTransactionManager removeTransaction:transaction]; + } + } +} + ++ (void)removeConfigCache { + [[QNServerConfigMonitor share].cache removeConfigCache]; +} + +- (void)monitor { + if (!self.enable) { + return; + } + + if (self.cache.config == nil) { + QNServerConfig *config = [self.cache getConfigFromDisk]; + [self handleServerConfig:config]; + self.cache.config = config; + } + + if (!self.cache.config.isValid) { + [QNServerConfigSynchronizer getServerConfigFromServer:^(QNServerConfig * _Nonnull config) { + if (config == nil) { + return; + } + [self handleServerConfig:config]; + self.cache.config = config; + [self.cache saveConfigToDisk:config]; + }]; + } + + if (self.cache.userConfig == nil) { + QNServerUserConfig *config = [self.cache getUserConfigFromDisk]; + [self handleServerUserConfig:config]; + self.cache.userConfig = config; + } + + if (!self.cache.userConfig.isValid) { + [QNServerConfigSynchronizer getServerUserConfigFromServer:^(QNServerUserConfig * _Nonnull config) { + if (config == nil) { + return; + } + [self handleServerUserConfig:config]; + self.cache.userConfig = config; + [self.cache saveUserConfigToDisk:config]; + }]; + } +} + +- (void)handleServerConfig:(QNServerConfig *)config { + if (config == nil) { + return; + } + + // 清理 region 缓存 + if (self.cache.config.regionConfig && + config.regionConfig.clearId > self.cache.config.regionConfig.clearId && + config.regionConfig.clearCache) { + QNLogDebug(@"server config: clear region cache"); + [QNAutoZone clearCache]; + } + + // dns 配置 + if (config.dnsConfig.enable) { + QNLogDebug(@"server config: dns enable %@", config.dnsConfig.enable); + kQNGlobalConfiguration.isDnsOpen = [config.dnsConfig.enable boolValue]; + } + + // 清理 dns 缓存 + if (self.cache.config.dnsConfig && + config.dnsConfig.clearId > self.cache.config.dnsConfig.clearId && + config.dnsConfig.clearCache) { + QNLogDebug(@"server config: clear dns cache"); + [kQNDnsPrefetch clearDnsCache:nil]; + } + + // udp 配置 + if (config.dnsConfig.udpConfig.enable) { + QNLogDebug(@"server config: udp enable %@", config.dnsConfig.udpConfig.enable); + kQNGlobalConfiguration.udpDnsEnable = [config.dnsConfig.udpConfig.enable boolValue]; + } + + if (config.dnsConfig.udpConfig.ipv4Server.isOverride && + [config.dnsConfig.udpConfig.ipv4Server.servers isKindOfClass:[NSArray class]]) { + QNLogDebug(@"server config: udp config ipv4Server %@", config.dnsConfig.udpConfig.ipv4Server.servers); + kQNGlobalConfiguration.defaultUdpDnsIpv4Servers = [config.dnsConfig.udpConfig.ipv4Server.servers copy]; + } + if (config.dnsConfig.udpConfig.ipv6Server.isOverride && + [config.dnsConfig.udpConfig.ipv6Server.servers isKindOfClass:[NSArray class]]) { + QNLogDebug(@"server config: udp config ipv6Server %@", config.dnsConfig.udpConfig.ipv6Server.servers); + kQNGlobalConfiguration.defaultUdpDnsIpv6Servers = [config.dnsConfig.udpConfig.ipv6Server.servers copy]; + } + + // doh 配置 + if (config.dnsConfig.dohConfig.enable) { + kQNGlobalConfiguration.dohEnable = [config.dnsConfig.dohConfig.enable boolValue]; + QNLogDebug(@"server config: doh enable %@", config.dnsConfig.dohConfig.enable); + } + if (config.dnsConfig.dohConfig.ipv4Server.isOverride && + [config.dnsConfig.dohConfig.ipv4Server.servers isKindOfClass:[NSArray class]]) { + QNLogDebug(@"server config: doh config ipv4Server %@", config.dnsConfig.dohConfig.ipv4Server.servers); + kQNGlobalConfiguration.defaultDohIpv4Servers = [config.dnsConfig.dohConfig.ipv4Server.servers copy]; + } + if (config.dnsConfig.dohConfig.ipv6Server.isOverride && + [config.dnsConfig.dohConfig.ipv6Server.servers isKindOfClass:[NSArray class]]) { + QNLogDebug(@"server config: doh config ipv6Server %@", config.dnsConfig.dohConfig.ipv6Server.servers); + kQNGlobalConfiguration.defaultDohIpv6Servers = [config.dnsConfig.dohConfig.ipv6Server.servers copy]; + } + + // connect check + if (config.connectCheckConfig.enable) { + kQNGlobalConfiguration.connectCheckEnable = [config.connectCheckConfig.enable boolValue]; + QNLogDebug(@"server config: connect check enable %@", config.dnsConfig.dohConfig.enable); + } + if (config.connectCheckConfig.timeoutMs) { + kQNGlobalConfiguration.connectCheckTimeout = [config.connectCheckConfig.timeoutMs doubleValue] / 1000; + QNLogDebug(@"server config: connect check timeout %@", config.connectCheckConfig.timeoutMs); + } + if (config.connectCheckConfig.isOverride && + config.connectCheckConfig.urls && + [config.connectCheckConfig.urls isKindOfClass:[NSArray class]]) { + kQNGlobalConfiguration.defaultConnectCheckUrls = config.connectCheckConfig.urls; + QNLogDebug(@"server config: connect check urls %@", config.connectCheckConfig.urls); + } +} + +- (void)handleServerUserConfig:(QNServerUserConfig *)config { + if (config == nil) { + return; + } + if (config.networkCheckEnable) { + QNLogDebug(@"server config: connect check enable %@", config.networkCheckEnable); + kQNGlobalConfiguration.connectCheckEnable = [config.networkCheckEnable boolValue]; + } +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h new file mode 100644 index 0000000..9aae220 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h @@ -0,0 +1,24 @@ +// +// QNServerConfigSynchronizer.h +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNServerConfig.h" +#import "QNServerUserConfig.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface QNServerConfigSynchronizer : NSObject + +@property(class, nonatomic, strong)NSString *token; +@property(class, nonatomic, strong)NSArray *hosts; + ++ (void)getServerConfigFromServer:(void(^)(QNServerConfig *config))complete; ++ (void)getServerUserConfigFromServer:(void(^)(QNServerUserConfig *config))complete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.m b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.m new file mode 100644 index 0000000..041b4cb --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.m @@ -0,0 +1,158 @@ +// +// QNServerConfigSynchronizer.m +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNConfig.h" +#import "QNUpToken.h" +#import "QNZoneInfo.h" +#import "QNResponseInfo.h" +#import "QNRequestTransaction.h" +#import "QNServerConfigSynchronizer.h" +#import + +static NSString *Token = nil; +static NSArray *Hosts = nil; +static pthread_mutex_t TokenMutexLock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t HostsMutexLock = PTHREAD_MUTEX_INITIALIZER; + +static QNRequestTransaction *serverConfigTransaction = nil; +static QNRequestTransaction *serverUserConfigTransaction = nil; + +@implementation QNServerConfigSynchronizer + +//MARK: --- server config ++ (void)getServerConfigFromServer:(void(^)(QNServerConfig *config))complete { + if (complete == nil) { + return; + } + + QNRequestTransaction *transaction = [self createServerConfigTransaction]; + if (transaction == nil) { + complete(nil); + return; + } + + [transaction serverConfig:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + if (responseInfo.isOK && response != nil) { + complete([QNServerConfig config:response]); + } else { + complete(nil); + } + [self destroyServerConfigRequestTransaction]; + }]; +} + ++ (QNRequestTransaction *)createServerConfigTransaction { + @synchronized (self) { + // 上传时才会有 token,不上传不请求,避免不必要请求 + if (serverConfigTransaction != nil) { + return nil; + } + + QNUpToken *token = [QNUpToken parse:self.token]; + if (token == nil) { + token = [QNUpToken getInvalidToken]; + } + + NSArray *hosts = self.hosts; + if (hosts == nil) { + hosts = kQNPreQueryHosts; + } + QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithHosts:hosts + regionId:QNZoneInfoEmptyRegionId + token:token]; + serverConfigTransaction = transaction; + return transaction; + } +} + ++ (void)destroyServerConfigRequestTransaction { + @synchronized (self) { + serverConfigTransaction = nil; + } +} + +//MARK: --- server user config ++ (void)getServerUserConfigFromServer:(void(^)(QNServerUserConfig *config))complete { + if (complete == nil) { + return; + } + + QNRequestTransaction *transaction = [self createServerUserConfigTransaction]; + if (transaction == nil) { + complete(nil); + return; + } + + [transaction serverUserConfig:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) { + if (responseInfo.isOK && response != nil) { + complete([QNServerUserConfig config:response]); + } else { + complete(nil); + } + [self destroyServerConfigRequestTransaction]; + }]; +} + ++ (QNRequestTransaction *)createServerUserConfigTransaction { + @synchronized (self) { + if (serverConfigTransaction != nil) { + return nil; + } + + QNUpToken *token = [QNUpToken parse:self.token]; + if (token == nil || !token.isValid) { + return nil; + } + + NSArray *hosts = self.hosts; + if (hosts == nil) { + hosts = kQNPreQueryHosts; + } + QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithHosts:hosts + regionId:QNZoneInfoEmptyRegionId + token:token]; + serverUserConfigTransaction = transaction; + return transaction; + } +} + ++ (void)destroyServerUserConfigRequestTransaction { + @synchronized (self) { + serverUserConfigTransaction = nil; + } +} + ++ (void)setToken:(NSString *)token { + pthread_mutex_lock(&TokenMutexLock); + Token = token; + pthread_mutex_unlock(&TokenMutexLock); +} + ++ (NSString *)token { + NSString *token = nil; + pthread_mutex_lock(&TokenMutexLock); + token = Token; + pthread_mutex_unlock(&TokenMutexLock); + return token; +} + ++ (void)setHosts:(NSArray *)servers { + pthread_mutex_lock(&HostsMutexLock); + Hosts = [servers copy]; + pthread_mutex_unlock(&HostsMutexLock); +} + ++ (NSArray *)hosts { + NSArray *hosts = nil; + pthread_mutex_lock(&HostsMutexLock); + hosts = [Hosts copy]; + pthread_mutex_unlock(&HostsMutexLock); + return hosts; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h new file mode 100644 index 0000000..eeb5e3c --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h @@ -0,0 +1,27 @@ +// +// QNServerUserConfig.h +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNCache.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNServerUserConfig : NSObject + +@property(nonatomic, assign, readonly)BOOL isValid; +@property(nonatomic, assign, readonly)long ttl; +@property(nonatomic, strong, readonly)NSNumber *http3Enable; +@property(nonatomic, strong, readonly)NSNumber *networkCheckEnable; + +@property(nonatomic, strong, readonly)NSDictionary *info; + ++ (instancetype)config:(NSDictionary *)info; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.m b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.m new file mode 100644 index 0000000..2391604 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.m @@ -0,0 +1,58 @@ +// +// QNServerUserConfig.m +// QiniuSDK +// +// Created by yangsen on 2021/8/30. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNServerUserConfig.h" + +@interface QNServerUserConfig() +@property(nonatomic, strong)NSDictionary *info; +@property(nonatomic, assign)double timestamp; +@property(nonatomic, assign)long ttl; +@property(nonatomic, strong)NSNumber *http3Enable; +@property(nonatomic, strong)NSNumber *retryMax; +@property(nonatomic, strong)NSNumber *networkCheckEnable; +@end +@implementation QNServerUserConfig + ++ (instancetype)config:(NSDictionary *)info { + return [[QNServerUserConfig alloc] initWithDictionary:info]; +} + +- (nonnull id)initWithDictionary:(nullable NSDictionary *)info { + if (self = [super init]) { + if (info) { + self.ttl = [info[@"ttl"] longValue]; + self.http3Enable = info[@"http3"][@"enabled"]; + self.networkCheckEnable = info[@"network_check"][@"enabled"]; + + if (self.ttl < 10) { + self.ttl = 10; + } + + NSMutableDictionary *mutableInfo = [info mutableCopy]; + if (info[@"timestamp"] != nil) { + self.timestamp = [info[@"timestamp"] doubleValue]; + } + if (self.timestamp == 0) { + self.timestamp = [[NSDate date] timeIntervalSince1970]; + mutableInfo[@"timestamp"] = @(self.timestamp); + } + self.info = [mutableInfo copy]; + } + } + return self; +} + +- (nullable NSDictionary *)toDictionary { + return [self.info copy]; +} + +- (BOOL)isValid { + return [[NSDate date] timeIntervalSince1970] < (self.timestamp + self.ttl); +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Transaction/QNTransactionManager.h b/Pods/Qiniu/QiniuSDK/Transaction/QNTransactionManager.h new file mode 100644 index 0000000..409f8db --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Transaction/QNTransactionManager.h @@ -0,0 +1,76 @@ +// +// QNTransactionManager.h +// QiniuSDK +// +// Created by yangsen on 2020/4/1. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNTransaction : NSObject + +/// 事务名称 +@property(nonatomic, copy, readonly)NSString *name; +/// 事务延迟执行时间 单位:秒 +@property(nonatomic, assign, readonly)NSInteger after; +/// 事务内容 +@property(nonatomic, copy, readonly)void(^action)(void); +/// 是否正在执行 +@property(nonatomic, assign, readonly)BOOL isExecuting; + +/// MARK: -- 构造方法 +/// 普通事务,事务体仅仅执行一次 +/// @param name 事务名称 +/// @param after 事务延后时间 单位:秒 +/// @param action 事务体 ++ (instancetype)transaction:(NSString *)name + after:(NSInteger)after + action:(void(^)(void))action; +/// 定时事务 +/// @param name 事务名称 +/// @param after 事务延后时间 单位:秒 +/// @param interval 事务执行间隔 单位:秒 +/// @param action 事务体 ++ (instancetype)timeTransaction:(NSString *)name + after:(NSInteger)after + interval:(NSInteger)interval + action:(void(^)(void))action; + +@end + + +#define kQNTransactionManager [QNTransactionManager shared] +@interface QNTransactionManager : NSObject + +/// 单例构造方法 ++ (instancetype)shared; + +/// 根据name查找事务 +/// @param name 事务名称 +- (NSArray *)transactionsForName:(NSString *)name; + +/// 是否存在某个名称的事务 +/// @param name 事务名称 +- (BOOL)existTransactionsForName:(NSString *)name; + +/// 添加一个事务 +/// @param transaction 事务 +- (void)addTransaction:(QNTransaction *)transaction; + +/// 移除一个事务 +/// @param transaction 事务 +- (void)removeTransaction:(QNTransaction *)transaction; + +/// 在下一次循环执行事务, 该事务如果未被添加到事务列表,会自动添加 +/// @param transaction 事务 +- (void)performTransaction:(QNTransaction *)transaction; + +/// 销毁资源 清空事务链表 销毁常驻线程 +- (void)destroyResource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Transaction/QNTransactionManager.m b/Pods/Qiniu/QiniuSDK/Transaction/QNTransactionManager.m new file mode 100644 index 0000000..0495a6e --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Transaction/QNTransactionManager.m @@ -0,0 +1,353 @@ +// +// QNTransactionManager.m +// QiniuSDK +// +// Created by yangsen on 2020/4/1. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNDefine.h" +#import "QNTransactionManager.h" + +//MARK: -- 事务对象 +typedef NS_ENUM(NSInteger, QNTransactionType){ + QNTransactionTypeNormal, // 普通类型事务,事务体仅会执行一次 + QNTransactionTypeTime, // 定时事务,事务体会定时执行 +}; + +@interface QNTransaction() +// 事务类型 +@property(nonatomic, assign)QNTransactionType type; +// 定时任务执行时间间隔 +@property(nonatomic, assign)NSInteger interval; +// 事务延后时间 单位:秒 +@property(nonatomic, assign)NSInteger after; +// 事务执行时间 与事务管理者定时器时间相关联 +@property(nonatomic, assign)double createTime; +// 执行次数 +@property(nonatomic, assign)long executedCount; +// 下次执行时的时间戳 +@property(nonatomic, assign)double nextExecutionTime; + +// 事务名称 +@property(nonatomic, copy)NSString *name; +// 事务执行体 +@property(nonatomic, copy)void(^action)(void); +// 下一个需要处理的事务 +@property(nonatomic, strong, nullable)QNTransaction *nextTransaction; + +@end +@implementation QNTransaction + ++ (instancetype)transaction:(NSString *)name + after:(NSInteger)after + action:(void (^)(void))action{ + QNTransaction *transaction = [[QNTransaction alloc] init]; + transaction.type = QNTransactionTypeNormal; + transaction.after = after; + transaction.name = name; + transaction.action = action; + transaction.executedCount = 0; + transaction.createTime = [[NSDate date] timeIntervalSince1970]; + transaction.nextExecutionTime = transaction.createTime + after; + return transaction; +} + ++ (instancetype)timeTransaction:(NSString *)name + after:(NSInteger)after + interval:(NSInteger)interval + action:(void (^)(void))action{ + QNTransaction *transaction = [[QNTransaction alloc] init]; + transaction.type = QNTransactionTypeTime; + transaction.after = after; + transaction.name = name; + transaction.interval = interval; + transaction.action = action; + transaction.executedCount = 0; + transaction.createTime = [[NSDate date] timeIntervalSince1970]; + transaction.nextExecutionTime = transaction.createTime + after; + return transaction; +} + +- (BOOL)shouldAction { + double currentTime = [[NSDate date] timeIntervalSince1970]; + if (self.type == QNTransactionTypeNormal) { + return self.executedCount < 1 && currentTime >= self.nextExecutionTime; + } else if (self.type == QNTransactionTypeTime) { + return currentTime >= self.nextExecutionTime; + } else { + return NO; + } +} + +- (BOOL)maybeCompleted { + if (self.type == QNTransactionTypeNormal) { + return self.executedCount > 0; + } else if (self.type == QNTransactionTypeTime) { + return false; + } else { + return false; + } +} + +- (void)handleAction { + if (![self shouldAction]) { + return; + } + if (self.action) { + _isExecuting = YES; + self.executedCount += 1; + self.nextExecutionTime = [[NSDate date] timeIntervalSince1970] + self.interval; + self.action(); + _isExecuting = NO; + } +} + +@end + + +//MARK: -- 事务链表 +@interface QNTransactionList : NSObject + +@property(nonatomic, strong)QNTransaction *header; + +@end +@implementation QNTransactionList + +- (BOOL)isEmpty{ + if (self.header == nil) { + return YES; + } else { + return NO; + } +} + +- (NSArray *)transactionsForName:(NSString *)name{ + NSMutableArray *transactions = [NSMutableArray array]; + [self enumerate:^(QNTransaction *transaction, BOOL * _Nonnull stop) { + if ((name == nil && transaction.name == nil) + || (name != nil && transaction.name != nil && [transaction.name isEqualToString:name])) { + [transactions addObject:transaction]; + } + }]; + return [transactions copy]; +} + +- (void)enumerate:(void(^)(QNTransaction *transaction, BOOL * _Nonnull stop))handler { + if (!handler) { + return; + } + BOOL isStop = NO; + QNTransaction *transaction = self.header; + while (transaction && !isStop) { + handler(transaction, &isStop); + transaction = transaction.nextTransaction; + } +} + +- (void)add:(QNTransaction *)transaction{ + + @synchronized (self) { + QNTransaction *transactionP = self.header; + while (transactionP.nextTransaction) { + transactionP = transactionP.nextTransaction; + } + + if (transactionP) { + transactionP.nextTransaction = transaction; + } else { + self.header = transaction; + } + } +} + +- (void)remove:(QNTransaction *)transaction{ + + @synchronized (self) { + QNTransaction *transactionP = self.header; + QNTransaction *transactionLast = nil; + while (transactionP) { + if (transactionP == transaction) { + if (transactionLast) { + transactionLast.nextTransaction = transactionP.nextTransaction; + } else { + self.header = transactionP.nextTransaction; + } + break; + } + transactionLast = transactionP; + transactionP = transactionP.nextTransaction; + } + } +} + +- (BOOL)has:(QNTransaction *)transaction{ + @synchronized (self) { + __block BOOL has = NO; + [self enumerate:^(QNTransaction *transactionP, BOOL * _Nonnull stop) { + if (transaction == transactionP) { + has = YES; + *stop = YES; + } + }]; + return has; + } +} + +- (void)removeAll{ + @synchronized (self) { + self.header = nil; + } +} + +@end + + +//MARK: -- 事务管理者 +@interface QNTransactionManager() +// 事务处理线程 +@property(nonatomic, strong)NSThread *thread; +// 事务链表 +@property(nonatomic, strong)QNTransactionList *transactionList; + +// 事务定时器 +@property(nonatomic, strong)NSTimer *timer; + +@end +@implementation QNTransactionManager + ++ (instancetype)shared{ + static QNTransactionManager *manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[QNTransactionManager alloc] init]; + }); + return manager; +} +- (instancetype)init{ + if (self = [super init]) { + _transactionList = [[QNTransactionList alloc] init]; + } + return self; +} + +- (NSArray *)transactionsForName:(NSString *)name{ + return [self.transactionList transactionsForName:name]; +} + +- (BOOL)existTransactionsForName:(NSString *)name{ + NSArray *transactionList = [self transactionsForName:name]; + if (transactionList && transactionList.count > 0) { + return YES; + } else { + return NO; + } +} + +- (void)addTransaction:(QNTransaction *)transaction{ + if (transaction == nil) { + return; + } + [self.transactionList add:transaction]; + [self createThread]; +} + +- (void)removeTransaction:(QNTransaction *)transaction{ + if (transaction == nil) { + return; + } + [self.transactionList remove:transaction]; +} + +- (void)performTransaction:(QNTransaction *)transaction{ + if (transaction == nil) { + return; + } + @synchronized (self) { + if (![self.transactionList has:transaction]) { + [self.transactionList add:transaction]; + } + transaction.createTime = [[NSDate date] timeIntervalSince1970] - transaction.interval; + } +} + +/// 销毁资源 +- (void)destroyResource{ + + @synchronized (self) { + [self invalidateTimer]; + [self.thread cancel]; + self.thread = nil; + [self.transactionList removeAll]; + } +} + + +//MARK: -- handle transaction action +- (void)handleAllTransaction{ + + [self.transactionList enumerate:^(QNTransaction *transaction, BOOL * _Nonnull stop) { + [self handleTransaction:transaction]; + if ([transaction maybeCompleted]) { + [self removeTransaction:transaction]; + } + }]; +} + +- (void)handleTransaction:(QNTransaction *)transaction{ + [transaction handleAction]; +} + +//MARK: -- thread +- (void)createThread{ + @synchronized (self) { + if (self.thread == nil) { + kQNWeakSelf; + self.thread = [[NSThread alloc] initWithTarget:weak_self + selector:@selector(threadAction) + object:nil]; + self.thread.name = @"com.qiniu.transaction"; + [self.thread start]; + } + } +} + +- (void)threadAction{ + + @autoreleasepool { + if (self.timer == nil) { + [self createTimer]; + } + NSThread *thread = [NSThread currentThread]; + while (thread && !thread.isCancelled) { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + } +} + +//MARK: -- timer +- (void)createTimer{ + kQNWeakSelf; + NSTimer *timer = [NSTimer timerWithTimeInterval:1 + target:weak_self + selector:@selector(timerAction) + userInfo:nil + repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:timer + forMode:NSDefaultRunLoopMode]; + + [self timerAction]; + _timer = timer; +} + +- (void)invalidateTimer{ + [self.timer invalidate]; + self.timer = nil; +} + +- (void)timerAction{ + [self handleAllTransaction]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Utils/NSData+QNGZip.h b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNGZip.h new file mode 100644 index 0000000..cdab0d0 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNGZip.h @@ -0,0 +1,21 @@ +// +// NSData+QNGZip.h +// GZipTest +// +// Created by yangsen on 2020/8/12. +// Copyright © 2020 yangsen. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSData(QNGZip) + ++ (NSData *)qn_gZip:(NSData *)data; + ++ (NSData *)qn_gUnzip:(NSData *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/NSData+QNGZip.m b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNGZip.m new file mode 100644 index 0000000..c904aa0 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNGZip.m @@ -0,0 +1,95 @@ +// +// NSData+QNGZip.m +// GZipTest +// +// Created by yangsen on 2020/8/12. +// Copyright © 2020 yangsen. All rights reserved. +// + +#import "NSData+QNGZip.h" +#import + +#pragma clang diagnostic ignored "-Wcast-qual" + +@implementation NSData(QNGZip) + ++ (NSData *)qn_gZip:(NSData *)data{ + + if (data.length == 0 || [self qn_isGzippedData:data]){ + return data; + } + + z_stream stream; + stream.opaque = Z_NULL; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.total_out = 0; + stream.avail_out = 0; + stream.avail_in = (uint)data.length; + stream.next_in = (Bytef *)(void *)data.bytes; + + static const NSUInteger chunkSize = 16384; + + NSMutableData *gzippedData = nil; + + if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) { + gzippedData = [NSMutableData dataWithLength:chunkSize]; + while (stream.avail_out == 0) { + if (stream.total_out >= gzippedData.length) { + gzippedData.length += chunkSize; + } + stream.next_out = (uint8_t *)gzippedData.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(gzippedData.length - stream.total_out); + deflate(&stream, Z_FINISH); + } + deflateEnd(&stream); + gzippedData.length = stream.total_out; + } + + return gzippedData; +} + ++ (NSData *)qn_gUnzip:(NSData *)data{ + if (data.length == 0 || ![self qn_isGzippedData:data]){ + return data; + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.total_out = 0; + stream.avail_out = 0; + stream.avail_in = (uint)data.length; + stream.next_in = (Bytef *)data.bytes; + + NSMutableData *gunzippedData = nil; + if (inflateInit2(&stream, 47) == Z_OK) { + int status = Z_OK; + gunzippedData = [NSMutableData dataWithCapacity:data.length * 2]; + while (status == Z_OK) { + if (stream.total_out >= gunzippedData.length) { + gunzippedData.length += data.length / 2; + } + stream.next_out = (uint8_t *)gunzippedData.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(gunzippedData.length - stream.total_out); + status = inflate (&stream, Z_SYNC_FLUSH); + } + if (inflateEnd(&stream) == Z_OK) { + if (status == Z_STREAM_END) { + gunzippedData.length = stream.total_out; + } + } + } + + return gunzippedData; +} + ++ (BOOL)qn_isGzippedData:(NSData *)data{ + if (!data || data.length == 0) { + return false; + } + const UInt8 *bytes = (const UInt8 *)data.bytes; + return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Utils/NSData+QNMD5.h b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNMD5.h new file mode 100644 index 0000000..00da6e3 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNMD5.h @@ -0,0 +1,19 @@ +// +// NSData+MD5.h +// QiniuSDK +// +// Created by 杨森 on 2020/7/28. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSData(QNMD5) + +- (NSString *)qn_md5; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/NSData+QNMD5.m b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNMD5.m new file mode 100644 index 0000000..d849688 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/NSData+QNMD5.m @@ -0,0 +1,28 @@ +// +// NSData+MD5.m +// QiniuSDK +// +// Created by 杨森 on 2020/7/28. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "NSData+QNMD5.h" +#import + +@implementation NSData(QNMD5) + +- (NSString *)qn_md5{ + + CC_MD5_CTX md5; + CC_MD5_Init(&md5); + CC_MD5_Update(&md5, self.bytes, (CC_LONG)self.length); + unsigned char digest[CC_MD5_DIGEST_LENGTH]; + CC_MD5_Final(digest, &md5); + NSMutableString *result = [NSMutableString string]; + for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { + [result appendFormat:@"%02X", digest[i]]; + } + return result; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.h b/Pods/Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.h new file mode 100644 index 0000000..48950a9 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.h @@ -0,0 +1,28 @@ +// +// NSObject+QNSwizzle.h +// HappyDNS +// +// Created by yangsen on 2020/4/13. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSObject(QNSwizzle) + +/// swizzle 两个对象方法 +/// @param selectorA 方法a的sel +/// @param selectorB 方法b的sel ++ (BOOL)qn_swizzleInstanceMethodsOfSelectorA:(SEL)selectorA + selectorB:(SEL)selectorB; + +/// swizzle 两个类方法 +/// @param selectorA 方法a的sel +/// @param selectorB 方法b的sel ++ (BOOL)qn_swizzleClassMethodsOfSelectorA:(SEL)selectorA + selectorB:(SEL)selectorB; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.m b/Pods/Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.m new file mode 100644 index 0000000..abc24a3 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.m @@ -0,0 +1,63 @@ +// +// NSObject+QNSwizzle.m +// HappyDNS +// +// Created by yangsen on 2020/4/13. +// + +#import "NSObject+QNSwizzle.h" +#import + +@implementation NSObject(QNSwizzle) + ++ (BOOL)qn_swizzleInstanceMethodsOfSelectorA:(SEL)selectorA + selectorB:(SEL)selectorB{ + + Method methodA = class_getInstanceMethod(self, selectorA); + Method methodB = class_getInstanceMethod(self, selectorB); + if (!methodA || !methodB) { + return NO; + } + + class_addMethod(self, + selectorA, + class_getMethodImplementation(self, selectorA), + method_getTypeEncoding(methodA)); + + class_addMethod(self, + selectorB, + class_getMethodImplementation(self, selectorB), + method_getTypeEncoding(methodB)); + + method_exchangeImplementations(class_getInstanceMethod(self, selectorA), + class_getInstanceMethod(self, selectorB)); + + return YES; +} + ++ (BOOL)qn_swizzleClassMethodsOfSelectorA:(SEL)selectorA + selectorB:(SEL)selectorB{ + + Method methodA = class_getInstanceMethod(object_getClass(self), selectorA); + Method methodB = class_getInstanceMethod(object_getClass(self), selectorB); + if (!methodA || !methodB) { + return NO; + } + + class_addMethod(self, + selectorA, + class_getMethodImplementation(self, selectorA), + method_getTypeEncoding(methodA)); + + class_addMethod(self, + selectorB, + class_getMethodImplementation(self, selectorB), + method_getTypeEncoding(methodB)); + + method_exchangeImplementations(class_getInstanceMethod(self, selectorA), + class_getInstanceMethod(self, selectorB)); + + return YES; +} + +@end diff --git a/msext/QiniuSDK/Common/QNALAssetFile.h b/Pods/Qiniu/QiniuSDK/Utils/QNALAssetFile.h similarity index 65% rename from msext/QiniuSDK/Common/QNALAssetFile.h rename to Pods/Qiniu/QiniuSDK/Utils/QNALAssetFile.h index 2438af4..a597793 100755 --- a/msext/QiniuSDK/Common/QNALAssetFile.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNALAssetFile.h @@ -11,18 +11,20 @@ #import "QNFileDelegate.h" #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) +#if !TARGET_OS_MACCATALYST @class ALAsset; -@interface QNALAssetFile : NSObject +@interface QNALAssetFile : NSObject ; /** * 打开指定文件 * - * @param path 文件路径 + * @param asset 资源文件 * @param error 输出的错误信息 * * @return 实例 */ - (instancetype)init:(ALAsset *)asset - error:(NSError *__autoreleasing *)error; + error:(NSError *__autoreleasing *)error NS_DEPRECATED_IOS(4_0, 9_0); @end -#endif \ No newline at end of file +#endif +#endif diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNALAssetFile.m b/Pods/Qiniu/QiniuSDK/Utils/QNALAssetFile.m new file mode 100755 index 0000000..abadd8f --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNALAssetFile.m @@ -0,0 +1,91 @@ +// +// QNALAssetFile.m +// QiniuSDK +// +// Created by bailong on 15/7/25. +// Copyright (c) 2015年 Qiniu. All rights reserved. +// + +#import "QNALAssetFile.h" + +#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED +#if !TARGET_OS_MACCATALYST +#import +#import "QNResponseInfo.h" + +@interface QNALAssetFile () + +@property (nonatomic) ALAsset *asset NS_DEPRECATED_IOS(4_0, 9_0); + +@property (readonly) int64_t fileSize; + +@property (readonly) int64_t fileModifyTime; + +@property (nonatomic, strong) NSLock *lock; + +@end + +@implementation QNALAssetFile +- (instancetype)init:(ALAsset *)asset + error:(NSError *__autoreleasing *)error { + if (self = [super init]) { + NSDate *createTime = [asset valueForProperty:ALAssetPropertyDate]; + int64_t t = 0; + if (createTime != nil) { + t = [createTime timeIntervalSince1970]; + } + _fileModifyTime = t; + _fileSize = asset.defaultRepresentation.size; + _asset = asset; + _lock = [[NSLock alloc] init]; + } + + return self; +} + +- (NSData *)read:(long long)offset + size:(long)size + error:(NSError **)error NS_DEPRECATED_IOS(4_0, 9_0) { + + NSData *data = nil; + @try { + [_lock lock]; + ALAssetRepresentation *rep = [self.asset defaultRepresentation]; + Byte *buffer = (Byte *)malloc(size); + NSUInteger buffered = [rep getBytes:buffer fromOffset:offset length:size error:error]; + data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES]; + } @catch (NSException *exception) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}]; + NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols); + } @finally { + [_lock unlock]; + } + return data; +} + +- (NSData *)readAllWithError:(NSError **)error { + return [self read:0 size:(long)_fileSize error:error]; +} + +- (void)close { +} + +- (NSString *)path NS_DEPRECATED_IOS(4_0, 9_0) { + ALAssetRepresentation *rep = [self.asset defaultRepresentation]; + return [rep url].path; +} + +- (int64_t)modifyTime { + return _fileModifyTime; +} + +- (int64_t)size { + return _fileSize; +} + +- (NSString *)fileType { + return @"ALAsset"; +} +@end +#endif +#endif diff --git a/msext/QiniuSDK/Common/QNAsyncRun.h b/Pods/Qiniu/QiniuSDK/Utils/QNAsyncRun.h similarity index 50% rename from msext/QiniuSDK/Common/QNAsyncRun.h rename to Pods/Qiniu/QiniuSDK/Utils/QNAsyncRun.h index 8af4661..aa71e4f 100755 --- a/msext/QiniuSDK/Common/QNAsyncRun.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNAsyncRun.h @@ -6,8 +6,15 @@ // Copyright (c) 2014年 Qiniu. All rights reserved. // +#import + +#define kQNBackgroundQueue dispatch_get_global_queue(0, 0) +#define kQNMainQueue dispatch_get_main_queue() + typedef void (^QNRun)(void); void QNAsyncRun(QNRun run); void QNAsyncRunInMain(QNRun run); + +void QNAsyncRunAfter(NSTimeInterval time, dispatch_queue_t queue, QNRun run); diff --git a/msext/QiniuSDK/Common/QNAsyncRun.m b/Pods/Qiniu/QiniuSDK/Utils/QNAsyncRun.m similarity index 69% rename from msext/QiniuSDK/Common/QNAsyncRun.m rename to Pods/Qiniu/QiniuSDK/Utils/QNAsyncRun.m index ea745de..f60e449 100755 --- a/msext/QiniuSDK/Common/QNAsyncRun.m +++ b/Pods/Qiniu/QiniuSDK/Utils/QNAsyncRun.m @@ -20,3 +20,9 @@ void QNAsyncRunInMain(QNRun run) { run(); }); } + +void QNAsyncRunAfter(NSTimeInterval time, dispatch_queue_t queue, QNRun run) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), queue, ^{ + run(); + }); +} diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNCache.h b/Pods/Qiniu/QiniuSDK/Utils/QNCache.h new file mode 100644 index 0000000..07b3645 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNCache.h @@ -0,0 +1,48 @@ +// +// QNCache.h +// QiniuSDK +// +// Created by yangsen on 2023/9/20. +// Copyright © 2023 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol QNCacheObject + +- (nullable NSDictionary *)toDictionary; + +- (nonnull id )initWithDictionary:(nullable NSDictionary *)dictionary; + +@end + + +@interface QNCacheOption : NSObject + +// 当 cache 修改数量到达这个值时,就会 flush,默认是 1 +@property (nonatomic, assign) int flushCount; +// 缓存被持久化为一个文件,此文件的文件名为 version,version 默认为:v1.0.0 +@property (nonatomic, copy) NSString *version; + +@end + +@interface QNCache : NSObject + ++ (instancetype)cache:(Class)objectClass option:(QNCacheOption *)option; + +- (id )cacheForKey:(NSString *)cacheKey; +- (void)cache:(id)object forKey:(NSString *)cacheKey atomically:(BOOL)atomically; + +- (NSDictionary > *)allMemoryCache; + +- (void)flush:(BOOL)atomically; + +- (void)clearMemoryCache; + +- (void)clearDiskCache; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNCache.m b/Pods/Qiniu/QiniuSDK/Utils/QNCache.m new file mode 100644 index 0000000..59cea4e --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNCache.m @@ -0,0 +1,193 @@ +// +// QNCache.m +// QiniuSDK +// +// Created by yangsen on 2023/9/20. +// Copyright © 2023 Qiniu. All rights reserved. +// + +#import "QNCache.h" +#import "QNAsyncRun.h" +#import "QNUtils.h" +#import "QNFileRecorder.h" + +@implementation QNCacheOption +- (instancetype)init { + if (self = [super init]) { + self.flushCount = 1; + } + return self; +} + +- (NSString *)version { + if (_version == nil || _version.length == 0) { + _version = @"v1.0.0"; + } + return _version; +} +@end + +@interface QNCache() + +@property (nonatomic, strong) Class objectClass; +@property (nonatomic, strong) QNCacheOption *option; +@property (nonatomic, strong) QNFileRecorder *diskCache; +@property (nonatomic, assign) BOOL isFlushing; +@property (nonatomic, assign) int needFlushCount; +@property (nonatomic, strong) NSMutableDictionary> *memCache; + +@end +@implementation QNCache + ++ (instancetype)cache:(Class)objectClass option:(QNCacheOption *)option { + QNCache *cache = [[QNCache alloc] init]; + cache.objectClass = objectClass; + cache.option = option ? option : [[QNCacheOption alloc] init]; + cache.isFlushing = false; + cache.needFlushCount = 0; + cache.memCache = [[NSMutableDictionary alloc] init]; + NSString *path = [[QNUtils sdkCacheDirectory] stringByAppendingFormat:@"/%@", objectClass]; + cache.diskCache = [QNFileRecorder fileRecorderWithFolder:path error:nil]; + [cache load]; + return cache; +} + +- (void)load { + if (![self.objectClass conformsToProtocol:@protocol(QNCacheObject)]) { + return; + } + + NSData *data = nil; + @synchronized (self) { + data = [self.diskCache get:self.option.version]; + } + if (data == nil) { + return; + } + + NSError *error = nil; + NSDictionary *cacheDict = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:&error]; + if (error != nil || cacheDict == nil || cacheDict.count == 0) { + [self.diskCache del:self.option.version]; + return; + } + + NSMutableDictionary> *cache = [NSMutableDictionary dictionary]; + for (NSString *key in cacheDict.allKeys) { + NSDictionary *objectDict = cacheDict[key]; + if (!objectDict || objectDict.count == 0) { + continue; + } + + id object = [[self.objectClass alloc] initWithDictionary:objectDict]; + if (object != nil) { + cache[key] = object; + } + } + + if (!cache || cache.count == 0) { + [self.diskCache del:self.option.version]; + return; + } + + @synchronized (self) { + self.memCache = cache; + } +} + +- (NSDictionary> *)allMemoryCache { + @synchronized (self) { + return [self.memCache copy]; + } +} + +- (void)cache:(id)object forKey:(NSString *)cacheKey atomically:(BOOL)atomically { + if (!cacheKey || [cacheKey isEqualToString:@""] || object == nil || + ![object isKindOfClass:self.objectClass]) { + return; + } + + @synchronized (self) { + self.needFlushCount ++; + self.memCache[cacheKey] = object; + } + + if (self.needFlushCount >= self.option.flushCount) { + [self flush:atomically]; + } +} + +- (void)flush:(BOOL)atomically { + @synchronized (self) { + if (self.isFlushing) { + return; + } + self.needFlushCount = 0; + self.isFlushing = true; + } + + NSDictionary> *flushCache = nil; + @synchronized (self) { + if (self.memCache == nil || self.memCache.count == 0) { + return; + } + + flushCache = [self.memCache copy]; + } + + if (atomically) { + [self flushCache:flushCache]; + } else { + QNAsyncRun(^{ + [self flushCache:flushCache]; + }); + } +} + +- (void)flushCache:(NSDictionary > *)flushCache { + if (flushCache == nil || flushCache.count == 0) { + return; + } + + NSMutableDictionary *flushDict = [NSMutableDictionary dictionary]; + for (NSString *key in flushCache.allKeys) { + id object = flushCache[key]; + if (![object respondsToSelector:@selector(toDictionary)]) { + continue; + } + flushDict[key] = [object toDictionary]; + } + + NSData *data = [NSJSONSerialization dataWithJSONObject:flushDict options:NSJSONWritingPrettyPrinted error:nil]; + if (!data || data.length == 0) { + return; + } + + [self.diskCache set:self.option.version data:data]; + + @synchronized (self) { + self.isFlushing = false; + } +} + +- (id )cacheForKey:(NSString *)cacheKey { + @synchronized (self) { + return [self.memCache valueForKey:cacheKey]; + } +} + +- (void)clearMemoryCache { + @synchronized (self) { + self.memCache = [NSMutableDictionary dictionary]; + } +} + +- (void)clearDiskCache { + @synchronized (self) { + [self.diskCache deleteAll]; + } +} + +@end diff --git a/msext/QiniuSDK/Common/QNCrc32.h b/Pods/Qiniu/QiniuSDK/Utils/QNCrc32.h similarity index 100% rename from msext/QiniuSDK/Common/QNCrc32.h rename to Pods/Qiniu/QiniuSDK/Utils/QNCrc32.h diff --git a/msext/QiniuSDK/Common/QNCrc32.m b/Pods/Qiniu/QiniuSDK/Utils/QNCrc32.m similarity index 100% rename from msext/QiniuSDK/Common/QNCrc32.m rename to Pods/Qiniu/QiniuSDK/Utils/QNCrc32.m diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNDefine.h b/Pods/Qiniu/QiniuSDK/Utils/QNDefine.h new file mode 100644 index 0000000..952b6bf --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNDefine.h @@ -0,0 +1,18 @@ +// +// QNDefine.h +// QiniuSDK +// +// Created by yangsen on 2020/9/4. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +#define kQNWeakSelf __weak typeof(self) weak_self = self +#define kQNStrongSelf __strong typeof(self) self = weak_self + +#define kQNWeakObj(object) __weak typeof(object) weak_##object = object +#define kQNStrongObj(object) __strong typeof(object) object = weak_##object + +// 过期 +#define kQNDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead) diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNDefine.m b/Pods/Qiniu/QiniuSDK/Utils/QNDefine.m new file mode 100644 index 0000000..3a9dbb2 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNDefine.m @@ -0,0 +1,11 @@ +// +// QNDefine.m +// QiniuSDK +// +// Created by yangsen on 2020/9/4. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNDefine.h" + + diff --git a/msext/QiniuSDK/Common/QNEtag.h b/Pods/Qiniu/QiniuSDK/Utils/QNEtag.h similarity index 87% rename from msext/QiniuSDK/Common/QNEtag.h rename to Pods/Qiniu/QiniuSDK/Utils/QNEtag.h index e1e1d7e..33112c9 100755 --- a/msext/QiniuSDK/Common/QNEtag.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNEtag.h @@ -14,7 +14,7 @@ @interface QNEtag : NSObject /** - * 文件etag + * 文件etag 【已废除】 * * @param filePath 文件路径 * @param error 输出文件读取错误 @@ -25,7 +25,7 @@ error:(NSError **)error; /** - * 二进制数据etag + * 二进制数据etag 【已废除】 * * @param data 数据 * diff --git a/msext/QiniuSDK/Common/QNEtag.m b/Pods/Qiniu/QiniuSDK/Utils/QNEtag.m similarity index 98% rename from msext/QiniuSDK/Common/QNEtag.m rename to Pods/Qiniu/QiniuSDK/Utils/QNEtag.m index 36ecfe8..e5b03bc 100755 --- a/msext/QiniuSDK/Common/QNEtag.m +++ b/Pods/Qiniu/QiniuSDK/Utils/QNEtag.m @@ -17,7 +17,7 @@ error:(NSError **)error { @autoreleasepool { NSData *data = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:error]; - if (*error != nil) { + if (error && *error) { return 0; } return [QNEtag data:data]; diff --git a/msext/QiniuSDK/Common/QNFile.h b/Pods/Qiniu/QiniuSDK/Utils/QNFile.h similarity index 100% rename from msext/QiniuSDK/Common/QNFile.h rename to Pods/Qiniu/QiniuSDK/Utils/QNFile.h diff --git a/msext/QiniuSDK/Common/QNFile.m b/Pods/Qiniu/QiniuSDK/Utils/QNFile.m similarity index 66% rename from msext/QiniuSDK/Common/QNFile.m rename to Pods/Qiniu/QiniuSDK/Utils/QNFile.m index 255a9d3..89d3bb1 100755 --- a/msext/QiniuSDK/Common/QNFile.m +++ b/Pods/Qiniu/QiniuSDK/Utils/QNFile.m @@ -21,6 +21,8 @@ @property (nonatomic) NSFileHandle *file; +@property (nonatomic) NSLock *lock; + @end @implementation QNFile @@ -67,22 +69,39 @@ } _file = f; _data = d; + _lock = [[NSLock alloc] init]; } return self; } -- (NSData *)read:(long)offset - size:(long)size { - if (_data != nil) { - return [_data subdataWithRange:NSMakeRange(offset, (unsigned int)size)]; +- (NSData *)read:(long long)offset + size:(long)size + error:(NSError **)error { + + NSData *data = nil; + @try { + [_lock lock]; + if (_data != nil && offset < _data.length) { + NSUInteger realSize = MIN((NSUInteger)size, _data.length - ((NSUInteger)offset)); + data = [_data subdataWithRange:NSMakeRange((NSUInteger)offset, realSize)]; + } else if (_file != nil && offset < _fileSize) { + [_file seekToFileOffset:offset]; + data = [_file readDataOfLength:size]; + } else { + data = [NSData data]; + } + } @catch (NSException *exception) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}]; + NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols); + } @finally { + [_lock unlock]; } - [_file seekToFileOffset:offset]; - return [_file readDataOfLength:size]; + return data; } -- (NSData *)readAll { - return [self read:0 size:(long)_fileSize]; +- (NSData *)readAllWithError:(NSError **)error { + return [self read:0 size:(long)_fileSize error:error]; } - (void)close { @@ -103,4 +122,7 @@ return _fileSize; } +- (NSString *)fileType { + return @"File"; +} @end diff --git a/msext/QiniuSDK/Common/QNFileDelegate.h b/Pods/Qiniu/QiniuSDK/Utils/QNFileDelegate.h similarity index 75% rename from msext/QiniuSDK/Common/QNFileDelegate.h rename to Pods/Qiniu/QiniuSDK/Utils/QNFileDelegate.h index e6cbeb8..6f84e72 100755 --- a/msext/QiniuSDK/Common/QNFileDelegate.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNFileDelegate.h @@ -18,22 +18,23 @@ * * @param offset 偏移地址 * @param size 大小 + * @param error 错误信息 * * @return 数据 */ -- (NSData *)read:(long)offset - size:(long)size; +- (NSData *)read:(long long)offset + size:(long)size + error:(NSError **)error; /** * 读取所有文件内容 - * + * @param error 错误信息 * @return 数据 */ -- (NSData *)readAll; +- (NSData *)readAllWithError:(NSError **)error; /** * 关闭文件 - * */ - (void)close; @@ -58,4 +59,7 @@ */ - (int64_t)size; +@optional +- (NSString *)fileType; + @end diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNLogUtil.h b/Pods/Qiniu/QiniuSDK/Utils/QNLogUtil.h new file mode 100644 index 0000000..922533a --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNLogUtil.h @@ -0,0 +1,52 @@ +// +// QNLogUtil.h +// QiniuSDK +// +// Created by yangsen on 2020/12/25. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, QNLogLevel){ + QNLogLevelNone, + QNLogLevelError, + QNLogLevelWarn, + QNLogLevelInfo, + QNLogLevelDebug, + QNLogLevelVerbose +}; + +@interface QNLogUtil : NSObject + ++ (void)setLogLevel:(QNLogLevel)level; + ++ (void)enableLogDate:(BOOL)enable; ++ (void)enableLogFile:(BOOL)enable; ++ (void)enableLogFunction:(BOOL)enable; + ++ (void)log:(QNLogLevel)level + file:(const char *)file + function:(const char *)function + line:(NSUInteger)line + format:(NSString * _Nullable)format, ...; + + +@end + +#define QNLog(level, fmt, ...) \ + [QNLogUtil log:level \ + file:__FILE__ \ + function:__FUNCTION__ \ + line:__LINE__ \ + format:(fmt), ##__VA_ARGS__] + +#define QNLogError(format, ...) QNLog(QNLogLevelError, format, ##__VA_ARGS__) +#define QNLogWarn(format, ...) QNLog(QNLogLevelWarn, format, ##__VA_ARGS__) +#define QNLogInfo(format, ...) QNLog(QNLogLevelInfo, format, ##__VA_ARGS__) +#define QNLogDebug(format, ...) QNLog(QNLogLevelDebug, format, ##__VA_ARGS__) +#define QNLogVerbose(format, ...) QNLog(QNLogLevelVerbose, format, ##__VA_ARGS__) + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNLogUtil.m b/Pods/Qiniu/QiniuSDK/Utils/QNLogUtil.m new file mode 100644 index 0000000..24f7d4c --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNLogUtil.m @@ -0,0 +1,84 @@ +// +// QNLogUtil.m +// QiniuSDK +// +// Created by yangsen on 2020/12/25. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNLogUtil.h" + +#if DEBUG +static QNLogLevel _level = QNLogLevelError; +#else +static QNLogLevel _level = QNLogLevelNone; +#endif + +static BOOL _enableDate = false; +static BOOL _enableFile = true; +static BOOL _enableFunction = false; + +@implementation QNLogUtil + ++ (void)setLogLevel:(QNLogLevel)level { + _level = level < 0 ? 0 : level; +} + ++ (void)enableLogDate:(BOOL)enable { + _enableDate = enable; +} ++ (void)enableLogFile:(BOOL)enable { + _enableFile = enable; +} ++ (void)enableLogFunction:(BOOL)enable { + _enableFunction = enable; +} + + ++ (void)log:(QNLogLevel)level + file:(const char *)file + function:(const char *)function + line:(NSUInteger)line + format:(NSString *)format, ... { + + if (!format || level > _level) { + return; + } + + va_list args; + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + NSString *fileName = @""; + if (_enableFile) { + fileName = [NSString stringWithFormat:@"%s", file]; + if ([fileName containsString:@"/"]) { + fileName = [fileName componentsSeparatedByString:@"/"].lastObject; + } + } + + NSString *functionName = @""; + if (_enableFunction) { + functionName = [NSString stringWithFormat:@"->%s", function]; + } + + NSString *lineNumber = [NSString stringWithFormat:@"->%ld", line]; + + NSString *date = @""; + if (_enableDate) { + date = [NSString stringWithFormat:@"%@", [NSDate date]]; + if ([date length] > 20) { + date = [date substringToIndex:19]; + } + } + + NSThread *thread = [NSThread currentThread]; + NSString *levelString = @[@"N", @"E", @"W", @"I", @"D", @"V"][level%6]; + message = [NSString stringWithFormat:@"%@[%@] %@ %@%@%@ %@", date, levelString, thread, fileName, functionName, lineNumber, message]; + + NSLog(@"%@", message); +} + + +@end diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNMutableArray.h b/Pods/Qiniu/QiniuSDK/Utils/QNMutableArray.h new file mode 100644 index 0000000..48debdf --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNMutableArray.h @@ -0,0 +1,17 @@ +// +// QNMutableArray.h +// QiniuSDK +// +// Created by yangsen on 2021/7/5. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNMutableArray : NSMutableArray + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNMutableArray.m b/Pods/Qiniu/QiniuSDK/Utils/QNMutableArray.m new file mode 100644 index 0000000..20dd9c4 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNMutableArray.m @@ -0,0 +1,373 @@ +// +// QNMutableArray.m +// QiniuSDK +// +// Created by yangsen on 2021/7/5. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNMutableArray.h" + +#define INIT(...) self = super.init; \ +if (!self) return nil; \ +__VA_ARGS__; \ +if (!_arr) return nil; \ +_lock = dispatch_semaphore_create(1); \ +return self; + + +#define LOCK(...) dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \ +__VA_ARGS__; \ +dispatch_semaphore_signal(_lock); + + +@implementation QNMutableArray { + NSMutableArray *_arr; //Subclass a class cluster... + dispatch_semaphore_t _lock; +} + +#pragma mark - init + +- (instancetype)init { + INIT(_arr = [[NSMutableArray alloc] init]); +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + INIT(_arr = [[NSMutableArray alloc] initWithCapacity:numItems]); +} + +- (instancetype)initWithArray:(NSArray *)array { + INIT(_arr = [[NSMutableArray alloc] initWithArray:array]); +} + +- (instancetype)initWithObjects:(const id[])objects count:(NSUInteger)cnt { + INIT(_arr = [[NSMutableArray alloc] initWithObjects:objects count:cnt]); +} + +- (instancetype)initWithContentsOfFile:(NSString *)path { + INIT(_arr = [[NSMutableArray alloc] initWithContentsOfFile:path]); +} + +- (instancetype)initWithContentsOfURL:(NSURL *)url { + INIT(_arr = [[NSMutableArray alloc] initWithContentsOfURL:url]); +} + +#pragma mark - method + +- (NSUInteger)count { + LOCK(NSUInteger count = _arr.count); return count; +} + +- (id)objectAtIndex:(NSUInteger)index { + LOCK(id obj = [_arr objectAtIndex:index]); return obj; +} + +- (NSArray *)arrayByAddingObject:(id)anObject { + LOCK(NSArray * arr = [_arr arrayByAddingObject:anObject]); return arr; +} + +- (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)otherArray { + LOCK(NSArray * arr = [_arr arrayByAddingObjectsFromArray:otherArray]); return arr; +} + +- (NSString *)componentsJoinedByString:(NSString *)separator { + LOCK(NSString * str = [_arr componentsJoinedByString:separator]); return str; +} + +- (BOOL)containsObject:(id)anObject { + LOCK(BOOL c = [_arr containsObject:anObject]); return c; +} + +- (NSString *)description { + LOCK(NSString * d = _arr.description); return d; +} + +- (NSString *)descriptionWithLocale:(id)locale { + LOCK(NSString * d = [_arr descriptionWithLocale:locale]); return d; +} + +- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level { + LOCK(NSString * d = [_arr descriptionWithLocale:locale indent:level]); return d; +} + +- (id)firstObjectCommonWithArray:(NSArray *)otherArray { + LOCK(id o = [_arr firstObjectCommonWithArray:otherArray]); return o; +} + +- (void)getObjects:(id __unsafe_unretained[])objects range:(NSRange)range { + LOCK([_arr getObjects:objects range:range]); +} + +- (NSUInteger)indexOfObject:(id)anObject { + LOCK(NSUInteger i = [_arr indexOfObject:anObject]); return i; +} + +- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range { + LOCK(NSUInteger i = [_arr indexOfObject:anObject inRange:range]); return i; +} + +- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject { + LOCK(NSUInteger i = [_arr indexOfObjectIdenticalTo:anObject]); return i; +} + +- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range { + LOCK(NSUInteger i = [_arr indexOfObjectIdenticalTo:anObject inRange:range]); return i; +} + +- (id)firstObject { + LOCK(id o = _arr.firstObject); return o; +} + +- (id)lastObject { + LOCK(id o = _arr.lastObject); return o; +} + +- (NSEnumerator *)objectEnumerator { + LOCK(NSEnumerator * e = [_arr objectEnumerator]); return e; +} + +- (NSEnumerator *)reverseObjectEnumerator { + LOCK(NSEnumerator * e = [_arr reverseObjectEnumerator]); return e; +} + +- (NSData *)sortedArrayHint { + LOCK(NSData * d = [_arr sortedArrayHint]); return d; +} + +- (NSArray *)sortedArrayUsingFunction:(NSInteger (NS_NOESCAPE *)(id, id, void *))comparator context:(void *)context { + LOCK(NSArray * arr = [_arr sortedArrayUsingFunction:comparator context:context]) return arr; +} + +- (NSArray *)sortedArrayUsingFunction:(NSInteger (NS_NOESCAPE *)(id, id, void *))comparator context:(void *)context hint:(NSData *)hint { + LOCK(NSArray * arr = [_arr sortedArrayUsingFunction:comparator context:context hint:hint]); return arr; +} + +- (NSArray *)sortedArrayUsingSelector:(SEL)comparator { + LOCK(NSArray * arr = [_arr sortedArrayUsingSelector:comparator]); return arr; +} + +- (NSArray *)subarrayWithRange:(NSRange)range { + LOCK(NSArray * arr = [_arr subarrayWithRange:range]) return arr; +} + +- (void)makeObjectsPerformSelector:(SEL)aSelector { + LOCK([_arr makeObjectsPerformSelector:aSelector]); +} + +- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)argument { + LOCK([_arr makeObjectsPerformSelector:aSelector withObject:argument]); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + LOCK(NSArray * arr = [_arr objectsAtIndexes:indexes]); return arr; +} + +- (id)objectAtIndexedSubscript:(NSUInteger)idx { + LOCK(id o = [_arr objectAtIndexedSubscript:idx]); return o; +} + +- (void)enumerateObjectsUsingBlock:(void (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))block { + LOCK([_arr enumerateObjectsUsingBlock:block]); +} + +- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))block { + LOCK([_arr enumerateObjectsWithOptions:opts usingBlock:block]); +} + +- (void)enumerateObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))block { + LOCK([_arr enumerateObjectsAtIndexes:s options:opts usingBlock:block]); +} + +- (NSUInteger)indexOfObjectPassingTest:(BOOL (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))predicate { + LOCK(NSUInteger i = [_arr indexOfObjectPassingTest:predicate]); return i; +} + +- (NSUInteger)indexOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))predicate { + LOCK(NSUInteger i = [_arr indexOfObjectWithOptions:opts passingTest:predicate]); return i; +} + +- (NSUInteger)indexOfObjectAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(BOOL (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))predicate { + LOCK(NSUInteger i = [_arr indexOfObjectAtIndexes:s options:opts passingTest:predicate]); return i; +} + +- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))predicate { + LOCK(NSIndexSet * i = [_arr indexesOfObjectsPassingTest:predicate]); return i; +} + +- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))predicate { + LOCK(NSIndexSet * i = [_arr indexesOfObjectsWithOptions:opts passingTest:predicate]); return i; +} + +- (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(BOOL (NS_NOESCAPE ^)(id obj, NSUInteger idx, BOOL *stop))predicate { + LOCK(NSIndexSet * i = [_arr indexesOfObjectsAtIndexes:s options:opts passingTest:predicate]); return i; +} + +- (NSArray *)sortedArrayUsingComparator:(NSComparator NS_NOESCAPE)cmptr { + LOCK(NSArray * a = [_arr sortedArrayUsingComparator:cmptr]); return a; +} + +- (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(NSComparator NS_NOESCAPE)cmptr { + LOCK(NSArray * a = [_arr sortedArrayWithOptions:opts usingComparator:cmptr]); return a; +} + +- (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator NS_NOESCAPE)cmp { + LOCK(NSUInteger i = [_arr indexOfObject:obj inSortedRange:r options:opts usingComparator:cmp]); return i; +} + +#pragma mark - mutable + +- (void)addObject:(id)anObject { + LOCK([_arr addObject:anObject]); +} + +- (void)insertObject:(id)anObject atIndex:(NSUInteger)index { + LOCK([_arr insertObject:anObject atIndex:index]); +} + +- (void)removeLastObject { + LOCK([_arr removeLastObject]); +} + +- (void)removeObjectAtIndex:(NSUInteger)index { + LOCK([_arr removeObjectAtIndex:index]); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { + LOCK([_arr replaceObjectAtIndex:index withObject:anObject]); +} + +- (void)addObjectsFromArray:(NSArray *)otherArray { + LOCK([_arr addObjectsFromArray:otherArray]); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2 { + LOCK([_arr exchangeObjectAtIndex:idx1 withObjectAtIndex:idx2]); +} + +- (void)removeAllObjects { + LOCK([_arr removeAllObjects]); +} + +- (void)removeObject:(id)anObject inRange:(NSRange)range { + LOCK([_arr removeObject:anObject inRange:range]); +} + +- (void)removeObject:(id)anObject { + LOCK([_arr removeObject:anObject]); +} + +- (void)removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range { + LOCK([_arr removeObjectIdenticalTo:anObject inRange:range]); +} + +- (void)removeObjectIdenticalTo:(id)anObject { + LOCK([_arr removeObjectIdenticalTo:anObject]); +} + +- (void)removeObjectsInArray:(NSArray *)otherArray { + LOCK([_arr removeObjectsInArray:otherArray]); +} + +- (void)removeObjectsInRange:(NSRange)range { + LOCK([_arr removeObjectsInRange:range]); +} + +- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray range:(NSRange)otherRange { + LOCK([_arr replaceObjectsInRange:range withObjectsFromArray:otherArray range:otherRange]); +} + +- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray { + LOCK([_arr replaceObjectsInRange:range withObjectsFromArray:otherArray]); +} + +- (void)setArray:(NSArray *)otherArray { + LOCK([_arr setArray:otherArray]); +} + +- (void)sortUsingFunction:(NSInteger (NS_NOESCAPE *)(id, id, void *))compare context:(void *)context { + LOCK([_arr sortUsingFunction:compare context:context]); +} + +- (void)sortUsingSelector:(SEL)comparator { + LOCK([_arr sortUsingSelector:comparator]); +} + +- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes { + LOCK([_arr insertObjects:objects atIndexes:indexes]); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + LOCK([_arr removeObjectsAtIndexes:indexes]); +} + +- (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects { + LOCK([_arr replaceObjectsAtIndexes:indexes withObjects:objects]); +} + +- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx { + LOCK([_arr setObject:obj atIndexedSubscript:idx]); +} + +- (void)sortUsingComparator:(NSComparator NS_NOESCAPE)cmptr { + LOCK([_arr sortUsingComparator:cmptr]); +} + +- (void)sortWithOptions:(NSSortOptions)opts usingComparator:(NSComparator NS_NOESCAPE)cmptr { + LOCK([_arr sortWithOptions:opts usingComparator:cmptr]); +} + +- (BOOL)isEqualToArray:(NSArray *)otherArray { + if (otherArray == self) return YES; + if ([otherArray isKindOfClass:QNMutableArray.class]) { + QNMutableArray *other = (id)otherArray; + BOOL isEqual; + dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); + dispatch_semaphore_wait(other->_lock, DISPATCH_TIME_FOREVER); + isEqual = [_arr isEqualToArray:other->_arr]; + dispatch_semaphore_signal(other->_lock); + dispatch_semaphore_signal(_lock); + return isEqual; + } + return NO; +} + +#pragma mark - protocol + +- (id)copyWithZone:(NSZone *)zone { + return [self mutableCopyWithZone:zone]; +} + +- (id)mutableCopyWithZone:(NSZone *)zone { + LOCK(id copiedDictionary = [[self.class allocWithZone:zone] initWithArray:_arr]); + return copiedDictionary; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(id __unsafe_unretained[])stackbuf + count:(NSUInteger)len { + LOCK(NSUInteger count = [_arr countByEnumeratingWithState:state objects:stackbuf count:len]); + return count; +} + +- (BOOL)isEqual:(id)object { + if (object == self) return YES; + + if ([object isKindOfClass:QNMutableArray.class]) { + QNMutableArray *other = object; + BOOL isEqual; + dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); + dispatch_semaphore_wait(other->_lock, DISPATCH_TIME_FOREVER); + isEqual = [_arr isEqual:other->_arr]; + dispatch_semaphore_signal(other->_lock); + dispatch_semaphore_signal(_lock); + return isEqual; + } + return NO; +} + +- (NSUInteger)hash { + LOCK(NSUInteger hash = [_arr hash]); + return hash; +} + +@end diff --git a/msext/QiniuSDK/Common/QNPHAssetFile.h b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetFile.h similarity index 66% rename from msext/QiniuSDK/Common/QNPHAssetFile.h rename to Pods/Qiniu/QiniuSDK/Utils/QNPHAssetFile.h index 0ac6293..75571d7 100755 --- a/msext/QiniuSDK/Common/QNPHAssetFile.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetFile.h @@ -10,13 +10,12 @@ #import "QNFileDelegate.h" -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) @class PHAsset; -@interface QNPHAssetFile : NSObject +API_AVAILABLE(ios(9.1)) @interface QNPHAssetFile : NSObject /** * 打开指定文件 * - * @param path 文件路径 + * @param phAsset 文件资源 * @param error 输出的错误信息 * * @return 实例 @@ -24,4 +23,3 @@ - (instancetype)init:(PHAsset *)phAsset error:(NSError *__autoreleasing *)error; @end -#endif diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetFile.m b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetFile.m new file mode 100644 index 0000000..c04d646 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetFile.m @@ -0,0 +1,242 @@ +// +// QNPHAssetFile.m +// Pods +// +// Created by 何舒 on 15/10/21. +// +// + +#import "QNPHAssetFile.h" +#import +#import "QNResponseInfo.h" + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100) + +@interface QNPHAssetFile () + +@property (nonatomic) PHAsset *phAsset; + +@property (nonatomic) int64_t fileSize; + +@property (nonatomic) int64_t fileModifyTime; + +@property (nonatomic, strong) NSData *assetData; + +// file path 可能是导出的 file path,并不是真正的 filePath, 导出的文件在上传结束会被删掉,并不是真正有效的文件路径。 +@property(nonatomic, assign)BOOL hasRealFilePath; +@property (nonatomic, copy) NSString *filePath; + +@property (nonatomic) NSFileHandle *file; + +@property (nonatomic, strong) NSLock *lock; + +@end + +@implementation QNPHAssetFile + +- (instancetype)init:(PHAsset *)phAsset error:(NSError *__autoreleasing *)error { + if (self = [super init]) { + NSDate *createTime = phAsset.creationDate; + int64_t t = 0; + if (createTime != nil) { + t = [createTime timeIntervalSince1970]; + } + _fileModifyTime = t; + _phAsset = phAsset; + [self getInfo]; + + _lock = [[NSLock alloc] init]; + if (self.assetData == nil && self.filePath != nil) { + NSError *error2 = nil; + NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error2]; + if (error2 != nil) { + if (error != nil) { + *error = error2; + } + return self; + } + _fileSize = [fileAttr fileSize]; + NSFileHandle *f = nil; + NSData *d = nil; + if (_fileSize > 16 * 1024 * 1024) { + f = [NSFileHandle fileHandleForReadingFromURL:[NSURL fileURLWithPath:self.filePath] error:error]; + if (f == nil) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:self.filePath code:kQNFileError userInfo:[*error userInfo]]; + } + return self; + } + } else { + d = [NSData dataWithContentsOfFile:self.filePath options:NSDataReadingMappedIfSafe error:&error2]; + if (error2 != nil) { + if (error != nil) { + *error = error2; + } + return self; + } + } + _file = f; + _assetData = d; + } + } + return self; +} + +- (NSData *)read:(long long)offset + size:(long)size + error:(NSError **)error { + + NSData *data = nil; + @try { + [_lock lock]; + if (_assetData != nil && offset < _assetData.length) { + NSUInteger realSize = MIN((NSUInteger)size, _assetData.length - (NSUInteger)offset); + data = [_assetData subdataWithRange:NSMakeRange((NSUInteger)offset, realSize)]; + } else if (_file != nil && offset < _fileSize) { + [_file seekToFileOffset:offset]; + data = [_file readDataOfLength:size]; + } else { + data = [NSData data]; + } + } @catch (NSException *exception) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}]; + NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols); + } @finally { + [_lock unlock]; + } + return data; +} + +- (NSData *)readAllWithError:(NSError **)error { + return [self read:0 size:(long)_fileSize error:error]; +} + +- (void)close { + if (PHAssetMediaTypeVideo == self.phAsset.mediaType) { + if (_file != nil) { + [_file closeFile]; + } + // 如果是导出的 file 删除 + if (!self.hasRealFilePath && self.filePath) { + [[NSFileManager defaultManager] removeItemAtPath:self.filePath error:nil]; + } + } +} + +- (NSString *)path { + return self.hasRealFilePath ? self.filePath : nil; +} + +- (int64_t)modifyTime { + return _fileModifyTime; +} + +- (int64_t)size { + return _fileSize; +} + +- (NSString *)fileType { + return @"PHAsset"; +} + +- (void)getInfo { + if (PHAssetMediaTypeImage == self.phAsset.mediaType) { + [self getImageInfo]; + } else if (PHAssetMediaTypeVideo == self.phAsset.mediaType) { + // 1. 获取 video url 在此处打断点 debug 时 file path 有效,去除断点不进行 debug file path 无效,所以取消这种方式。 + // [self getVideoInfo]; + + // 2. video url 获取失败则导出文件 + if (self.filePath == nil) { + [self exportAssert]; + } + } else { + [self exportAssert]; + } +} + +- (void)getImageInfo { + PHImageRequestOptions *options = [PHImageRequestOptions new]; + options.version = PHImageRequestOptionsVersionCurrent; + options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; + options.resizeMode = PHImageRequestOptionsResizeModeNone; + //不支持icloud上传 + options.networkAccessAllowed = NO; + options.synchronous = YES; + +#if TARGET_OS_MACCATALYST + if (@available(macOS 10.15, *)) { + [[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:self.phAsset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, CGImagePropertyOrientation orientation, NSDictionary *info) { + self.assetData = imageData; + self.fileSize = imageData.length; + self.hasRealFilePath = NO; + }]; + } +#else + if (@available(iOS 13, *)) { + [[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:self.phAsset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, CGImagePropertyOrientation orientation, NSDictionary *info) { + self.assetData = imageData; + self.fileSize = imageData.length; + self.hasRealFilePath = NO; + }]; + } else { + [[PHImageManager defaultManager] requestImageDataForAsset:self.phAsset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + self.assetData = imageData; + self.fileSize = imageData.length; + self.hasRealFilePath = NO; + }]; + } +#endif + +} + +- (void)getVideoInfo { + PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; + options.version = PHVideoRequestOptionsVersionCurrent; + options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat; + //不支持icloud上传 + options.networkAccessAllowed = NO; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [[PHImageManager defaultManager] requestAVAssetForVideo:self.phAsset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { + if ([asset isKindOfClass:[AVURLAsset class]]) { + self.filePath = [[(AVURLAsset *)asset URL] path]; + self.hasRealFilePath = YES; + } + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); +} + +- (void)exportAssert { + NSArray *assetResources = [PHAssetResource assetResourcesForAsset:self.phAsset]; + PHAssetResource *resource; + for (PHAssetResource *assetRes in assetResources) { + if (assetRes.type == PHAssetResourceTypePairedVideo || assetRes.type == PHAssetResourceTypeVideo) { + resource = assetRes; + } + } + NSString *fileName = [NSString stringWithFormat:@"tempAsset-%f-%d.mov", [[NSDate date] timeIntervalSince1970], arc4random()%100000]; + PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; + //不支持icloud上传 + options.networkAccessAllowed = NO; + + NSString *PATH_VIDEO_FILE = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + [[NSFileManager defaultManager] removeItemAtPath:PATH_VIDEO_FILE error:nil]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [[PHAssetResourceManager defaultManager] writeDataForAssetResource:resource toFile:[NSURL fileURLWithPath:PATH_VIDEO_FILE] options:options completionHandler:^(NSError *_Nullable error) { + if (error) { + self.filePath = nil; + } else { + self.filePath = PATH_VIDEO_FILE; + } + self.hasRealFilePath = NO; + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); +} + +@end + +#endif diff --git a/msext/QiniuSDK/Common/QNPHAssetResource.h b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetResource.h similarity index 67% rename from msext/QiniuSDK/Common/QNPHAssetResource.h rename to Pods/Qiniu/QiniuSDK/Utils/QNPHAssetResource.h index 709de63..73bf946 100755 --- a/msext/QiniuSDK/Common/QNPHAssetResource.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetResource.h @@ -10,16 +10,13 @@ #import "QNFileDelegate.h" -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100) - @class PHAssetResource; - -@interface QNPHAssetResource : NSObject +API_AVAILABLE(ios(9.0)) @interface QNPHAssetResource : NSObject /** * 打开指定文件 * - * @param path PHLivePhoto的PHAssetResource文件 + * @param phAssetResource PHLivePhoto的PHAssetResource文件 * @param error 输出的错误信息 * * @return 实例 @@ -28,4 +25,3 @@ error:(NSError *__autoreleasing *)error; @end -#endif diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetResource.m b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetResource.m new file mode 100755 index 0000000..b11845a --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNPHAssetResource.m @@ -0,0 +1,177 @@ +// +// QNPHAssetResource.m +// QiniuSDK +// +// Created by 何舒 on 16/2/14. +// Copyright © 2016年 Qiniu. All rights reserved. +// + +#import "QNPHAssetResource.h" +#import +#import "QNResponseInfo.h" + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000) + +enum { + kAMASSETMETADATA_PENDINGREADS = 1, + kAMASSETMETADATA_ALLFINISHED = 0 +}; + +@interface QNPHAssetResource () + +@property (nonatomic) PHAssetResource *phAssetResource; + +@property (nonatomic) int64_t fileSize; + +@property (nonatomic) int64_t fileModifyTime; + +@property (nonatomic, strong) NSData *assetData; + +@property (nonatomic, assign)BOOL hasRealFilePath; +@property (nonatomic, copy) NSString *filePath; +@property (nonatomic, strong) NSFileHandle *file; + +@property (nonatomic, strong) NSLock *lock; + +@end + +@implementation QNPHAssetResource +- (instancetype)init:(PHAssetResource *)phAssetResource + error:(NSError *__autoreleasing *)error { + if (self = [super init]) { + PHFetchResult *results = [PHAsset fetchAssetsWithBurstIdentifier:phAssetResource.assetLocalIdentifier options:nil]; + if (results.firstObject != nil) { + PHAsset *phasset = results.firstObject; + NSDate *createTime = phasset.creationDate; + int64_t t = 0; + if (createTime != nil) { + t = [createTime timeIntervalSince1970]; + } + _fileModifyTime = t; + } + + _phAssetResource = phAssetResource; + _lock = [[NSLock alloc] init]; + [self getInfo:error]; + } + return self; +} + +- (NSData *)read:(long long)offset + size:(long)size + error:(NSError **)error { + + NSData *data = nil; + @try { + [_lock lock]; + if (_assetData != nil && offset < _assetData.length) { + NSUInteger realSize = MIN((NSUInteger)size, _assetData.length - (NSUInteger)offset); + data = [_assetData subdataWithRange:NSMakeRange((NSUInteger)offset, realSize)]; + } else if (_file != nil && offset < _fileSize) { + [_file seekToFileOffset:offset]; + data = [_file readDataOfLength:size]; + } else { + data = [NSData data]; + } + } @catch (NSException *exception) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}]; + NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols); + } @finally { + [_lock unlock]; + } + return data; +} + +- (NSData *)readAllWithError:(NSError **)error { + return [self read:0 size:(long)_fileSize error:error]; +} + +- (void)close { + if (self.file) { + [self.file closeFile]; + } + + // 如果是导出的 file 删除 + if (self.filePath) { + [[NSFileManager defaultManager] removeItemAtPath:self.filePath error:nil]; + } +} + +- (NSString *)path { + return self.filePath ? self.filePath : nil; +} + +- (int64_t)modifyTime { + return _fileModifyTime; +} + +- (int64_t)size { + return _fileSize; +} + +- (NSString *)fileType { + return @"PHAssetResource"; +} + +- (void)getInfo:(NSError **)error { + [self exportAssert]; + + NSError *error2 = nil; + NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error2]; + if (error2 != nil) { + if (error != nil) { + *error = error2; + } + return; + } + + _fileSize = [fileAttr fileSize]; + NSFileHandle *file = nil; + NSData *data = nil; + if (_fileSize > 16 * 1024 * 1024) { + file = [NSFileHandle fileHandleForReadingFromURL:[NSURL fileURLWithPath:self.filePath] error:error]; + if (file == nil) { + if (error != nil) { + *error = [[NSError alloc] initWithDomain:self.filePath code:kQNFileError userInfo:[*error userInfo]]; + } + return; + } + } else { + data = [NSData dataWithContentsOfFile:self.filePath options:NSDataReadingMappedIfSafe error:&error2]; + if (error2 != nil) { + if (error != nil) { + *error = error2; + } + return; + } + } + + self.file = file; + self.assetData = data; +} + +- (void)exportAssert { + PHAssetResource *resource = self.phAssetResource; + NSString *fileName = [NSString stringWithFormat:@"tempAsset-%f-%d.mov", [[NSDate date] timeIntervalSince1970], arc4random()%100000]; + PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; + //不支持icloud上传 + options.networkAccessAllowed = NO; + + NSString *PATH_VIDEO_FILE = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + [[NSFileManager defaultManager] removeItemAtPath:PATH_VIDEO_FILE error:nil]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [[PHAssetResourceManager defaultManager] writeDataForAssetResource:resource toFile:[NSURL fileURLWithPath:PATH_VIDEO_FILE] options:options completionHandler:^(NSError *_Nullable error) { + if (error) { + self.filePath = nil; + } else { + self.filePath = PATH_VIDEO_FILE; + } + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); +} + +@end + +#endif diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNSingleFlight.h b/Pods/Qiniu/QiniuSDK/Utils/QNSingleFlight.h new file mode 100644 index 0000000..3418967 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNSingleFlight.h @@ -0,0 +1,30 @@ +// +// QNSingleFlight.h +// QiniuSDK +// +// Created by yangsen on 2021/1/4. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef void(^QNSingleFlightComplete)(id _Nullable value, NSError * _Nullable error); +typedef void(^QNSingleFlightAction)(QNSingleFlightComplete _Nonnull complete); + +@interface QNSingleFlight : NSObject + +/** + * 异步 SingleFlight 执行函数 + * @param key actionHandler 对应的 key,同一时刻同一个 key 最多只有一个对应的 actionHandler 在执行 + * @param action 执行函数,注意:action 有且只能回调一次 + * @param complete single flight 执行 complete 后的完成回调 + */ +- (void)perform:(NSString * _Nullable)key + action:(QNSingleFlightAction _Nonnull)action + complete:(QNSingleFlightComplete _Nullable)complete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNSingleFlight.m b/Pods/Qiniu/QiniuSDK/Utils/QNSingleFlight.m new file mode 100644 index 0000000..8397ef1 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNSingleFlight.m @@ -0,0 +1,112 @@ +// +// QNSingleFlight.m +// QiniuSDK +// +// Created by yangsen on 2021/1/4. +// Copyright © 2021 Qiniu. All rights reserved. +// + +#import "QNDefine.h" +#import "QNSingleFlight.h" + +@interface QNSingleFlightTask : NSObject +@property(nonatomic, copy)QNSingleFlightComplete complete; +@end +@implementation QNSingleFlightTask +@end + +@interface QNSingleFlightCall : NSObject +@property(nonatomic, assign)BOOL isComplete; +@property(nonatomic, strong)NSMutableArray *tasks; +@property(nonatomic, strong)id value; +@property(nonatomic, strong)NSError *error; +@end +@implementation QNSingleFlightCall +@end + +@interface QNSingleFlight() +@property(nonatomic, strong)NSMutableDictionary *callInfo; +@end +@implementation QNSingleFlight + +- (void)perform:(NSString * _Nullable)key + action:(QNSingleFlightAction _Nonnull)action + complete:(QNSingleFlightComplete _Nullable)complete { + if (!action) { + return; + } + + BOOL isFirstTask = false; + BOOL shouldComplete = false; + QNSingleFlightCall *call = nil; + @synchronized (self) { + if (!self.callInfo) { + self.callInfo = [NSMutableDictionary dictionary]; + } + + if (key) { + call = self.callInfo[key]; + } + + if (!call) { + call = [[QNSingleFlightCall alloc] init]; + call.isComplete = false; + call.tasks = [NSMutableArray array]; + if (key) { + self.callInfo[key] = call; + } + isFirstTask = true; + } + + @synchronized (call) { + shouldComplete = call.isComplete; + if (!shouldComplete) { + QNSingleFlightTask *task = [[QNSingleFlightTask alloc] init]; + task.complete = complete; + [call.tasks addObject:task]; + } + } + } + + if (shouldComplete) { + if (complete) { + complete(call.value, call.error); + } + return; + } + if (!isFirstTask) { + return; + } + + kQNWeakSelf; + kQNWeakObj(call); + action(^(id value, NSError *error){ + kQNStrongSelf; + kQNStrongObj(call); + + NSArray *tasksP = nil; + @synchronized (call) { + if (call.isComplete) { + return; + } + call.isComplete = true; + call.value = value; + call.error = error; + tasksP = [call.tasks copy]; + } + + if (key) { + @synchronized (self) { + [self.callInfo removeObjectForKey:key]; + } + } + + for (QNSingleFlightTask *task in tasksP) { + if (task.complete) { + task.complete(value, error); + } + } + }); +} + +@end diff --git a/msext/QiniuSDK/Common/QNSystem.h b/Pods/Qiniu/QiniuSDK/Utils/QNSystem.h similarity index 63% rename from msext/QiniuSDK/Common/QNSystem.h rename to Pods/Qiniu/QiniuSDK/Utils/QNSystem.h index 4c96c65..f819b99 100755 --- a/msext/QiniuSDK/Common/QNSystem.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNSystem.h @@ -9,12 +9,12 @@ #ifndef QNSystem_h #define QNSystem_h -BOOL hasNSURLSession(); +BOOL hasNSURLSession(void); -BOOL hasAts(); +BOOL hasAts(void); -BOOL allowsArbitraryLoads(); +BOOL allowsArbitraryLoads(void); -BOOL isIpV6FullySupported(); +BOOL isIpV6FullySupported(void); #endif /* QNSystem_h */ diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNSystem.m b/Pods/Qiniu/QiniuSDK/Utils/QNSystem.m new file mode 100755 index 0000000..afa8512 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNSystem.m @@ -0,0 +1,33 @@ +// +// QNSystem.m +// QiniuSDK +// +// Created by bailong on 15/10/13. +// Copyright © 2015年 Qiniu. All rights reserved. +// + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#import +#else +#import +#endif + +BOOL isIpV6FullySupported(void) { +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) + float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; + if (sysVersion < 9.0) { + return NO; + } +#else + NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + if (sysVersion.majorVersion < 10) { + return NO; + } else if (sysVersion.majorVersion == 10) { + return sysVersion.minorVersion >= 11; + } +#endif + return YES; +} diff --git a/msext/QiniuSDK/Common/QNUrlSafeBase64.h b/Pods/Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.h similarity index 95% rename from msext/QiniuSDK/Common/QNUrlSafeBase64.h rename to Pods/Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.h index 8d5e6a5..5400714 100755 --- a/msext/QiniuSDK/Common/QNUrlSafeBase64.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.h @@ -33,7 +33,7 @@ /** * 字符串解码 * - * @param base64 字符串 + * @param data 字符串 * * @return 数据 */ diff --git a/msext/QiniuSDK/Common/QNUrlSafeBase64.m b/Pods/Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.m similarity index 100% rename from msext/QiniuSDK/Common/QNUrlSafeBase64.m rename to Pods/Qiniu/QiniuSDK/Utils/QNUrlSafeBase64.m diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNUrlUtils.h b/Pods/Qiniu/QiniuSDK/Utils/QNUrlUtils.h new file mode 100644 index 0000000..af6090c --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNUrlUtils.h @@ -0,0 +1,19 @@ +// +// QNUrlUtils.h +// QiniuSDK +// +// Created by yangsen on 2023/11/16. +// Copyright © 2023 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUrlUtils : NSObject + ++ (NSString *)setHostScheme:(NSString *)host useHttps:(BOOL)useHttps; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNUrlUtils.m b/Pods/Qiniu/QiniuSDK/Utils/QNUrlUtils.m new file mode 100644 index 0000000..ed3ff46 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNUrlUtils.m @@ -0,0 +1,25 @@ +// +// QNUrlUtils.m +// QiniuSDK +// +// Created by yangsen on 2023/11/16. +// Copyright © 2023 Qiniu. All rights reserved. +// + +#import "QNUrlUtils.h" + +@implementation QNUrlUtils + ++ (NSString *)setHostScheme:(NSString *)host useHttps:(BOOL)useHttps { + if (host == nil || host.length == 0) { + return nil; + } + + if ([host hasPrefix:@"http://"] || [host hasPrefix:@"https://"]) { + return host; + } + + return [NSString stringWithFormat:@"%@%@", (useHttps ? @"https://" : @"http://"), host]; +} + +@end diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNUtils.h b/Pods/Qiniu/QiniuSDK/Utils/QNUtils.h new file mode 100644 index 0000000..10d00e9 --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNUtils.h @@ -0,0 +1,68 @@ +// +// QNUtils.h +// QiniuSDK_Mac +// +// Created by yangsen on 2020/3/27. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface QNUtils : NSObject + +/// SDK 名称 ++ (NSString *)sdkVersion; + +/// SDK 开发语言 ++ (NSString *)sdkLanguage; + +/// 获取当前进程ID ++ (int64_t)getCurrentProcessID; + +/// 获取当前线程ID ++ (int64_t)getCurrentThreadID; + +/// 系统名称 ++ (NSString *)systemName; + +/// 系统版本 ++ (NSString *)systemVersion; + +/// 信号格数 ++ (NSNumber *)getCurrentSignalStrength; + +/// 网络类型 ++ (NSString *)getCurrentNetworkType; + +/// 获取当前时间戳 单位:ms ++ (NSTimeInterval)currentTimestamp; + +/// sdk document文件路径 ++ (NSString *)sdkDocumentDirectory; + +/// sdk cache文件路径 ++ (NSString *)sdkCacheDirectory; + +/// form escape +/// @param string escape string ++ (NSString *)formEscape:(NSString *)string; + +/// 两个时间的时间段 单位:毫秒 ++ (NSNumber *)dateDuration:(NSDate *)startDate endDate:(NSDate *)endDate; + +/// 计算 上传 或 下载 速度 单位:B/s +/// @param bytes 单位: B +/// @param totalTime 单位:ms +/// @return 速度 ++ (NSNumber *)calculateSpeed:(long long)bytes totalTime:(long long)totalTime; + +/// 根据ip和host来确定IP的类型,host可为空 +/// @param ip ip +/// @param host host ++ (NSString *)getIpType:(NSString * _Nullable)ip host:(NSString * _Nullable)host; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/Qiniu/QiniuSDK/Utils/QNUtils.m b/Pods/Qiniu/QiniuSDK/Utils/QNUtils.m new file mode 100644 index 0000000..5c3fe6d --- /dev/null +++ b/Pods/Qiniu/QiniuSDK/Utils/QNUtils.m @@ -0,0 +1,169 @@ +// +// QNUtils.m +// QiniuSDK_Mac +// +// Created by yangsen on 2020/3/27. +// Copyright © 2020 Qiniu. All rights reserved. +// + +#import "QNUtils.h" +#include +#import "QNVersion.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#endif + +@implementation QNUtils + ++ (NSString *)sdkVersion{ + return kQiniuVersion; +} + ++ (NSString *)sdkLanguage{ + return @"Object-C"; +} + ++ (int64_t)getCurrentProcessID { + return [[NSProcessInfo processInfo] processIdentifier]; +} + ++ (int64_t)getCurrentThreadID { + __uint64_t threadId = 0; + if (pthread_threadid_np(0, &threadId)) { + threadId = pthread_mach_thread_np(pthread_self()); + } + return threadId; +} + ++ (NSString *)systemName{ + NSString *name = nil; + #if __IPHONE_OS_VERSION_MIN_REQUIRED + name = [[UIDevice currentDevice] model]; + #else + name = @"Mac OS X"; + #endif + return name; +} + ++ (NSString *)systemVersion{ + NSString *version = nil; + #if __IPHONE_OS_VERSION_MIN_REQUIRED + version = [[UIDevice currentDevice] systemVersion]; + #else + version = [[NSProcessInfo processInfo] operatingSystemVersionString]; + #endif + return version; +} + +/// 信号格数 ++ (NSNumber *)getCurrentSignalStrength{ + NSNumber *strength = nil; + return strength; +} + +/// 网络类型 ++ (NSString *)getCurrentNetworkType{ + NSString *type = nil; + return type; +} + ++ (NSTimeInterval)currentTimestamp{ + return [[NSDate date] timeIntervalSince1970] * 1000; +} + + ++ (NSString *)sdkDocumentDirectory{ + return [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"/qiniu"]; +} + ++ (NSString *)sdkCacheDirectory{ + return [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"/qiniu"]; +} + ++ (NSString *)formEscape:(NSString *)string{ + NSString *ret = string; + ret = [ret stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; + ret = [ret stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + return ret; +} + ++ (NSNumber *)dateDuration:(NSDate *)startDate endDate:(NSDate *)endDate { + if (startDate && endDate) { + double time = [endDate timeIntervalSinceDate:startDate] * 1000; + return @(time); + } else { + return nil; + } +} + ++ (NSNumber *)calculateSpeed:(long long)bytes totalTime:(long long)totalTime { + if (bytes < 0 || totalTime == 0) { + return nil; + } + long long speed = bytes * 1000 / totalTime; + return @(speed); +} + ++ (NSString *)getIpType:(NSString *)ip host:(NSString *)host{ + + NSString *type = host; + if (!ip || ip.length == 0) { + return type; + } + if ([ip rangeOfString:@":"].location != NSNotFound) { + type = [self getIPV6StringType:ip host:host]; + } else if ([ip rangeOfString:@"."].location != NSNotFound){ + type = [self getIPV4StringType:ip host:host]; + } + return type; +} + ++ (NSString *)getIPV4StringType:(NSString *)ipv4String host:(NSString *)host{ + NSString *type = nil; + NSArray *ipNumberStrings = [ipv4String componentsSeparatedByString:@"."]; + if (ipNumberStrings.count == 4) { + NSInteger firstNumber = [ipNumberStrings.firstObject integerValue]; + NSInteger secondNumber = [ipNumberStrings[1] integerValue]; + type = [NSString stringWithFormat:@"%ld-%ld",(long)firstNumber, (long)secondNumber]; + } + type = [NSString stringWithFormat:@"%@-%@", host ?:@"", type]; + return type; +} + ++ (NSString *)getIPV6StringType:(NSString *)ipv6String host:(NSString *)host{ + NSArray *ipNumberStrings = [ipv6String componentsSeparatedByString:@":"]; + NSMutableArray *ipNumberStringsReal = [@[@"0000", @"0000", @"0000", @"0000", + @"0000", @"0000", @"0000", @"0000"] mutableCopy]; + NSArray *suppleStrings = @[@"0000", @"000", @"00", @"0", @""]; + NSInteger i = 0; + while (i < ipNumberStrings.count) { + NSString *ipNumberString = ipNumberStrings[i]; + if (ipNumberString.length > 0) { + ipNumberString = [NSString stringWithFormat:@"%@%@", suppleStrings[ipNumberString.length], ipNumberString]; + ipNumberStringsReal[i] = ipNumberString; + } else { + break; + } + i++; + } + + NSInteger j = ipNumberStrings.count - 1; + NSInteger indexReal = ipNumberStringsReal.count - 1; + while (i < j) { + NSString *ipNumberString = ipNumberStrings[j]; + if (ipNumberString.length > 0) { + ipNumberString = [NSString stringWithFormat:@"%@%@", suppleStrings[ipNumberString.length], ipNumberString]; + ipNumberStringsReal[indexReal] = ipNumberString; + } else { + break; + } + j--; + indexReal--; + } + NSString *numberInfo = [[ipNumberStringsReal subarrayWithRange:NSMakeRange(0, 4)] componentsJoinedByString:@"-"]; + return [NSString stringWithFormat:@"%@-%@-%@", host ?:@"", @"ipv6", numberInfo]; +} + +@end + diff --git a/msext/QiniuSDK/Common/QNVersion.h b/Pods/Qiniu/QiniuSDK/Utils/QNVersion.h similarity index 79% rename from msext/QiniuSDK/Common/QNVersion.h rename to Pods/Qiniu/QiniuSDK/Utils/QNVersion.h index 8b0a7e3..1601f70 100755 --- a/msext/QiniuSDK/Common/QNVersion.h +++ b/Pods/Qiniu/QiniuSDK/Utils/QNVersion.h @@ -11,4 +11,4 @@ /** * sdk 版本 */ -static const NSString *kQiniuVersion = @"7.1.5"; +static NSString *const kQiniuVersion = @"8.8.1"; diff --git a/msext/QiniuSDK/Common/QN_GTM_Base64.h b/Pods/Qiniu/QiniuSDK/Utils/QN_GTM_Base64.h similarity index 100% rename from msext/QiniuSDK/Common/QN_GTM_Base64.h rename to Pods/Qiniu/QiniuSDK/Utils/QN_GTM_Base64.h diff --git a/msext/QiniuSDK/Common/QN_GTM_Base64.m b/Pods/Qiniu/QiniuSDK/Utils/QN_GTM_Base64.m similarity index 100% rename from msext/QiniuSDK/Common/QN_GTM_Base64.m rename to Pods/Qiniu/QiniuSDK/Utils/QN_GTM_Base64.m diff --git a/Pods/Qiniu/README.md b/Pods/Qiniu/README.md new file mode 100755 index 0000000..293d1ec --- /dev/null +++ b/Pods/Qiniu/README.md @@ -0,0 +1,153 @@ +# Qiniu Resource Storage SDK for Objective-C + +[![@qiniu on weibo](http://img.shields.io/badge/weibo-%40qiniutek-blue.svg)](http://weibo.com/qiniutek) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md) +[![Build Status](https://github.com/qiniu/objc-sdk/workflows/Run%20Test%20Cases/badge.svg)](https://github.com/qiniu/objc-sdk/actions) +[![Badge w/ Version](https://cocoapod-badges.herokuapp.com/v/Qiniu/badge.png)](http://cocoadocs.org/docsets/Qiniu) +[![GitHub release](https://img.shields.io/github/v/tag/qiniu/objc-sdk.svg?label=release)](https://github.com/qiniu/objc-sdk/releases) +[![codecov](https://codecov.io/gh/qiniu/objc-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/objc-sdk) +![Platform](http://img.shields.io/cocoapods/p/Qiniu.svg) + + +## 安装 + +通过 CocoaPods + +```ruby +pod "Qiniu", "~> 8.8.1" +``` + +通过 Swift Package Manager (Xcode 11+) +``` +App 对接: +File -> Swift Packages -> Add Package Dependency,输入库链接,选择相应版本即可 +库链接: https://github.com/qiniu/objc-sdk + +库对接: +let package = Package( + dependencies: [ + .package(url: "https://github.com/qiniu/objc-sdk", from: "8.8.0") + ], + // ... +) + +``` + +## 运行环境 + +| Qiniu SDK 版本 | 最低 iOS版本 | 最低 OS X 版本 | Notes | +| :--------------------------------------: | :------: | :--------: | :-----------: | +| 8.8.x | iOS 9 | OS X 10.15 | Xcode 最低版本 11 | +| 8.7.x | iOS 9 | OS X 10.15 | Xcode 最低版本 11 | +| 8.6.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 8.5.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 8.4.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 8.3.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 8.2.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 8.1.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 8.0.x | iOS 7 | OS X 10.15 | Xcode 最低版本 11 | +| 7.5.x | iOS 7 | OS X 10.9 | Xcode 最低版本 6. | +| 7.4.x | iOS 7 | OS X 10.9 | Xcode 最低版本 6. | +| 7.3.x | iOS 7 | OS X 10.9 | Xcode 最低版本 6. | +| 7.2.x | iOS 7 | OS X 10.9 | Xcode 最低版本 6. | +| 7.1.x / AFNetworking-3.x | iOS 7 | OS X 10.9 | Xcode 最低版本 6. | +| [7.0.x / AFNetworking-2.x](https://github.com/qiniu/objc-sdk/tree/7.0.x/AFNetworking-2.x) | iOS 6 | OS X 10.8 | Xcode 最低版本 5. | +| [7.x / AFNetworking-1.x](https://github.com/qiniu/objc-sdk/tree/AFNetworking-1.x) | iOS 5 | OS X 10.7 | Xcode 最低版本 5. | +| [6.x](https://github.com/qiniu/ios-sdk) | iOS 6 | None | Xcode 最低版本 5. | + +## 使用方法 + +### 简单上传 +```Objective-C +#import +... + NSString *token = @"从服务端SDK获取"; + QNUploadManager *upManager = [[QNUploadManager alloc] init]; + NSData *data = [@"Hello, World!" dataUsingEncoding : NSUTF8StringEncoding]; + [upManager putData:data key:@"hello" token:token + complete: ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) { + NSLog(@"%@", info); + NSLog(@"%@", resp); + } option:[QNUploadOption defaultOptions]]; +... +``` + +### 如使用最新版的sdk,默认自动判断上传空间。如需要指定上传区域,可以按如下方式上传: +```Objective-C +#import +... + QNConfiguration *config = [QNConfiguration build:^(QNConfigurationBuilder *builder) { + builder.useHttps = YES;// 是否使用https + builder.zone = [[QNAutoZone alloc] init];// 根据 bucket 自动查询区域 + // builder.zone = [QNFixedZone createWithRegionId:@"z0"];// 指定华东区域 + // builder.zone = [QNFixedZone createWithRegionId:@"z1"];// 指定华北区域 + // builder.zone = [QNFixedZone createWithRegionId:@"z2"];// 指定华南区域 + // builder.zone = [QNFixedZone createWithRegionId:@"na0"];// 指定北美区域 + // builder.zone = [QNFixedZone createWithRegionId:@"as0"];// 指定东南亚区域 + }]; + + QNUploadManager *upManager = [[QNUploadManager alloc] initWithConfiguration:config]; + QNUploadOption *option = [[QNUploadOption alloc] initWithProgressHandler:^(NSString *key, float percent) { + NSLog(@"progress %f", percent); + }]; + + NSData *data = [@"Hello, World!" dataUsingEncoding:NSUTF8StringEncoding]; + NSString *token = @"从服务端SDK获取"; + [upManager putData:data key:@"hello" token:token complete: ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) { + NSLog(@"%@", info); + NSLog(@"%@", resp); + } option:option]; +... +``` + +建议 QNUploadManager 创建一次重复使用, 或者使用单例方式创建. + +## 测试 + +### 所有测试 + +``` bash +$ xcodebuild test -workspace QiniuSDK.xcworkspace -scheme QiniuSDK_Mac -configuration Release -destination 'platform=macOS,arch=x86_64' +``` +### 指定测试 + +可以在单元测试上修改, 熟悉 SDK + +``` bash +$ xcodebuild test -workspace QiniuSDK.xcworkspace -scheme QiniuSDK_Mac -configuration Release -destination 'platform=macOS,arch=x86_64' -only-testing:"QiniuSDK_MacTests/QNResumeUploadTest/test5M" +``` + +## 示例代码 +* 完整的demo 见 QiniuDemo 目录下的代码 +* 具体细节的一些配置 可参考 QiniuSDKTests 下面的一些单元测试,以及源代码 + +## 常见问题 + +- 如果碰到 crc 链接错误, 请把 libz.dylib 加入到项目中去 +- 如果碰到 res_9_ninit 链接错误, 请把 libresolv.dylib 加入到项目中去 +- 如果需要支持 iOS 5 或者支持 RestKit, 请用 AFNetworking 1.x 分支的版本 +- 如果碰到其他编译错误, 请参考 CocoaPods 的 [troubleshooting](http://guides.cocoapods.org/using/troubleshooting.html) +- iOS 9+ 强制使用https,需要在project build info 添加NSAppTransportSecurity类型Dictionary。在NSAppTransportSecurity下添加NSAllowsArbitraryLoads类型Boolean,值设为YES。 具体操作可参见 http://blog.csdn.net/guoer9973/article/details/48622823 +- 上传返回错误码理解,[status code 注释](https://github.com/qiniu/objc-sdk/blob/master/QiniuSDK/Common/QNErrorCode.h) + +## 代码贡献 + +详情参考 [代码提交指南](https://github.com/qiniu/objc-sdk/blob/master/Contributing.md). + +## 贡献记录 + +- [所有贡献者](https://github.com/qiniu/objc-sdk/contributors) + +## 联系我们 + +- 如果需要帮助, 请提交工单 (在 portal 右侧点击咨询和建议提交工单, 或者直接向 support@qiniu.com 发送邮件) +- 如果有什么问题, 可以到问答社区提问, [问答社区](http://qiniu.segmentfault.com/) +- 更详细的文档, 见 [官方文档站](http://developer.qiniu.com/) +- 如果发现了 bug, 欢迎提交 [issue](https://github.com/qiniu/objc-sdk/issues) +- 如果有功能需求, 欢迎提交 [issue](https://github.com/qiniu/objc-sdk/issues) +- 如果要提交代码, 欢迎提交 pull request +- 欢迎关注我们的 [微信](http://www.qiniu.com/#weixin) && [微博](http://weibo.com/qiniutek), 及时获取动态信息 + +## 代码许可 + +The MIT License (MIT). 详情见 [License 文件](https://github.com/qiniu/objc-sdk/blob/master/LICENSE). diff --git a/Pods/Target Support Files/HappyDNS/HappyDNS-dummy.m b/Pods/Target Support Files/HappyDNS/HappyDNS-dummy.m new file mode 100644 index 0000000..a00a1e0 --- /dev/null +++ b/Pods/Target Support Files/HappyDNS/HappyDNS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_HappyDNS : NSObject +@end +@implementation PodsDummy_HappyDNS +@end diff --git a/Pods/Target Support Files/HappyDNS/HappyDNS-prefix.pch b/Pods/Target Support Files/HappyDNS/HappyDNS-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/HappyDNS/HappyDNS-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/HappyDNS/HappyDNS.debug.xcconfig b/Pods/Target Support Files/HappyDNS/HappyDNS.debug.xcconfig new file mode 100644 index 0000000..b43f550 --- /dev/null +++ b/Pods/Target Support Files/HappyDNS/HappyDNS.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/HappyDNS" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HappyDNS" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/HappyDNS +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/HappyDNS/HappyDNS.release.xcconfig b/Pods/Target Support Files/HappyDNS/HappyDNS.release.xcconfig new file mode 100644 index 0000000..b43f550 --- /dev/null +++ b/Pods/Target Support Files/HappyDNS/HappyDNS.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/HappyDNS" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HappyDNS" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/HappyDNS +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/HappyDNS/ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist b/Pods/Target Support Files/HappyDNS/ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist new file mode 100644 index 0000000..82617c3 --- /dev/null +++ b/Pods/Target Support Files/HappyDNS/ResourceBundle-HappyDNS.privacy-HappyDNS-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.4 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods-msext/Pods-msext-acknowledgements.markdown b/Pods/Target Support Files/Pods-msext/Pods-msext-acknowledgements.markdown new file mode 100644 index 0000000..ea41fd0 --- /dev/null +++ b/Pods/Target Support Files/Pods-msext/Pods-msext-acknowledgements.markdown @@ -0,0 +1,53 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## HappyDNS + +The MIT License (MIT) + +Copyright (c) 2011-2024 qiniu.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## Qiniu + +The MIT License (MIT) + +Copyright (c) 2011-2024 qiniu.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-msext/Pods-msext-acknowledgements.plist b/Pods/Target Support Files/Pods-msext/Pods-msext-acknowledgements.plist new file mode 100644 index 0000000..127e73e --- /dev/null +++ b/Pods/Target Support Files/Pods-msext/Pods-msext-acknowledgements.plist @@ -0,0 +1,91 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) + +Copyright (c) 2011-2024 qiniu.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + License + MIT + Title + HappyDNS + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) + +Copyright (c) 2011-2024 qiniu.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + License + MIT + Title + Qiniu + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Pods/Target Support Files/Pods-msext/Pods-msext-dummy.m b/Pods/Target Support Files/Pods-msext/Pods-msext-dummy.m new file mode 100644 index 0000000..162780f --- /dev/null +++ b/Pods/Target Support Files/Pods-msext/Pods-msext-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_msext : NSObject +@end +@implementation PodsDummy_Pods_msext +@end diff --git a/Pods/Target Support Files/Pods-msext/Pods-msext-resources.sh b/Pods/Target Support Files/Pods-msext/Pods-msext-resources.sh new file mode 100755 index 0000000..7608e44 --- /dev/null +++ b/Pods/Target Support Files/Pods-msext/Pods-msext-resources.sh @@ -0,0 +1,131 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then + # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy + # resources to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +case "${TARGETED_DEVICE_FAMILY:-}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + 4) + TARGET_DEVICE_ARGS="--target-device watch" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" || true + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS/HappyDNS.privacy.bundle" + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/Qiniu/Qiniu.privacy.bundle" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS/HappyDNS.privacy.bundle" + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/Qiniu/Qiniu.privacy.bundle" +fi + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find -L "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + else + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" + fi +fi diff --git a/Pods/Target Support Files/Pods-msext/Pods-msext.debug.xcconfig b/Pods/Target Support Files/Pods-msext/Pods-msext.debug.xcconfig new file mode 100644 index 0000000..fd70e45 --- /dev/null +++ b/Pods/Target Support Files/Pods-msext/Pods-msext.debug.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HappyDNS" "${PODS_ROOT}/Headers/Public/Qiniu" +LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS" "${PODS_CONFIGURATION_BUILD_DIR}/Qiniu" +OTHER_LDFLAGS = $(inherited) -ObjC -l"HappyDNS" -l"Qiniu" -l"resolv" -l"z" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-msext/Pods-msext.release.xcconfig b/Pods/Target Support Files/Pods-msext/Pods-msext.release.xcconfig new file mode 100644 index 0000000..fd70e45 --- /dev/null +++ b/Pods/Target Support Files/Pods-msext/Pods-msext.release.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HappyDNS" "${PODS_ROOT}/Headers/Public/Qiniu" +LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS" "${PODS_CONFIGURATION_BUILD_DIR}/Qiniu" +OTHER_LDFLAGS = $(inherited) -ObjC -l"HappyDNS" -l"Qiniu" -l"resolv" -l"z" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Qiniu/Qiniu-dummy.m b/Pods/Target Support Files/Qiniu/Qiniu-dummy.m new file mode 100644 index 0000000..19e4bb6 --- /dev/null +++ b/Pods/Target Support Files/Qiniu/Qiniu-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Qiniu : NSObject +@end +@implementation PodsDummy_Qiniu +@end diff --git a/Pods/Target Support Files/Qiniu/Qiniu-prefix.pch b/Pods/Target Support Files/Qiniu/Qiniu-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/Qiniu/Qiniu-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/Qiniu/Qiniu.debug.xcconfig b/Pods/Target Support Files/Qiniu/Qiniu.debug.xcconfig new file mode 100644 index 0000000..e2401e0 --- /dev/null +++ b/Pods/Target Support Files/Qiniu/Qiniu.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Qiniu +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Qiniu" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HappyDNS" "${PODS_ROOT}/Headers/Public/Qiniu" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Qiniu +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Qiniu/Qiniu.release.xcconfig b/Pods/Target Support Files/Qiniu/Qiniu.release.xcconfig new file mode 100644 index 0000000..e2401e0 --- /dev/null +++ b/Pods/Target Support Files/Qiniu/Qiniu.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Qiniu +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Qiniu" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HappyDNS" "${PODS_ROOT}/Headers/Public/Qiniu" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Qiniu +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Qiniu/ResourceBundle-Qiniu.privacy-Qiniu-Info.plist b/Pods/Target Support Files/Qiniu/ResourceBundle-Qiniu.privacy-Qiniu-Info.plist new file mode 100644 index 0000000..e7e8d7b --- /dev/null +++ b/Pods/Target Support Files/Qiniu/ResourceBundle-Qiniu.privacy-Qiniu-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 8.8.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/msext.xcodeproj/project.pbxproj b/msext.xcodeproj/project.pbxproj old mode 100755 new mode 100644 index 5513e3c..d94c80e --- a/msext.xcodeproj/project.pbxproj +++ b/msext.xcodeproj/project.pbxproj @@ -7,8 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 1A6D67D02DFE70BD00C72F69 /* QiniuConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6D67CD2DFE70BD00C72F69 /* QiniuConfig.m */; }; + 1A6D67D12DFE70BD00C72F69 /* QiniuManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6D67CF2DFE70BD00C72F69 /* QiniuManager.m */; }; 31E803772250BF51005DEBFA /* versionConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 31E803762250BF51005DEBFA /* versionConfig.m */; }; 31E803792250C28F005DEBFA /* gameid in Resources */ = {isa = PBXBuildFile; fileRef = 31E803782250C28F005DEBFA /* gameid */; }; + 8021797BA72DAFC4131F956B /* libPods-msext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B09474A14AD64EAA7687626 /* libPods-msext.a */; }; A85333BA200F05DB00E1D646 /* HTTPErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = A8533384200F05DB00E1D646 /* HTTPErrorResponse.m */; }; A85333BB200F05DB00E1D646 /* HTTPDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = A8533385200F05DB00E1D646 /* HTTPDataResponse.m */; }; A85333BC200F05DB00E1D646 /* HTTPDynamicFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = A8533387200F05DB00E1D646 /* HTTPDynamicFileResponse.m */; }; @@ -197,9 +200,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 1A6D67CC2DFE70BC00C72F69 /* QiniuConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QiniuConfig.h; sourceTree = ""; }; + 1A6D67CD2DFE70BD00C72F69 /* QiniuConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QiniuConfig.m; sourceTree = ""; }; + 1A6D67CE2DFE70BD00C72F69 /* QiniuManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QiniuManager.h; sourceTree = ""; }; + 1A6D67CF2DFE70BD00C72F69 /* QiniuManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QiniuManager.m; sourceTree = ""; }; 31E803752250BF51005DEBFA /* versionConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = versionConfig.h; sourceTree = ""; }; 31E803762250BF51005DEBFA /* versionConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = versionConfig.m; sourceTree = ""; }; 31E803782250C28F005DEBFA /* gameid */ = {isa = PBXFileReference; lastKnownFileType = folder; path = gameid; sourceTree = ""; }; + 3B09474A14AD64EAA7687626 /* libPods-msext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-msext.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 734B0339AAE4094E11F418FF /* Pods-msext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msext.debug.xcconfig"; path = "Target Support Files/Pods-msext/Pods-msext.debug.xcconfig"; sourceTree = ""; }; + 7488B78FA872D919485B61D5 /* Pods-msext.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msext.release.xcconfig"; path = "Target Support Files/Pods-msext/Pods-msext.release.xcconfig"; sourceTree = ""; }; A853337D200F05DB00E1D646 /* HTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnection.h; sourceTree = ""; }; A853337E200F05DB00E1D646 /* HTTPLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPLogging.h; sourceTree = ""; }; A853337F200F05DB00E1D646 /* HTTPMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPMessage.h; sourceTree = ""; }; @@ -537,6 +547,7 @@ E5FA4FA61B60BFAB006FB4C2 /* Foundation.framework in Frameworks */, E5FA4FA41B60BFA5006FB4C2 /* CoreGraphics.framework in Frameworks */, E5FA4FA21B60BF98006FB4C2 /* UIKit.framework in Frameworks */, + 8021797BA72DAFC4131F956B /* libPods-msext.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -550,6 +561,26 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1A6D67CB2DFE6E7100C72F69 /* Utils */ = { + isa = PBXGroup; + children = ( + 1A6D67CC2DFE70BC00C72F69 /* QiniuConfig.h */, + 1A6D67CD2DFE70BD00C72F69 /* QiniuConfig.m */, + 1A6D67CE2DFE70BD00C72F69 /* QiniuManager.h */, + 1A6D67CF2DFE70BD00C72F69 /* QiniuManager.m */, + ); + path = Utils; + sourceTree = ""; + }; + 549E8113987B440757151824 /* Pods */ = { + isa = PBXGroup; + children = ( + 734B0339AAE4094E11F418FF /* Pods-msext.debug.xcconfig */, + 7488B78FA872D919485B61D5 /* Pods-msext.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; A853337B200F05DB00E1D646 /* http */ = { isa = PBXGroup; children = ( @@ -810,6 +841,7 @@ E54080171B60DCA60021849A /* Class */ = { isa = PBXGroup; children = ( + 1A6D67CB2DFE6E7100C72F69 /* Utils */, A8BB1A4C21F99C73006D324A /* XiaoliaoSDK_iOS */, A8DEEC27208DBDDD005E9AED /* Video */, A8D14E82206F7F6800DEB914 /* libs */, @@ -1075,6 +1107,7 @@ E5FA4EBD1B607BC9006FB4C2 /* msext */, E5FA4ED71B607BC9006FB4C2 /* msextTests */, E5FA4EBC1B607BC9006FB4C2 /* Products */, + 549E8113987B440757151824 /* Pods */, ); sourceTree = ""; }; @@ -1181,6 +1214,7 @@ E5FA4FA51B60BFAB006FB4C2 /* Foundation.framework */, E5FA4FA31B60BFA5006FB4C2 /* CoreGraphics.framework */, E5FA4FA11B60BF98006FB4C2 /* UIKit.framework */, + 3B09474A14AD64EAA7687626 /* libPods-msext.a */, ); name = Frameworks; sourceTree = ""; @@ -1192,10 +1226,12 @@ isa = PBXNativeTarget; buildConfigurationList = E5FA4EDE1B607BC9006FB4C2 /* Build configuration list for PBXNativeTarget "msext" */; buildPhases = ( + ADFBC0A5852956B34FF1C551 /* [CP] Check Pods Manifest.lock */, E5FA4EB71B607BC9006FB4C2 /* Sources */, E5FA4EB81B607BC9006FB4C2 /* Frameworks */, E5FA4EB91B607BC9006FB4C2 /* Resources */, E5FCE4021F27A9F700FAC174 /* Run Script */, + 4C579F725E35C90596F78F32 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -1343,6 +1379,48 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 4C579F725E35C90596F78F32 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-msext/Pods-msext-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/HappyDNS/HappyDNS.privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Qiniu/Qiniu.privacy.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/HappyDNS.privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Qiniu.privacy.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-msext/Pods-msext-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + ADFBC0A5852956B34FF1C551 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-msext-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; E5FCE4021F27A9F700FAC174 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1398,6 +1476,7 @@ A85333BF200F05DB00E1D646 /* HTTPRedirectResponse.m in Sources */, E54335081DEC0F7600E45ECD /* Bridge.m in Sources */, E58FD8381DEEA55B00220EAE /* WXApiManager.m in Sources */, + 1A6D67D02DFE70BD00C72F69 /* QiniuConfig.m in Sources */, A85333CB200F05DB00E1D646 /* DDTTYLogger.m in Sources */, E56C80051E5CB57B00916DD9 /* mztools.c in Sources */, E5BA3CFD1E2E819C006D41DB /* AFURLRequestSerialization.m in Sources */, @@ -1411,6 +1490,7 @@ A8DEEC43208DCD27005E9AED /* AppID.m in Sources */, E54080641B60DCA60021849A /* SGGateway.m in Sources */, E518CB7B1E5C2EC9003C5B23 /* ASIDownloadCache.m in Sources */, + 1A6D67D12DFE70BD00C72F69 /* QiniuManager.m in Sources */, E540806B1B60DCCB0021849A /* FuncPublic.m in Sources */, E54080611B60DCA60021849A /* SBJsonBase.m in Sources */, E56F24D91E1F4E0500F32036 /* CustomWindow.m in Sources */, @@ -1519,7 +1599,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1559,7 +1639,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -1568,6 +1648,7 @@ }; E5FA4EDF1B607BC9006FB4C2 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 734B0339AAE4094E11F418FF /* Pods-msext.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-1"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-1"; @@ -1592,7 +1673,7 @@ /usr/include/libxml2, ); INFOPLIST_FILE = msext/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -1604,12 +1685,7 @@ "$(PROJECT_DIR)/msext/Class/Video", "$(PROJECT_DIR)/msext/Class/XiaoliaoSDK_iOS", ); - OTHER_LDFLAGS = ( - "-lxml2", - "-Objc", - "-all_load", - "\"$(SRCROOT)/msext/Class/SDKExport/libWeChatSDK.a\"", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = com.skyapp.ylgamehall; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "a8315ce6-c429-4b17-afb5-dbd05b31821a"; @@ -1621,6 +1697,7 @@ }; E5FA4EE01B607BC9006FB4C2 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7488B78FA872D919485B61D5 /* Pods-msext.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-1"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-1"; @@ -1645,7 +1722,7 @@ /usr/include/libxml2, ); INFOPLIST_FILE = msext/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -1657,12 +1734,7 @@ "$(PROJECT_DIR)/msext/Class/Video", "$(PROJECT_DIR)/msext/Class/XiaoliaoSDK_iOS", ); - OTHER_LDFLAGS = ( - "-lxml2", - "-Objc", - "-all_load", - "\"$(SRCROOT)/msext/Class/SDKExport/libWeChatSDK.a\"", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = com.skyapp.ylgamehall; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "a8315ce6-c429-4b17-afb5-dbd05b31821a"; diff --git a/msext.xcworkspace/contents.xcworkspacedata b/msext.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..73828ec --- /dev/null +++ b/msext.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/msext.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/msext.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/msext.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/msext/Class/RootVC/gameController.m b/msext/Class/RootVC/gameController.m index 2eeb6b1..7ab58af 100755 --- a/msext/Class/RootVC/gameController.m +++ b/msext/Class/RootVC/gameController.m @@ -43,6 +43,8 @@ #import #import #import "XianliaoApiManager.h" +#import "QiniuManager.h" +#import "QiniuConfig.h" @interface gameController () { @@ -844,7 +846,7 @@ CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; CTCarrier *carrier = [telephonyInfo subscriberCellularProvider]; NSString *currentCountry=[carrier carrierName]; - // NSLog(@"[carrier isoCountryCode]==%@,[carrier allowsVOIP]=%d,[carrier mobileCountryCode=%@,[carrier mobileCountryCode]=%@",[carrier isoCountryCode],[carrier allowsVOIP],[carrier mobileCountryCode],[carrier mobileNetworkCode]); + // NSLog(@"[carrier isoCountryCode]==%@,[carrier allowsVOIP]=%d,[carrier mobileCountryCode=%@,[carrier mobileNetworkCode]=%@",[carrier isoCountryCode],[carrier allowsVOIP],[carrier mobileCountryCode],[carrier mobileNetworkCode]); UIDevice *device = [[UIDevice alloc] init]; // NSString *name = device.name; //获取设备所有者的名称 NSString *model = device.model; //获取设备的类别 @@ -2194,6 +2196,15 @@ NSLog(@"录音时长过短,可能无效: %.2f秒", interval); return; } + + //4.播放 + if (play == nil) + { + NSLog(@"ERror creating player: %@", [play description]); + }else{ + [play play]; + } + NSString *amrPath = [FuncPublic GetPathByFileName:_fileName ofType:@"amr"]; NSLog(@"尝试转换WAV到AMR,源文件: %@,目标文件: %@", _filePath, amrPath); @@ -2223,23 +2234,67 @@ NSLog(@"转换WAV到AMR成功"); NSData *amrData = [NSData dataWithContentsOfFile:amrPath]; if (amrData && amrData.length > 0) { - // 数据有效,继续上传流程 - AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; - //接收类型不一致请替换一致text/html或别的 - manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", - @"text/html", - @"image/jpeg", - @"image/png", - @"application/octet-stream", - @"text/json", - @"audio/amr", - nil]; - NSString *string=@"http://gameapi.0791ts.cn/api/UpLoad/PostFile"; + + + + + // 数据有效,使用QiniuManager上传到七牛云 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; - formatter.dateFormat =@"yyyyMMddHHmmss"; - NSString *str = [formatter stringFromDate:[NSDate date]]; - NSString *fileName = [NSString stringWithFormat:@"%@%08X.amr", str, arc4random()]; - // 继续原有的上传逻辑... + formatter.dateFormat = @"yyyyMMddHHmmss"; + NSString *timeStr = [formatter stringFromDate:[NSDate date]]; + NSString *uniqueFileName = [NSString stringWithFormat:@"%@_%08X.amr", timeStr, arc4random()]; + + // 显示上传状态提示 +// UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" +// message:@"正在上传录音文件..." +// preferredStyle:UIAlertControllerStyleAlert]; +// [self presentViewController:alertController animated:YES completion:nil]; + + // 调用七牛云管理器上传文件 + [[QiniuManager sharedManager] uploadAudioFile:amrPath + fileName:uniqueFileName + progressHandler:^(float progress) { + // 更新上传进度提示 +// dispatch_async(dispatch_get_main_queue(), ^{ +// alertController.message = [NSString stringWithFormat:@"正在上传录音文件... %.0f%%", progress * 100]; +// }); + } + completionHandler:^(NSString *key, NSError *error) { + // 关闭上传进度提示 + dispatch_async(dispatch_get_main_queue(), ^{ +// [alertController dismissViewControllerAnimated:YES completion:nil]; + + if (error) { + // 上传失败处理 +// UIAlertController *errorAlert = [UIAlertController alertControllerWithTitle:@"上传失败" +// message:error.localizedDescription +// preferredStyle:UIAlertControllerStyleAlert]; +// UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; +// [errorAlert addAction:okAction]; +// [self presentViewController:errorAlert animated:YES completion:nil]; +// + NSLog(@"七牛云上传失败: %@", error); + } else { + // 上传成功,获取文件URL + NSString *fileUrl = [[QiniuManager sharedManager] getFileUrlWithKey:key]; + NSString *audiourl=[NSString stringWithFormat:@"%@/%@",kQiniuDomain,uniqueFileName]; + [_bridge callHandler:@"getaudiourl" data:@{ @"audiourl":audiourl,@"time":[NSString stringWithFormat:@"%ld",(long)time]} ]; + NSLog(@"七牛云上传成功,文件URL: %@", fileUrl); + + // 将录音文件URL传递给JS接口 + if (self->_bridge) { + [self->_bridge callHandler:@"recordSuccess" data:@{ + @"fileUrl": fileUrl, + @"fileName": uniqueFileName, + @"fileKey": key + }]; + } + } + }); + }]; + + // 原有的上传流程代码注释掉或删除 + } else { NSLog(@"AMR文件无效或为空"); } @@ -2476,3 +2531,5 @@ }} @end + + diff --git a/msext/Class/Utils/QiniuConfig.h b/msext/Class/Utils/QiniuConfig.h new file mode 100644 index 0000000..16830f6 --- /dev/null +++ b/msext/Class/Utils/QiniuConfig.h @@ -0,0 +1,25 @@ +// +// QiniuConfig.h +// msext +// +// Created on June 15, 2025. +// + +#ifndef QiniuConfig_h +#define QiniuConfig_h + +/* 七牛云相关配置常量 */ +// AccessKey 和 SecretKey,从七牛云控制台获取 +extern NSString *const kQiniuAccessKey; +extern NSString *const kQiniuSecretKey; + +// 存储空间名称 +extern NSString *const kQiniuBucketName; + +// 七牛云默认域名 +extern NSString *const kQiniuDomain; + +// 录音文件目录 +extern NSString *const kQiniuRecordingDirectory; + +#endif /* QiniuConfig_h */ \ No newline at end of file diff --git a/msext/Class/Utils/QiniuConfig.m b/msext/Class/Utils/QiniuConfig.m new file mode 100644 index 0000000..8942d83 --- /dev/null +++ b/msext/Class/Utils/QiniuConfig.m @@ -0,0 +1,22 @@ +// +// QiniuConfig.m +// msext +// +// Created on June 15, 2025. +// + +#import +#import "QiniuConfig.h" + +// 七牛云 AccessKey 和 SecretKey +NSString *const kQiniuAccessKey = @"dQbQLUm1jIuL9PEq4jd6VKB-6pPxPEdg7le9KeBm"; +NSString *const kQiniuSecretKey = @"RCZpwLhAPoQ2sQQyWXzMJc7Po2MyZWfUJeW4Jmfq"; + +// 存储空间名称 +NSString *const kQiniuBucketName = @"iosaudio"; + +// 七牛云默认域名,用于访问上传后的文件 +NSString *const kQiniuDomain = @"iosaudio.daoqi88.cn"; + +// 录音文件在七牛云中的目录 +NSString *const kQiniuRecordingDirectory = @""; diff --git a/msext/Class/Utils/QiniuManager.h b/msext/Class/Utils/QiniuManager.h new file mode 100644 index 0000000..8f15697 --- /dev/null +++ b/msext/Class/Utils/QiniuManager.h @@ -0,0 +1,76 @@ +// +// QiniuManager.h +// msext +// +// Created on June 15, 2025. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * 上传完成后的回调 + * @param key 文件在七牛云中的key + * @param error 错误信息,如果上传成功则为nil + */ +typedef void(^QiniuUploadCompletionHandler)(NSString * _Nullable key, NSError * _Nullable error); + +/** + * 下载完成后的回调 + * @param filePath 下载文件的本地路径 + * @param error 错误信息,如果下载成功则为nil + */ +typedef void(^QiniuDownloadCompletionHandler)(NSString * _Nullable filePath, NSError * _Nullable error); + +/** + * 进度回调 + * @param progress 进度值,范围0-1 + */ +typedef void(^QiniuProgressHandler)(float progress); + +@interface QiniuManager : NSObject + +/** + * 获取QiniuManager的单例 + * @return QiniuManager实例 + */ ++ (instancetype)sharedManager; + +/** + * 初始化七牛云SDK + */ +- (void)setupQiniuSDK; + +/** + * 上传本地音频文件到七牛云 + * @param filePath 本地文件路径 + * @param fileName 上传后的文件名(不含路径) + * @param progressHandler 上传进度回调 + * @param completionHandler 上传完成回调 + */ +- (void)uploadAudioFile:(NSString *)filePath + fileName:(NSString *)fileName + progressHandler:(nullable QiniuProgressHandler)progressHandler + completionHandler:(QiniuUploadCompletionHandler)completionHandler; + +/** + * 从七牛云下载音频文件 + * @param key 文件在七牛云中的key + * @param progressHandler 下载进度回调 + * @param completionHandler 下载完成回调 + */ +- (void)downloadAudioFile:(NSString *)key + progressHandler:(nullable QiniuProgressHandler)progressHandler + completionHandler:(QiniuDownloadCompletionHandler)completionHandler; + +/** + * 根据key获取七牛云文件的URL + * @param key 文件在七牛云中的key + * @return 完整的URL字符串 + */ +- (NSString *)getFileUrlWithKey:(NSString *)key; + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/msext/Class/Utils/QiniuManager.m b/msext/Class/Utils/QiniuManager.m new file mode 100644 index 0000000..ebfd9e2 --- /dev/null +++ b/msext/Class/Utils/QiniuManager.m @@ -0,0 +1,256 @@ +// +// QiniuManager.m +// msext +// +// Created on June 15, 2025. +// + +#import "QiniuManager.h" +#import +#import "QiniuConfig.h" +#import +#import +#import + +@implementation QiniuManager + ++ (instancetype)sharedManager { + static QiniuManager *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + [instance setupQiniuSDK]; + }); + return instance; +} + +- (void)setupQiniuSDK { + // Qiniu SDK doesn't require explicit initialization + // The configuration will be applied when creating the QNUploadManager instance +} + +- (void)uploadAudioFile:(NSString *)filePath + fileName:(NSString *)fileName + progressHandler:(QiniuProgressHandler)progressHandler + completionHandler:(QiniuUploadCompletionHandler)completionHandler { + + // 检查文件是否存在 + if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + NSError *error = [NSError errorWithDomain:@"QiniuManager" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"上传文件不存在"}]; + if (completionHandler) { + completionHandler(nil, error); + } + return; + } + + // 创建上传配置 + QNConfiguration *config = [QNConfiguration build:^(QNConfigurationBuilder *builder) { + builder.zone = [QNFixedZone zone2]; // 使用华东区域 + builder.timeoutInterval = 60; // 超时设置,单位为秒 + }]; + + // 生成上传策略 + QNUploadManager *uploadManager = [[QNUploadManager alloc] initWithConfiguration:config]; + NSString *token = [self generateUploadToken]; + + // 文件在七牛云存储中的完整路径 + NSString *key = [NSString stringWithFormat:@"%@%@", kQiniuRecordingDirectory, fileName]; + + // 配置上传选项 + QNUploadOption *option = [[QNUploadOption alloc] initWithMime:@"audio/amr" + progressHandler:^(NSString *key, float percent) { + if (progressHandler) { + progressHandler(percent); + } + } params:nil checkCrc:NO cancellationSignal:nil]; + + // 执行上传 + [uploadManager putFile:filePath + key:key + token:token + complete:^(QNResponseInfo *info, NSString *key, NSDictionary *resp) { + if (info.statusCode == 200) { + if (completionHandler) { + completionHandler(key, nil); + } + } else { + NSError *error = [NSError errorWithDomain:@"QiniuManager" + code:info.statusCode + userInfo:@{NSLocalizedDescriptionKey: info.error.localizedDescription ?: @"上传失败"}]; + if (completionHandler) { + completionHandler(nil, error); + } + } + } + option:option]; +} + +- (void)downloadAudioFile:(NSString *)key + progressHandler:(QiniuProgressHandler)progressHandler + completionHandler:(QiniuDownloadCompletionHandler)completionHandler { + + // 获取完整的下载URL + NSString *urlString = [self getFileUrlWithKey:key]; + NSURL *url = [NSURL URLWithString:urlString]; + + // 创建下载任务 + NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; + + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { + if (error) { + if (completionHandler) { + completionHandler(nil, error); + } + return; + } + + // 获取临时文件URL + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if (httpResponse.statusCode != 200) { + NSError *downloadError = [NSError errorWithDomain:@"QiniuManager" + code:httpResponse.statusCode + userInfo:@{NSLocalizedDescriptionKey: @"下载失败"}]; + if (completionHandler) { + completionHandler(nil, downloadError); + } + return; + } + + // 从URL中获取文件名 + NSString *fileName = [key lastPathComponent]; + if ([fileName length] == 0) { + fileName = [NSString stringWithFormat:@"qiniu_download_%@", [[NSUUID UUID] UUIDString]]; + } + + // 创建目标路径 + NSString *cachesDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; + NSString *downloadDirectory = [cachesDirectory stringByAppendingPathComponent:@"QiniuDownloads"]; + + // 确保目录存在 + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:downloadDirectory]) { + [fileManager createDirectoryAtPath:downloadDirectory withIntermediateDirectories:YES attributes:nil error:nil]; + } + + // 构建最终路径 + NSString *destinationPath = [downloadDirectory stringByAppendingPathComponent:fileName]; + + // 移动文件到目标路径 + if ([fileManager fileExistsAtPath:destinationPath]) { + [fileManager removeItemAtPath:destinationPath error:nil]; + } + + NSError *moveError = nil; + [fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:destinationPath] error:&moveError]; + + if (moveError) { + if (completionHandler) { + completionHandler(nil, moveError); + } + } else { + if (completionHandler) { + completionHandler(destinationPath, nil); + } + } + }]; + + // 添加进度追踪 + if (progressHandler) { + [downloadTask addObserver:self forKeyPath:@"countOfBytesReceived" options:NSKeyValueObservingOptionNew context:NULL]; + objc_setAssociatedObject(downloadTask, "progressHandler", [progressHandler copy], OBJC_ASSOCIATION_COPY); + objc_setAssociatedObject(downloadTask, "totalBytes", @(0), OBJC_ASSOCIATION_RETAIN); + } + + // 启动下载任务 + [downloadTask resume]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if ([object isKindOfClass:[NSURLSessionDownloadTask class]]) { + NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)object; + + if ([keyPath isEqualToString:@"countOfBytesReceived"]) { + NSNumber *totalBytes = objc_getAssociatedObject(task, "totalBytes"); + if ([totalBytes longLongValue] == 0 && task.countOfBytesExpectedToReceive > 0) { + objc_setAssociatedObject(task, "totalBytes", @(task.countOfBytesExpectedToReceive), OBJC_ASSOCIATION_RETAIN); + } + + float progress = 0; + if (task.countOfBytesExpectedToReceive > 0) { + progress = (float)task.countOfBytesReceived / (float)task.countOfBytesExpectedToReceive; + } + + QiniuProgressHandler progressHandler = objc_getAssociatedObject(task, "progressHandler"); + if (progressHandler) { + dispatch_async(dispatch_get_main_queue(), ^{ + progressHandler(progress); + }); + } + } + } +} + +- (NSString *)getFileUrlWithKey:(NSString *)key { + return [NSString stringWithFormat:@"%@/%@", kQiniuDomain, key]; +} + +#pragma mark - Private Methods + +- (NSString *)generateUploadToken { + // 构建上传策略(putPolicy) + NSMutableDictionary *policy = [NSMutableDictionary dictionary]; + + // 指定上传的目标资源空间(确保完整格式为bucketName或bucketName:keyPrefix) + NSString *scope = [NSString stringWithFormat:@"%@", kQiniuBucketName]; + [policy setObject:scope forKey:@"scope"]; + + // 上传策略的过期时间(1小时) + NSInteger deadline = (NSInteger)[[NSDate dateWithTimeIntervalSinceNow:3600] timeIntervalSince1970]; + [policy setObject:@(deadline) forKey:@"deadline"]; + + // 将上传策略转换为JSON + NSError *error = nil; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:policy options:0 error:&error]; + if (error) { + NSLog(@"生成JSON数据失败: %@", error); + return nil; + } + + // Base64编码JSON数据 + NSString *encodedPolicy = [self urlsafeBase64EncodeData:jsonData]; + + // 使用HMAC-SHA1算法进行签名(注意签名的内容只是encodedPolicy) + NSData *signData = [encodedPolicy dataUsingEncoding:NSUTF8StringEncoding]; + NSString *encodedSign = [self hmacSha1:kQiniuSecretKey data:signData]; + + // 构造上传凭证 - 格式为: accessKey:encodedSign:encodedPolicy + NSString *uploadToken = [NSString stringWithFormat:@"%@:%@:%@", kQiniuAccessKey, encodedSign, encodedPolicy]; + +// NSLog(@"七牛云配置信息 - AccessKey: %@, BucketName: %@, Domain: %@", +// kQiniuAccessKey, kQiniuBucketName, kQiniuDomain); +// NSLog(@"生成的上传凭证: %@", uploadToken); + return uploadToken; +} + +#pragma mark - Utility Methods + +- (NSString *)urlsafeBase64EncodeData:(NSData *)data { + NSString *base64 = [data base64EncodedStringWithOptions:0]; + base64 = [base64 stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + base64 = [base64 stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + return base64; +} + +- (NSString *)hmacSha1:(NSString *)key data:(NSData *)data { + const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding]; + const char *cData = [data bytes]; + unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; + + CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, [data length], cHMAC); + + NSData *hmacData = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; + return [self urlsafeBase64EncodeData:hmacData]; +} + +@end diff --git a/msext/QiniuSDK/Common/QNALAssetFile.m b/msext/QiniuSDK/Common/QNALAssetFile.m deleted file mode 100755 index af9408d..0000000 --- a/msext/QiniuSDK/Common/QNALAssetFile.m +++ /dev/null @@ -1,72 +0,0 @@ -// -// QNALAssetFile.m -// QiniuSDK -// -// Created by bailong on 15/7/25. -// Copyright (c) 2015年 Qiniu. All rights reserved. -// - -#import "QNALAssetFile.h" - -#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED -#import - -#import "QNResponseInfo.h" - -@interface QNALAssetFile () - -@property (nonatomic) ALAsset *asset; - -@property (readonly) int64_t fileSize; - -@property (readonly) int64_t fileModifyTime; - -@end - -@implementation QNALAssetFile -- (instancetype)init:(ALAsset *)asset - error:(NSError *__autoreleasing *)error { - if (self = [super init]) { - NSDate *createTime = [asset valueForProperty:ALAssetPropertyDate]; - int64_t t = 0; - if (createTime != nil) { - t = [createTime timeIntervalSince1970]; - } - _fileModifyTime = t; - _fileSize = asset.defaultRepresentation.size; - _asset = asset; - } - - return self; -} - -- (NSData *)read:(long)offset - size:(long)size { - ALAssetRepresentation *rep = [self.asset defaultRepresentation]; - Byte *buffer = (Byte *)malloc(size); - NSUInteger buffered = [rep getBytes:buffer fromOffset:offset length:size error:nil]; - - return [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES]; -} - -- (NSData *)readAll { - return [self read:0 size:(long)_fileSize]; -} - -- (void)close { -} - -- (NSString *)path { - ALAssetRepresentation *rep = [self.asset defaultRepresentation]; - return [rep url].path; -} - -- (int64_t)modifyTime { - return _fileModifyTime; -} - -- (int64_t)size { - return _fileSize; -} -@end -#endif diff --git a/msext/QiniuSDK/Common/QNPHAssetFile.m b/msext/QiniuSDK/Common/QNPHAssetFile.m deleted file mode 100755 index 4285781..0000000 --- a/msext/QiniuSDK/Common/QNPHAssetFile.m +++ /dev/null @@ -1,165 +0,0 @@ -// -// QNPHAssetFile.m -// Pods -// -// Created by 何舒 on 15/10/21. -// -// - -#import "QNPHAssetFile.h" - -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) -#import -#import - -#import "QNResponseInfo.h" - -@interface QNPHAssetFile () - -@property (nonatomic) PHAsset *phAsset; - -@property (readonly) int64_t fileSize; - -@property (readonly) int64_t fileModifyTime; - -@property (nonatomic, strong) NSData *assetData; - -@property (nonatomic, strong) NSURL *assetURL; - -@property (nonatomic, readonly) NSString *filepath; - -@property (nonatomic) NSFileHandle *file; - -@end - -@implementation QNPHAssetFile - -- (instancetype)init:(PHAsset *)phAsset error:(NSError *__autoreleasing *)error { - if (self = [super init]) { - NSDate *createTime = phAsset.creationDate; - int64_t t = 0; - if (createTime != nil) { - t = [createTime timeIntervalSince1970]; - } - _fileModifyTime = t; - _phAsset = phAsset; - _filepath = [self getInfo]; - if (PHAssetMediaTypeVideo == self.phAsset.mediaType) { - NSError *error2 = nil; - NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:_filepath error:&error2]; - if (error2 != nil) { - if (error != nil) { - *error = error2; - } - return self; - } - _fileSize = [fileAttr fileSize]; - NSFileHandle *f = nil; - NSData *d = nil; - if (_fileSize > 16 * 1024 * 1024) { - f = [NSFileHandle fileHandleForReadingAtPath:_filepath]; - if (f == nil) { - if (error != nil) { - *error = [[NSError alloc] initWithDomain:_filepath code:kQNFileError userInfo:nil]; - } - return self; - } - } else { - d = [NSData dataWithContentsOfFile:_filepath options:NSDataReadingMappedIfSafe error:&error2]; - if (error2 != nil) { - if (error != nil) { - *error = error2; - } - return self; - } - } - _file = f; - _assetData = d; - } - } - return self; -} - -- (NSData *)read:(long)offset size:(long)size { - if (_assetData != nil) { - return [_assetData subdataWithRange:NSMakeRange(offset, (unsigned int)size)]; - } - [_file seekToFileOffset:offset]; - return [_file readDataOfLength:size]; -} - -- (NSData *)readAll { - return [self read:0 size:(long)_fileSize]; -} - -- (void)close { - if (PHAssetMediaTypeVideo == self.phAsset.mediaType) { - if (_file != nil) { - [_file closeFile]; - } - [[NSFileManager defaultManager] removeItemAtPath:_filepath error:nil]; - } -} - -- (NSString *)path { - return _filepath; -} - -- (int64_t)modifyTime { - return _fileModifyTime; -} - -- (int64_t)size { - return _fileSize; -} - -- (NSString *)getInfo { - __block NSString *filePath = nil; - if (PHAssetMediaTypeImage == self.phAsset.mediaType) { - PHImageRequestOptions *options = [PHImageRequestOptions new]; - options.version = PHImageRequestOptionsVersionCurrent; - options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; - options.resizeMode = PHImageRequestOptionsResizeModeNone; - //不支持icloud上传 - options.networkAccessAllowed = NO; - options.synchronous = YES; - - [[PHImageManager defaultManager] requestImageDataForAsset:self.phAsset - options:options - resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { - _assetData = imageData; - _fileSize = imageData.length; - _assetURL = [NSURL URLWithString:self.phAsset.localIdentifier]; - filePath = _assetURL.path; - }]; - } else if (PHAssetMediaTypeVideo == self.phAsset.mediaType) { - NSArray *assetResources = [PHAssetResource assetResourcesForAsset:self.phAsset]; - PHAssetResource *resource; - for (PHAssetResource *assetRes in assetResources) { - if (assetRes.type == PHAssetResourceTypePairedVideo || assetRes.type == PHAssetResourceTypeVideo) { - resource = assetRes; - } - } - NSString *fileName = @"tempAssetVideo.mov"; - if (resource.originalFilename) { - fileName = resource.originalFilename; - } - PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; - //不支持icloud上传 - options.networkAccessAllowed = NO; - - NSString *PATH_VIDEO_FILE = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; - [[NSFileManager defaultManager] removeItemAtPath:PATH_VIDEO_FILE error:nil]; - [[PHAssetResourceManager defaultManager] writeDataForAssetResource:resource toFile:[NSURL fileURLWithPath:PATH_VIDEO_FILE] options:options completionHandler:^(NSError *_Nullable error) { - if (error) { - filePath = nil; - } else { - filePath = PATH_VIDEO_FILE; - } - }]; - } - return filePath; -} - -@end -#endif diff --git a/msext/QiniuSDK/Common/QNPHAssetResource.m b/msext/QiniuSDK/Common/QNPHAssetResource.m deleted file mode 100755 index d0458a0..0000000 --- a/msext/QiniuSDK/Common/QNPHAssetResource.m +++ /dev/null @@ -1,175 +0,0 @@ -// -// QNPHAssetResource.m -// QiniuSDK -// -// Created by 何舒 on 16/2/14. -// Copyright © 2016年 Qiniu. All rights reserved. -// - -#import "QNPHAssetResource.h" -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100) -#import -#import - -enum { - kAMASSETMETADATA_PENDINGREADS = 1, - kAMASSETMETADATA_ALLFINISHED = 0 -}; - -#import "QNResponseInfo.h" - -@interface QNPHAssetResource () - - { - BOOL _hasGotInfo; -} - -@property (nonatomic) PHAsset *phAsset; - -@property (nonatomic) PHLivePhoto *phLivePhoto; - -@property (nonatomic) PHAssetResource *phAssetResource; - -@property (readonly) int64_t fileSize; - -@property (readonly) int64_t fileModifyTime; - -@property (nonatomic, strong) NSData *assetData; - -@property (nonatomic, strong) NSURL *assetURL; - -@end - -@implementation QNPHAssetResource -- (instancetype)init:(PHAssetResource *)phAssetResource - error:(NSError *__autoreleasing *)error { - if (self = [super init]) { - PHAsset *phasset = [PHAsset fetchAssetsWithBurstIdentifier:self.phAssetResource.assetLocalIdentifier options:nil][0]; - NSDate *createTime = phasset.creationDate; - int64_t t = 0; - if (createTime != nil) { - t = [createTime timeIntervalSince1970]; - } - _fileModifyTime = t; - _phAssetResource = phAssetResource; - [self getInfo]; - } - return self; -} - -- (NSData *)read:(long)offset size:(long)size { - NSRange subRange = NSMakeRange(offset, size); - if (!self.assetData) { - self.assetData = [self fetchDataFromAsset:self.phAssetResource]; - } - NSData *subData = [self.assetData subdataWithRange:subRange]; - - return subData; -} - -- (NSData *)readAll { - return [self read:0 size:(long)_fileSize]; -} - -- (void)close { -} - -- (NSString *)path { - return self.assetURL.path; -} - -- (int64_t)modifyTime { - return _fileModifyTime; -} - -- (int64_t)size { - return _fileSize; -} - -- (void)getInfo { - if (!_hasGotInfo) { - _hasGotInfo = YES; - NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS]; - - NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:self.phAssetResource.originalFilename]; - NSURL *localpath = [NSURL fileURLWithPath:pathToWrite]; - PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; - options.networkAccessAllowed = YES; - [[PHAssetResourceManager defaultManager] writeDataForAssetResource:self.phAssetResource toFile:localpath options:options completionHandler:^(NSError *_Nullable error) { - if (error == nil) { - AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:localpath options:nil]; - NSNumber *fileSize = nil; - [urlAsset.URL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil]; - _fileSize = [fileSize unsignedLongLongValue]; - _assetURL = urlAsset.URL; - self.assetData = [NSData dataWithData:[NSData dataWithContentsOfURL:urlAsset.URL]]; - } else { - NSLog(@"%@", error); - } - - BOOL blHave = [[NSFileManager defaultManager] fileExistsAtPath:pathToWrite]; - if (!blHave) { - NSLog(@"no have"); - return; - } else { - NSLog(@" have"); - BOOL blDele = [[NSFileManager defaultManager] removeItemAtPath:pathToWrite error:nil]; - if (blDele) { - NSLog(@"dele success"); - } else { - NSLog(@"dele fail"); - } - } - [assetReadLock lock]; - [assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED]; - }]; - - [assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED]; - [assetReadLock unlock]; - assetReadLock = nil; - } -} - -- (NSData *)fetchDataFromAsset:(PHAssetResource *)videoResource { - __block NSData *tmpData = [NSData data]; - - NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS]; - - NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:videoResource.originalFilename]; - NSURL *localpath = [NSURL fileURLWithPath:pathToWrite]; - PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; - options.networkAccessAllowed = YES; - [[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:localpath options:options completionHandler:^(NSError *_Nullable error) { - if (error == nil) { - AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:localpath options:nil]; - NSData *videoData = [NSData dataWithContentsOfURL:urlAsset.URL]; - tmpData = [NSData dataWithData:videoData]; - } else { - NSLog(@"%@", error); - } - BOOL blHave = [[NSFileManager defaultManager] fileExistsAtPath:pathToWrite]; - if (!blHave) { - NSLog(@"no have"); - return; - } else { - NSLog(@" have"); - BOOL blDele = [[NSFileManager defaultManager] removeItemAtPath:pathToWrite error:nil]; - if (blDele) { - NSLog(@"dele success"); - } else { - NSLog(@"dele fail"); - } - } - [assetReadLock lock]; - [assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED]; - }]; - - [assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED]; - [assetReadLock unlock]; - assetReadLock = nil; - - return tmpData; -} - -@end -#endif diff --git a/msext/QiniuSDK/Common/QNSystem.m b/msext/QiniuSDK/Common/QNSystem.m deleted file mode 100755 index ed5c403..0000000 --- a/msext/QiniuSDK/Common/QNSystem.m +++ /dev/null @@ -1,89 +0,0 @@ -// -// QNSystem.m -// QiniuSDK -// -// Created by bailong on 15/10/13. -// Copyright © 2015年 Qiniu. All rights reserved. -// - -#import - -#if __IPHONE_OS_VERSION_MIN_REQUIRED -#import -#import -#else -#import -#endif - -BOOL hasNSURLSession() { -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) - float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; - if (sysVersion < 7.0) { - return NO; - } -#else - NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; - if (sysVersion.majorVersion < 10) { - return NO; - } else if (sysVersion.majorVersion == 10) { - return sysVersion.minorVersion >= 9; - } -#endif - return YES; -} - -BOOL hasAts() { -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) - float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; - if (sysVersion < 9.0) { - return NO; - } -#else - NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; - if (sysVersion.majorVersion < 10) { - return NO; - } else if (sysVersion.majorVersion == 10) { - return sysVersion.minorVersion >= 11; - } -#endif - return YES; -} - -BOOL allowsArbitraryLoads() { - if (!hasAts()) { - return YES; - } - - // for unit test - NSDictionary* d = [[NSBundle mainBundle] infoDictionary]; - if (d == nil || d.count == 0) { - return YES; - } - - NSDictionary* sec = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSAppTransportSecurity"]; - if (sec == nil) { - return NO; - } - NSNumber* ats = [sec objectForKey:@"NSAllowsArbitraryLoads"]; - if (ats == nil) { - return NO; - } - return ats.boolValue; -} - -BOOL isIpV6FullySupported() { -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) - float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; - if (sysVersion < 9.0) { - return NO; - } -#else - NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; - if (sysVersion.majorVersion < 10) { - return NO; - } else if (sysVersion.majorVersion == 10) { - return sysVersion.minorVersion >= 11; - } -#endif - return YES; -} diff --git a/msext/QiniuSDK/Http/QNHttpDelegate.h b/msext/QiniuSDK/Http/QNHttpDelegate.h deleted file mode 100755 index b73d62e..0000000 --- a/msext/QiniuSDK/Http/QNHttpDelegate.h +++ /dev/null @@ -1,33 +0,0 @@ -#import - -@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 - -- (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 diff --git a/msext/QiniuSDK/Http/QNResponseInfo.h b/msext/QiniuSDK/Http/QNResponseInfo.h deleted file mode 100755 index 7978ba2..0000000 --- a/msext/QiniuSDK/Http/QNResponseInfo.h +++ /dev/null @@ -1,206 +0,0 @@ -// -// QNResponseInfo.h -// QiniuSDK -// -// Created by bailong on 14/10/2. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import - -/** - * 中途取消的状态码 - */ -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 diff --git a/msext/QiniuSDK/Http/QNResponseInfo.m b/msext/QiniuSDK/Http/QNResponseInfo.m deleted file mode 100755 index 7dda06f..0000000 --- a/msext/QiniuSDK/Http/QNResponseInfo.m +++ /dev/null @@ -1,210 +0,0 @@ -// -// 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 diff --git a/msext/QiniuSDK/Http/QNSessionManager.m b/msext/QiniuSDK/Http/QNSessionManager.m deleted file mode 100755 index a369d9a..0000000 --- a/msext/QiniuSDK/Http/QNSessionManager.m +++ /dev/null @@ -1,333 +0,0 @@ -// -// 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 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 diff --git a/msext/QiniuSDK/Storage/QNConfiguration.h b/msext/QiniuSDK/Storage/QNConfiguration.h deleted file mode 100755 index 37946a4..0000000 --- a/msext/QiniuSDK/Storage/QNConfiguration.h +++ /dev/null @@ -1,205 +0,0 @@ -// -// QNConfiguration.h -// QiniuSDK -// -// Created by bailong on 15/5/21. -// Copyright (c) 2015年 Qiniu. All rights reserved. -// - -#import - -#import "QNRecorderDelegate.h" - -/** - * 断点上传时的分块大小 - */ -extern const UInt32 kQNBlockSize; - -/** - * 转换为用户需要的url - * - * @param url 上传url - * - * @return 根据上传url算出代理url - */ -typedef NSString * (^QNUrlConvert)(NSString *url); - -@class QNConfigurationBuilder; -@class QNDnsManager; -@class QNServiceAddress; -@class QNZone; -/** - * Builder block - * - * @param builder builder实例 - */ -typedef void (^QNConfigurationBuilderBlock)(QNConfigurationBuilder *builder); - -@interface QNConfiguration : NSObject - -/** - * 存储区域 - */ -@property (copy, nonatomic, readonly) QNZone *zone; - -/** - * 断点上传时的分片大小 - */ -@property (readonly) UInt32 chunkSize; - -/** - * 如果大于此值就使用断点上传,否则使用form上传 - */ -@property (readonly) UInt32 putThreshold; - -/** - * 上传失败的重试次数 - */ -@property (readonly) UInt32 retryMax; - -/** - * 超时时间 单位 秒 - */ -@property (readonly) UInt32 timeoutInterval; - -@property (nonatomic, readonly) id recorder; - -@property (nonatomic, readonly) QNRecorderKeyGenerator recorderKeyGen; - -@property (nonatomic, readonly) NSDictionary *proxy; - -@property (nonatomic, readonly) QNUrlConvert converter; - -@property (nonatomic, readonly) QNDnsManager *dns; - -@property (readonly) BOOL disableATS; - -+ (instancetype)build:(QNConfigurationBuilderBlock)block; - -@end - -/** - * 上传服务地址 - */ -@interface QNServiceAddress : NSObject - -- (instancetype)init:(NSString *)address ips:(NSArray *)ips; - -@property (nonatomic, readonly) NSString *address; -@property (nonatomic, readonly) NSArray *ips; - -@end - -typedef void (^QNPrequeryReturn)(int code); - -@class QNUpToken; - -@interface QNZone : NSObject - -/** - * 默认上传服务器地址 - */ -- (QNServiceAddress *)up:(QNUpToken *)token; - -/** - * 备用上传服务器地址 - */ -- (QNServiceAddress *)upBackup:(QNUpToken *)token; - -/** - * zone 0 华东 - * - * @return 实例 - */ -+ (instancetype)zone0; - -/** - * zone 1 华北 - * - * @return 实例 - */ -+ (instancetype)zone1; - -/** - * zone 2 华南 - * - * @return 实例 - */ -+ (instancetype)zone2; - -/** - * zone Na0 北美 - * - * @return 实例 - */ -+ (instancetype)zoneNa0; - -- (void)preQuery:(QNUpToken *)token - on:(QNPrequeryReturn)ret; - -+ (void)addIpToDns:(QNDnsManager *)dns; - -@end - -@interface QNFixedZone : QNZone -/** - * Zone初始化方法 - * - * @param upHost 默认上传服务器地址 - * @param upHostBackup 备用上传服务器地址 - * @param upIp 备用上传IP - * - * @return Zone实例 - */ -- (instancetype)initWithUp:(QNServiceAddress *)up - upBackup:(QNServiceAddress *)upBackup; - -@end - -@interface QNAutoZone : QNZone - -- (instancetype)initWithHttps:(BOOL)flag - dns:(QNDnsManager *)dns; - -@end - -@interface QNConfigurationBuilder : NSObject - -/** - * 默认上传服务器地址 - */ -@property (nonatomic, strong) QNZone *zone; - -/** - * 断点上传时的分片大小 - */ -@property (assign) UInt32 chunkSize; - -/** - * 如果大于此值就使用断点上传,否则使用form上传 - */ -@property (assign) UInt32 putThreshold; - -/** - * 上传失败的重试次数 - */ -@property (assign) UInt32 retryMax; - -/** - * 超时时间 单位 秒 - */ -@property (assign) UInt32 timeoutInterval; - -@property (nonatomic, strong) id recorder; - -@property (nonatomic, strong) QNRecorderKeyGenerator recorderKeyGen; - -@property (nonatomic, strong) NSDictionary *proxy; - -@property (nonatomic, strong) QNUrlConvert converter; - -@property (nonatomic, strong) QNDnsManager *dns; - -@property (assign) BOOL disableATS; - -@end diff --git a/msext/QiniuSDK/Storage/QNConfiguration.m b/msext/QiniuSDK/Storage/QNConfiguration.m deleted file mode 100755 index 6c84fa0..0000000 --- a/msext/QiniuSDK/Storage/QNConfiguration.m +++ /dev/null @@ -1,360 +0,0 @@ -// -// QNConfiguration.m -// QiniuSDK -// -// Created by bailong on 15/5/21. -// Copyright (c) 2015年 Qiniu. All rights reserved. -// - -#import "QNConfiguration.h" -#import "HappyDNS.h" -#import "QNNetworkInfo.h" -#import "QNResponseInfo.h" -#import "QNSessionManager.h" -#import "QNSystem.h" -#import "QNUpToken.h" - -const UInt32 kQNBlockSize = 4 * 1024 * 1024; - -static void addServiceToDns(QNServiceAddress *address, QNDnsManager *dns) { - NSArray *ips = address.ips; - if (ips == nil) { - return; - } - NSURL *u = [[NSURL alloc] initWithString:address.address]; - NSString *host = u.host; - for (int i = 0; i < ips.count; i++) { - [dns putHosts:host ip:ips[i]]; - } -} - -static void addZoneToDns(QNZone *zone, QNDnsManager *dns) { - addServiceToDns([zone up:nil], dns); - addServiceToDns([zone upBackup:nil], dns); -} - -static QNDnsManager *initDns(QNConfigurationBuilder *builder) { - QNDnsManager *d = builder.dns; - if (d == nil) { - id r1 = [QNResolver systemResolver]; - id r2 = [[QNResolver alloc] initWithAddress:@"119.29.29.29"]; - id r3 = [[QNResolver alloc] initWithAddress:@"114.114.115.115"]; - d = [[QNDnsManager alloc] init:[NSArray arrayWithObjects:r1, r2, r3, nil] networkInfo:[QNNetworkInfo normal]]; - } - return d; -} - -@implementation QNConfiguration - -+ (instancetype)build:(QNConfigurationBuilderBlock)block { - QNConfigurationBuilder *builder = [[QNConfigurationBuilder alloc] init]; - block(builder); - return [[QNConfiguration alloc] initWithBuilder:builder]; -} - -- (instancetype)initWithBuilder:(QNConfigurationBuilder *)builder { - if (self = [super init]) { - - _chunkSize = builder.chunkSize; - _putThreshold = builder.putThreshold; - _retryMax = builder.retryMax; - _timeoutInterval = builder.timeoutInterval; - - _recorder = builder.recorder; - _recorderKeyGen = builder.recorderKeyGen; - - _proxy = builder.proxy; - - _converter = builder.converter; - - _disableATS = builder.disableATS; - if (_disableATS) { - _dns = initDns(builder); - [QNZone addIpToDns:_dns]; - } else { - _dns = nil; - } - _zone = builder.zone; - } - return self; -} - -@end - -@implementation QNConfigurationBuilder - -- (instancetype)init { - if (self = [super init]) { - _zone = [QNZone zone0]; - _chunkSize = 256 * 1024; - _putThreshold = 512 * 1024; - _retryMax = 2; - _timeoutInterval = 60; - - _recorder = nil; - _recorderKeyGen = nil; - - _proxy = nil; - _converter = nil; - - if (hasAts() && !allowsArbitraryLoads()) { - _disableATS = NO; - } else { - _disableATS = YES; - } - } - return self; -} - -@end - -@implementation QNServiceAddress : NSObject - -- (instancetype)init:(NSString *)address ips:(NSArray *)ips { - if (self = [super init]) { - _address = address; - _ips = ips; - } - return self; -} - -@end - -@implementation QNFixedZone { - QNServiceAddress *up; - QNServiceAddress *upBackup; -} - -/** - * 备用上传服务器地址 - */ -- (QNServiceAddress *)upBackup:(NSString *)token { - return upBackup; -} - -- (QNServiceAddress *)up:(NSString *)token { - return up; -} - -- (instancetype)initWithUp:(QNServiceAddress *)up1 - upBackup:(QNServiceAddress *)upBackup1 { - if (self = [super init]) { - up = up1; - upBackup = upBackup1; - } - - return self; -} -@end - -@interface QNAutoZoneInfo : NSObject -@property (readonly, nonatomic) NSString *upHost; -@property (readonly, nonatomic) NSString *upIp; -@property (readonly, nonatomic) NSString *upBackup; -@property (readonly, nonatomic) NSString *upHttps; - -- (instancetype)init:(NSString *)uphost - upIp:(NSString *)upip - upBackup:(NSString *)upbackup - upHttps:(NSString *)uphttps; -@end - -@implementation QNAutoZoneInfo - -- (instancetype)init:(NSString *)uphost - upIp:(NSString *)upip - upBackup:(NSString *)upbackup - upHttps:(NSString *)uphttps { - if (self = [super init]) { - _upHost = uphost; - _upIp = upip; - _upBackup = upbackup; - _upHttps = uphttps; - } - return self; -} - -@end - -@implementation QNAutoZone { - NSString *server; - BOOL https; - NSMutableDictionary *cache; - NSLock *lock; - QNSessionManager *sesionManager; - QNDnsManager *dns; -} - -- (instancetype)initWithHttps:(BOOL)flag - dns:(QNDnsManager *)dns1 { - if (self = [super init]) { - dns = dns1; - server = @"https://uc.qbox.me"; - https = flag; - cache = [NSMutableDictionary new]; - lock = [NSLock new]; - sesionManager = [[QNSessionManager alloc] initWithProxy:nil timeout:10 urlConverter:nil dns:dns]; - } - return self; -} - -- (QNServiceAddress *)upBackup:(QNUpToken *)token { - NSString *index = [token index]; - [lock lock]; - QNAutoZoneInfo *info = [cache objectForKey:index]; - [lock unlock]; - if (info == nil) { - return nil; - } - if (https) { - return [[QNServiceAddress alloc] init:info.upHttps ips:@[ info.upIp ]]; - } - return [[QNServiceAddress alloc] init:info.upBackup ips:@[ info.upIp ]]; -} - -- (QNServiceAddress *)up:(QNUpToken *)token { - NSString *index = [token index]; - [lock lock]; - QNAutoZoneInfo *info = [cache objectForKey:index]; - [lock unlock]; - if (info == nil) { - return nil; - } - if (https) { - return [[QNServiceAddress alloc] init:info.upHttps ips:@[ info.upIp ]]; - } - return [[QNServiceAddress alloc] init:info.upHost ips:@[ info.upIp ]]; -} - -- (QNAutoZoneInfo *)buildInfoFromJson:(NSDictionary *)resp { - NSDictionary *http = [resp objectForKey:@"http"]; - NSArray *up = [http objectForKey:@"up"]; - NSString *upHost = [up objectAtIndex:1]; - NSString *upBackup = [up objectAtIndex:0]; - NSString *ipTemp = [up objectAtIndex:2]; - NSArray *a1 = [ipTemp componentsSeparatedByString:@" "]; - NSString *ip1 = [a1 objectAtIndex:2]; - NSArray *a2 = [ip1 componentsSeparatedByString:@"//"]; - NSString *upIp = [a2 objectAtIndex:1]; - NSDictionary *https_ = [resp objectForKey:@"https"]; - NSArray *a3 = [https_ objectForKey:@"up"]; - NSString *upHttps = [a3 objectAtIndex:0]; - return [[QNAutoZoneInfo alloc] init:upHost upIp:upIp upBackup:upBackup upHttps:upHttps]; -} - -- (void)preQuery:(QNUpToken *)token - on:(QNPrequeryReturn)ret { - if (token == nil) { - ret(-1); - } - [lock lock]; - QNAutoZoneInfo *info = [cache objectForKey:[token index]]; - [lock unlock]; - if (info != nil) { - ret(0); - return; - } - - NSString *url = [NSString stringWithFormat:@"%@/v1/query?ak=%@&bucket=%@", server, token.access, token.bucket]; - [sesionManager get:url withHeaders:nil withCompleteBlock:^(QNResponseInfo *info, NSDictionary *resp) { - if ([info isOK]) { - QNAutoZoneInfo *info = [self buildInfoFromJson:resp]; - if (info == nil) { - ret(kQNInvalidToken); - } else { - ret(0); - [lock lock]; - [cache setValue:info forKey:[token index]]; - [lock unlock]; - if (dns != nil) { - QNServiceAddress *address = [[QNServiceAddress alloc] init:info.upHttps ips:@[ info.upIp ]]; - addServiceToDns(address, dns); - address = [[QNServiceAddress alloc] init:info.upHost ips:@[ info.upIp ]]; - addServiceToDns(address, dns); - address = [[QNServiceAddress alloc] init:info.upBackup ips:@[ info.upIp ]]; - addServiceToDns(address, dns); - } - } - } else { - ret(kQNNetworkError); - } - }]; -} - -@end - -@implementation QNZone - -- (instancetype)init { - self = [super init]; - return self; -} - -/** - * 备用上传服务器地址 - */ -- (QNServiceAddress *)upBackup:(QNUpToken *)token { - return nil; -} - -- (QNServiceAddress *)up:(QNUpToken *)token { - return nil; -} - -+ (instancetype)createWithHost:(NSString *)up backupHost:(NSString *)backup ip1:(NSString *)ip1 ip2:(NSString *)ip2 { - NSArray *ips = [NSArray arrayWithObjects:ip1, ip2, nil]; - NSString *a = [NSString stringWithFormat:@"http://%@", up]; - QNServiceAddress *s1 = [[QNServiceAddress alloc] init:a ips:ips]; - NSString *b = [NSString stringWithFormat:@"http://%@", backup]; - QNServiceAddress *s2 = [[QNServiceAddress alloc] init:b ips:ips]; - return [[QNFixedZone alloc] initWithUp:s1 upBackup:s2]; -} - -+ (instancetype)zone0 { - static QNZone *z0 = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - z0 = [QNZone createWithHost:@"upload.qiniu.com" backupHost:@"up.qiniu.com" ip1:@"183.136.139.10" ip2:@"115.231.182.136"]; - }); - return z0; -} - -+ (instancetype)zone1 { - static QNZone *z1 = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - z1 = [QNZone createWithHost:@"upload-z1.qiniu.com" backupHost:@"up-z1.qiniu.com" ip1:@"106.38.227.28" ip2:@"106.38.227.27"]; - }); - return z1; -} - -+ (instancetype)zone2 { - static QNZone *z2 = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - z2 = [QNZone createWithHost:@"upload-z2.qiniu.com" backupHost:@"up-z2.qiniu.com" ip1:@"14.152.37.7" ip2:@"183.60.214.199"]; - }); - return z2; -} - -+ (instancetype)zoneNa0 { - static QNZone *zNa0 = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - zNa0 = [QNZone createWithHost:@"upload-na0.qiniu.com" backupHost:@"up-na0.qiniu.com" ip1:@"14.152.37.7" ip2:@"183.60.214.199"]; - }); - return zNa0; -} - -+ (void)addIpToDns:(QNDnsManager *)dns { - addZoneToDns([QNZone zone0], dns); - addZoneToDns([QNZone zone1], dns); - addZoneToDns([QNZone zone2], dns); -} - -- (void)preQuery:(QNUpToken *)token - on:(QNPrequeryReturn)ret { - ret(0); -} - -@end diff --git a/msext/QiniuSDK/Storage/QNFormUpload.h b/msext/QiniuSDK/Storage/QNFormUpload.h deleted file mode 100755 index 179fc2f..0000000 --- a/msext/QiniuSDK/Storage/QNFormUpload.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// QNFormUpload.h -// QiniuSDK -// -// Created by bailong on 15/1/4. -// Copyright (c) 2015年 Qiniu. All rights reserved. -// - -#import "QNHttpDelegate.h" -#import "QNUpToken.h" -#import "QNUploadManager.h" -#import - -@interface QNFormUpload : NSObject - -- (instancetype)initWithData:(NSData *)data - withKey:(NSString *)key - withToken:(QNUpToken *)token - withCompletionHandler:(QNUpCompletionHandler)block - withOption:(QNUploadOption *)option - withHttpManager:(id)http - withConfiguration:(QNConfiguration *)config; - -- (void)put; - -@end diff --git a/msext/QiniuSDK/Storage/QNFormUpload.m b/msext/QiniuSDK/Storage/QNFormUpload.m deleted file mode 100755 index 30401ef..0000000 --- a/msext/QiniuSDK/Storage/QNFormUpload.m +++ /dev/null @@ -1,133 +0,0 @@ -// -// QNFormUpload.m -// QiniuSDK -// -// Created by bailong on 15/1/4. -// Copyright (c) 2015年 Qiniu. All rights reserved. -// - -#import "QNFormUpload.h" -#import "QNConfiguration.h" -#import "QNCrc32.h" -#import "QNRecorderDelegate.h" -#import "QNResponseInfo.h" -#import "QNUploadManager.h" -#import "QNUploadOption+Private.h" -#import "QNUrlSafeBase64.h" - -@interface QNFormUpload () - -@property (nonatomic, strong) NSData *data; -@property (nonatomic, strong) id httpManager; -@property (nonatomic) int retryTimes; -@property (nonatomic, strong) NSString *key; -@property (nonatomic, strong) QNUpToken *token; -@property (nonatomic, strong) QNUploadOption *option; -@property (nonatomic, strong) QNUpCompletionHandler complete; -@property (nonatomic, strong) QNConfiguration *config; -@property (nonatomic) float previousPercent; - -@property (nonatomic, strong) NSString *access; //AK - -@end - -@implementation QNFormUpload - -- (instancetype)initWithData:(NSData *)data - withKey:(NSString *)key - withToken:(QNUpToken *)token - withCompletionHandler:(QNUpCompletionHandler)block - withOption:(QNUploadOption *)option - withHttpManager:(id)http - withConfiguration:(QNConfiguration *)config { - if (self = [super init]) { - _data = data; - _key = key; - _token = token; - _option = option != nil ? option : [QNUploadOption defaultOptions]; - _complete = block; - _httpManager = http; - _config = config; - _previousPercent = 0; - _access = token.access; - } - return self; -} - -- (void)put { - NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - NSString *fileName = _key; - if (_key) { - parameters[@"key"] = _key; - } else { - fileName = @"?"; - } - - parameters[@"token"] = _token.token; - - [parameters addEntriesFromDictionary:_option.params]; - - if (_option.checkCrc) { - parameters[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:_data]]; - } - - QNInternalProgressBlock p = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) { - float percent = (float)totalBytesWritten / (float)totalBytesExpectedToWrite; - if (percent > 0.95) { - percent = 0.95; - } - if (percent > _previousPercent) { - _previousPercent = percent; - } else { - percent = _previousPercent; - } - _option.progressHandler(_key, percent); - }; - - QNCompleteBlock complete = ^(QNResponseInfo *info, NSDictionary *resp) { - if (info.isOK) { - _option.progressHandler(_key, 1.0); - } - if (info.isOK || !info.couldRetry) { - _complete(info, _key, resp); - return; - } - if (_option.cancellationSignal()) { - _complete([QNResponseInfo cancel], _key, nil); - return; - } - NSString *nextHost = [_config.zone up:_token].address; - if (info.isConnectionBroken || info.needSwitchServer) { - nextHost = [_config.zone upBackup:_token].address; - } - - QNCompleteBlock retriedComplete = ^(QNResponseInfo *info, NSDictionary *resp) { - if (info.isOK) { - _option.progressHandler(_key, 1.0); - } - _complete(info, _key, resp); - }; - - [_httpManager multipartPost:nextHost - withData:_data - withParams:parameters - withFileName:fileName - withMimeType:_option.mimeType - withCompleteBlock:retriedComplete - withProgressBlock:p - withCancelBlock:_option.cancellationSignal - withAccess:_access]; - }; - - [_httpManager multipartPost:[_config.zone up:_token].address - withData:_data - withParams:parameters - withFileName:fileName - withMimeType:_option.mimeType - withCompleteBlock:complete - withProgressBlock:p - withCancelBlock:_option.cancellationSignal - withAccess:_access]; -} - -@end diff --git a/msext/QiniuSDK/Storage/QNResumeUpload.h b/msext/QiniuSDK/Storage/QNResumeUpload.h deleted file mode 100755 index c96fe7f..0000000 --- a/msext/QiniuSDK/Storage/QNResumeUpload.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// QNResumeUpload.h -// QiniuSDK -// -// Created by bailong on 14/10/1. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import "QNFileDelegate.h" -#import "QNHttpDelegate.h" -#import "QNUpToken.h" -#import "QNUploadManager.h" -#import - -@interface QNResumeUpload : NSObject - -- (instancetype)initWithFile:(id)file - withKey:(NSString *)key - withToken:(QNUpToken *)token - withCompletionHandler:(QNUpCompletionHandler)block - withOption:(QNUploadOption *)option - withRecorder:(id)recorder - withRecorderKey:(NSString *)recorderKey - withHttpManager:(id)http - withConfiguration:(QNConfiguration *)config; - -- (void)run; - -@end diff --git a/msext/QiniuSDK/Storage/QNResumeUpload.m b/msext/QiniuSDK/Storage/QNResumeUpload.m deleted file mode 100755 index 1f6e799..0000000 --- a/msext/QiniuSDK/Storage/QNResumeUpload.m +++ /dev/null @@ -1,337 +0,0 @@ -// -// QNResumeUpload.m -// QiniuSDK -// -// Created by bailong on 14/10/1. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import "QNResumeUpload.h" -#import "QNConfiguration.h" -#import "QNCrc32.h" -#import "QNRecorderDelegate.h" -#import "QNResponseInfo.h" -#import "QNUploadManager.h" -#import "QNUploadOption+Private.h" -#import "QNUrlSafeBase64.h" - -typedef void (^task)(void); - -@interface QNResumeUpload () - -@property (nonatomic, strong) id httpManager; -@property UInt32 size; -@property (nonatomic) int retryTimes; -@property (nonatomic, strong) NSString *key; -@property (nonatomic, strong) NSString *recorderKey; -@property (nonatomic) NSDictionary *headers; -@property (nonatomic, strong) QNUploadOption *option; -@property (nonatomic, strong) QNUpToken *token; -@property (nonatomic, strong) QNUpCompletionHandler complete; -@property (nonatomic, strong) NSMutableArray *contexts; - -@property int64_t modifyTime; -@property (nonatomic, strong) id recorder; - -@property (nonatomic, strong) QNConfiguration *config; - -@property UInt32 chunkCrc; - -@property (nonatomic, strong) id file; - -//@property (nonatomic, strong) NSArray *fileAry; - -@property (nonatomic) float previousPercent; - -@property (nonatomic, strong) NSString *access; //AK - -- (void)makeBlock:(NSString *)uphost - offset:(UInt32)offset - blockSize:(UInt32)blockSize - chunkSize:(UInt32)chunkSize - progress:(QNInternalProgressBlock)progressBlock - complete:(QNCompleteBlock)complete; - -- (void)putChunk:(NSString *)uphost - offset:(UInt32)offset - size:(UInt32)size - context:(NSString *)context - progress:(QNInternalProgressBlock)progressBlock - complete:(QNCompleteBlock)complete; - -- (void)makeFile:(NSString *)uphost - complete:(QNCompleteBlock)complete; - -@end - -@implementation QNResumeUpload - -- (instancetype)initWithFile:(id)file - withKey:(NSString *)key - withToken:(QNUpToken *)token - withCompletionHandler:(QNUpCompletionHandler)block - withOption:(QNUploadOption *)option - withRecorder:(id)recorder - withRecorderKey:(NSString *)recorderKey - withHttpManager:(id)http - withConfiguration:(QNConfiguration *)config; -{ - if (self = [super init]) { - _file = file; - _size = (UInt32)[file size]; - _key = key; - NSString *tokenUp = [NSString stringWithFormat:@"UpToken %@", token.token]; - _option = option != nil ? option : [QNUploadOption defaultOptions]; - _complete = block; - _headers = @{@"Authorization" : tokenUp, @"Content-Type" : @"application/octet-stream"}; - _recorder = recorder; - _httpManager = http; - _modifyTime = [file modifyTime]; - _recorderKey = recorderKey; - _contexts = [[NSMutableArray alloc] initWithCapacity:(_size + kQNBlockSize - 1) / kQNBlockSize]; - _config = config; - - _token = token; - _previousPercent = 0; - - _access = token.access; - } - return self; -} - -// save json value -//{ -// "size":filesize, -// "offset":lastSuccessOffset, -// "modify_time": lastFileModifyTime, -// "contexts": contexts -//} - -- (void)record:(UInt32)offset { - NSString *key = self.recorderKey; - if (offset == 0 || _recorder == nil || key == nil || [key isEqualToString:@""]) { - return; - } - NSNumber *n_size = @(self.size); - NSNumber *n_offset = @(offset); - NSNumber *n_time = [NSNumber numberWithLongLong:_modifyTime]; - NSMutableDictionary *rec = [NSMutableDictionary dictionaryWithObjectsAndKeys:n_size, @"size", n_offset, @"offset", n_time, @"modify_time", _contexts, @"contexts", nil]; - - NSError *error; - NSData *data = [NSJSONSerialization dataWithJSONObject:rec options:NSJSONWritingPrettyPrinted error:&error]; - if (error != nil) { - NSLog(@"up record json error %@ %@", key, error); - return; - } - error = [_recorder set:key data:data]; - if (error != nil) { - NSLog(@"up record set error %@ %@", key, error); - } -} - -- (void)removeRecord { - if (_recorder == nil) { - return; - } - [_recorder del:self.recorderKey]; -} - -- (UInt32)recoveryFromRecord { - NSString *key = self.recorderKey; - if (_recorder == nil || key == nil || [key isEqualToString:@""]) { - return 0; - } - - NSData *data = [_recorder get:key]; - if (data == nil) { - return 0; - } - - NSError *error; - NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; - if (error != nil) { - NSLog(@"recovery error %@ %@", key, error); - [_recorder del:self.key]; - return 0; - } - NSNumber *n_offset = info[@"offset"]; - NSNumber *n_size = info[@"size"]; - NSNumber *time = info[@"modify_time"]; - NSArray *contexts = info[@"contexts"]; - if (n_offset == nil || n_size == nil || time == nil || contexts == nil) { - return 0; - } - - UInt32 offset = [n_offset unsignedIntValue]; - UInt32 size = [n_size unsignedIntValue]; - if (offset > size || size != self.size) { - return 0; - } - UInt64 t = [time unsignedLongLongValue]; - if (t != _modifyTime) { - NSLog(@"modify time changed %llu, %llu", t, _modifyTime); - return 0; - } - _contexts = [[NSMutableArray alloc] initWithArray:contexts copyItems:true]; - return offset; -} - -- (void)nextTask:(UInt32)offset retriedTimes:(int)retried host:(NSString *)host { - if (self.option.cancellationSignal()) { - self.complete([QNResponseInfo cancel], self.key, nil); - return; - } - - if (offset == self.size) { - QNCompleteBlock completionHandler = ^(QNResponseInfo *info, NSDictionary *resp) { - if (info.isOK) { - [self removeRecord]; - self.option.progressHandler(self.key, 1.0); - } else if (info.couldRetry && retried < _config.retryMax) { - [self nextTask:offset retriedTimes:retried + 1 host:host]; - return; - } - self.complete(info, self.key, resp); - }; - [self makeFile:host complete:completionHandler]; - return; - } - - UInt32 chunkSize = [self calcPutSize:offset]; - QNInternalProgressBlock progressBlock = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) { - float percent = (float)(offset + totalBytesWritten) / (float)self.size; - if (percent > 0.95) { - percent = 0.95; - } - if (percent > _previousPercent) { - _previousPercent = percent; - } else { - percent = _previousPercent; - } - self.option.progressHandler(self.key, percent); - }; - - QNCompleteBlock completionHandler = ^(QNResponseInfo *info, NSDictionary *resp) { - if (info.error != nil) { - if (info.statusCode == 701) { - [self nextTask:(offset / kQNBlockSize) * kQNBlockSize retriedTimes:0 host:host]; - return; - } - if (retried >= _config.retryMax || !info.couldRetry) { - self.complete(info, self.key, resp); - return; - } - - NSString *nextHost = host; - if (info.isConnectionBroken || info.needSwitchServer) { - nextHost = [_config.zone upBackup:_token].address; - } - - [self nextTask:offset retriedTimes:retried + 1 host:nextHost]; - return; - } - - if (resp == nil) { - [self nextTask:offset retriedTimes:retried host:host]; - return; - } - - NSString *ctx = resp[@"ctx"]; - NSNumber *crc = resp[@"crc32"]; - if (ctx == nil || crc == nil || [crc unsignedLongValue] != _chunkCrc) { - [self nextTask:offset retriedTimes:retried host:host]; - return; - } - _contexts[offset / kQNBlockSize] = ctx; - [self record:offset + chunkSize]; - [self nextTask:offset + chunkSize retriedTimes:retried host:host]; - }; - if (offset % kQNBlockSize == 0) { - UInt32 blockSize = [self calcBlockSize:offset]; - [self makeBlock:host offset:offset blockSize:blockSize chunkSize:chunkSize progress:progressBlock complete:completionHandler]; - return; - } - NSString *context = _contexts[offset / kQNBlockSize]; - [self putChunk:host offset:offset size:chunkSize context:context progress:progressBlock complete:completionHandler]; -} - -- (UInt32)calcPutSize:(UInt32)offset { - UInt32 left = self.size - offset; - return left < _config.chunkSize ? left : _config.chunkSize; -} - -- (UInt32)calcBlockSize:(UInt32)offset { - UInt32 left = self.size - offset; - return left < kQNBlockSize ? left : kQNBlockSize; -} - -- (void)makeBlock:(NSString *)uphost - offset:(UInt32)offset - blockSize:(UInt32)blockSize - chunkSize:(UInt32)chunkSize - progress:(QNInternalProgressBlock)progressBlock - complete:(QNCompleteBlock)complete { - NSData *data = [self.file read:offset size:chunkSize]; - NSString *url = [[NSString alloc] initWithFormat:@"%@/mkblk/%u", uphost, (unsigned int)blockSize]; - _chunkCrc = [QNCrc32 data:data]; - [self post:url withData:data withCompleteBlock:complete withProgressBlock:progressBlock]; -} - -- (void)putChunk:(NSString *)uphost - offset:(UInt32)offset - size:(UInt32)size - context:(NSString *)context - progress:(QNInternalProgressBlock)progressBlock - complete:(QNCompleteBlock)complete { - NSData *data = [self.file read:offset size:size]; - UInt32 chunkOffset = offset % kQNBlockSize; - NSString *url = [[NSString alloc] initWithFormat:@"%@/bput/%@/%u", uphost, context, (unsigned int)chunkOffset]; - _chunkCrc = [QNCrc32 data:data]; - [self post:url withData:data withCompleteBlock:complete withProgressBlock:progressBlock]; -} - -- (void)makeFile:(NSString *)uphost - complete:(QNCompleteBlock)complete { - NSString *mime = [[NSString alloc] initWithFormat:@"/mimeType/%@", [QNUrlSafeBase64 encodeString:self.option.mimeType]]; - - __block NSString *url = [[NSString alloc] initWithFormat:@"%@/mkfile/%u%@", uphost, (unsigned int)self.size, mime]; - - if (self.key != nil) { - NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [QNUrlSafeBase64 encodeString:self.key]]; - url = [NSString stringWithFormat:@"%@%@", url, keyStr]; - } - - [self.option.params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { - url = [NSString stringWithFormat:@"%@/%@/%@", url, key, [QNUrlSafeBase64 encodeString:obj]]; - }]; - - //添加路径 - NSString *fname = [[NSString alloc] initWithFormat:@"/fname/%@", [QNUrlSafeBase64 encodeString:[self fileBaseName]]]; - url = [NSString stringWithFormat:@"%@%@", url, fname]; - - NSMutableData *postData = [NSMutableData data]; - NSString *bodyStr = [self.contexts componentsJoinedByString:@","]; - [postData appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]]; - [self post:url withData:postData withCompleteBlock:complete withProgressBlock:nil]; -} - -#pragma mark - 处理文件路径 -- (NSString *)fileBaseName { - return [[_file path] lastPathComponent]; -} - -- (void)post:(NSString *)url - withData:(NSData *)data - withCompleteBlock:(QNCompleteBlock)completeBlock - withProgressBlock:(QNInternalProgressBlock)progressBlock { - [_httpManager post:url withData:data withParams:nil withHeaders:_headers withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:_option.cancellationSignal withAccess:_access]; -} - -- (void)run { - @autoreleasepool { - UInt32 offset = [self recoveryFromRecord]; - [self nextTask:offset retriedTimes:0 host:[_config.zone up:_token].address]; - } -} - -@end diff --git a/msext/QiniuSDK/Storage/QNUpToken.h b/msext/QiniuSDK/Storage/QNUpToken.h deleted file mode 100755 index 03d3a4e..0000000 --- a/msext/QiniuSDK/Storage/QNUpToken.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// QNUpToken.h -// QiniuSDK -// -// Created by bailong on 15/6/7. -// Copyright (c) 2015年 Qiniu. All rights reserved. -// - -#import - -@interface QNUpToken : NSObject - -+ (instancetype)parse:(NSString *)token; - -@property (copy, nonatomic, readonly) NSString *access; -@property (copy, nonatomic, readonly) NSString *bucket; -@property (copy, nonatomic, readonly) NSString *token; - -@property (readonly) BOOL hasReturnUrl; - -- (NSString *)index; - -@end diff --git a/msext/QiniuSDK/Storage/QNUploadManager.m b/msext/QiniuSDK/Storage/QNUploadManager.m deleted file mode 100755 index 789ddc3..0000000 --- a/msext/QiniuSDK/Storage/QNUploadManager.m +++ /dev/null @@ -1,321 +0,0 @@ -// -// QNUploader.h -// QiniuSDK -// -// Created by bailong on 14-9-28. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import - -#if __IPHONE_OS_VERSION_MIN_REQUIRED -#import "QNALAssetFile.h" -#import -#import -#import - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 -#import "QNPHAssetFile.h" -#import -#endif - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100 -#import "QNPHAssetResource.h" -#endif - -#else -#import -#endif - -#import "QNAsyncRun.h" -#import "QNConfiguration.h" -#import "QNCrc32.h" -#import "QNFile.h" -#import "QNFormUpload.h" -#import "QNResponseInfo.h" -#import "QNResumeUpload.h" -#import "QNSessionManager.h" -#import "QNSystem.h" -#import "QNUpToken.h" -#import "QNUploadManager.h" -#import "QNUploadOption+Private.h" - -@interface QNUploadManager () -@property (nonatomic) id httpManager; -@property (nonatomic) QNConfiguration *config; -@end - -@implementation QNUploadManager - -- (instancetype)init { - return [self initWithConfiguration:nil]; -} - -- (instancetype)initWithRecorder:(id)recorder { - return [self initWithRecorder:recorder recorderKeyGenerator:nil]; -} - -- (instancetype)initWithRecorder:(id)recorder - recorderKeyGenerator:(QNRecorderKeyGenerator)recorderKeyGenerator { - QNConfiguration *config = [QNConfiguration build:^(QNConfigurationBuilder *builder) { - builder.recorder = recorder; - builder.recorderKeyGen = recorderKeyGenerator; - }]; - return [self initWithConfiguration:config]; -} - -- (instancetype)initWithConfiguration:(QNConfiguration *)config { - if (self = [super init]) { - if (config == nil) { - config = [QNConfiguration build:^(QNConfigurationBuilder *builder){ - }]; - } - _config = config; -#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) - _httpManager = [[QNSessionManager alloc] initWithProxy:config.proxy timeout:config.timeoutInterval urlConverter:config.converter dns:config.dns]; -#endif - } - return self; -} - -+ (instancetype)sharedInstanceWithConfiguration:(QNConfiguration *)config { - static QNUploadManager *sharedInstance = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [[self alloc] initWithConfiguration:config]; - }); - - return sharedInstance; -} - -+ (BOOL)checkAndNotifyError:(NSString *)key - token:(NSString *)token - input:(NSObject *)input - complete:(QNUpCompletionHandler)completionHandler { - NSString *desc = nil; - if (completionHandler == nil) { - @throw [NSException exceptionWithName:NSInvalidArgumentException - reason:@"no completionHandler" - userInfo:nil]; - return YES; - } - if (input == nil) { - desc = @"no input data"; - } else if (token == nil || [token isEqualToString:@""]) { - desc = @"no token"; - } - if (desc != nil) { - QNAsyncRunInMain(^{ - completionHandler([QNResponseInfo responseInfoWithInvalidArgument:desc], key, nil); - }); - return YES; - } - return NO; -} - -- (void)putData:(NSData *)data - key:(NSString *)key - token:(NSString *)token - complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option { - if ([QNUploadManager checkAndNotifyError:key token:token input:data complete:completionHandler]) { - return; - } - - QNUpToken *t = [QNUpToken parse:token]; - if (t == nil) { - QNAsyncRunInMain(^{ - completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"invalid token"], key, nil); - }); - return; - } - - [_config.zone preQuery:t on:^(int code) { - if (code != 0) { - QNAsyncRunInMain(^{ - completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"get zone failed"], key, nil); - }); - return; - } - if ([data length] == 0) { - QNAsyncRunInMain(^{ - completionHandler([QNResponseInfo responseInfoOfZeroData:nil], key, nil); - }); - return; - } - QNUpCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) { - QNAsyncRunInMain(^{ - completionHandler(info, key, resp); - }); - }; - QNFormUpload *up = [[QNFormUpload alloc] - initWithData:data - withKey:key - withToken:t - withCompletionHandler:complete - withOption:option - withHttpManager:_httpManager - withConfiguration:_config]; - QNAsyncRun(^{ - [up put]; - }); - }]; -} - -- (void)putFileInternal:(id)file - key:(NSString *)key - token:(NSString *)token - complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option { - @autoreleasepool { - QNUpToken *t = [QNUpToken parse:token]; - if (t == nil) { - QNAsyncRunInMain(^{ - completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"invalid token"], key, nil); - }); - return; - } - - [_config.zone preQuery:t on:^(int code) { - if (code != 0) { - QNAsyncRunInMain(^{ - completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"get zone failed"], key, nil); - }); - return; - } - QNUpCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) { - [file close]; - QNAsyncRunInMain(^{ - completionHandler(info, key, resp); - }); - }; - - if ([file size] <= _config.putThreshold) { - NSData *data = [file readAll]; - [self putData:data key:key token:token complete:complete option:option]; - return; - } - - NSString *recorderKey = key; - if (_config.recorder != nil && _config.recorderKeyGen != nil) { - recorderKey = _config.recorderKeyGen(key, [file path]); - } - - NSLog(@"recorder %@", _config.recorder); - - QNResumeUpload *up = [[QNResumeUpload alloc] - initWithFile:file - withKey:key - withToken:t - withCompletionHandler:complete - withOption:option - withRecorder:_config.recorder - withRecorderKey:recorderKey - withHttpManager:_httpManager - withConfiguration:_config]; - QNAsyncRun(^{ - [up run]; - }); - }]; - } -} - -- (void)putFile:(NSString *)filePath - key:(NSString *)key - token:(NSString *)token - complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option { - if ([QNUploadManager checkAndNotifyError:key token:token input:filePath complete:completionHandler]) { - return; - } - - @autoreleasepool { - NSError *error = nil; - __block QNFile *file = [[QNFile alloc] init:filePath error:&error]; - if (error) { - QNAsyncRunInMain(^{ - QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; - completionHandler(info, key, nil); - }); - return; - } - [self putFileInternal:file key:key token:token complete:completionHandler option:option]; - } -} - -- (void)putALAsset:(ALAsset *)asset - key:(NSString *)key - token:(NSString *)token - complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option { -#if __IPHONE_OS_VERSION_MIN_REQUIRED - if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) { - return; - } - - @autoreleasepool { - NSError *error = nil; - __block QNALAssetFile *file = [[QNALAssetFile alloc] init:asset error:&error]; - if (error) { - QNAsyncRunInMain(^{ - QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; - completionHandler(info, key, nil); - }); - return; - } - [self putFileInternal:file key:key token:token complete:completionHandler option:option]; - } -#endif -} - -- (void)putPHAsset:(PHAsset *)asset - key:(NSString *)key - token:(NSString *)token - complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option { -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) - if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) { - return; - } - - @autoreleasepool { - NSError *error = nil; - __block QNPHAssetFile *file = [[QNPHAssetFile alloc] init:asset error:&error]; - if (error) { - QNAsyncRunInMain(^{ - QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; - completionHandler(info, key, nil); - }); - return; - } - [self putFileInternal:file key:key token:token complete:completionHandler option:option]; - } -#endif -} - -- (void)putPHAssetResource:(PHAssetResource *)assetResource - key:(NSString *)key - token:(NSString *)token - complete:(QNUpCompletionHandler)completionHandler - option:(QNUploadOption *)option { -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100) - if ([QNUploadManager checkAndNotifyError:key token:token input:assetResource complete:completionHandler]) { - return; - } - @autoreleasepool { - NSError *error = nil; - __block QNPHAssetResource *file = [[QNPHAssetResource alloc] init:assetResource error:&error]; - if (error) { - QNAsyncRunInMain(^{ - QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error]; - completionHandler(info, key, nil); - }); - return; - } - [self putFileInternal:file key:key token:token complete:completionHandler option:option]; - } -#endif -} - -@end diff --git a/msext/QiniuSDK/Storage/QNUploadOption+Private.h b/msext/QiniuSDK/Storage/QNUploadOption+Private.h deleted file mode 100755 index 370d05f..0000000 --- a/msext/QiniuSDK/Storage/QNUploadOption+Private.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// QNUploadOption+Private.h -// QiniuSDK -// -// Created by bailong on 14/10/5. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import "QNUploadOption.h" - -@interface QNUploadOption (Private) - -@property (nonatomic, getter=priv_isCancelled, readonly) BOOL cancelled; -@end diff --git a/msext/QiniuSDK/Storage/QNUploadOption.h b/msext/QiniuSDK/Storage/QNUploadOption.h deleted file mode 100755 index 3e941b6..0000000 --- a/msext/QiniuSDK/Storage/QNUploadOption.h +++ /dev/null @@ -1,83 +0,0 @@ -// -// QNUploadOption.h -// QiniuSDK -// -// Created by bailong on 14/10/4. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import - -/** - * 上传进度回调函数 - * - * @param key 上传时指定的存储key - * @param percent 进度百分比 - */ -typedef void (^QNUpProgressHandler)(NSString *key, float percent); - -/** - * 上传中途取消函数 - * - * @return 如果想取消,返回True, 否则返回No - */ -typedef BOOL (^QNUpCancellationSignal)(void); - -/** - * 可选参数集合,此类初始化后sdk上传使用时 不会对此进行改变;如果参数没有变化以及没有使用依赖,可以重复使用。 - */ -@interface QNUploadOption : NSObject - -/** - * 用于服务器上传回调通知的自定义参数,参数的key必须以x: 开头 - */ -@property (copy, nonatomic, readonly) NSDictionary *params; - -/** - * 指定文件的mime类型 - */ -@property (copy, nonatomic, readonly) NSString *mimeType; - -/** - * 是否进行crc校验 - */ -@property (readonly) BOOL checkCrc; - -/** - * 进度回调函数 - */ -@property (copy, readonly) QNUpProgressHandler progressHandler; - -/** - * 中途取消函数 - */ -@property (copy, readonly) QNUpCancellationSignal cancellationSignal; - -/** - * 可选参数的初始化方法 - * - * @param mimeType mime类型 - * @param progress 进度函数 - * @param params 自定义服务器回调参数 - * @param check 是否进行crc检查 - * @param cancellation 中途取消函数 - * - * @return 可选参数类实例 - */ -- (instancetype)initWithMime:(NSString *)mimeType - progressHandler:(QNUpProgressHandler)progress - params:(NSDictionary *)params - checkCrc:(BOOL)check - cancellationSignal:(QNUpCancellationSignal)cancellation; - -- (instancetype)initWithProgessHandler:(QNUpProgressHandler)progress DEPRECATED_ATTRIBUTE; -- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress; - -/** - * 内部使用,默认的参数实例 - * - * @return 可选参数类实例 - */ -+ (instancetype)defaultOptions; - -@end diff --git a/msext/QiniuSDK/Storage/QNUploadOption.m b/msext/QiniuSDK/Storage/QNUploadOption.m deleted file mode 100755 index 95857c5..0000000 --- a/msext/QiniuSDK/Storage/QNUploadOption.m +++ /dev/null @@ -1,67 +0,0 @@ -// -// QNUploadOption.m -// QiniuSDK -// -// Created by bailong on 14/10/4. -// Copyright (c) 2014年 Qiniu. All rights reserved. -// - -#import "QNUploadOption+Private.h" -#import "QNUploadManager.h" - -static NSString *mime(NSString *mimeType) { - if (mimeType == nil || [mimeType isEqualToString:@""]) { - return @"application/octet-stream"; - } - return mimeType; -} - -@implementation QNUploadOption - -+ (NSDictionary *)filteParam:(NSDictionary *)params { - NSMutableDictionary *ret = [NSMutableDictionary dictionary]; - if (params == nil) { - return ret; - } - - [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { - if ([key hasPrefix:@"x:"] && ![obj isEqualToString:@""]) { - ret[key] = obj; - } - }]; - - return ret; -} - -- (instancetype)initWithProgessHandler:(QNUpProgressHandler)progress { - return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil]; -} - -- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress { - return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil]; -} - -- (instancetype)initWithMime:(NSString *)mimeType - progressHandler:(QNUpProgressHandler)progress - params:(NSDictionary *)params - checkCrc:(BOOL)check - cancellationSignal:(QNUpCancellationSignal)cancel { - if (self = [super init]) { - _mimeType = mime(mimeType); - _progressHandler = progress != nil ? progress : ^(NSString *key, float percent) { - }; - _params = [QNUploadOption filteParam:params]; - _checkCrc = check; - _cancellationSignal = cancel != nil ? cancel : ^BOOL() { - return NO; - }; - } - - return self; -} - -+ (instancetype)defaultOptions { - return [[QNUploadOption alloc] initWithMime:nil progressHandler:nil params:nil checkCrc:NO cancellationSignal:nil]; -} - -@end