SSErrorDomain error code 109. NewsStand download from Amazon S3 - ios

While downloading a file from Amazon S3 in iOS. Intermittently NSURLConnectionDownloadDelegate's method didFailWithError: get called and this is what I got when I logged received NSError object
Error Code: 109
Error Domain: SSErrorDomain
Error Description: "Cannot connect to .s3.amazonaws.com"
Searched all the Apple documentation, StackOverflow and other sites but not found anything on this. Today I raised a technical query to Apple also for this using my developer account.
Any idea ?
Update:
So after looking into HTTP response error code (403 Forbidden), I got the idea. It is because of "RequestTimeTooSkewed" error from S3 (The difference between the request time and the current time is too large.). I cross checked it by changing iPad's/Mac's system time by 1 hour and this error is coming immediately now, even for a small (200kb) file.
Now as suggested in many blogs I am first making a HEAD request to AWS as below to get the Date string and not passing the system Date
NSString *awsURL = #"http://s3.amazonaws.com";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:awsURL]];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse *response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error: NULL];
NSString *dateString = nil;
if ([response respondsToSelector:#selector(allHeaderFields)]) {
dateString = [[response allHeaderFields] objectForKey:#"Date"];
}
return dateString;
and setting this as Date header in NSMutableURLRequest
[urlRequest setValue:awsDateString forHTTPHeaderField:#"Date"];
This request I am adding to my issue for download
NKAssetDownload *nkAssetDownload = [nkIssue addAssetWithRequest:urlRequest];
Still the same error !!!! It now more crazier than my last situation.
Anyone ?
Update 2
I was able to make request successfully (even the system clock of my iPad is incorrect) by replacing "GMT" with "+0000" in the date string.
Update 3
Still some requests fail with same error which is weird, but I am assuming it is something the NewsStand Framework is messing up.

So it is RequestTimeTooSkewed error and the above code to fetch date from S3 server's head response to add in request does the trick.

Related

HTTP response from dropbox zip download request (?dl=1)

I'm downloading a zipped folder from dropbox, by adding the ?dl=1 code at the end of the shared link.
Everything works fine and dandy, except for the connection response content length field. When I check response.expectedContentLength value, it always comes up as -1
I've tried avoiding response gzip compression with
[httpRequest setValue:#"" forHTTPHeaderField:#"Accept-Encoding"];
I've tried checking in the didReceiveResponse method if expectedContentLength was -1 and doing a manual check just for headers using the absolute zip file link (contained in response.URL) with
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:response.URL
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
theRequest.timeoutInterval = 5.0;
theRequest.HTTPMethod = #"HEAD";
NSHTTPURLResponse *res;
NSData * resData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&res error:nil];
long length = res.expectedContentLength;
"length" still comes up as -1.
The zip is generated by dropbox on the fly, so the initial request might be unable to get the content length. But in theory the response.URL value SHOULD be the final zipped file, and requesting it's headers should return a proper contentLength field, right?
Any ideas?
For anyone coming here later on:
I never got to find a way of getting it, short of fully downloading it (which kinda defeats the purpose), so that's that.
This is something you can't access (written on 16/06/16, do check again when you read). Dropbox doesn't set that particular header when downloading zipped folders.

I'm getting header info for a file that doesn't exist?

I'm using code that I got from a tutorial for finding the "Date Modified" info of a file on a server. It goes as follows...
// create a HTTP request to get the file information from the web server
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:remoteFileURL];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse* response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
// get the last modified info from the HTTP header
NSString* httpLastModified = nil;
if ([response respondsToSelector:#selector(allHeaderFields)]) {
httpLastModified = [[response allHeaderFields] objectForKey:#"Last-Modified"];
}
And, for the most part, it works! Wa-hoo.
Except, for a few files, it seems to be returning outdated information. In fact, for at least one, it's returning a date (Fri, 24 Apr 2015 04:32:55 GMT) for a file that doesn't even exist anymore. I deleted it from the server, but it's still returning that value every time I run my app, as if the file still existed.
I've checked and re-checked that the remoteFileURL is pointing to the right URL, and I've confirmed that the file doesn't exist on the server anymore. And, like I said, for most files it works perfectly, so obviously the system isn't entirely broken.
This is my first experience with NSMutableURLRequest and NSHTTPURLResponse and getting file headers and such. Is there something I don't know, that would explain this? Could there be a cache or something that needs to be cleared?
And ideally, what can I do to ensure that the proper info is being received by my app?
Thanks in advance!
Posting my comment as an answer
This type of thing happends because of caching mechanism of NSURL.
Try to add below line to remove all cached data.
[[NSURLCache sharedURLCache] removeAllCachedResponses];
If you want to ignore caching for particulate request try below code
NSURL *url = [NSURL URLWithString:aStrFinalURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

iOS sending a POST and GET in the same request

I am successfully posting data as follows:
NSMutableURLRequest *scriptrequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"myurl.com"]];
[scriptrequest setHTTPMethod:#"POST"];
NSString *sendData =[NSString stringWithFormat:#"ID=%#&action=List", ID, nil];
NSData *scriptdata = [sendData dataUsingEncoding:NSUTF8StringEncoding];
[scriptrequest setHTTPBody:scriptdata];
NSError *scripterr;
NSURLResponse *scriptresponse;
NSData *scriptResponseData = [NSURLConnection sendSynchronousRequest:scriptrequest returningResponse:&scriptresponse error:&scripterr];
My question is, is it possible to also attach GET data to the same call?
GET and POST are different types of HTTP Request.
GET Request is majorly used for fetching the web content while POST is for insert/update some content.
So eventually A single HTTP request can only be of one of the following.
Http types include:
GET
HEAD
POST
PUT
DELETE
TRACE
OPTIONS
CONNECT
PATCH
More technical details at Wikipedia:
http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
It looks to me like you are trying to retrieve data from your server, not update. A more typical way to form the request would be to GET http://myurl.com?ID=123&action=List. However, this really depends on how the server code is written.

Garmin Connect API for iOS

I'm trying to create a library to download content from Garmin Connect.
There's not too much documentation, or is not public, but I tried to base my code on the great Tapiriik project
It seems that the Garmin API needs to create a session (Based on BasicAutentication cookie) before be able to download the content.
I tried to do that using NSURLConnection and NSURLSession unsuccessfully (Sync/Async & With delegate and with CompletionHandler also tried).
// POST request with the params I have found on the tapiriik example
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://connect.garmin.com/signin"]];
NSString *post = [NSString stringWithFormat:#"j_id1=javax.faces.ViewState&login=login&login:loginUsernameField=%#&login:password=%#&login:signInButton=Sign In", theUsername, thePassword];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[post dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
The response is a 200, and I checked the user profile and seem that works successfully. But If I tried to download the activity I receive a 403
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://connect.garmin.com/proxy/activity-search-service-1.2/json/activities?start=0&limit=10"]];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
PD: I checked other github projects but all of them work in a similar way as tapiriik code
Any suggestions?
I finally solved it. It seems that Garmin has a new development policy.
Finally I follow the steps here: https://forums.garmin.com/showthread.php?72150-connect-garmin-com-signin-question&p=264580#post264580
I will upload the code to GitHub and share here.
Regards

HTTP Post - Time Out - Multiple Request getting initiated within timeout interval

I am using HTTP Post method and initiating a synchronous request.
[NSURLConnection sendSynchronousRequest: ..]
For HTTP POST requests, the default time out is happening at 75 seconds as discussed in many threads.
But during that time out period of 75 seconds, Multiple web service requests are getting initiated for us for the same request raised with all the same parameters.
Please let us know What causes this multiple requests to get initiated? Is this due to HTTP POST in general or because of Synchronous request?
#iOS Sample Code
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
[request addValue:[NSString stringWithFormat:#"%d", body.length] forHTTPHeaderField: #"Content-Length"];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
NSURLResponse *response;
response = nil;
urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(urlData)
{
NSString *responseString = [[NSString alloc] initWithData:urlData encoding:NSASCIIStringEncoding];
[self parseStringInformation:responseString infoDict:informationDictionary];
//NSLog(#"%#",responseString);
}
Without the server's request-response logs there are several possibilities.
Programmer Error: Have you already gone through all of "gotchya" type situations?
Have you put a logging message right before your "urlData = [NSURLConnection sendSynchronousRequest: ..." line to make sure your code is only calling it once?
Are you calling this function from within your main GUI thread, if you are that's not supported/recommended, which means it could be causing side-effects like what you're describing. https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
Are you sure your Request is set up as a POST and has the proper headers like "Content-type: multipart/form-data, boundary=X"
Web Server Responses: Without the web servers logs (or the code for the service your POSTing to) it's hard to say...
Perhaps your server is sending cyclical redirects to the client. If you don't implement a "connection:willSendRequest" then the redirects could be followed for ?X? amount of times for one request. http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/urlloadingsystem/Articles/RequestChanges.html
API Error: You've found some corner case which is causing unwanted side effects. Maybe apple has an bug tracker or developer support forum?
If this is the case you'll have to work around the bug, until it's fixed. I suggest implementing the Asynchronous call chain. "Loading Data Asynchronously" https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html

Resources