Auth challenge for NSURLSession not working with Custom protocol

I have implemented custom protocol with session delegate as below -


- (void)startLoading 
{ 
     NSMutableURLRequest *mReq = [self.request mutableCopy];
     NSURL *url = [[self request] URL]; 
     NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
     //... 
     //... 
     if(!_mySession) {
           _mySession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
      } 
    //task creation here
} 


- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler{
  
    NSURLAuthenticationChallenge* challengeWrapper = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:challenge sender:[[CustomAuthChallengeWrappers alloc] initWithSessionCompletionHandler:completionHandler]];
        if(self.client){
                if([self.client respondsToSelector:@selector(URLProtocol:didReceiveAuthenticationChallenge:)]) {
                     NSLog("auth-challenge");
                     [self.client URLProtocol:self didReceiveAuthenticationChallenge:challengeWrapper];
                }
        }
}


If client uses NSURLConnection, it is working fine. If I use NSURLSession on client side, its forwarding the Auth challenge but not receiving back in custom protocol. Challenge wrapper is implemented as per this link: http://stackoverflow.com/questions/27604052/nsurlsessiontask-authentication-challenge-completionhandler-and-nsurlauthenticat

Am I missing anything for NSURLSession?


Its not working with xcode 7.3.1 with latest iOS 9.3. It was working with previous versions.

Replies

OK, let’s start with the basics: why are you using a custom NSURLProtocol subclass? In general it’s best to avoid this where you can.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I have requirement to set proxy, can't avoid NSURLProtocol subclassing.

What’s wrong with setting the proxies via the NSURLSession via the

connectionProxyDictionary
property of the NSURLConfiguration object you use to create the session?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Its a lib which can be integrated with apps, so subclassing NSURLProtocol. Lib doesn't know app implementation, it can be NSURLSession or NSURLConnection etc.


its working in iOS 10. Looks like there was some issue in iOS 9.3 which has been fixed by Apple in iOS 10. Also it was wokring in old versions.

Its a lib which can be integrated with apps, so subclassing NSURLProtocol. Lib doesn't know app implementation, it can be NSURLSession or NSURLConnection etc.

This is not a great long-term strategy. There’s a bunch of problems trying to integrate with arbitrary apps via NSURLProtocol:

  • NSURLSession-based apps that use a custom NSURLSession have to explicitly opt in to your protocol (via the

    protocolClasses
    property of NSURLSessionConfiguration).
  • Lots of networking tasks are done out of process (like with WKWebView, or the media subsystem, or even something as common as NSURLSession background sessions), and that work doesn’t see your NSURLProtocol subclass. This trend is likely to continue going forward.

  • The NSURLProtocol interface has not been maintained properly in recent years, leading to situations like the one you started this thread with (the semantic mismatch between authentication challenge handling at the NSURLSession level and authentication challenge handling in NSURLProtocolClient).

I encourage you to think about how you could move away from using NSURLProtocol for this work, filing enhancement requests for any features that you need to achieve this.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

But as long as classes like WKWebView does not allow to customize the network requests or responses (for example to implement filtering), NSURLProtocol is important, because this is the only option that is available.

But as long as classes like WKWebView does not allow to customize the network requests or responses (for example to implement filtering), NSURLProtocol is important, because this is the only option that is available.

I think you mean UIWebView here; WKWebView does its networking out of process and, as such, does not ‘see’ your NSURLProtocol subclass. This distinction matters because WKWebView is very much the future of web views, whereas UIWebView, while not officially deprecated, is very much the past.

In recent years we’ve done a bunch of stuff to eliminate many of the situations where folks needed to use an NSURLProtocol underneath UIWebView. These include:

  • support for authentication challenges in WKWebView (except

    NSURLAuthenticationMethodClientCertificate
    , grumble) (r. 22659960)
  • excellent web/native integration in WKWebView

  • support for VPN and content filter providers under the aegis of the Network Extension framework

  • various content blocking extension points

If your product’s requirements are not covered, I encourage you to file enhancement requests for the specific features you need. Please post the numbers of any bugs you file, just for the record.

Finally, I want to stress that NSURLProtocol was originally designed as a way of adding new protocol support to the NSURLConnection infrastructure (things like

data:
URLs). It was never intended to be used to provide filtering of existing protocols. The fact that this works (up to a point) is an artefact of how the various parts fit together, not an original design goạl. That’s been useful over the years, but we’re getting to the point where we need to draw a line under that approach and switch to things that are more supportable in the long term.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

UIWebView does allow to customize and filter the network requests via NSURLProtocol, but WKWebView does not. Therefore for many Apps which do need to do this, using UIWebView and NSURLProtocol is the only option right now. I would love to switch to WKWebView, but right now it is impossible, this would completely kill my App.


It would be great if WKWebView would provide an API where a delegate method would be called for all(!) network requests (including those for resources like images, AJAX calls, stylesheets and Javascript files), allowing the App to modify those requests or even block them. This would eliminate the need for NSURLProtocol and UIWebView. Unfortunately I do not see that Apple intends to go to this direction. Internally WKWebView is already doing this, I bet, but there's just no public API available for this.

I've send feature requests, they all were marked as duplicate, so I'm not the only one requesting this. But I do not yet give up hope ;-)


I do understand that Apple wants to get rid of old stuff, but if Apple does not offer an alternative, and developers have either to kill their Apps or continue to use the old stuff with all the issues, you will see developers being unhappy with the current situation ;-)

(except NSURLAuthenticationMethodClientCertificate, *grumble*)

There’s finally been some good news on this front. See this thread for details.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"