QNCFHttpClientInner.m 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. //
  2. // QNHttpClient.m
  3. // AppTest
  4. //
  5. // Created by yangsen on 2020/4/7.
  6. // Copyright © 2020 com.qiniu. All rights reserved.
  7. //
  8. #import "QNErrorCode.h"
  9. #import "QNDefine.h"
  10. #import "QNCFHttpClientInner.h"
  11. #import "NSURLRequest+QNRequest.h"
  12. #import <sys/errno.h>
  13. #define kQNCFHttpClientErrorDomain @"CFNetwork"
  14. @interface QNCFHttpClientInner()<NSStreamDelegate>
  15. @property(nonatomic, assign)BOOL isCallFinishOrError;
  16. @property(nonatomic, assign)BOOL isCompleted;
  17. @property(nonatomic, strong)NSMutableURLRequest *request;
  18. @property(nonatomic, strong)NSDictionary *connectionProxy;
  19. @property(nonatomic, assign)BOOL isReadResponseHeader;
  20. @property(nonatomic, assign)BOOL isReadResponseBody;
  21. @property(nonatomic, assign)BOOL isInputStreamEvaluated;
  22. @property(nonatomic, strong)NSInputStream *inputStream;
  23. // 上传进度
  24. @property(nonatomic, strong)NSTimer *progressTimer; // 进度定时器
  25. @property(nonatomic, assign)int64_t totalBytesSent; // 已上传大小
  26. @property(nonatomic, assign)int64_t totalBytesExpectedToSend; // 总大小
  27. @end
  28. @implementation QNCFHttpClientInner
  29. + (instancetype)client:(NSURLRequest *)request connectionProxy:(nonnull NSDictionary *)connectionProxy{
  30. if (!request) {
  31. return nil;
  32. }
  33. QNCFHttpClientInner *client = [[QNCFHttpClientInner alloc] init];
  34. client.connectionProxy = connectionProxy;
  35. client.request = [request mutableCopy];
  36. client.isCompleted = false;
  37. return client;
  38. }
  39. - (void)main {
  40. [self prepare];
  41. [self openInputStream];
  42. [self startProgress];
  43. }
  44. - (void)prepare {
  45. @autoreleasepool {
  46. self.inputStream = [self createInputStream:self.request];
  47. }
  48. NSString *host = [self.request qn_domain];
  49. if ([self.request qn_isHttps]) {
  50. [self setInputStreamSNI:self.inputStream sni:host];
  51. }
  52. [self setupProgress];
  53. }
  54. - (void)releaseResource{
  55. [self endProgress:YES];
  56. [self closeInputStream];
  57. }
  58. - (void)cancel {
  59. [self releaseResource];
  60. [self delegate_onError:[self createError:NSURLErrorCancelled errorDescription:@"user cancel"]];
  61. }
  62. //MARK: -- request -> stream
  63. - (NSInputStream *)createInputStream:(NSURLRequest *)urlRequest{
  64. CFReadStreamRef readStream = NULL;
  65. @autoreleasepool {
  66. CFStringRef urlString = (__bridge CFStringRef) [urlRequest.URL absoluteString];
  67. CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault,
  68. urlString,
  69. NULL);
  70. CFStringRef httpMethod = (__bridge CFStringRef) urlRequest.HTTPMethod;
  71. CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
  72. httpMethod,
  73. url,
  74. kCFHTTPVersion1_1);
  75. CFRelease(url);
  76. NSDictionary *headFieldInfo = self.request.qn_allHTTPHeaderFields;
  77. for (NSString *headerField in headFieldInfo) {
  78. CFStringRef headerFieldP = (__bridge CFStringRef)headerField;
  79. CFStringRef headerFieldValueP = (__bridge CFStringRef)(headFieldInfo[headerField]);
  80. CFHTTPMessageSetHeaderFieldValue(request, headerFieldP, headerFieldValueP);
  81. }
  82. NSData *httpBody = [self.request qn_getHttpBody];
  83. if (httpBody) {
  84. CFDataRef bodyData = (__bridge CFDataRef) httpBody;
  85. CFHTTPMessageSetBody(request, bodyData);
  86. }
  87. readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
  88. CFRelease(request);
  89. }
  90. @autoreleasepool {
  91. if (self.connectionProxy) {
  92. for (NSString *key in self.connectionProxy.allKeys) {
  93. NSObject *value = self.connectionProxy[key];
  94. if (key.length > 0) {
  95. CFReadStreamSetProperty(readStream, (__bridge CFTypeRef _Null_unspecified)key, (__bridge CFTypeRef _Null_unspecified)(value));
  96. }
  97. }
  98. }
  99. }
  100. return (__bridge_transfer NSInputStream *) readStream;
  101. }
  102. - (void)setInputStreamSNI:(NSInputStream *)inputStream sni:(NSString *)sni{
  103. if (!sni || sni.length == 0) {
  104. return;
  105. }
  106. NSMutableDictionary *settings = [NSMutableDictionary dictionary];
  107. [settings setObject:NSStreamSocketSecurityLevelNegotiatedSSL
  108. forKey:NSStreamSocketSecurityLevelKey];
  109. [settings setObject:sni
  110. forKey:(NSString *)kCFStreamSSLPeerName];
  111. [inputStream setProperty:settings forKey:(NSString *)CFBridgingRelease(kCFStreamPropertySSLSettings)];
  112. }
  113. //MARK: -- stream action
  114. - (void)openInputStream{
  115. [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  116. self.inputStream.delegate = self;
  117. [self.inputStream open];
  118. }
  119. - (void)closeInputStream {
  120. @synchronized (self) {
  121. if (self.inputStream) {
  122. [self.inputStream close];
  123. [self.inputStream setDelegate:nil];
  124. [self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  125. self.inputStream = nil;
  126. }
  127. }
  128. }
  129. - (BOOL)shouldEvaluateInputStreamServerTrust{
  130. if (![self.request qn_isHttps] || self.isInputStreamEvaluated) {
  131. return NO;
  132. } else {
  133. return YES;
  134. }
  135. }
  136. - (void)inputStreamGetAndNotifyHttpResponse{
  137. @synchronized (self) {
  138. if (self.isReadResponseHeader) {
  139. return;
  140. }
  141. self.isReadResponseHeader = YES;
  142. }
  143. CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
  144. CFHTTPMessageRef httpMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
  145. CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(httpMessage);
  146. NSDictionary *headInfo = (__bridge_transfer NSDictionary *)headerFields;
  147. CFStringRef httpVersion = CFHTTPMessageCopyVersion(httpMessage);
  148. NSString *httpVersionInfo = (__bridge_transfer NSString *)httpVersion;
  149. CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(httpMessage);
  150. if (![self isHttpRedirectStatusCode:statusCode]) {
  151. NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:statusCode HTTPVersion:httpVersionInfo headerFields:headInfo];
  152. [self delegate_onReceiveResponse:response httpVersion:httpVersionInfo];
  153. }
  154. CFRelease(httpMessage);
  155. }
  156. - (void)inputStreamGetAndNotifyHttpData{
  157. @synchronized (self) {
  158. if (self.isReadResponseBody) {
  159. return;
  160. }
  161. self.isReadResponseBody = YES;
  162. }
  163. UInt8 buffer[16 * 1024];
  164. UInt8 *buf = NULL;
  165. NSUInteger length = 0;
  166. if (![self.inputStream getBuffer:&buf length:&length]) {
  167. NSInteger amount = [self.inputStream read:buffer maxLength:sizeof(buffer)];
  168. buf = buffer;
  169. length = amount;
  170. }
  171. NSData *data = [[NSData alloc] initWithBytes:buf length:length];
  172. [self delegate_didLoadData:data];
  173. }
  174. - (BOOL)isInputStreamHttpResponseHeaderComplete{
  175. CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
  176. CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
  177. BOOL isComplete = CFHTTPMessageIsHeaderComplete(responseMessage);
  178. CFRelease(responseMessage);
  179. return isComplete;
  180. }
  181. - (BOOL)shouldInputStreamRedirect{
  182. CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
  183. CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
  184. CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(responseMessage);
  185. CFRelease(responseMessage);
  186. return [self isHttpRedirectStatusCode:statusCode];
  187. }
  188. - (BOOL)isHttpRedirectStatusCode:(NSInteger)code{
  189. if (code == 301 || code == 302 || code == 303 || code == 307) {
  190. return YES;
  191. } else {
  192. return NO;
  193. }
  194. }
  195. - (void)inputStreamRedirect{
  196. CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
  197. CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
  198. CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(responseMessage);
  199. NSDictionary *headInfo = (__bridge_transfer NSDictionary *)headerFields;
  200. NSString *urlString = headInfo[@"Location"];
  201. if (!urlString) {
  202. urlString = headInfo[@"location"];
  203. }
  204. if (!urlString) {
  205. return;
  206. }
  207. CFStringRef httpVersion = CFHTTPMessageCopyVersion(responseMessage);
  208. NSString *httpVersionString = (__bridge_transfer NSString *)httpVersion;
  209. CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(responseMessage);
  210. NSDictionary *requestHeader = self.request.allHTTPHeaderFields;
  211. if (statusCode == 303) {
  212. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  213. if (requestHeader[@"User-Agent"]) {
  214. header[@"User-Agent"] = requestHeader[@"User-Agent"];
  215. }
  216. if (requestHeader[@"Accept"]) {
  217. header[@"Accept"] = requestHeader[@"Accept"];
  218. }
  219. requestHeader = [header copy];
  220. }
  221. NSURL *url = [NSURL URLWithString:urlString];
  222. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  223. request.HTTPMethod = @"GET";
  224. [request setAllHTTPHeaderFields:requestHeader];
  225. NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL
  226. statusCode:statusCode
  227. HTTPVersion:httpVersionString
  228. headerFields:headInfo];
  229. [self releaseResource];
  230. [self delegate_redirectedToRequest:request redirectResponse:response];
  231. CFRelease(responseMessage);
  232. }
  233. //MARK: -- NSStreamDelegate
  234. - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
  235. @autoreleasepool {
  236. switch (eventCode) {
  237. case NSStreamEventHasBytesAvailable:{
  238. if (![self isInputStreamHttpResponseHeaderComplete]) {
  239. break;
  240. }
  241. [self inputStreamGetAndNotifyHttpResponse];
  242. [self inputStreamGetAndNotifyHttpData];
  243. }
  244. break;
  245. case NSStreamEventHasSpaceAvailable:
  246. break;
  247. case NSStreamEventErrorOccurred:{
  248. [self releaseResource];
  249. [self endProgress: YES];
  250. [self delegate_onError:[self translateCFNetworkErrorIntoUrlError:[aStream streamError]]];
  251. }
  252. break;
  253. case NSStreamEventEndEncountered:{
  254. if ([self shouldInputStreamRedirect]) {
  255. [self inputStreamRedirect];
  256. } else {
  257. [self inputStreamGetAndNotifyHttpResponse];
  258. [self inputStreamGetAndNotifyHttpData];
  259. [self releaseResource];
  260. [self endProgress: NO];
  261. [self delegate_didFinish];
  262. }
  263. }
  264. break;
  265. default:
  266. break;
  267. }
  268. }
  269. }
  270. //MARK: -- progress and timer action
  271. - (void)setupProgress{
  272. self.totalBytesExpectedToSend = [self.request.qn_getHttpBody length];
  273. }
  274. - (void)startProgress{
  275. [self createTimer];
  276. }
  277. - (void)endProgress:(BOOL)hasError{
  278. [self invalidateTimer];
  279. if (!hasError) {
  280. [self delegate_didSendBodyData:self.totalBytesExpectedToSend - self.totalBytesSent
  281. totalBytesSent:self.totalBytesExpectedToSend
  282. totalBytesExpectedToSend:self.totalBytesExpectedToSend];
  283. }
  284. }
  285. - (void)createTimer{
  286. if (_progressTimer) {
  287. [self invalidateTimer];
  288. }
  289. kQNWeakSelf;
  290. NSTimer *timer = [NSTimer timerWithTimeInterval:0.3
  291. target:weak_self
  292. selector:@selector(timerAction)
  293. userInfo:nil
  294. repeats:YES];
  295. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  296. [self timerAction];
  297. _progressTimer = timer;
  298. }
  299. - (void)invalidateTimer{
  300. [self.progressTimer invalidate];
  301. self.progressTimer = nil;
  302. }
  303. - (void)timerAction{
  304. long long totalBytesSent = [(NSNumber *)CFBridgingRelease(CFReadStreamCopyProperty((CFReadStreamRef)[self inputStream], kCFStreamPropertyHTTPRequestBytesWrittenCount)) longLongValue];
  305. long long bytesSent = totalBytesSent - self.totalBytesSent;
  306. self.totalBytesSent = totalBytesSent;
  307. if (bytesSent > 0 && self.totalBytesSent <= self.totalBytesSent) {
  308. [self delegate_didSendBodyData:bytesSent
  309. totalBytesSent:self.totalBytesSent
  310. totalBytesExpectedToSend:self.totalBytesExpectedToSend];
  311. }
  312. }
  313. - (NSError *)translateCFNetworkErrorIntoUrlError:(NSError *)cfError{
  314. if (cfError == nil) {
  315. return nil;
  316. }
  317. NSInteger errorCode = kQNNetworkError;
  318. NSString *errorInfo = [NSString stringWithFormat:@"cf client:[%ld] %@", (long)cfError.code, cfError.localizedDescription];
  319. switch (cfError.code) {
  320. case ENOENT: /* No such file or directory */
  321. errorCode = NSFileNoSuchFileError;
  322. break;
  323. case EIO: /* Input/output error */
  324. errorCode = kQNLocalIOError;
  325. break;
  326. case E2BIG: /* Argument list too long */
  327. break;
  328. case ENOEXEC: /* Exec format error */
  329. errorCode = kQNLocalIOError;
  330. break;
  331. case EBADF: /* Bad file descriptor */
  332. errorCode = kQNLocalIOError;
  333. break;
  334. case ECHILD: /* No child processes */
  335. errorCode = kQNUnexpectedSysCallError;
  336. break;
  337. case EDEADLK: /* Resource deadlock avoided */
  338. errorCode = kQNUnexpectedSysCallError;
  339. break;
  340. case ENOMEM: /* Cannot allocate memory */
  341. errorCode = kQNUnexpectedSysCallError;
  342. break;
  343. case EACCES: /* Permission denied */
  344. errorCode = NSURLErrorNoPermissionsToReadFile;
  345. break;
  346. case EFAULT: /* Bad address */
  347. errorCode = NSURLErrorBadURL;
  348. break;
  349. case EBUSY: /* Device / Resource busy */
  350. errorCode = kQNUnexpectedSysCallError;
  351. break;
  352. case EEXIST: /* File exists */
  353. errorCode = kQNUnexpectedSysCallError;
  354. break;
  355. case ENODEV: /* Operation not supported by device */
  356. errorCode = kQNUnexpectedSysCallError;
  357. break;
  358. case EISDIR: /* Is a directory */
  359. errorCode = NSURLErrorFileIsDirectory;
  360. break;
  361. case ENOTDIR: /* Not a directory */
  362. errorCode = kQNUnexpectedSysCallError;
  363. break;
  364. case EINVAL: /* Invalid argument */
  365. errorCode = kQNUnexpectedSysCallError;
  366. break;
  367. case ENFILE: /* Too many open files in system */
  368. errorCode = kQNUnexpectedSysCallError;
  369. break;
  370. case EMFILE: /* Too many open files */
  371. errorCode = kQNUnexpectedSysCallError;
  372. break;
  373. case EFBIG: /* File too large */
  374. errorCode = kQNUnexpectedSysCallError;
  375. break;
  376. case ENOSPC: /* No space left on device */
  377. errorCode = kQNUnexpectedSysCallError;
  378. break;
  379. case ESPIPE: /* Illegal seek */
  380. errorCode = kQNUnexpectedSysCallError;
  381. break;
  382. case EMLINK: /* Too many links */
  383. errorCode = kQNUnexpectedSysCallError;
  384. break;
  385. case EPIPE: /* Broken pipe */
  386. errorCode = kQNUnexpectedSysCallError;
  387. break;
  388. case EDOM: /* Numerical argument out of domain */
  389. errorCode = kQNUnexpectedSysCallError;
  390. break;
  391. case ERANGE: /* Result too large */
  392. errorCode = kQNUnexpectedSysCallError;
  393. break;
  394. case EAGAIN: /* Resource temporarily unavailable */
  395. break;
  396. case ENOTSOCK: /* Socket operation on non-socket */
  397. break;
  398. case EDESTADDRREQ: /* Destination address required */
  399. errorCode = NSURLErrorBadURL;
  400. break;
  401. case EMSGSIZE: /* Message too long */
  402. break;
  403. case EPROTOTYPE: /* Protocol wrong type for socket */
  404. break;
  405. case ENOPROTOOPT: /* Protocol not available */
  406. break;
  407. case EPROTONOSUPPORT: /* Protocol not supported */
  408. break;
  409. case ENOTSUP: /* Operation not supported */
  410. break;
  411. case EPFNOSUPPORT: /* Protocol family not supported */
  412. break;
  413. case EAFNOSUPPORT: /* Address family not supported by protocol family */
  414. break;
  415. case EADDRINUSE: /* Address already in use */
  416. break;
  417. case EADDRNOTAVAIL: /* Can't assign requested address */
  418. break;
  419. case ENETDOWN: /* Network is down */
  420. errorCode = NSURLErrorCannotConnectToHost;
  421. break;
  422. case ENETUNREACH: /* Network is unreachable */
  423. errorCode = NSURLErrorNetworkConnectionLost;
  424. break;
  425. case ENETRESET: /* Network dropped connection on reset */
  426. errorCode = NSURLErrorNetworkConnectionLost;
  427. break;
  428. case ECONNABORTED: /* Software caused connection abort */
  429. errorCode = NSURLErrorNetworkConnectionLost;
  430. break;
  431. case ECONNRESET: /* Connection reset by peer */
  432. errorCode = NSURLErrorNetworkConnectionLost;
  433. break;
  434. case ENOBUFS: /* No buffer space available */
  435. errorCode = kQNUnexpectedSysCallError;
  436. break;
  437. case EISCONN: /* Socket is already connected */
  438. break;
  439. case ENOTCONN: /* Socket is not connected */
  440. errorCode = NSURLErrorCannotConnectToHost;
  441. break;
  442. case ESHUTDOWN: /* Can't send after socket shutdown */
  443. break;
  444. case ETOOMANYREFS: /* Too many references: can't splice */
  445. break;
  446. case ETIMEDOUT: /* Operation timed out */
  447. errorCode = NSURLErrorTimedOut;
  448. break;
  449. case ECONNREFUSED: /* Connection refused */
  450. errorCode = NSURLErrorCannotConnectToHost;
  451. break;
  452. case ELOOP: /* Too many levels of symbolic links */
  453. errorCode = kQNUnexpectedSysCallError;
  454. break;
  455. case ENAMETOOLONG: /* File name too long */
  456. break;
  457. case EHOSTDOWN: /* Host is down */
  458. break;
  459. case EHOSTUNREACH: /* No route to host */
  460. break;
  461. case ENOTEMPTY: /* Directory not empty */
  462. break;
  463. case EPROCLIM: /* Too many processes */
  464. errorCode = kQNUnexpectedSysCallError;
  465. break;
  466. case EUSERS: /* Too many users */
  467. errorCode = kQNUnexpectedSysCallError;
  468. break;
  469. case EDQUOT: /* Disc quota exceeded */
  470. errorCode = kQNUnexpectedSysCallError;
  471. break;
  472. case ESTALE: /* Stale NFS file handle */
  473. errorCode = kQNUnexpectedSysCallError;
  474. break;
  475. case EREMOTE: /* Too many levels of remote in path */
  476. break;
  477. case EBADRPC: /* RPC struct is bad */
  478. errorCode = kQNUnexpectedSysCallError;
  479. break;
  480. case ERPCMISMATCH: /* RPC version wrong */
  481. errorCode = kQNUnexpectedSysCallError;
  482. break;
  483. case EPROGUNAVAIL: /* RPC prog. not avail */
  484. errorCode = kQNUnexpectedSysCallError;
  485. break;
  486. case EPROGMISMATCH: /* Program version wrong */
  487. errorCode = kQNUnexpectedSysCallError;
  488. break;
  489. case EPROCUNAVAIL: /* Bad procedure for program */
  490. errorCode = kQNUnexpectedSysCallError;
  491. break;
  492. case ENOLCK: /* No locks available */
  493. errorCode = kQNUnexpectedSysCallError;
  494. break;
  495. case ENOSYS: /* Function not implemented */
  496. errorCode = kQNUnexpectedSysCallError;
  497. break;
  498. case EFTYPE: /* Inappropriate file type or format */
  499. break;
  500. case EAUTH: /* Authentication error */
  501. break;
  502. case ENEEDAUTH: /* Need authenticator */
  503. break;
  504. case EPWROFF: /* Device power is off */
  505. errorCode = kQNUnexpectedSysCallError;
  506. break;
  507. case EDEVERR: /* Device error, e.g. paper out */
  508. errorCode = kQNUnexpectedSysCallError;
  509. break;
  510. case EOVERFLOW: /* Value too large to be stored in data type */
  511. errorCode = kQNUnexpectedSysCallError;
  512. break;
  513. case EBADEXEC: /* Bad executable */
  514. errorCode = kQNUnexpectedSysCallError;
  515. break;
  516. case EBADARCH: /* Bad CPU type in executable */
  517. errorCode = kQNUnexpectedSysCallError;
  518. break;
  519. case ESHLIBVERS: /* Shared library version mismatch */
  520. errorCode = kQNUnexpectedSysCallError;
  521. break;
  522. case EBADMACHO: /* Malformed Macho file */
  523. errorCode = kQNUnexpectedSysCallError;
  524. break;
  525. case ECANCELED: /* Operation canceled */
  526. errorCode = NSURLErrorCancelled;
  527. break;
  528. case EIDRM: /* Identifier removed */
  529. break;
  530. case ENOMSG: /* No message of desired type */
  531. break;
  532. case EILSEQ: /* Illegal byte sequence */
  533. break;
  534. case ENOATTR: /* Attribute not found */
  535. break;
  536. case EBADMSG: /* Bad message */
  537. break;
  538. case EMULTIHOP: /* Reserved */
  539. break;
  540. case ENODATA: /* No message available on STREAM */
  541. break;
  542. case ENOLINK: /* Reserved */
  543. break;
  544. case ENOSR: /* No STREAM resources */
  545. break;
  546. case ENOSTR: /* Not a STREAM */
  547. break;
  548. case EPROTO: /* Protocol error */
  549. break;
  550. case ETIME: /* STREAM ioctl timeout */
  551. errorCode = NSURLErrorTimedOut;
  552. break;
  553. case EOPNOTSUPP: /* Operation not supported on socket */
  554. break;
  555. case ENOPOLICY: /* No such policy registered */
  556. break;
  557. case ENOTRECOVERABLE: /* State not recoverable */
  558. break;
  559. case EOWNERDEAD: /* Previous owner died */
  560. errorCode = kQNUnexpectedSysCallError;
  561. break;
  562. case EQFULL: /* Interface output queue is full */
  563. break;
  564. case -9800: /* SSL protocol error */
  565. errorCode = NSURLErrorSecureConnectionFailed;
  566. break;
  567. case -9801: /* Cipher Suite negotiation failure */
  568. errorCode = NSURLErrorSecureConnectionFailed;
  569. break;
  570. case -9802: /* Fatal alert */
  571. errorCode = kQNUnexpectedSysCallError;
  572. break;
  573. case -9803: /* I/O would block (not fatal) */
  574. errorCode = kQNUnexpectedSysCallError;
  575. break;
  576. case -9804: /* attempt to restore an unknown session */
  577. errorCode = kQNUnexpectedSysCallError;
  578. break;
  579. case -9805: /* connection closed gracefully */
  580. errorCode = NSURLErrorNetworkConnectionLost;
  581. break;
  582. case -9806: /* connection closed via error */
  583. errorCode = NSURLErrorNetworkConnectionLost;
  584. break;
  585. case -9807: /* invalid certificate chain */
  586. errorCode = NSURLErrorServerCertificateNotYetValid;
  587. break;
  588. case -9808: /* bad certificate format */
  589. errorCode = NSURLErrorServerCertificateNotYetValid;
  590. break;
  591. case -9809: /* underlying cryptographic error */
  592. errorCode = NSURLErrorSecureConnectionFailed;
  593. break;
  594. case -9810: /* Internal error */
  595. errorCode = NSURLErrorNotConnectedToInternet;
  596. break;
  597. case -9811: /* module attach failure */
  598. errorCode = kQNUnexpectedSysCallError;
  599. break;
  600. case -9812: /* valid cert chain, untrusted root */
  601. errorCode = NSURLErrorServerCertificateHasUnknownRoot;
  602. break;
  603. case -9813: /* cert chain not verified by root */
  604. errorCode = NSURLErrorServerCertificateHasUnknownRoot;
  605. break;
  606. case -9814: /* chain had an expired cert */
  607. errorCode = NSURLErrorServerCertificateHasBadDate;
  608. break;
  609. case -9815: /* chain had a cert not yet valid */
  610. errorCode = NSURLErrorServerCertificateNotYetValid;
  611. break;
  612. case -9816: /* server closed session with no notification */
  613. errorCode = NSURLErrorNetworkConnectionLost;
  614. break;
  615. case -9817: /* insufficient buffer provided */
  616. errorCode = NSURLErrorCannotDecodeRawData;
  617. break;
  618. case -9818: /* bad SSLCipherSuite */
  619. errorCode = NSURLErrorClientCertificateRejected;
  620. break;
  621. case -9819: /* unexpected message received */
  622. errorCode = NSURLErrorNotConnectedToInternet;
  623. break;
  624. case -9820: /* bad MAC */
  625. errorCode = NSURLErrorNotConnectedToInternet;
  626. break;
  627. case -9821: /* decryption failed */
  628. errorCode = NSURLErrorNotConnectedToInternet;
  629. break;
  630. case -9822: /* record overflow */
  631. errorCode = NSURLErrorDataLengthExceedsMaximum;
  632. break;
  633. case -9823: /* decompression failure */
  634. errorCode = NSURLErrorDownloadDecodingFailedMidStream;
  635. break;
  636. case -9824: /* handshake failure */
  637. errorCode = NSURLErrorClientCertificateRejected;
  638. break;
  639. case -9825: /* misc. bad certificate */
  640. errorCode = NSURLErrorServerCertificateNotYetValid;
  641. break;
  642. case -9826: /* bad unsupported cert format */
  643. errorCode = NSURLErrorServerCertificateNotYetValid;
  644. break;
  645. case -9827: /* certificate revoked */
  646. errorCode = NSURLErrorServerCertificateNotYetValid;
  647. break;
  648. case -9828: /* certificate expired */
  649. errorCode = NSURLErrorServerCertificateNotYetValid;
  650. break;
  651. case -9829: /* unknown certificate */
  652. errorCode = NSURLErrorServerCertificateNotYetValid;
  653. break;
  654. case -9830: /* illegal parameter */
  655. errorCode = NSURLErrorCannotDecodeRawData;
  656. break;
  657. case -9831: /* unknown Cert Authority */
  658. errorCode = NSURLErrorServerCertificateNotYetValid;
  659. break;
  660. case -9832: /* access denied */
  661. errorCode = NSURLErrorClientCertificateRejected;
  662. break;
  663. case -9833: /* decoding error */
  664. errorCode = NSURLErrorServerCertificateNotYetValid;
  665. break;
  666. case -9834: /* decryption error */
  667. errorCode = NSURLErrorCannotDecodeRawData;
  668. break;
  669. case -9835: /* export restriction */
  670. errorCode = NSURLErrorCannotConnectToHost;
  671. break;
  672. case -9836: /* bad protocol version */
  673. errorCode = NSURLErrorCannotConnectToHost;
  674. break;
  675. case -9837: /* insufficient security */
  676. errorCode = NSURLErrorClientCertificateRejected;
  677. break;
  678. case -9838: /* internal error */
  679. errorCode = NSURLErrorTimedOut;
  680. break;
  681. case -9839: /* user canceled */
  682. errorCode = NSURLErrorCancelled;
  683. break;
  684. case -9840: /* no renegotiation allowed */
  685. errorCode = NSURLErrorCannotConnectToHost;
  686. break;
  687. case -9841: /* peer cert is valid, or was ignored if verification disabled */
  688. errorCode = NSURLErrorServerCertificateNotYetValid;
  689. break;
  690. case -9842: /* server has requested a client cert */
  691. errorCode = NSURLErrorClientCertificateRejected;
  692. break;
  693. case -9843: /* peer host name mismatch */
  694. errorCode = NSURLErrorNotConnectedToInternet;
  695. break;
  696. case -9844: /* peer dropped connection before responding */
  697. errorCode = NSURLErrorNetworkConnectionLost;
  698. break;
  699. case -9845: /* decryption failure */
  700. errorCode = NSURLErrorCannotDecodeRawData;
  701. break;
  702. case -9846: /* bad MAC */
  703. errorCode = NSURLErrorNotConnectedToInternet;
  704. break;
  705. case -9847: /* record overflow */
  706. errorCode = NSURLErrorDataLengthExceedsMaximum;
  707. break;
  708. case -9848: /* configuration error */
  709. errorCode = kQNUnexpectedSysCallError;
  710. break;
  711. case -9849: /* unexpected (skipped) record in DTLS */
  712. errorCode = kQNUnexpectedSysCallError;
  713. break;
  714. case -9850: /* weak ephemeral dh key */
  715. errorCode = kQNUnexpectedSysCallError;
  716. break;
  717. case -9851: /* SNI */
  718. errorCode = NSURLErrorClientCertificateRejected;
  719. break;
  720. default:
  721. break;
  722. }
  723. return [NSError errorWithDomain:NSURLErrorDomain code:errorCode userInfo:@{@"UserInfo" : errorInfo ?: @""}];
  724. }
  725. //MARK: -- delegate action
  726. - (void)delegate_redirectedToRequest:(NSURLRequest *)request
  727. redirectResponse:(NSURLResponse *)redirectResponse{
  728. if ([self.delegate respondsToSelector:@selector(redirectedToRequest:redirectResponse:)]) {
  729. [self.delegate redirectedToRequest:request redirectResponse:redirectResponse];
  730. }
  731. }
  732. - (void)delegate_onError:(NSError *)error{
  733. @synchronized (self) {
  734. if (self.isCallFinishOrError) {
  735. return;
  736. }
  737. self.isCallFinishOrError = YES;
  738. }
  739. if ([self.delegate respondsToSelector:@selector(onError:)]) {
  740. [self.delegate onError:error];
  741. }
  742. }
  743. - (void)delegate_didSendBodyData:(int64_t)bytesSent
  744. totalBytesSent:(int64_t)totalBytesSent
  745. totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
  746. if ([self.delegate respondsToSelector:@selector(didSendBodyData:
  747. totalBytesSent:
  748. totalBytesExpectedToSend:)]) {
  749. [self.delegate didSendBodyData:bytesSent
  750. totalBytesSent:totalBytesSent
  751. totalBytesExpectedToSend:totalBytesExpectedToSend];
  752. }
  753. }
  754. - (void)delegate_onReceiveResponse:(NSURLResponse *)response httpVersion:(NSString *)httpVersion{
  755. if ([self.delegate respondsToSelector:@selector(onReceiveResponse:httpVersion:)]) {
  756. [self.delegate onReceiveResponse:response httpVersion:httpVersion];
  757. }
  758. }
  759. - (void)delegate_didLoadData:(NSData *)data{
  760. if ([self.delegate respondsToSelector:@selector(didLoadData:)]) {
  761. [self.delegate didLoadData:data];
  762. }
  763. }
  764. - (void)delegate_didFinish{
  765. @synchronized (self) {
  766. if (self.isCallFinishOrError) {
  767. return;
  768. }
  769. self.isCallFinishOrError = YES;
  770. }
  771. if ([self.delegate respondsToSelector:@selector(didFinish)]) {
  772. [self.delegate didFinish];
  773. }
  774. }
  775. // MARK: error
  776. - (NSError *)createError:(NSInteger)errorCode errorDescription:(NSString *)errorDescription {
  777. if (errorDescription) {
  778. return [NSError errorWithDomain:kQNCFHttpClientErrorDomain
  779. code:errorCode
  780. userInfo:@{@"userInfo":errorDescription}];
  781. } else {
  782. return [NSError errorWithDomain:kQNCFHttpClientErrorDomain
  783. code:NSURLErrorSecureConnectionFailed
  784. userInfo:nil];
  785. }
  786. }
  787. @end