ASIHTTPRequest seems to cache JSON data always - objective-c

I'm using ASIHTTPRequest API to get some JSON data from a web side. I'm using an asynchronous request without changing default cache properties. Code is as follows:
__unsafe_unretained ASIHTTPRequest * request = [ASIHTTPRequest requestWithURL:url];
request.timeOutSeconds = 30;
[request setCompletionBlock:^(void)
{
NSString *str = [request responseString];
/*
*
*
*/
}];
[request setFailedBlock:^(void)
{
NSLog(#"status: %#",[request responseStatusMessage]);
NSLog(#"%# : %#",[request url],[[request error] debugDescription]);
}];
[request startAsynchronous];
However, obtained JSON data remains as the old one although content of JSON data in server changes.
I checked data using web browser, both on laptop and on iPhone safari. When i request url after a change in JSON, it first returns old data, but if i refresh the page, it returns updated data. But in the app, ASIHTTPRequest always returns the old data.
I also try to debug ASIHTTPRequest code in order to see whether any cached data used. But it seems like it never uses download cache because it has not been set. It never enters [useDataFromCache] method.
What could be the problem? How can i force ASIHTTPRequest to check whether there is an updated data on server, and make it get the true updated JSON?
EDIT
I used Cache-Control header, and now i get the correct updated JSON data. Code is as follows:
[request addRequestHeader:#"Cache-Control" value:#"no-cache"];
However, i think from now on request will always try to retrieve JSON even if it is not modified, which will decrease performance.
How can i make it first check the server whether data is modified, and retrieve if it is modified? Currently i get JSON data as a dynamic response from a php url, so there is no file which i can check up to dateness of the data.
What could be the solution?
Regards,

Given everything you've said, it seems unlikely that ASIHTTPRequest is cacheing the response.
So, something else must be - it seems like you have a cacheing proxy server inbetween you and the server, and that's why setting Cache-Control makes a difference.
It could be a proxy server on your local network, or it could be at your ISP, or it could be in front of the web server you're using.

According to ASIHTTPRequest's documentation, calling the method
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
will clear the cache. Call this method before you send the request and it should give you the updated JSON data.

Related

NSURLSessionDataTask for multipart form returns empty data even though "Content-Length" header has value

I am attempting to upload multiple images to a server using a multipart form following this example using NSURLSession and NSURLSessionDataTask block based api.
Additionally for all calls made to the server I am sending an authentication token that verifies I am authorized to do the upload.
Everything is working well except for the case when I do the upload and my authentication token has expired. When the token has expired I should be getting an HTTP 400 response with a body saying that the expired token is the reason for the failure (this works on all other calls to the server).
However for the multipart-form upload when my token is expired, I get the 400 response as expected but the NSData object returned in the completion block of
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSData *data,
NSURLResponse *response,
NSError *error))completionHandler
is empty. It's interesting that the NSData object is NOT nil, it's just an empty NSData object.
It's also interesting that in the response object I see a "Content-Length" header which is the length of the response I EXPECT to see, i.e. the "Content-Length" header is greater than 0, however the length of the NSData object IS 0.
So my question boils down to, is there any reason why an NSURLSession would not expose the data returned from the server? Is there something about setting the "multipart-form" header on the request that is making the response have an empty body?
I'm assuming that when you say "returned from the completion block", you really mean "when examined from within the completion block".
If there's an error set, then an empty object may indicate that the connection timed out while waiting for the server to actually send data.
Otherwise, I have this vague recollection that NSURLSession tasks don't retrieve the body of the error page if the server returns certain result codes, and that you have to do something to change that behavior, like implementing a custom authentication delegate that tells it to load anyway. But this is a vague, distant memory, and I can't find any details about that online, so I could be remembering wrong.

Is there a way to register custom accept headers to parse as JSON in AFNetworking 1.3?

I have a server that is sending back JSON using the following accept header:
[self setDefaultHeader:#"Accept" value:#"application/vnd.com.test.v1+json"];
In the success block of the API calls, the response data is coming back as a NSData object.
I read in the following question Issue with retrieving JSON with AFNetworking that I need to set #"application/json" if I want JSON to be parsed into an NSDictionary automatically, otherwise I have to manually do it for each call using NSJSONSerialization.
Is there a way that I can get #"application/vnd.com.test.v1+json" to be recognized as JSON and automatically do JSON deserialization for each request?
Add your desired content types to AFHTTPRequestOperation using addAcceptableContentTypes::
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:#"application/vnd.com.test.v1+json"];

Clear cookies for a given iOS App

My App connects to a server and based on a cookie the server will issue a different response.
Is it no possible to programmatically clear the cookie store, so that the server will not recognize my App when it contacts the server the next time.
I gathered that clearing the Cookies in the Settings.app does only apply for cookies within Safari.
Thanks very much for your comment.
Okay... following up on my earlier comment (and hoping this is the solution you are looking for), you probably want to utilize:
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:]
for each of the cookies for your site.
If you want your changes to the NSHTTPCookieStorage to be retained, you'll also want to call off to
[[NSUserDefaults standardUserDefaults] synchronize];
To prevent this from slowing down your app, you may also want to call this on a background thread like so:
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(backgroundQueue, ^{
//TODO: Cookie deletion logic here
});
EDIT:
If you just need to disregard cookies altogether for a given NSURLRequest, you can do so with:
[request setHTTPShouldHandleCookies:NO];
Where request is your instance of NSURLRequest.
As mentioned by #Niralp it isn't possible to delete all cookies by passing nil to deleteCookie: on an instance of NSHTTPStorage. However, since iOS 8 there has been a removeFromDate: method that can be utilised to the same effect.
In Swift 4 this would be:
HTTPCookieStorage.shared.removeCookies(since: Date(timeIntervalSince1970: 0))
That would remove all cookies in the app since the 1970 epoch which is likely suitable for most needs.

Objective-C – ASIHTTPRequest caches even if new content is available

I'm using ASIHTTPRequest to download data from the internet. It has a nifty cacheing feature that you can turn on so that it caches the downloaded data. So far so good. But when I upload new data to my webserver and try to download it again I'm expecting it not to use the cache since the data is new and modified. But even so it will still use the cache.
I'm using the following code for my request:
[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
// When you turn shouldRespectCacheControlHeaders off, the cache will store responses even if the server
// has explictly asked for them not be be cached (eg with a cache-control or pragma: no-cache header)
[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
NSURL *officesUrl = [NSURL URLWithString:#"http://www.example.com/example.json"];
ASIHTTPRequest *officesRequest = [ASIHTTPRequest requestWithURL:officesUrl];
[officesRequest setDefaultResponseEncoding:NSUTF8StringEncoding];
[officesRequest addRequestHeader:#"Cache-Control" value:#"no-cache"];
// Always ask the server if there is new content available,
// If the request fails, use data from the cache even if it should have expired.
[officesRequest setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];
[officesRequest setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[officesRequest setDelegate:self];
[officesRequest startAsynchronous];
EDIT:
Two images to show the different headers from HTTPScoop. First image is a fresh download with no cached content. Second image I have uploaded new and modified data.
First:
Second:
EDIT2: Added logs
https://gist.github.com/1139351
I was expecting way more debug output than that, I'm not sure why you got so little.
I think you are just going to have to step through the response processing and see why it decides the cached version is okay to use. The code's pretty easy to follow.
Try setting a breakpoint on useDataFromCache in ASIHTTPRequest.m to start with and canUseCachedDataForRequest, particularly when called from readResponseHeaders.

Retrieve file size from web server

Looking for a way to retrieve a file size from a web server using cocoa/foundation. I know one can use NSURLconnection which will return NSURLResponse that contains the file size. Is there any other way to get the size. I'm looking for a synchronous way of doing it so when i do [myClass getsize] the size is returned.
Thanks
You can use a NSMutableURLRequest to send a HTTP HEAD request (there’s a method called setHTTPMethod). You’ll get the same response headers as with GET, but you won’t have to download the whole resource body. And if you want to get the data synchronously, use the sendSynchronousRequest… method of NSURLConnection.