QNSessionManager.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. //
  2. // QNHttpManager.m
  3. // QiniuSDK
  4. //
  5. // Created by bailong on 14/10/1.
  6. // Copyright (c) 2014年 Qiniu. All rights reserved.
  7. //
  8. #import "QNAsyncRun.h"
  9. #import "QNConfiguration.h"
  10. #import "QNSessionManager.h"
  11. #import "QNUserAgent.h"
  12. #import "QNResponseInfo.h"
  13. #import "NSURLRequest+QNRequest.h"
  14. #import "QNURLProtocol.h"
  15. #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)
  16. typedef void (^QNSessionComplete)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error);
  17. @interface QNSessionDelegateHandler : NSObject <NSURLSessionDataDelegate>
  18. @property (nonatomic, copy) QNInternalProgressBlock progressBlock;
  19. @property (nonatomic, copy) QNCancelBlock cancelBlock;
  20. @property (nonatomic, copy) QNSessionComplete completeBlock;
  21. @property (nonatomic, strong) NSData *responseData;
  22. @end
  23. @implementation QNSessionDelegateHandler
  24. #pragma mark - NSURLSessionDataDelegate
  25. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
  26. completionHandler(NSURLSessionResponseAllow);
  27. }
  28. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
  29. _responseData = data;
  30. }
  31. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
  32. didCompleteWithError:(nullable NSError *)error {
  33. // bytes_sent & bytes_total
  34. self.completeBlock(_responseData, task.response, error);
  35. [session finishTasksAndInvalidate];
  36. }
  37. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
  38. didSendBodyData:(int64_t)bytesSent
  39. totalBytesSent:(int64_t)totalBytesSent
  40. totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
  41. if (_progressBlock) {
  42. _progressBlock(totalBytesSent, totalBytesExpectedToSend);
  43. }
  44. if (_cancelBlock && _cancelBlock()) {
  45. [task cancel];
  46. }
  47. }
  48. - (uint64_t)getTimeintervalWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
  49. if (!startDate || !endDate) return 0;
  50. NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
  51. return interval * 1000;
  52. }
  53. @end
  54. @interface QNSessionManager ()
  55. @property UInt32 timeout;
  56. @property (nonatomic, strong) QNUrlConvert converter;
  57. @property (nonatomic, strong) NSDictionary *proxyDict;
  58. @property (nonatomic, strong) NSOperationQueue *delegateQueue;
  59. @property (nonatomic, strong) NSMutableArray *sessionArray;
  60. @property (nonatomic, strong) NSLock *lock;
  61. @end
  62. @implementation QNSessionManager
  63. - (instancetype)initWithProxy:(NSDictionary *)proxyDict
  64. timeout:(UInt32)timeout
  65. urlConverter:(QNUrlConvert)converter {
  66. if (self = [super init]) {
  67. _delegateQueue = [[NSOperationQueue alloc] init];
  68. _timeout = timeout;
  69. _converter = converter;
  70. _proxyDict = proxyDict;
  71. _sessionArray = [NSMutableArray array];
  72. [QNURLProtocol registerProtocol];
  73. _lock = [[NSLock alloc] init];
  74. }
  75. return self;
  76. }
  77. - (instancetype)init {
  78. return [self initWithProxy:nil timeout:60 urlConverter:nil];
  79. }
  80. - (void)sendRequest:(NSMutableURLRequest *)request
  81. withIdentifier:(NSString *)identifier
  82. withCompleteBlock:(QNCompleteBlock)completeBlock
  83. withProgressBlock:(QNInternalProgressBlock)progressBlock
  84. withCancelBlock:(QNCancelBlock)cancelBlock
  85. withAccess:(NSString *)access {
  86. NSString *domain = request.URL.host;
  87. NSString *u = request.URL.absoluteString;
  88. NSURL *url = request.URL;
  89. if (_converter != nil) {
  90. url = [[NSURL alloc] initWithString:_converter(u)];
  91. request.URL = url;
  92. domain = url.host;
  93. }
  94. request.qn_domain = request.URL.host;
  95. [request setTimeoutInterval:_timeout];
  96. [request setValue:[[QNUserAgent sharedInstance] getUserAgent:access] forHTTPHeaderField:@"User-Agent"];
  97. [request setValue:nil forHTTPHeaderField:@"Accept-Language"];
  98. QNSessionDelegateHandler *delegate = [[QNSessionDelegateHandler alloc] init];
  99. NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration qn_sessionConfiguration];
  100. configuration.connectionProxyDictionary = _proxyDict ? _proxyDict : nil;
  101. __block NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:_delegateQueue];
  102. [_sessionArray addObject:@{@"identifier":identifier,@"session":session}];
  103. delegate.cancelBlock = cancelBlock;
  104. delegate.progressBlock = progressBlock ? progressBlock : ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
  105. };
  106. delegate.completeBlock = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  107. [self finishSession:session];
  108. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
  109. QNResponseInfo *info = [[QNResponseInfo alloc] initWithResponseInfoHost:request.qn_domain response:httpResponse body:data error:error];
  110. completeBlock(info, info.responseDictionary);
  111. };
  112. NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request];
  113. [uploadTask resume];
  114. }
  115. - (void)multipartPost:(NSString *)url
  116. withData:(NSData *)data
  117. withParams:(NSDictionary *)params
  118. withFileName:(NSString *)key
  119. withMimeType:(NSString *)mime
  120. withIdentifier:(NSString *)identifier
  121. withCompleteBlock:(QNCompleteBlock)completeBlock
  122. withProgressBlock:(QNInternalProgressBlock)progressBlock
  123. withCancelBlock:(QNCancelBlock)cancelBlock
  124. withAccess:(NSString *)access {
  125. NSURL *URL = [[NSURL alloc] initWithString:url];
  126. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
  127. request.HTTPMethod = @"POST";
  128. NSString *boundary = @"werghnvt54wef654rjuhgb56trtg34tweuyrgf";
  129. request.allHTTPHeaderFields = @{
  130. @"Content-Type" : [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
  131. };
  132. NSMutableData *postData = [[NSMutableData alloc] init];
  133. for (NSString *paramsKey in params) {
  134. NSString *pair = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n", boundary, paramsKey];
  135. [postData appendData:[pair dataUsingEncoding:NSUTF8StringEncoding]];
  136. id value = [params objectForKey:paramsKey];
  137. if ([value isKindOfClass:[NSString class]]) {
  138. [postData appendData:[value dataUsingEncoding:NSUTF8StringEncoding]];
  139. } else if ([value isKindOfClass:[NSData class]]) {
  140. [postData appendData:value];
  141. }
  142. [postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  143. }
  144. NSString *filePair = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\nContent-Type:%@\r\n\r\n", boundary, @"file", key, mime];
  145. [postData appendData:[filePair dataUsingEncoding:NSUTF8StringEncoding]];
  146. [postData appendData:data];
  147. [postData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  148. request.HTTPBody = postData;
  149. [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)postData.length] forHTTPHeaderField:@"Content-Length"];
  150. [self sendRequest:request withIdentifier:identifier withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:cancelBlock
  151. withAccess:access];
  152. }
  153. - (void)post:(NSString *)url
  154. withData:(NSData *)data
  155. withParams:(NSDictionary *)params
  156. withHeaders:(NSDictionary *)headers
  157. withIdentifier:(NSString *)identifier
  158. withCompleteBlock:(QNCompleteBlock)completeBlock
  159. withProgressBlock:(QNInternalProgressBlock)progressBlock
  160. withCancelBlock:(QNCancelBlock)cancelBlock
  161. withAccess:(NSString *)access {
  162. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:url]];
  163. if (headers) {
  164. [request setAllHTTPHeaderFields:headers];
  165. }
  166. [request setHTTPMethod:@"POST"];
  167. if (params) {
  168. [request setValuesForKeysWithDictionary:params];
  169. }
  170. [request setHTTPBody:data];
  171. identifier = !identifier ? [[NSUUID UUID] UUIDString] : identifier;
  172. QNAsyncRun(^{
  173. [self sendRequest:request
  174. withIdentifier:identifier
  175. withCompleteBlock:completeBlock
  176. withProgressBlock:progressBlock
  177. withCancelBlock:cancelBlock
  178. withAccess:access];
  179. });
  180. }
  181. - (void)get:(NSString *)url
  182. withHeaders:(NSDictionary *)headers
  183. withCompleteBlock:(QNCompleteBlock)completeBlock {
  184. QNAsyncRun(^{
  185. NSURL *URL = [NSURL URLWithString:url];
  186. // NSString *domain = URL.host;
  187. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  188. request.qn_domain = URL.host;
  189. QNSessionDelegateHandler *delegate = [[QNSessionDelegateHandler alloc] init];
  190. NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration qn_sessionConfiguration];
  191. __block NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:self.delegateQueue];
  192. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
  193. delegate.cancelBlock = nil;
  194. delegate.progressBlock = nil;
  195. delegate.completeBlock = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  196. [self finishSession:session];
  197. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
  198. QNResponseInfo *info = [[QNResponseInfo alloc] initWithResponseInfoHost:request.qn_domain response:httpResponse body:data error:error];
  199. completeBlock(info, info.responseDictionary);
  200. };
  201. [dataTask resume];
  202. });
  203. }
  204. - (void)finishSession:(NSURLSession *)session {
  205. [_lock lock];
  206. for (int i = 0; i < _sessionArray.count; i++) {
  207. NSDictionary *sessionInfo = _sessionArray[i];
  208. if (sessionInfo[@"session"] == session) {
  209. [session finishTasksAndInvalidate];
  210. [_sessionArray removeObject:sessionInfo];
  211. break;
  212. }
  213. }
  214. [_lock unlock];
  215. }
  216. - (void)invalidateSessionWithIdentifier:(NSString *)identifier {
  217. [_lock lock];
  218. for (int i = 0; i < _sessionArray.count; i++) {
  219. NSDictionary *sessionInfo = _sessionArray[i];
  220. if ([sessionInfo[@"identifier"] isEqualToString:identifier]) {
  221. NSURLSession *session = sessionInfo[@"session"];
  222. [session invalidateAndCancel];
  223. [_sessionArray removeObject:sessionInfo];
  224. break;
  225. }
  226. }
  227. [_lock unlock];
  228. }
  229. @end
  230. #endif