QNCFHttpClient.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. //
  2. // QNCFHttpClient.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2021/10/11.
  6. // Copyright © 2021 Qiniu. All rights reserved.
  7. //
  8. #import "QNAsyncRun.h"
  9. #import "QNCFHttpClient.h"
  10. #import "QNCFHttpClientInner.h"
  11. #import "NSURLRequest+QNRequest.h"
  12. #import "QNUploadRequestMetrics.h"
  13. #import "QNCFHttpThreadPool.h"
  14. @interface QNCFHttpClient() <QNCFHttpClientInnerDelegate>
  15. @property(nonatomic, assign)BOOL hasCallBack;
  16. @property(nonatomic, assign)NSInteger redirectCount;
  17. @property(nonatomic, assign)NSInteger maxRedirectCount;
  18. @property(nonatomic, strong)NSURLRequest *request;
  19. @property(nonatomic, strong)NSURLResponse *response;
  20. @property(nonatomic, strong)NSDictionary *connectionProxy;
  21. @property(nonatomic, strong)QNUploadSingleRequestMetrics *requestMetrics;
  22. @property(nonatomic, strong)NSMutableData *responseData;
  23. @property(nonatomic, copy)void(^progress)(long long totalBytesWritten, long long totalBytesExpectedToWrite);
  24. @property(nonatomic, copy)QNRequestClientCompleteHandler complete;
  25. @property(nonatomic, strong)QNCFHttpClientInner *httpClient;
  26. @property(nonatomic, strong)QNCFHttpThread *thread;
  27. @end
  28. @implementation QNCFHttpClient
  29. - (NSString *)clientId {
  30. return @"CFNetwork";
  31. }
  32. - (instancetype)init {
  33. if (self = [super init]) {
  34. self.redirectCount = 0;
  35. self.maxRedirectCount = 15;
  36. self.hasCallBack = false;
  37. }
  38. return self;
  39. }
  40. - (void)request:(NSURLRequest *)request
  41. server:(id <QNUploadServer>)server
  42. connectionProxy:(NSDictionary *)connectionProxy
  43. progress:(void (^)(long long, long long))progress
  44. complete:(QNRequestClientCompleteHandler)complete {
  45. self.thread = [[QNCFHttpThreadPool shared] getOneThread];
  46. // 有 ip 才会使用
  47. if (server && server.ip.length > 0 && server.host.length > 0) {
  48. NSString *urlString = request.URL.absoluteString;
  49. urlString = [urlString stringByReplacingOccurrencesOfString:server.host withString:server.ip];
  50. NSMutableURLRequest *requestNew = [request mutableCopy];
  51. requestNew.URL = [NSURL URLWithString:urlString];
  52. requestNew.qn_domain = server.host;
  53. self.request = [requestNew copy];
  54. } else {
  55. self.request = request;
  56. }
  57. self.connectionProxy = connectionProxy;
  58. self.progress = progress;
  59. self.complete = complete;
  60. self.requestMetrics = [QNUploadSingleRequestMetrics emptyMetrics];
  61. self.requestMetrics.request = self.request;
  62. self.requestMetrics.remoteAddress = self.request.qn_ip;
  63. self.requestMetrics.remotePort = self.request.qn_isHttps ? @443 : @80;
  64. [self.requestMetrics start];
  65. self.responseData = [NSMutableData data];
  66. self.httpClient = [QNCFHttpClientInner client:self.request connectionProxy:connectionProxy];
  67. self.httpClient.delegate = self;
  68. [self.httpClient performSelector:@selector(main)
  69. onThread:self.thread
  70. withObject:nil
  71. waitUntilDone:NO];
  72. }
  73. - (void)cancel {
  74. if (self.thread) {
  75. return;
  76. }
  77. [self.httpClient performSelector:@selector(cancel)
  78. onThread:self.thread
  79. withObject:nil
  80. waitUntilDone:NO];
  81. }
  82. - (void)completeAction:(NSError *)error {
  83. @synchronized (self) {
  84. if (self.hasCallBack) {
  85. return;
  86. }
  87. self.hasCallBack = true;
  88. }
  89. self.requestMetrics.response = self.response;
  90. [self.requestMetrics end];
  91. if (self.complete) {
  92. self.complete(self.response, self.requestMetrics, self.responseData, error);
  93. }
  94. [[QNCFHttpThreadPool shared] subtractOperationCountOfThread:self.thread];
  95. }
  96. //MARK: -- delegate
  97. - (void)didSendBodyData:(int64_t)bytesSent
  98. totalBytesSent:(int64_t)totalBytesSent
  99. totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
  100. self.requestMetrics.countOfRequestBodyBytesSent = totalBytesSent;
  101. if (self.progress) {
  102. self.progress(totalBytesSent, totalBytesExpectedToSend);
  103. }
  104. }
  105. - (void)didFinish {
  106. self.requestMetrics.responseEndDate = [NSDate date];
  107. [self completeAction:nil];
  108. }
  109. - (void)didLoadData:(nonnull NSData *)data {
  110. [self.responseData appendData:data];
  111. }
  112. - (void)onError:(nonnull NSError *)error {
  113. [self completeAction:error];
  114. }
  115. - (void)onReceiveResponse:(NSURLResponse *)response httpVersion:(NSString *)httpVersion{
  116. self.requestMetrics.responseStartDate = [NSDate date];
  117. if ([httpVersion isEqualToString:@"http/1.0"]) {
  118. self.requestMetrics.httpVersion = @"1.0";
  119. } else if ([httpVersion isEqualToString:@"http/1.1"]) {
  120. self.requestMetrics.httpVersion = @"1.1";
  121. } else if ([httpVersion isEqualToString:@"h2"]) {
  122. self.requestMetrics.httpVersion = @"2";
  123. } else if ([httpVersion isEqualToString:@"h3"]) {
  124. self.requestMetrics.httpVersion = @"3";
  125. } else {
  126. self.requestMetrics.httpVersion = httpVersion;
  127. }
  128. self.response = response;
  129. }
  130. - (void)redirectedToRequest:(nonnull NSURLRequest *)request redirectResponse:(nonnull NSURLResponse *)redirectResponse {
  131. if (self.redirectCount < self.maxRedirectCount) {
  132. self.redirectCount += 1;
  133. [self request:request server:nil connectionProxy:self.connectionProxy progress:self.progress complete:self.complete];
  134. } else {
  135. [self didFinish];
  136. }
  137. }
  138. @end