How do iOS HTTP request retries work? - ios

I'm using NSURLConnection to send an HTTP request and running it with
[[NSURLConnection alloc] initWithRequest:self.request delegate:self];
where "self.request" is a configured NSMutableURLRequest object. Upon a network failure and callback to
-(void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
I'd like to cancel the request and write the payload to file to be uploaded later. However if I reconnect too quickly the payload ends up getting sent still (and I later send the same payload from the file). In the failure callback, I've tried to use
[connection cancel];
But the http request still goes through upon reconnecting within a few seconds. Is this due to some retry mechanic that I can disable?

From Apple's docs on didFailWithError:
// Once the delegate receives this message, it will receive no further messages for connection.
So I'd say you have a bug somewhere else in the code. Once that delegate message is called, the connection is done and it will never be restarted unless you do so.
From the question it seems like you are trying to cancel the connection in the failure delegate method, is that correct? That should not be necessary since the connection is already dead. I'm also a bit confused when you say you "retry to quickly". I don't see any "retry" code so it would help if you could post that too.
Can you post more code to help diagnose the issue?

Related

AFNetwork: Getting "finished with error - code: -999" warning

I am doing a get API request and everything works fine, but I am getting the following warning in the console.
Task <13369ECB-128E-41B7-B9E4-DC7D3E47D0C1>.<2> finished with error -
code: -999
This only occurs for a certain API endpoint. This makes no sense to me at all. I thought -999 stands for cancelled request, but my requests are finished.
I think this might be a security issue simply because all my get requests work for multiple api endpoints, but not a specific one. Any suggestions are appreciated.
Yes, this means it was canceled, but the question is why
be patient to make sure you didn't cancel the request.
returned when an asynchronous load is canceled. A Web Kit framework delegate will receive this error when it performs a cancel operation on a loading resource.
may be caused by an invalid SSL certificate

AFHTTPSessionManager POST request executes successfully but calls failure block

Sometimes a POST request with AFHTTPSessionManager executes the failure block with the following error: The network connection was lost. BUT the server side code executes successfully, sending a 200 OK response. How is that possible and what to do about it? What is a good strategy in general if a network connection is lost while the server executes a routine (successfully)? Could it be a problem with the AFNetworkReachabilityManager? I have it set up like this in the AppDelegate:
// Monitor network connection
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
DDLogInfo(#"AFNetworkReachabilityStatusReachableViaWiFi:");
// Resume callbacks for remote operations
[[[TSHTTPSessionManager sharedManager] operationQueue] setSuspended:NO];
// Notify app
[[NSNotificationCenter defaultCenter] postNotificationName:TSDidConnectToNetworkNotification
object:self userInfo:nil];
break;
case AFNetworkReachabilityStatusNotReachable:
DDLogInfo(#"AFNetworkReachabilityStatusNotReachable:");
// Suspend callbacks for remote operations
[[[TSHTTPSessionManager sharedManager] operationQueue] setSuspended:YES];
// Notify app
[[NSNotificationCenter defaultCenter] postNotificationName:TSDidDisconnectFromNetworkNotification
object:self userInfo:nil];
break;
default:
break;
}
}];
EDIT: I guess I did not make myself clear: The question is not about AFNetworkReachabilityManager (I just added the code to show how the app detects connectivity issues and forwards them as notifications such that other parts of the app get notified if they decide to do so). The questions is about a request (POST) which is transmitted successfully to the server which causes the server side code to execute. At the same time, and before the server is able to send its response, the connection is lost, which in turn causes the client side failure block to execute (after the network is reachable again but that does not really make a difference I guess). How do I know on the client side that the server succeeded nonetheless?
If a device loses connectivity, AFNetworking's underlying AFHTTPRequestOperation and NSURLSessionDataTask objects will fail immediately. All you're doing by suspending the operationQueue is preventing the completion blocks you've set from running, so you don't hear about the failure until the connection comes back online and the operationQueue is resumed.
In general, when dealing with connectivity issues, it's simplest merely to handle it like any other failure. Perhaps present an error message to the user letting them know their connection is offline and to try their request again when connectivity is restored. If you really, really need to you can build a convenience wrapper around the various AFNetworking calls that attempts to retry them on failure or loss of connectivity, but that seems like a lot of work for little benefit, given you have no idea when connectivity will resume. For all you know the user has switched away from your app and it was killed in the background. But your current approach is certainly not the right way.

