NSURLSession didReceiveChallenge only called once - ios

I'm using NSURLSession dataTaskWithRequest:completionHandler: to make some requests to my server. I'm using a self-signed certificate, so when the delegate's URLSession:didReceiveChallenge:completionHandler: gets called, I can do my internal checks to verify it everything is fine.
This all works great on the first request I send. After I call the completion handler with NSURLSessionAuthChallengeUseCredential, then the next requests never call URLSession:didReceiveChallenge:completionHandler:.
For reasons I won't go into in this post, I would really like URLSession:didReceiveChallenge:completionHandler: to be called each time, so that I can do my own checking. I'm assuming NSURLSession is somehow caching the certificate and keeping it in some sort of "valid certificates" list so it's not doing this check each time. I want to clear this cache so that I can make my own check each time. If I restart the App, then URLSession:didReceiveChallenge:completionHandler: does get called once more.
I have tried setting the Credential Storage to nil with no success:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.URLCredentialStorage = nil;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
[[session dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
...
}] resume];
Any ideas how to accomplish this?
Thank you!

For someone who tried everything here can be problem in the backend. So this problem was fixed by disabling ssl session caching in nginx server.

Related

NSURLSession Redirection handler different behaviour on WatchOS

I am working on updating an old WatchOS app to support WatchOS 4.0. The app makes some network requests, one of which responds with a 302 redirect status code and corresponding Location header. I do not want to follow the redirection, and the 302 response headers contains all the info I need for this particular request.
I am using NSURLSession and have implemented the delegate method - URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:.
The delegate method is called as expected, and inside it I call completionHandler(nil) to tell the OS not to follow the redirect. All is fine up to this point.
The NSURLSessionTask completion handler at this point typically gets called immediately after this with a request cancelled error, and that's fine too.
Here's the strange part. When the Apple Watch is paired with an iPhone, I get the behaviour described above. However when I put the iPhone into Aeroplane Mode to simulate the Watch being out of range, with the network requests being made directly over wifi or cellular, I get a different behaviour.
The redirection delegate method is still called, as expected, however the NSURLSessionTask completion handler does not get called immediately. Rather, it gets called some time later with a -1001 Request Timed Out error.
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// Odd behaviour described above here
}];
[task resume];
The delegate redirection method:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
completionHandler(nil);
}
This has been frustratingly difficult to debug to this point as I cannot debug through Xcode and have not been able to find a way to proxy the watch network requests.
Has anyone experienced this behaviour, or have any clues on why it's behaving differently? Is this a WatchOS defect?

NSUrlSession: is it possible to upload files in the background?

Using NSUrlSession with a background configuration let's me download files even if the app gets terminated by iOS. Being curious, I tried to add an upload task and noticed that it won't continue, even not if the app is only suspended.
Apple talks about "Downloading in the background" but they don't explicitly state that uploading would not be possible.
Can somebody confirm that uploads and background session configuration don't work together?
They DO work together.
What you need to do is the following:
Have a NSURLSessionConfiguration with background configuration
NSURLSessionConfiguration *conf = [NSURLSessionConfiguration backgroundSessionConfiguration:#"backgroundSession"];
Setup a NSURLSession (#property NSURLSession *urlSession)
Obtain the path to the file (fullPath)
Create the NSURLRequest (request)
Create a NSURLSessionTask
NSURLSessionTask*task = [self.urlSession uploadTaskWithRequest:request fromFile:fullPath];
[task resume];
And the task will run in background. You can get the status from NSURLSession delegate methods.
Cheers

How to disable sslv3 for NSURLconnection or NSURLSession

With respect to the recent security threat with SSLV3,https://isc.sans.edu/forums/diary/OpenSSL+SSLv3+POODLE+Vulnerability+Official+Release/18827
How can I make NSURLconnection communication secure from this threat?
Can I disable sslv3 programmaticaly in iOS?
Is there any way in iOS by which I can get the supported security protocol list from server url?
I have figure out the way to set it into NSURLSession but still struggling with NSURLConnection.
NSURLSessionConfiguration *config =
[NSURLSessionConfiguration defaultSessionConfiguration];
config.TLSMaximumSupportedProtocol = kTLSProtocol12;
config.TLSMinimumSupportedProtocol = kTLSProtocol12
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];
Depending on how you connect try to use kCFStreamSocketSecurityLevelTLSv1 instead of kCFStreamSocketSecurityLevelNegotiatedSSL.

IOS Checking Active internet connection even connected via WIFI without internet

Please help me out how to check internet connection in iPhone.
I tried by checking the Apple's reachability framework, but it is not returning if connected via WIFI without internet.
What I am getting is reachable via wifi.
The other option I tried is making a synchronous request with google.com etc and checking the response code.
Is there any other way to check so that I can avoid making a url request and checking the response code.
Thanks in advance.
Check if wifi reachable (using Apple's reachability), and then make request to ensure host is reachable.
// wifi checking code here
//...
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:#"http://yourServer.com/someLightFile.html"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (!error) {
// Your host is reachable
}
}] resume];

How to work with large file uploads in ios?

My app requires upload of video files from users phone which will then be processed on server.
THe problem is the size of the file can go to 200 MB plus and the user won't keep the application open to wait for the file to upload. Since apple doesn't allow apps to run in background for more than a limited time. How can I ensure that my files are uploaded. I am using afnetworking to set up an upload task as given by ios 7 library.
Please if anyone can point me in the right direction or have any solution it would be greatly appreciated. I have banged my head on this for too long. Thanks.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
[manager setTaskDidSendBodyDataBlock:^(NSURLSession *session,NSURLSessionTask *task ,int64_t bytesSent, int64_t totalBytesSent,int64_t totalBytesExpectedToSend){
CGFloat progress = ((CGFloat)totalBytesSent / (CGFloat)sensize);
NSLog(#"Uploading files %lld -- > %lld",totalBytesSent,totalBytesExpectedToSend);
[self.delegate showingProgress:progress forIndex:ind];
}];
dataTask = [manager uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
}
}];
My request is a normal multipart form request.
Use:
NSURLSessionConfiguration:backgroundSessionConfiguration:
instead of
NSURLSessionConfiguration:defaultSessionConfiguration
From the NSURLSessionConfiguration:backgroundSessionConfiguration: documentation:
Upload and download tasks in background sessions are performed by an external daemon instead of by the app itself. As a result, the transfers continue in the background even if the app is suspended, exits, or crashes.
So in your case, change:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
to:
NSString *appID = [[NSBundle mainBundle] bundleIdentifier];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:appID];
Implementing application:handleEventsForBackgroundURLSession:completionHandler: on your app delegate will allow your app to be woken up (ie. un-suspended or un-terminated in background mode) when an upload has completed (whether it has completed successfully or not).
Don't get confused with Background Fetching. You don't need it. Background Fetching simply wakes you app up to periodically give your app the chance to fetch small amounts of content regularly. It may however, be useful for restarting failed "background-mode" uploads periodically.
You should use a background session configuration instead if a default session configuration. This ensures that your data transfer will continue in the background once the user has exited your app.
Of course, this is correct as long as the user has background fetching enabled for your app in the Settings app of the device.
Be sure to enable the Background fetch capability on your project settings:
(source: migueldiazrubio.com)
(source: migueldiazrubio.com)
Then implement the application:handleEventsForBackgroundURLSession:completionHandler: in your App Delegate to be informed when the data transfer ends and do whatever you need to do (UI update…) inside your app with the received/sent file. Don't forget to call the completionHandler to inform the system that you have ended your tasks. iOS then will take a screenshot of the active screen of your app and update the one in the iOS 7 multitasking screen.

Resources