In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-09 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)05/31 Report--
What is the solution to the problem of body loss when NSURLProtocol intercepts NSURLSession requests? aiming at this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
The main purpose of "IP direct connection solution" is to solve DNS pollution and save DNS parsing time. Usually, we can use NSURLProtocol to intercept NSURLSession requests in a project. Here is a challenge in supporting Post requests and an introduction to how to deal with them.
The "IP direct connection solution" is mainly to solve DNS pollution and save DNS parsing time. Usually, we can use NSURLProtocol to intercept NSURLSession requests in a project. Here is a challenge in supporting Post requests, as well as an introduction to the countermeasures:
The problem of missing body will be encountered in the process of supporting POST requests, and there are several solutions:
The plan is as follows:
Swap with NSURLConnection
Put body into Header
Use HTTPBodyStream to get body and assign it to body
Switch to Get requests instead of using Post requests.
Make the following analysis of the scheme
Switch to NSURLConnection. Compared with NSURLSession, NSURLConnection will encounter more performance problems, at the same time, some new features of Apple can not be used, will eventually be eliminated, do not consider.
For the method of putting header in body, there is no problem if it is less than 2m. If it exceeds 2m, it will cause request delay. If it exceeds 10m, it will directly Request timeout. And can not solve the problem that Body is binary data, because Header is full of text data.
Switch to Get requests instead of using Post requests. This is also feasible, but after all, there are restrictions on the way the request is made, and the problem with the Post request has to be solved after all. If the changes are based on the old project, it will be too intrusive. This scheme is suitable for the new project.
Another method we will mainly talk about below is to use HTTPBodyStream to obtain body and assign it to body. The specific code is as follows, which can solve the problems mentioned above:
/ NSURLRequest+CYLNSURLProtocolExtension.h/ Created by ElonChan on 28/07/2017.// Copyright ©2017 ChenYilong. All rights reserved.//#import @ interface NSURLRequest (CYLNSURLProtocolExtension)-(NSURLRequest *) cyl_getPostRequestIncludeBody;@end//// NSURLRequest+CYLNSURLProtocolExtension.h/ Created by ElonChan on 28 cyl_getPostRequestIncludeBody;@end//// NSURLRequest+CYLNSURLProtocolExtension.h/ Created by ElonChan on 07 ChenYilong / Copyright ©2017. All rights reserved.//#import "NSURLRequest+CYLNSURLProtocolExtension.h" @ implementation NSURLRequest (CYLNSURLProtocolExtension)-(NSURLRequest *) cyl_getPostRequestIncludeBody {return [[self cyl_getMutablePostRequestIncludeBody] copy];}-(NSMutableURLRequest *) cyl_getMutablePostRequestIncludeBody {NSMutableURLRequest * req = [self mutableCopy]; if ([self.HTTPMethod isEqualToString:@ "POST"]) {if (! self.HTTPBody) {NSInteger maxLength = 1024; uint8_t d [maxLength] NSInputStream * stream = self.HTTPBodyStream; NSMutableData * data = [[NSMutableData alloc] init]; [stream open]; BOOL endOfStreamReached = NO; / / cannot be judged by [stream hasBytesAvailable]). When processing image files, the [stream hasBytesAvailable] here will always return YES, resulting in an endless loop in while. While (! endOfStreamReached) {NSInteger bytesRead = [stream read:d maxLength:maxLength]; if (bytesRead = = 0) {/ / File read to the last endOfStreamReached = YES;} else if (bytesRead = =-1) {/ / File read error endOfStreamReached = YES } else if (stream.streamError = = nil) {[data appendBytes: (void *) d length:bytesRead];}} req.HTTPBody = [data copy]; [stream close];}} return req;} @ end
The above is my implementation, and notice here that someone has done something like this at the beginning:
-(void) cyl_handlePostRequestBody {if ([self.HTTPMethod isEqualToString:@ "POST"]) {if (! self.HTTPBody) {uint8_t d [1024] = {0}; NSInputStream * stream = self.HTTPBodyStream; NSMutableData * data = [[NSMutableData alloc] init]; [stream open] While ([stream hasBytesAvailable]) {NSInteger len = [stream read:d maxLength:1024]; if (len > 0 & & stream.streamError = = nil) {[data appendBytes: (void *) d length:len];}} self.HTTPBody = [data copy]; [stream close] }}}
The problem with this implementation is that [stream hasBytesAvailable] cannot be used to judge that [stream hasBytesAvailable] here will always return YES when processing image files, resulting in an endless loop in while.
The Apple documentation also makes it clear:
/ / returns in O (1) a pointer to the buffer in 'buffer' and by reference in' len' how many bytes are available. This buffer is only valid until the next stream operation. Subclassers may return NO for this if it is not appropriate for the stream type. This may return NO if the buffer is not available. @ property (readonly) BOOL hasBytesAvailable
The implementation is given, and the following is how to use it:
Implement the method + canonicalRequestForRequest: and handle the request object in a subclass of the NSURLProtocol used to intercept the request:
+ (NSURLRequest *) canonicalRequestForRequest: (NSURLRequest *) request {return [request cyl_getPostRequestIncludeBody];}
The functions of the related methods are described below:
/ / NSURLProtocol.hUniverse! @ method canInitWithRequest: @ abstract This method determines whether this protocol can handle the given request. @ discussion A concrete subclass should inspect the given request and determine whether or not the implementation can perform a load with that request. This is an abstract method. Sublasses must provide an implementation. @ param request A request to inspect. @ result YES if the protocol can handle the given request, NO if not.*/+ (BOOL) canInitWithRequest: (NSURLRequest *) request _ leadership! @ method canonicalRequestForRequest: @ abstract This method returns a canonical version of the given request. Discussion It is up to each concrete protocol implementation to define what "canonical" means. However, a protocol should guarantee that the same input request always yields the same canonical form. Special consideration should be given when implementing this method since the canonical form of a request is used to look up objects in the URL cache, a process which performs equality checks between NSURLRequest objects.
This is an abstract method; sublasses must provide an implementation. @ param request A request to make canonical. @ result The canonical form of the given request. * / + (NSURLRequest *) canonicalRequestForRequest: (NSURLRequest *) request
Translate:
/ / NSURLProtocol.hUniverse requests * @ method: create a NSURLProtocol instance. After NSURLProtocol registration, all NSURLConnection will use this method to check whether the Http request is held. @ parma: @ return: YES: hold the Http request NO: do not hold the Http request * / + (BOOL) canInitWithRequest: (NSURLRequest *) request _ request requests * @ method: the NSURLProtocol abstract class must be implemented. In general, there is a minimum standard: input and output requests meet the most basic protocol specifications. So the simple approach here can be returned directly. Normally, we don't change this request. If you want to change, such as adding a title to the request, combine it into a new http request. @ parma: local HttpRequest request: request@return: direct forwarding * / + (NSURLRequest*) canonicalRequestForRequest: (NSURLRequest*) request
To put it simply:
+ [NSURLProtocol canInitWithRequest:] is responsible for filtering which network requests need to be intercepted
+ [NSURLProtocol canonicalRequestForRequest:] is responsible for reconstructing the NSURLRequest of network requests to be intercepted.
There is a note here: the execution condition of + [NSURLProtocol canonicalRequestForRequest:] is that the return value of + [NSURLProtocol canInitWithRequest:] is YES.
Note that when intercepting a NSURLSession request, the subclass of the NSURLProtocol used to intercept the request needs to be added to the NSURLSessionConfiguration, as follows:
NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSArray * protocolArray = @ [[CYLURLProtocol class]]; configuration.protocolClasses = protocolArray; NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue: [NSOperationQueue mainQueue]]; switch to other lower-level network libraries that provide SNI field configuration interface
If you use a third-party network library: curl, there is a-resolve method to access the https website using the specified ip. The curl library is integrated in iOS, and refer to the curl documentation.
Another thing to note is that it also supports the IPv6 environment, as long as you add-- enable-ipv6 to the build.
Curl supports specifying SNI field. When setting SNI, we need to construct parameters such as: {HTTPS domain name}: 443: {IP address}
Suppose you want to visit. Www.example.org. If IP is 127.0.0.1, you can set SNI by calling it in this way:
Curl *-- resolve 'www.example.org:443:127.0.0.1'
IOS CURL library
Using libcurl to solve the problem, libcurl / cURL compiles a SSL/TLS toolkit with SNI support at least 7.18.1 (March 30th, 2008). There is a resolve method in curl that allows you to access the https website using the specified ip.
In the iOS implementation, the code is as follows
/ / {HTTPS domain name}: 443: {IP address} NSString * curlHost =.; _ hosts_list = curl_slist_append (_ hosts_list, curlHost.UTF8String); curl_easy_setopt (_ curl, CURLOPT_RESOLVE, _ hosts_list)
The shape of curlHost is like:
{HTTPS domain name}: 443: {IP address}
_ hosts_list is the structure type hosts_list, which can set the mapping relationship between multiple IP and Host. The CURLOPT_RESOLVE is passed in the curl_easy_setopt method to set the mapping to the HTTPS request.
In this way, the goal of setting up SNI can be achieved.
I have written a Demo:CYLCURLNetworking here that contains a compiled libcurl package that supports IPv6 and demonstrates how to do something similar to NSURLSession through curl.
Reference link:
Apple-Communicating with HTTP Servers
Apple-HTTPS Server Trust Evaluation-Server Name Failures
Apple-HTTPS Server Trust Evaluation-Trusting One Specific Certificate
["HTTPDNS > Best practices > HTTPS (including SNI) Business scenario" IP Direct connection scenario description
HTTPS (including SNI) Business scenario "IP Direct connection" solution description] (https://help.aliyun.com/document_detail/30143.html?spm=5176.doc30141.6.591.A8B1d3)
"request https using the specified ip in curl"
Alicloud-ios-demo that supports SNI and WebView
"SNI: realizing SSL/TLS authentication of multi-domain name virtual hosts"
Supplementary explanation
Note that the above discussion does not involve the loss of body that intercepts NSURLSession requests in WKWebView.
Several concepts mentioned in this paper:
An example of concept explanation: host can be IP or FQDN. Www.xxx.com or 1.1.1.1FQDNfully qualified domain name, composed of host name and domain name, www.xxx.com domain name is divided into full name and abbreviation. The full name is FQDN, and the abbreviation is FQDN that does not include the host name. For example: xxx.com, that is, www.xxx.com, in this FQDN, www is the host name and xxx.com is the domain name.
The domain name mentioned in part of this article refers to FQDN if there is no special description.
The solution to the problem of body loss when NSURLProtocol intercepts NSURLSession requests is shared here. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.