cancel file uploading with NSURLConnection

I've got NSURLConnection with timeout = 30s which is uploading an image on server.
If connection is horrible and call delegate method didFailWithError: then i need to cancel current connection.
But if i just call the [myConnection cancel] connection will still alive but will not call delegates methods (apple docs say it - NSURLConnection cancel method). And i want to abort connection but not only remove delegate methods. How i can do what?
upd:
My problem is if connection is fails by timeout - in business logic i must recreate connection with similar request. If i have got horrible connection for 1 min and after that connection will be good - server will get a lot of (about 3 times retry count) photos. But first 2 connections is canceled. –
At the moment i make "dirty hack" like "if it's photo uploading request" - do not retry recreate connection.
I do a ton of network stuff and don't recall a scenario where everything was successfully received but the iOS app timed out. I'm trying to grok the scenario you describe, where you're seeing this happen a lot and I'm not seeing how that would happen. We might need to see some of your code.
Regardless, when you cancel a NSURLConnection, it not only stops the delegate methods from being called, but it stops the upload, too. I just did a test:
I attempting to upload a 20mb file (non-chunked request);
At the 1mb mark (as identified by didSendBodyData), I canceled the connection (by calling [connection cancel]);
I immediately stopped receiving any delegate messages at that point;
Looking at Charles, I'm only seeing 1.3mb of data in the hex log of the request. When I look at the "Network" tab of the Mac OS "Activity Monitor" and looking at by "Sent Bytes", it's at 2.1mb uploaded.
So canceling a connection will stop further data from being sent. Perhaps if there is some transmission in progress that still gets out (that's the asynchronous world we live it), but the it's not true to conclude that canceled connections will routinely send their full HTTP request. There must be something about the nature of the timeout that is unique to your environment.
In terms of your immediate problem, I might suggest that when uploading a file that the iOS app assign some unique identifier to the upload so that the server code can immediately recognize duplicate requests and handle them appropriately. But the question is why you are seeing so many time-outs and notably ones where the request appears to be successfully received in toto, but the response is not. That's very curious.
You cannot forcefully abort an ongoing connection.
In case if connection is not yet started cancel and unscheduleFromRunLoop for the NSURLConnection will work.
Try with following step
[myConnection cancel];
myConnection = nil;
Might be helpful in your case and If this step is not working then also try with myConnection.delegate = nil;

AFNetworking UIAlertView when in background and no network

I am using AFNetworking to update location details to a server in the background (using significant location change).
Everything works fine, except when driving round and it attempts to upload to my server and my phone has no data signal, when I re-launch the application later it has UIAlertViews on the screen saying "The Internet connection appears to be offline."
I have done a search on my project for the string, but it doesn't exist. So where is it coming from?
I would like to stop this being displayed when the app is backgrounded.
Thanks
That error message is passed to [NSURLConnection connection:didFailWithError:] when the Internet is offline. I believe AFNetworking passes this to a failure code block or delegate callback depending on your implementation. You have code somewhere to make a UIAlertView display text from an NSError object but that string isn't in your project so that's why you can't find it.

XMPPFramework: Sending a message with timeout

I'm using XMPPFramework in my iOS app to send and receive command messages between client and server. The server would answer to different command messages immediately.
Sometime the connection is very slow, the message sent from client would have no response for a long time. So I want to know how can I send an XMPP message with timeout or I have to implement this myself.
Anyway:
This goes to - (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message.
Using Reachability, the internet is still reachable via [[Reachability reachabilityForInternetConnection] isReachable].
Why not just set a timer when you send the message, override the response callback on the XMPPStream, and see which is called first?

Resources