2

According to the documentation of NSURLSessionConfiguration::protocolClasses, there is no guaranty, that my custom url protocol will be used. How can I ensure, that it is used whenever I set it to protocolClasses property?

Prior to handling a request, an NSURLSession object searches the default protocols first and then checks your custom protocols until it finds one capable of handling the specified request. It uses the protocol whose canInitWithRequest: class method returns YES, indicating that the class is capable of handling the specified request.

I can't set an array with single URL protocol, because it has logic for canInitWithRequest: method and might not handle all request.

NSArray *currentProtocolClasses = sessionConfiguration.protocolClasses ?: @[]; NSMutableArray *protocolClasses = [NSMutableArray arrayWithArray:currentProtocolClasses]; [protocolClasses insertObject:[CustomURLProtocol class] atIndex:0]; sessionConfiguration.protocolClasses = protocolClasses; 

1 Answer 1

3

If the docs say that, it's a bug. Please file one. The logic is actually much simpler than what is described there. Basically what the OS does is this:

NSURLProtocol *protocol = nil; for (Class protocolClass in sessionConfiguration.protocolClasses) { if ([protocolClass canInitWithRequest:request]) { protocol = [[protocolClass alloc] init]; } } if (!protocol) { fail } 

So as long as your protocols are listed first, they'll get priority. (For NSURLConnection, that bit of the doc was also wrong; your registered protocols are always asked first, before any of the built-in protocols.)

If you don't need to handle standard protocols, it is sufficient for you to do this:

sessionConfiguration.protocolClasses = @[[CustomURLProtocol class]]; 

You cannot force a URL protocol to be used. The protocol will be used if and only if its canInitWithRequest: class method returns YES for the request. If you want to make a different protocol handle a request (e.g. if you want to define a custom URL scheme that really uses a normal https request), then you would typically do so by writing a protocol that rewrites the URL and reissues the request in a new session that does not have your protocol handler class installed.

Alternatively, you can reissue the request in a session that does have your handler installed so long as you modify the request in some way so your protocol handler knows to return NO from its canInitWithRequest: method when it sees the request a second time. (Otherwise, you'll get infinite recursion.)

Sign up to request clarification or add additional context in comments.

4 Comments

Hi! Could you, please, change the example code to sessionConfiguration.protocolClasses = @[[CustomURLProtocol class]]; in order to be more generic? Thanks
Yeah, sure. Done.
Regarding "the array will always be empty or nil": I create default sessionConfiguration. Its protocolClasses array already contains 5 OS protocols: _NSURLHTTPProtocol, _NSURLDataProtocol, _NSURLFTPProtocol, _NSURLFileProtocol, NSAboutURLProtocol. I need to add my CustomURLProtocol. Whenever my CustomURLProtocol returns NO in canInitWithRequest:, the app must fallback to OS protocols.
Ah. I guess I'm remembering wrong about that. I'll edit that, then.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.