When connecting via HTTPS to a server, I implement the NSURLSessionDelegate
method URLSession:didReceiveChallenge:completionHandler:
to implement some custom functionality.
The problem is that this delegate method is only being called the first time a request is made (subsequent requests do not invoke this method). My custom functionality requires the delegate method to be called for every request.
Here's an example:
- (IBAction)reload:(id)sender {
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:self delegateQueue:nil];
// Note that https://www.example.com is not the site I'm really connecting to.
NSURL *URL = [NSURL URLWithString:@"https://www.example.com"];
NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL];
[[session dataTaskWithRequest:URLRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Response received here.
}] resume];
}
#pragma NSURLSessionDelegate
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
// Called only for the first request, subsequent requests do no invoke this method.
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
Since I want the URLCredential to be per session or per task, I checked the NSURLCredential
that I pass to completionHandler
, and I found it has a persistence
of NSURLCredentialPersistenceForSession
(which is immutable), which seems correct.
I also checked [NSURLCredentialStorage allCredentials]
and it's empty, so it's not caching the credentials there.
I noticed that if I subsequently make a request to a HTTPS URL with a different domain, the challenge is called for that domain once, so it is on a per domain basis.
So how come the challenge is only made once?
EDIT
Switching to the NSURLSessionTaskDelegate
and using URLSession:task:didReceiveChallenge:completionHandler:
makes no difference.
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
EDIT related question
EDIT Since there seems to be no way to fix this at the moment, I've filed an Apple bug report: 19072802
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…