From 60ed44da878e4e88918c95d31bc6d8e7a533db5c Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Mon, 26 Feb 2024 11:27:02 +0800 Subject: [PATCH 1/8] =?UTF-8?q?feat:=E8=B0=83=E6=95=B4wkwebview=E4=B8=AD?= =?UTF-8?q?=E7=9A=84NSURLProtocol=E6=8B=A6=E6=88=AA=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 396 ++++++++++++++++++------------ 1 file changed, 243 insertions(+), 153 deletions(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index 03755b7..7c2b1ac 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -31,14 +31,22 @@ @implementation MSDKDnsHttpMessageTools * @return 返回YES表示要拦截处理,返回NO表示不拦截处理 */ + (BOOL)canInitWithRequest:(NSURLRequest *)request { + NSLog(@"MSDKDnsHttpMessageTools"); + + if([[request.URL absoluteString] isEqual:@"about:blank"]) { + return NO; + } /* 防止无限循环,因为一个请求在被拦截处理过程中,也会发起一个请求,这样又会走到这里,如果不进行处理,就会造成无限循环 */ if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) { return NO; } NSString * url = request.URL.absoluteString; - NSString * domain = [request.allHTTPHeaderFields objectForKey:@"host"]; - + NSURL *URL = request.URL; +// NSString * domain = [request.allHTTPHeaderFields objectForKey:@"host"]; + NSString * originHost = [request.allHTTPHeaderFields objectForKey:@"host"]; + NSString * domain = request.URL.host; + NSArray * hijackDomainArray = [[[MSDKDnsParamsManager shareInstance] hijackDomainArray] copy]; NSArray * noHijackDomainArray = [[[MSDKDnsParamsManager shareInstance] noHijackDomainArray] copy]; @@ -56,7 +64,7 @@ + (BOOL)canInitWithRequest:(NSURLRequest *)request { } // 如果url以https开头,且不为httpdns服务器ip,则进行拦截处理,否则不处理 NSString *dnsIp = [[MSDKDnsManager shareInstance] currentDnsServer]; - if ([url hasPrefix:@"https"] && ![url containsString:dnsIp]) { + if (![url containsString:dnsIp]) { return YES; } return NO; @@ -76,18 +84,84 @@ - (void)startLoading { NSMutableURLRequest *request = [self.request mutableCopy]; // 表示该请求已经被处理,防止无限循环 [NSURLProtocol setProperty:@(YES) forKey:protocolKey inRequest:request]; - self.curRequest = request; + self.curRequest = [self applyHttpDnsIpDirectConnect:request]; [self startRequest]; } +- (NSString *)cookieForURL:(NSURL *)URL { + NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSMutableArray *cookieList = [NSMutableArray array]; + for (NSHTTPCookie *cookie in [cookieStorage cookies]) { + if (![self p_checkCookie:cookie URL:URL]) { + continue; + } + [cookieList addObject:cookie]; + } + + if (cookieList.count > 0) { + NSDictionary *cookieDic = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieList]; + if ([cookieDic objectForKey:@"Cookie"]) { + return cookieDic[@"Cookie"]; + } + } + return nil; +} + + +- (BOOL)p_checkCookie:(NSHTTPCookie *)cookie URL:(NSURL *)URL { + if (cookie.domain.length <= 0 || URL.host.length <= 0) { + return NO; + } + if ([URL.host containsString:cookie.domain]) { + return YES; + } + return NO; +} + +- (NSURLRequest*)applyHttpDnsIpDirectConnect:(NSURLRequest*)request { + NSURL* originUrl = request.URL; + NSString* originHost = originUrl.host; + NSString *cookie = [self cookieForURL:originUrl]; + NSURL* newUrl = [self getIpAndReplace:[originUrl absoluteString]]; + + NSMutableURLRequest* mutableRequest = [request copy]; + mutableRequest.URL = newUrl; + [mutableRequest setValue:originHost forHTTPHeaderField:@"Host"]; + [mutableRequest setValue:cookie forHTTPHeaderField:@"Cookie"]; + + return [mutableRequest copy]; +} + +- (NSURL*)getIpAndReplace:(NSString*)urlString { + NSURL* url = [NSURL URLWithString:urlString]; + NSString* originHost = url.host; + + NSTimeInterval start = [[NSDate date] timeIntervalSince1970]; + NSArray* result = [[MSDKDns sharedInstance] WGGetHostByName:url.host]; + NSString* ip = nil; + if (result && result.count > 1) { + if (![result[0] isEqualToString:@"0"]) { + ip = result[0]; + } else { + ip = result[1]; + } + } + // 通过HTTPDNS获取IP成功,进行URL替换和HOST头设置 + if (originHost.length > 0 && ip.length > 0) { + NSString* originUrlStringafterdispatch = [url absoluteString]; + NSRange hostRange = [originUrlStringafterdispatch rangeOfString:url.host]; + NSString* urlString = [originUrlStringafterdispatch stringByReplacingCharactersInRange:hostRange withString:ip]; + url = [NSURL URLWithString:urlString]; + } + return url; +} + /** * 取消请求 */ - (void)stopLoading { if (_inputStream.streamStatus == NSStreamStatusOpen) { - [_inputStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [_inputStream setDelegate:nil]; - [_inputStream close]; + [self closeStream:_inputStream]; } [self.client URLProtocol:self didFailWithError:[[NSError alloc] initWithDomain:@"stop loading" code:-1 userInfo:nil]]; } @@ -98,34 +172,40 @@ - (void)stopLoading { - (void)startRequest { // 原请求的header信息 NSDictionary *headFields = _curRequest.allHTTPHeaderFields; - // 添加http post请求所附带的数据 - CFStringRef requestBody = CFSTR(""); - CFDataRef bodyData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, requestBody, kCFStringEncodingUTF8, 0); - if (_curRequest.HTTPBody) { - bodyData = (__bridge_retained CFDataRef) _curRequest.HTTPBody; - } else if (headFields[@"originalBody"]) { - // 使用NSURLSession发POST请求时,将原始HTTPBody从header中取出 - bodyData = (__bridge_retained CFDataRef) [headFields[@"originalBody"] dataUsingEncoding:NSUTF8StringEncoding]; - } - CFStringRef url = (__bridge CFStringRef) [_curRequest.URL absoluteString]; CFURLRef requestURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL); - // 原请求所使用的方法,GET或POST CFStringRef requestMethod = (__bridge_retained CFStringRef) _curRequest.HTTPMethod; - // 根据请求的url、方法、版本创建CFHTTPMessageRef对象 CFHTTPMessageRef cfrequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, requestURL, kCFHTTPVersion1_1); - CFHTTPMessageSetBody(cfrequest, bodyData); + // 添加http post请求所附带的数据 + CFStringRef requestBody = CFSTR(""); + CFDataRef bodyData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, requestBody, kCFStringEncodingUTF8, 0); + if (_curRequest.HTTPBody) { + bodyData = (__bridge_retained CFDataRef) _curRequest.HTTPBody; + } else if(_curRequest.HTTPBodyStream) { + NSData *data = [self dataWithInputStream:_curRequest.HTTPBodyStream]; + CFDataRef body = (__bridge_retained CFDataRef) data; + CFHTTPMessageSetBody(cfrequest, body); + CFRelease(body); + } else { + CFHTTPMessageSetBody(cfrequest, bodyData); + } +// // copy原请求的header信息 +// for (NSString *header in headFields) { +// if (![header isEqualToString:@"originalBody"]) { +// // 不包含POST请求时存放在header的body信息 +// CFStringRef requestHeader = (__bridge CFStringRef) header; +// CFStringRef requestHeaderValue = (__bridge CFStringRef) [headFields valueForKey:header]; +// CFHTTPMessageSetHeaderFieldValue(cfrequest, requestHeader, requestHeaderValue); +// } +// } // copy原请求的header信息 - for (NSString *header in headFields) { - if (![header isEqualToString:@"originalBody"]) { - // 不包含POST请求时存放在header的body信息 - CFStringRef requestHeader = (__bridge CFStringRef) header; - CFStringRef requestHeaderValue = (__bridge CFStringRef) [headFields valueForKey:header]; - CFHTTPMessageSetHeaderFieldValue(cfrequest, requestHeader, requestHeaderValue); - } + for (NSString* header in headFields) { + CFStringRef requestHeader = (__bridge CFStringRef) header; + CFStringRef requestHeaderValue = (__bridge CFStringRef) [headFields valueForKey:header]; + CFHTTPMessageSetHeaderFieldValue(cfrequest, requestHeader, requestHeaderValue); } // 创建CFHTTPMessage对象的输入流 @@ -137,115 +217,50 @@ - (void)startRequest { if (!host) { host = _curRequest.URL.host; } + + NSLog(@"requestMethod = %@", requestMethod); + NSLog(@"requestURL = %@", requestURL); + NSLog(@"host = %@", host); + + // 可以选择使用SSL或者TLS1.2,目前CFNetwork不支持HTTP2.0. +// [_inputStream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel]; + [_inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey]; NSDictionary *sslProperties = [[NSDictionary alloc] initWithObjectsAndKeys: host, (__bridge id) kCFStreamSSLPeerName, nil]; [_inputStream setProperty:sslProperties forKey:(__bridge_transfer NSString *) kCFStreamPropertySSLSettings]; [_inputStream setDelegate:self]; - if (!_curRunLoop) + if (!_curRunLoop) { // 保存当前线程的runloop,这对于重定向的请求很关键 self.curRunLoop = [NSRunLoop currentRunLoop]; + } // 将请求放入当前runloop的事件队列 [_inputStream scheduleInRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; [_inputStream open]; - CFRelease(cfrequest); - CFRelease(requestURL); - // ARC模式下,需注释此句 - // CFRelease(url); - cfrequest = NULL; CFRelease(bodyData); - CFRelease(requestBody); - CFRelease(requestMethod); + CFRelease(requestURL); + CFRelease(cfrequest); } -/** - * 根据服务器返回的响应内容进行不同的处理 - */ -- (void)handleResponse { - // 获取响应头部信息 - CFReadStreamRef readStream = (__bridge_retained CFReadStreamRef) _inputStream; - CFHTTPMessageRef message = (CFHTTPMessageRef) CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); - if (CFHTTPMessageIsHeaderComplete(message)) { - // 确保response头部信息完整 - NSDictionary *headDict = (__bridge NSDictionary *) (CFHTTPMessageCopyAllHeaderFields(message)); - - // 获取响应头部的状态码 - CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(message); - - // 把当前请求关闭 - [_inputStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [_inputStream setDelegate:nil]; - [_inputStream close]; - - if (statusCode >= 200 && statusCode < 300) { - // 返回码为2xx,直接通知client - [self.client URLProtocolDidFinishLoading:self]; - } else if (statusCode >= 300 && statusCode < 400) { - // 返回码为3xx,需要重定向请求,继续访问重定向页面 - NSString *location = headDict[@"Location"]; - if (!location) { - location = headDict[@"location"]; - } - if (!location) { - // 直接返回响应信息给client - if (statusCode == 304) { - NSURL* url = (__bridge NSURL *) CFHTTPMessageCopyRequestURL(message); - NSString* httpVersion = (__bridge NSString *) CFHTTPMessageCopyVersion(message); - NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:statusCode - HTTPVersion:httpVersion headerFields:headDict]; - [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; - } - [self.client URLProtocolDidFinishLoading:self]; - return; - } - NSURL *url = [[NSURL alloc] initWithString:location]; - _curRequest.URL = url; - if ([[_curRequest.HTTPMethod lowercaseString] isEqualToString:@"post"]) { - // 根据RFC文档,当重定向请求为POST请求时,要将其转换为GET请求 - _curRequest.HTTPMethod = @"GET"; - _curRequest.HTTPBody = nil; - } - - /***********重定向通知client处理或内部处理*************/ - // client处理 - // NSURLResponse* response = [[NSURLResponse alloc] initWithURL:curRequest.URL MIMEType:headDict[@"Content-Type"] expectedContentLength:[headDict[@"Content-Length"] integerValue] textEncodingName:@"UTF8"]; - // [self.client URLProtocol:self wasRedirectedToRequest:curRequest redirectResponse:response]; - - // 内部处理,将url中的host通过HTTPDNS转换为IP,不能在startLoading线程中进行同步网络请求,会被阻塞 - __block NSArray* result; - [[MSDKDns sharedInstance] WGGetHostByNameAsync:url.host returnIps:^(NSArray *ipsArray) { - result = ipsArray; - }]; - NSString *ip = nil; - if (result && result.count > 1) { - if (![result[1] isEqualToString:@"0"]) { - ip = result[1]; - } else { - ip = result[0]; - } - } - if (ip && ip.length > 0 && ![ip isEqualToString:@"0"]) { - MSDKDNSLOG(@"Get IP from HTTPDNS Successfully!"); - NSRange hostFirstRange = [location rangeOfString:url.host]; - if (NSNotFound != hostFirstRange.location) { - NSString *urlString = [location stringByReplacingCharactersInRange:hostFirstRange withString:ip]; - _curRequest.URL = [NSURL URLWithString:urlString]; - [_curRequest setValue:url.host forHTTPHeaderField:@"host"]; - } - } - [self startRequest]; - } else { - // 其他情况,直接返回响应信息给client - [self.client URLProtocolDidFinishLoading:self]; - } - } else { - // 头部信息不完整,关闭inputstream,通知client - [_inputStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [_inputStream setDelegate:nil]; - [_inputStream close]; - [self.client URLProtocolDidFinishLoading:self]; +-(NSData*)dataWithInputStream:(NSInputStream*)stream { + NSMutableData *data = [NSMutableData data]; + [stream open]; + NSInteger result; + uint8_t buffer[1024]; + + while ((result = [stream read:buffer maxLength:1024]) != 0) { + if (result > 0) { + // buffer contains result bytes of data to be handled + [data appendBytes:buffer length:result]; + } else if (result < 0) { + // The stream had an error. You can get an NSError object using [iStream streamError] + data = nil; + break; } + } + [stream close]; + return data; } #pragma mark - NSStreamDelegate @@ -262,17 +277,23 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { UInt8 *buf = NULL; NSUInteger length = 0; NSInputStream *inputstream = (NSInputStream *) aStream; + CFDictionaryRef allheaderFields = CFHTTPMessageCopyAllHeaderFields(message); + NSDictionary *headDict = (__bridge NSDictionary *)allheaderFields; + CFRelease(allheaderFields); NSNumber *alreadyAdded = objc_getAssociatedObject(aStream, (__bridge const void *)(kAnchorAlreadyAdded)); if (!alreadyAdded || ![alreadyAdded boolValue]) { objc_setAssociatedObject(aStream, (__bridge const void *)(kAnchorAlreadyAdded), [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_COPY); // 通知client已收到response,只通知一次 - NSDictionary *headDict = (__bridge NSDictionary *) (CFHTTPMessageCopyAllHeaderFields(message)); + +// NSDictionary *headDict = (__bridge NSDictionary *) (CFHTTPMessageCopyAllHeaderFields(message)); CFStringRef httpVersion = CFHTTPMessageCopyVersion(message); // 获取响应头部的状态码 CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(message); + NSLog(@"response header, url is %@, code is %ld, headDict = %@", [_curRequest.URL absoluteString], (long)statusCode, [headDict objectForKey:@"Content-Type"]); NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:_curRequest.URL statusCode:statusCode HTTPVersion:(__bridge NSString *) httpVersion headerFields:headDict]; + [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; // 验证证书 @@ -290,39 +311,53 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { */ SecTrustSetPolicies(trust, (__bridge CFArrayRef) policies); if (SecTrustEvaluate(trust, &res) != errSecSuccess) { - [aStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [aStream setDelegate:nil]; - [aStream close]; + [self closeStream:aStream]; [self.client URLProtocol:self didFailWithError:[[NSError alloc] initWithDomain:@"can not evaluate the server trust" code:-1 userInfo:nil]]; + return; } if (res != kSecTrustResultProceed && res != kSecTrustResultUnspecified) { /* 证书验证不通过,关闭input stream */ - [aStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [aStream setDelegate:nil]; - [aStream close]; + [self closeStream:aStream]; [self.client URLProtocol:self didFailWithError:[[NSError alloc] initWithDomain:@"fail to evaluate the server trust" code:-1 userInfo:nil]]; - } else { - // 证书通过,返回数据 - if (![inputstream getBuffer:&buf length:&length]) { - NSInteger amount = [inputstream read:buffer maxLength:sizeof(buffer)]; - buf = buffer; - length = amount; - } - if ((NSInteger)length >= 0) { - NSData *data = [[NSData alloc] initWithBytes:buf length:length]; - [self.client URLProtocol:self didLoadData:data]; + // 证书校验通过 + if (statusCode >= 300 && statusCode < 400) { + // 处理重定向错误码 + [self closeStream:aStream]; + [self handleRedirect:message]; } else { - NSError *error = inputstream.streamError; - if (!error) { - error = [[NSError alloc] initWithDomain:@"inputstream length is invalid" - code:-2 - userInfo:nil]; + // 返回成功收到的数据 + if (![inputstream getBuffer:&buf length:&length]) { + NSInteger amount = [inputstream read:buffer maxLength:sizeof(buffer)]; + buf = buffer; + length = amount; + } + if ((NSInteger)length >= 0) { + NSData *data = [[NSData alloc] initWithBytes:buf length:length]; + if([[headDict objectForKey:@"Content-Type"] isEqualToString:@"text/css"]){ + NSLog(@"处理css文件内容"); + // 处理CSS文件内容,修改相对路径 + NSString *cssString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + // 这里需要写一个函数来解析CSS文件内容,并转换所有的相对路径为绝对路径 + cssString = [self convertRelativePathsInCSS:cssString]; + NSData *newData = [cssString dataUsingEncoding:NSUTF8StringEncoding]; + [self.client URLProtocol:self didLoadData:data]; + }else{ + [self.client URLProtocol:self didLoadData:data]; + } + + } else { + NSError *error = inputstream.streamError; + if (!error) { + error = [[NSError alloc] initWithDomain:@"inputstream length is invalid" + code:-2 + userInfo:nil]; + } + [aStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; + [aStream setDelegate:nil]; + [aStream close]; + [self.client URLProtocol:self didFailWithError:error]; } - [aStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [aStream setDelegate:nil]; - [aStream close]; - [self.client URLProtocol:self didFailWithError:error]; } } } else { @@ -334,7 +369,18 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { } if ((NSInteger)length >= 0) { NSData *data = [[NSData alloc] initWithBytes:buf length:length]; - [self.client URLProtocol:self didLoadData:data]; + if([[headDict objectForKey:@"Content-Type"] isEqualToString:@"text/css"]){ + NSLog(@"处理css文件内容"); + // 处理CSS文件内容,修改相对路径 + NSString *cssString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + // 这里需要写一个函数来解析CSS文件内容,并转换所有的相对路径为绝对路径 + cssString = [self convertRelativePathsInCSS:cssString]; + NSData *newData = [cssString dataUsingEncoding:NSUTF8StringEncoding]; + [self.client URLProtocol:self didLoadData:data]; + }else{ + [self.client URLProtocol:self didLoadData:data]; + } + } else { NSError *error = inputstream.streamError; if (!error) { @@ -348,16 +394,60 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { [self.client URLProtocol:self didFailWithError:error]; } } + CFRelease((CFReadStreamRef)inputstream); + CFRelease(message); } } else if (eventCode == NSStreamEventErrorOccurred) { - [aStream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; - [aStream setDelegate:nil]; - [aStream close]; + [self closeStream:aStream]; // 通知client发生错误了 - [self.client URLProtocol:self didFailWithError:[aStream streamError]]; +// [self.client URLProtocol:self didFailWithError:[aStream streamError]]; + [self.client URLProtocol:self didFailWithError: + [[NSError alloc] initWithDomain:@"NSStreamEventErrorOccurred" code:-1 userInfo:nil]]; } else if (eventCode == NSStreamEventEndEncountered) { - [self handleResponse]; + [self closeStream:_inputStream]; + [self.client URLProtocolDidFinishLoading:self]; +// [self handleResponse]; + } +} + +- (NSString *)convertRelativePathsInCSS:(NSString *)cssContent { + // 使用适当的正则表达式找到相对路径并替换为绝对路径 + // 以下代码仅作为示例: + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"url\\([']?(?:\\.\\./)*([^')]+)[']?\\)" options:NSRegularExpressionCaseInsensitive error:nil]; + NSString *modifiedCSS = [regex stringByReplacingMatchesInString:cssContent options:0 range:NSMakeRange(0, cssContent.length) withTemplate:@"url(https://actcdn.eebbk.com/parent_manage/$1)"]; + return modifiedCSS; +} + +- (void)closeStream:(NSStream*)stream { + [stream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; + [stream setDelegate:nil]; + [stream close]; +} + +- (void)handleRedirect:(CFHTTPMessageRef)messageRef { + // 响应头 + CFDictionaryRef headerFieldsRef = CFHTTPMessageCopyAllHeaderFields(messageRef); + NSDictionary *headDict = (__bridge_transfer NSDictionary *)headerFieldsRef; + [self redirect:headDict]; +} + +- (void)redirect:(NSDictionary *)headDict { + // 重定向时如果有cookie需求的话,注意处理 + NSString *location = headDict[@"Location"]; + if (!location) + location = headDict[@"location"]; + NSURL *url = [[NSURL alloc] initWithString:location]; + NSLog(@"location = %@", location); + _curRequest.URL = url; + if ([[_curRequest.HTTPMethod lowercaseString] isEqualToString:@"post"]) { + // 根据RFC文档,当重定向请求为POST请求时,要将其转换为GET请求 + _curRequest.HTTPMethod = @"GET"; + _curRequest.HTTPBody = nil; } + + _curRequest.URL = [self getIpAndReplace:[url absoluteString]]; + [_curRequest setValue:url.host forHTTPHeaderField:@"host"]; + [self startRequest]; } @end From bee3ff16cfbcf65da28a3d05c9ca495282bb9631 Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Mon, 4 Mar 2024 17:46:13 +0800 Subject: [PATCH 2/8] =?UTF-8?q?feat:=E4=BC=98=E5=8C=96=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 60 +++++-------------------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index 7c2b1ac..31a4ec7 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -31,7 +31,6 @@ @implementation MSDKDnsHttpMessageTools * @return 返回YES表示要拦截处理,返回NO表示不拦截处理 */ + (BOOL)canInitWithRequest:(NSURLRequest *)request { - NSLog(@"MSDKDnsHttpMessageTools"); if([[request.URL absoluteString] isEqual:@"about:blank"]) { return NO; @@ -43,7 +42,6 @@ + (BOOL)canInitWithRequest:(NSURLRequest *)request { } NSString * url = request.URL.absoluteString; NSURL *URL = request.URL; -// NSString * domain = [request.allHTTPHeaderFields objectForKey:@"host"]; NSString * originHost = [request.allHTTPHeaderFields objectForKey:@"host"]; NSString * domain = request.URL.host; @@ -192,15 +190,6 @@ - (void)startRequest { CFHTTPMessageSetBody(cfrequest, bodyData); } -// // copy原请求的header信息 -// for (NSString *header in headFields) { -// if (![header isEqualToString:@"originalBody"]) { -// // 不包含POST请求时存放在header的body信息 -// CFStringRef requestHeader = (__bridge CFStringRef) header; -// CFStringRef requestHeaderValue = (__bridge CFStringRef) [headFields valueForKey:header]; -// CFHTTPMessageSetHeaderFieldValue(cfrequest, requestHeader, requestHeaderValue); -// } -// } // copy原请求的header信息 for (NSString* header in headFields) { CFStringRef requestHeader = (__bridge CFStringRef) header; @@ -238,9 +227,12 @@ - (void)startRequest { [_inputStream scheduleInRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; [_inputStream open]; - CFRelease(bodyData); - CFRelease(requestURL); CFRelease(cfrequest); + CFRelease(requestURL); + cfrequest = NULL; + CFRelease(bodyData); + CFRelease(requestBody); + CFRelease(requestMethod); } -(NSData*)dataWithInputStream:(NSInputStream*)stream { @@ -277,19 +269,15 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { UInt8 *buf = NULL; NSUInteger length = 0; NSInputStream *inputstream = (NSInputStream *) aStream; - CFDictionaryRef allheaderFields = CFHTTPMessageCopyAllHeaderFields(message); - NSDictionary *headDict = (__bridge NSDictionary *)allheaderFields; - CFRelease(allheaderFields); NSNumber *alreadyAdded = objc_getAssociatedObject(aStream, (__bridge const void *)(kAnchorAlreadyAdded)); if (!alreadyAdded || ![alreadyAdded boolValue]) { objc_setAssociatedObject(aStream, (__bridge const void *)(kAnchorAlreadyAdded), [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_COPY); // 通知client已收到response,只通知一次 -// NSDictionary *headDict = (__bridge NSDictionary *) (CFHTTPMessageCopyAllHeaderFields(message)); + NSDictionary *headDict = (__bridge NSDictionary *) (CFHTTPMessageCopyAllHeaderFields(message)); CFStringRef httpVersion = CFHTTPMessageCopyVersion(message); // 获取响应头部的状态码 CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(message); - NSLog(@"response header, url is %@, code is %ld, headDict = %@", [_curRequest.URL absoluteString], (long)statusCode, [headDict objectForKey:@"Content-Type"]); NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:_curRequest.URL statusCode:statusCode HTTPVersion:(__bridge NSString *) httpVersion headerFields:headDict]; @@ -334,18 +322,7 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { } if ((NSInteger)length >= 0) { NSData *data = [[NSData alloc] initWithBytes:buf length:length]; - if([[headDict objectForKey:@"Content-Type"] isEqualToString:@"text/css"]){ - NSLog(@"处理css文件内容"); - // 处理CSS文件内容,修改相对路径 - NSString *cssString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - // 这里需要写一个函数来解析CSS文件内容,并转换所有的相对路径为绝对路径 - cssString = [self convertRelativePathsInCSS:cssString]; - NSData *newData = [cssString dataUsingEncoding:NSUTF8StringEncoding]; - [self.client URLProtocol:self didLoadData:data]; - }else{ - [self.client URLProtocol:self didLoadData:data]; - } - + [self.client URLProtocol:self didLoadData:data]; } else { NSError *error = inputstream.streamError; if (!error) { @@ -369,18 +346,7 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { } if ((NSInteger)length >= 0) { NSData *data = [[NSData alloc] initWithBytes:buf length:length]; - if([[headDict objectForKey:@"Content-Type"] isEqualToString:@"text/css"]){ - NSLog(@"处理css文件内容"); - // 处理CSS文件内容,修改相对路径 - NSString *cssString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - // 这里需要写一个函数来解析CSS文件内容,并转换所有的相对路径为绝对路径 - cssString = [self convertRelativePathsInCSS:cssString]; - NSData *newData = [cssString dataUsingEncoding:NSUTF8StringEncoding]; - [self.client URLProtocol:self didLoadData:data]; - }else{ - [self.client URLProtocol:self didLoadData:data]; - } - + [self.client URLProtocol:self didLoadData:data]; } else { NSError *error = inputstream.streamError; if (!error) { @@ -400,24 +366,14 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { } else if (eventCode == NSStreamEventErrorOccurred) { [self closeStream:aStream]; // 通知client发生错误了 -// [self.client URLProtocol:self didFailWithError:[aStream streamError]]; [self.client URLProtocol:self didFailWithError: [[NSError alloc] initWithDomain:@"NSStreamEventErrorOccurred" code:-1 userInfo:nil]]; } else if (eventCode == NSStreamEventEndEncountered) { [self closeStream:_inputStream]; [self.client URLProtocolDidFinishLoading:self]; -// [self handleResponse]; } } -- (NSString *)convertRelativePathsInCSS:(NSString *)cssContent { - // 使用适当的正则表达式找到相对路径并替换为绝对路径 - // 以下代码仅作为示例: - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"url\\([']?(?:\\.\\./)*([^')]+)[']?\\)" options:NSRegularExpressionCaseInsensitive error:nil]; - NSString *modifiedCSS = [regex stringByReplacingMatchesInString:cssContent options:0 range:NSMakeRange(0, cssContent.length) withTemplate:@"url(https://actcdn.eebbk.com/parent_manage/$1)"]; - return modifiedCSS; -} - - (void)closeStream:(NSStream*)stream { [stream removeFromRunLoop:_curRunLoop forMode:NSRunLoopCommonModes]; [stream setDelegate:nil]; From 46139fe7475f6777c853ed27087112650751447e Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Mon, 4 Mar 2024 19:48:20 +0800 Subject: [PATCH 3/8] =?UTF-8?q?feat:=E9=80=BB=E8=BE=91=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E5=8E=BB=E9=99=A4=E5=88=A4=E6=96=ADip=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index 31a4ec7..f7f4894 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -60,11 +60,6 @@ + (BOOL)canInitWithRequest:(NSURLRequest *)request { return NO; } } - // 如果url以https开头,且不为httpdns服务器ip,则进行拦截处理,否则不处理 - NSString *dnsIp = [[MSDKDnsManager shareInstance] currentDnsServer]; - if (![url containsString:dnsIp]) { - return YES; - } return NO; } From d5505b27b44d22501db7e2dd9276d47d42448017 Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Fri, 8 Mar 2024 14:54:05 +0800 Subject: [PATCH 4/8] =?UTF-8?q?feat:=E4=B8=8D=E6=8B=A6=E6=88=AA=E8=87=AA?= =?UTF-8?q?=E8=BA=AB=E6=9C=8D=E5=8A=A1=E5=99=A8IP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index f7f4894..512f827 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -60,7 +60,12 @@ + (BOOL)canInitWithRequest:(NSURLRequest *)request { return NO; } } - return NO; + // 如果为httpdns服务器ip,则不拦截处理 + NSString *dnsIp = [[MSDKDnsManager shareInstance] currentDnsServer]; + if ([url containsString:dnsIp]) { + return NO; + } + return YES; } /** @@ -143,7 +148,7 @@ - (NSURL*)getIpAndReplace:(NSString*)urlString { if (originHost.length > 0 && ip.length > 0) { NSString* originUrlStringafterdispatch = [url absoluteString]; NSRange hostRange = [originUrlStringafterdispatch rangeOfString:url.host]; - NSString* urlString = [originUrlStringafterdispatch stringByReplacingCharactersInRange:hostRange withString:ip]; + NSString* urlString = [originUrlStringafterdispatch stringByReplacingCharactersInRange:hostRange withString:@"1.194.250.190"]; url = [NSURL URLWithString:urlString]; } return url; From 438cc1130a0bbfcf6cdb8897d079b03737601df3 Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Thu, 14 Mar 2024 10:51:24 +0800 Subject: [PATCH 5/8] =?UTF-8?q?feat:=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index 512f827..ce8b656 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -148,7 +148,7 @@ - (NSURL*)getIpAndReplace:(NSString*)urlString { if (originHost.length > 0 && ip.length > 0) { NSString* originUrlStringafterdispatch = [url absoluteString]; NSRange hostRange = [originUrlStringafterdispatch rangeOfString:url.host]; - NSString* urlString = [originUrlStringafterdispatch stringByReplacingCharactersInRange:hostRange withString:@"1.194.250.190"]; + NSString* urlString = [originUrlStringafterdispatch stringByReplacingCharactersInRange:hostRange withString:ip]; url = [NSURL URLWithString:urlString]; } return url; From 7c49dab01b3621536d3791df42d8e67c1a5fb045 Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Thu, 14 Mar 2024 15:23:35 +0800 Subject: [PATCH 6/8] =?UTF-8?q?feat:=E5=8E=BB=E9=99=A4=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index ce8b656..f55e1d1 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -206,14 +206,7 @@ - (void)startRequest { if (!host) { host = _curRequest.URL.host; } - - NSLog(@"requestMethod = %@", requestMethod); - NSLog(@"requestURL = %@", requestURL); - NSLog(@"host = %@", host); - - // 可以选择使用SSL或者TLS1.2,目前CFNetwork不支持HTTP2.0. -// [_inputStream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel]; - + [_inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey]; NSDictionary *sslProperties = [[NSDictionary alloc] initWithObjectsAndKeys: host, (__bridge id) kCFStreamSSLPeerName, nil]; [_inputStream setProperty:sslProperties forKey:(__bridge_transfer NSString *) kCFStreamPropertySSLSettings]; @@ -393,7 +386,6 @@ - (void)redirect:(NSDictionary *)headDict { if (!location) location = headDict[@"location"]; NSURL *url = [[NSURL alloc] initWithString:location]; - NSLog(@"location = %@", location); _curRequest.URL = url; if ([[_curRequest.HTTPMethod lowercaseString] isEqualToString:@"post"]) { // 根据RFC文档,当重定向请求为POST请求时,要将其转换为GET请求 From c65197907842e09b68a38a73466574a1d2a6585c Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Fri, 15 Mar 2024 17:57:22 +0800 Subject: [PATCH 7/8] =?UTF-8?q?feat:=E9=92=88=E5=AF=B9ip=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E4=B8=8D=E5=81=9A=E6=8B=A6=E6=88=AA=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns/MSDKDnsHttpMessageTools.m | 43 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/MSDKDns/MSDKDnsHttpMessageTools.m b/MSDKDns/MSDKDnsHttpMessageTools.m index f55e1d1..168ac29 100644 --- a/MSDKDns/MSDKDnsHttpMessageTools.m +++ b/MSDKDns/MSDKDnsHttpMessageTools.m @@ -7,6 +7,7 @@ #import "MSDKDnsLog.h" #import "MSDKDnsParamsManager.h" #import "MSDKDnsManager.h" +#import #import #import "MSDKDns.h" @@ -60,14 +61,50 @@ + (BOOL)canInitWithRequest:(NSURLRequest *)request { return NO; } } - // 如果为httpdns服务器ip,则不拦截处理 - NSString *dnsIp = [[MSDKDnsManager shareInstance] currentDnsServer]; - if ([url containsString:dnsIp]) { + // 如果为ip,则不拦截处理 + if ([self isIPV4:domain]){ + return NO; + } + if ([self isIPV6:domain]){ return NO; } return YES; } ++ (BOOL)isIPV4:(NSString *)ipSting { + BOOL isIPV4 = YES; + + if (ipSting) { + const char *utf8 = [ipSting UTF8String]; + int success = 0; + struct in_addr dst; + success = inet_pton(AF_INET, utf8, &dst); + if (success != 1) { + isIPV4 = NO; + } + } else { + isIPV4 = NO; + } + return isIPV4; +} + ++ (BOOL)isIPV6:(NSString *)ipSting { + BOOL isIPV6 = YES; + + if (ipSting) { + const char *utf8 = [ipSting UTF8String]; + int success = 0; + struct in6_addr dst6; + success = inet_pton(AF_INET6, utf8, &dst6); + if (success != 1) { + isIPV6 = NO; + } + } else { + isIPV6 = NO; + } + return isIPV6; +} + /** * 如果需要对请求进行重定向,添加指定头部等操作,可以在该方法中进行 */ From dd9d61880ad85aec86c2d7b20ce7f3f9e2af977b Mon Sep 17 00:00:00 2001 From: erichuyuehu Date: Mon, 18 Mar 2024 15:18:04 +0800 Subject: [PATCH 8/8] =?UTF-8?q?feat:=E6=9B=B4=E6=96=B01.10.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSDKDns.xcodeproj/project.pbxproj | 16 ++++++++-------- MSDKDns/MSDKDns.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/MSDKDns.xcodeproj/project.pbxproj b/MSDKDns.xcodeproj/project.pbxproj index ead27de..189eac8 100644 --- a/MSDKDns.xcodeproj/project.pbxproj +++ b/MSDKDns.xcodeproj/project.pbxproj @@ -1047,7 +1047,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( @@ -1094,7 +1094,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( "-ObjC", @@ -1137,7 +1137,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( @@ -1179,7 +1179,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( "-ObjC", @@ -1228,7 +1228,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( @@ -1276,7 +1276,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( "-ObjC", @@ -1314,7 +1314,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( @@ -1354,7 +1354,7 @@ LINK_WITH_STANDARD_LIBRARIES = NO; MACH_O_TYPE = mh_object; MACOSX_DEPLOYMENT_TARGET = ""; - MARKETING_VERSION = 1.10.1; + MARKETING_VERSION = 1.10.2; OTHER_CFLAGS = "-fembed-bitcode"; OTHER_LDFLAGS = ( "-ObjC", diff --git a/MSDKDns/MSDKDns.h b/MSDKDns/MSDKDns.h index 4a8147f..19feb7a 100644 --- a/MSDKDns/MSDKDns.h +++ b/MSDKDns/MSDKDns.h @@ -5,7 +5,7 @@ #ifndef __MSDKDns_H__ #define __MSDKDns_H__ -#define MSDKDns_Version @"1.10.1" +#define MSDKDns_Version @"1.10.2" #import