Using NSURLProtocol with NSURLSession

My application uses NSURLConnection to communicate with the server. We use https for communication. To process authentication from the entire request in one place, I used NSURLProtocol and processed authentication in delegates of this class. Now I decided to use NSURLSession instead of NSURLConnection . I am trying to get NSURLProtocol by working with NSURLSession I created a task and used NSURLProtocol on

 NSMutableURLRequest *sampleRequest = [[NSMutableURLRequest alloc]initWithURL:someURL]; NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; configuration.protocolClasses = @[[CustomHTTPSProtocol class]]; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; NSURLSessionDataTask *task = [session dataTaskWithRequest:checkInInfoRequest]; [task resume]; 

CustomHTTPSProtocol , which is my NSURLProtocol class, looks like this:

 static NSString * const CustomHTTPSProtocolHandledKey = @"CustomHTTPSProtocolHandledKey"; @interface CustomHTTPSProtocol () <NSURLSessionDataDelegate,NSURLSessionTaskDelegate,NSURLSessionDelegate> @property (nonatomic, strong) NSURLSessionDataTask *connection; @property (nonatomic, strong) NSMutableData *mutableData; @end @implementation CustomHTTPSProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request { if ([NSURLProtocol propertyForKey:CustomHTTPSProtocolHandledKey inRequest:request]) { return NO; } return [[[[request URL]scheme]lowercaseString]isEqualToString:@"https"]; } + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { return request; } - (void) startLoading { NSMutableURLRequest *newRequest = [self.request mutableCopy]; [NSURLProtocol setProperty:@YES forKey:CustomHTTPSProtocolHandledKey inRequest:newRequest]; NSURLSession*session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; self.connection = [session dataTaskWithRequest:newRequest]; [self.connection resume]; self.mutableData = [[NSMutableData alloc] init]; } - (void) stopLoading { [self.connection cancel]; self.mutableData = nil; } -(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { NSLog(@"challenge..%@",challenge.protectionSpace.authenticationMethod); if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; } else { [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; } } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { [self.client URLProtocol:self didLoadData:data]; NSLog(@"data ...%@ ",data); //handle data here [self.mutableData appendData:data]; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (!error) { [self.client URLProtocolDidFinishLoading:self]; } else { NSLog(@"error ...%@ ",error); [self.client URLProtocol:self didFailWithError:error]; } } @end 

The download starts and authentication is performed, but the download stops immediately.

Error code -999 "Canceled" is returned after some time. didReceiveData is not called.

Note:NSURLProtocol and the Authentication Process worked fine with NSURLConnection.

What am I missing? My questions

  • Registration [NSURLProtocol registerClass: [CustomHTTPSProtocol class]]; worked fine with NSURLConnection, but how is Resister for NSURLProtocol globally with NSURLSession ?.

  • Why is the NSURLProtocol request (the same URL and the logic working withURLConnection), the URL failed and how to get NSURLProtocol to work with the URLSession?)

Please help me and let me know if you would like more information.

+7
ios xcode nsurl nsurlsession nsurlprotocol
source share
3 answers

I know this is old, but the problem you are facing is your didReceiveChallenge method. You end the method by calling

 [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; 

or

 [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; 

Instead, you need to use a completion handler to submit your results. It will look like this:

 completionHandler(.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust) 

or

 completionHandler(.PerformDefaultHandling, nil) 

They are in Swift 2.0, but should translate well to Obj-C.

0
source share

Registering a custom NSURLProtocol with NSUrlsession is similar to how you do it with NSURLConnection.

NSURLSession Api (NSURLSessionDataTask and other task classes) when used with a custom NSUrlProtocol does not properly handle HTTP authentication problems. This worked as expected on iOS 7.x and was broken on iOS 8.x. The apple radar developed and my radar was closed, saying it was a duplicate of another radar, and I still see that the original radar is still open. Therefore, I believe that this problem has not yet been fixed by an apple today.

I hope I was not late with the answer :)

+2
source share

My vague recollection is that NSURLSession automatically uses any globally registered protocols. Therefore, you do not need to register it again, but this should also not prevent you from doing this.

I wonder if the URL request is being copied, in which case your custom tagging may not work, and you can see infinite recursion until it reaches the internal limit. Have you tried setting the request header instead?

0
source share

All Articles