AFNetworking downloading a file despite getting 304 Server response - objective-c

So I want to download a file from a webserver even though the server response is 304 Not Modified.
I use the AFURLSessionManager's downloadTaskWithRequest: progress: destination: completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) method which works fine for files which aren't modified. However if the server response is 304, it seems there is no valid filePath in completionHandler block and the error says "Request failed: not modified (304)".
I tried configurating AFURLSessionManager's requestCachePolicy to NSURLRequestReloadIgnoringLocalAndRemoteCacheData but that doesn't help: although filePath is set, the data can't be reconstructed from this filepath.
Can someone help me by maybe specifying what exactly would be the best practice for downloading a file with AFNetworking and Server response 304. Thanks in advance!

Nevermind I found the problem. I don't have to set the requestCachePolicy of the NSURLSessionConfiguration. I always added IF_MODIFIED_SINCE_HEADER to the request parameter of downloadTaskWithRequest:. Omitting this, it works.

Related

Restcomm Media Player fail to paly file on S3 with error 312

I have a file on AWS S3 that is public:
https://s3-eu-west-1.amazonaws.com/voxist-greetings/33631222504/33651291239_95113eed-386b-4264-a4cf-46182faae125COUCOU1.wav
Now when RVD try to play it I get:
INFO [org.mobicents.servlet.restcomm.interpreter.VoiceInterpreter] (RestComm-akka.actor.default-dispatcher-8586) MediaGroupResponse, succeeded: false jain.protocol.ip.mgcp.JainIPMgcpException: The IVR request failed with the following error code 312
I don't know why... The same file used to work with another name.
Thanks for any hint on how to debug this.
The problem seems to happen on Media Server side. More specifically, it seems the file cannot be opened for some reason.
Relevant code line can be found here.
Can you please take a tcpdump and share it, so we can see the MGCP Play request?
Hope this helps.
UPDATE:
Here is an example:
The 200 OK simply indicates that the MGCP transaction completed successfully. Now we need to dissect the notification (NTFY) sent from Media Server to RestComm, mainly the ObservedEvents parameter.
If you look at the picture, you will see the event triggered is an OperationFailed (of) with ReturnCode (rc) equal to 312, which is an error.
Relevant link to specs can be found here.
To summarise, Media Server receives the request to play the file (in this case a cached version of it) but if fails to open the URL for some reason.
Is the URL reachable from Media Server side?

Block set by setDataTaskWillCacheResponseBlock on AFHTTPSessionManager is never called

I develop an application that relies heavily on AFNetworking to load data from a private API into Mantle models. My API client is a singleton subclass of AFHTTPSessionManager.
I'm trying to implement a basic offline mode by leveraging NSURLCache. The approach is to modify the request's cache policy on dataTaskWithRequest:request:completionHandler to NSURLRequestReturnCacheDataDontLoad if the AFNetworkReachabilityManager says the network is not reachable.
While I can verify that this actually works by using breakpoints during tests, the requests themselves are not being cached. I verified this by downloading the application container from Xcode, and checking the Cache.db sqlite file, which was empty. I also verified that I was looking at the correct cache by manually creating a dummy NSCachedURLResponse and forcefully storing it in the cache using storeCachedResponse:forRequest. Then the dummy response did show up in the Cache.db sqlite file.
So, I think I narrowed down the problem to my "usual" responses not being cached. I can also modify the headers sent by the server API. What I intend to do here is set a header Cache-Control: private on the API responses (so as not to make the other clients that use this API cache responses they shouldn't), and modify this cache header in the block of setDataTaskWillCacheResponseBlock, but this block never fires.
I understand that the URL system may decide when to call URLSession:dataTask:willCacheResponse:completionHandler, which calls the block, based on some undocumented rules, mainly the presence of a Cache-Control header, and the response size/cache size ratio. But my response is a 145-byte JSON, and the Cache-Control header is set (I verified both via curl -v and inspecting the task parameter of the success block of my request.
I also tried a more aggressive cache header, Cache-Control: public, max-age=2592000, to see if this caches the response or at least calls the block, but the behaviour was exactly the same. I also checked the myAFHTTPSessionManagerSubclass.session.delegate property, which was indeed pointing to myAFHTTPSessionManagerSubclass, as expected.
I also tried overriding URLSession:dataTask:willCacheResponse:completionHandler directly in my subclass, but it still was not called. Setting a breakpoint on this same delegate method on AFURLSessionManager.m in the Pods directory also does not work, the execution never stops on the breakpoint.
I'm using version 2.5.4 of AFNetworking, according to my Podfile.lock file.
So, how to make my responses cache (preferably without setting agressive caching policies on the response), so I can implement a quick offline mode in my app?
EDIT: I also tried to create a NSURLSession to see if this would work. So, I created a simple Node.js server that just answers something simple and sets a cache header:
$ curl -v http://192.168.1.107:1337/
* Hostname was NOT found in DNS cache
* Trying 192.168.1.107...
* Connected to 192.168.1.107 (192.168.1.107) port 1337 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 192.168.1.107:1337
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Cache-Control: public
< Date: Thu, 11 Jun 2015 14:38:14 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
Hello World
And then created a simple view controller to test:
- (void)viewDidLoad {
[super viewDidLoad];
// Prime the cache
[NSURLCache setSharedURLCache:[[NSURLCache alloc] initWithMemoryCapacity:2*1024 diskCapacity:10*1024*1024 diskPath:#"mytestcache"]];
// The sleep is to be absolutely sure the cache did initialise
sleep(2);
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
[[session dataTaskWithURL:[NSURL URLWithString:#"http://192.168.1.107:1337"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Got response: %#", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
}] resume];
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *))completionHandler {
completionHandler(proposedResponse);
}
The response is correctly printed, but willCacheResponse is never called (I set a breakpoint). I tried checking the container again, and the mytestcache directory was created, but it was empty. I also tried Cache-Control: max-age=86400, to the same result.
( cross-posted to AFNetworking issues at: https://github.com/AFNetworking/AFNetworking/issues/2780 )
Well, I will surprise you - the code you wrote above is working just fine, ...but it's incorrect for what you're trying to achieve ;)
Reason is simply - delegate methods are not being called when you create requests by method dataTaskWithRequest:completionHandler:. You need to use method dataTaskWithRequest: instead.
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW1 - read first Note
Second thing is that NSURLSession just really sux when we talk about caching. You may face several issues in iOS 7.x/8.x. I faced such nightmare when I was implementing custom cache in my app, which eventually has nothing in common with NSURLCache. Also I decided to create my kind of framework based on NSURLSession and AFNetworking.
One of the issues on iOS 7 is creating NSURLSession with defaultConfiguration, the NSURLCache object will be different than global one - quite unexpected behaviour.
One of the issues on iOS 8 is that the POST requests are also being cached, which may compromise security of your app. BTW https://www.google.pl/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=nsurlcache+ios+8+broken
Maybe it does not answer your questions, but you should be aware of that strange behaviours and differences between iOS versions.
Honestly I recommend you to use AFHTTPRequestOperationManager instead of AFHTTPSessionManager, because at least NSURLConnection works like a harm with NSURLCache :)

NSMutableURLRequest cannot connect to local network

I am using AFNetworking to connect from an iOS v6.0 app to my local Cold Fusion 8 server, not on the same machine but on the same network and the connection times out. When I use an external public server it works fine.
I have tried the connection via IP address and it doesn't work.
I have tried an entry in the hosts file assigning a domain name to the IP address and this doesn't work either. Please see the error below.
I can however connect via a web browser just fine.
Also, the server side files are exactly the same. Versions of Cold Fusion are the same. The only difference that I can find are the public server is Win2003 with IIS6 and the local server is Windows7 with IIS7.
Any thoughts on why this would not work on a local network. Makes local development kind of difficult.
Here is the relevant code:
// load params
NSMutableDictionary *myParams = [[NSMutableDictionary alloc] init];
[myParams setValue:#"Hello" forKey:#"Parameter1"];
[myParams setValue:#"There" forKey:#"Parameter2"];
// Load the base URL into a URL object
// Changing this to an external public server works fine
NSURL *baseURL = [NSURL URLWithString:#"http://www.mylocalmachine.com/"];
// Create HTTP client and init with base url
AFHTTPClient *myHttpClient = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
// POST request to path with the parameters
NSMutableURLRequest *myRequest = [myHttpClient requestWithMethod:#"POST" path:#"myfile.cfm" parameters:myParams];
// Block response from the HTTP client request and pass it back to the calling object
AFJSONRequestOperation *myOperation = [AFJSONRequestOperation JSONRequestOperationWithRequest:myRequest
success:^(NSURLRequest *mySuccessRequest, NSHTTPURLResponse *mySuccessResponse, id mySuccessJSON)
{
// PROCESS THE SUCCESS RESPONSE;
}
failure:^(NSURLRequest *myFailureRequest, NSHTTPURLResponse *myFailureResponse, NSError *myFaliureError, id myFailureJSON)
{
// PROCESS THE FAILURE RESPONSE... AFTER 60 seconds the system will fallout to this block.
}];
// Create a queue object
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
// Add the operation object to the queue
[myQueue addOperation:myOperation];
The following is the error I get print the myFailureError object
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x8481000 {NSErrorFailingURLStringKey=http://www.mylocalmachine.int/myfile.cfm, NSErrorFailingURLKey=http://www.mylocalmachine.int/myfile.cfm, NSLocalizedDescription=The request timed out., NSUnderlyingError=0x9189e20 "The request timed out."}
Update----
I believe I have narrowed the issue down to what I beleive to be an issue with the iPhone simulator accessing IIS 7. It will access previous versions of IIS on the same network using the same code no problem.
The problem may be in the iPhone Simulator's User-Agent. I have tried to find a way to change the iPhone Simulator's User-Agent or allow the User-Agent in IIS 7 but can not seem to figure it out. The User-Agent the iPhone Simulator 6 is presenting is (iPhone Simulator; ios 6.0; Scale/2.00).
Does anyone know how to either allow this User-Agent on IIS 7 or change the User-Agent in the iPhone simulator?
Has anyone else seen this issue?
Thanks in advance,
Ed
Update----
Hi Everyone
Ok so I figured out how to change the User-Agent and Content-Type using the NSMutableURLRequest. I changed these to match what the browser would send, FireFox browser, and tried again to no avail. I still believe there is an issue with the configuration of IIS 7.5 but I can not find it...
Thanks for anyones help!!!
Ed
please try to remove last 2 lines of code and write
remove this
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperation:myOperation];
add this instead
[myoperation start];
and also write failure:nil before that ending square bracket(]) like
AFJSONRequestOperation *myOperation = [AFJSONRequestOperation JSONRequestOperationWithRequest:myRequest
success:^(NSURLRequest *mySuccessRequest, NSHTTPURLResponse *mySuccessResponse, id mySuccessJSON)
{
// PROCESS THE SUCCESS RESPONSE;
}
failure:^(NSURLRequest *myFailureRequest, NSHTTPURLResponse *myFailureResponse, NSError *myFaliureError, id myFailureJSON)
{
// PROCESS THE FAILURE RESPONSE... AFTER 60 seconds the system will fallout to this block.
}failure:nil];
let me know is it working or not...!!!!
Happy Coding!!!!!!
I have resolved this issue. I will post what the resolution was to hopefully help someone else with a similar issue.
Turns out the problem was AVG installed on the system that was running IIS 7. It was a difficult issue to determine because any other system could access the web server with out any problems. It was only specific with the iPhone simulator accessing the system running IIS7. Even Safari or FireFox running on the same Mac would work just fine. Now what within AVG was causing the problem... That is yet to be determined.
I truly hope this helps someone along the way!

JMeter File Upload with HTTP Put Method Not Working

The idea is to build a sampler in JMeter that will upload a file using the HTTP PUT method. I'm trying to follow the official documentation to specify the entire content body as a file with no parameter name.
What should happen: The file gets uploaded and the server returns 201: created
What actually happens:
java.lang.NullPointerException: charsetName
at java.lang.String.<init>(Unknown Source)
at java.lang.String.<init>(Unknown Source)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sendPutData(HTTPHC4Impl.java:1067)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:274)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:62)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1054)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1043)
at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java:416)
at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:271)
at java.lang.Thread.run(Unknown Source)
This seems to indicate that JMeter has a problem with filling out the body of a request. I can get rid of this error by specifying a parameter with the request, but I want the entire body to be the photo data. Here's the CURL line of what I want accomplished:
curl -u testuser:testpass "http://localhost:8080/photo" -T photo.jpg -H "content-type:image/jpeg"
I've tried setting the content-encoding to UTF-8 as I've seen in one post, but that changed nothing.
I'm running Java 1.7.0 on Windows 7 x64. Nothing of interest gets generated in jmeter.log, and wireshark tells me that JMeter isn't sending the request.
Any ideas? Thanks in advance.
Turns out it was a bug that the nice folks at JMeter were able to fix very quickly: https://issues.apache.org/bugzilla/show_bug.cgi?id=52897
Using the nightly build solved my problem, and by now it has probably made it into the release.
Use Raw HTTP Request to accomplish this. You may specify headers in Request Data and also specify file containing PUT body for convinience.
Some details may be found here
I was having issues with image uploads and found the answers here https://stackoverflow.com/a/2115944/455363.
After making the suggested changes here I had to re-record the transaction and make my edits and I was successfully able to upload files.
Hope this helps.

Can I include a custom XML file in my application for default content?

I want to load content into my application from a web server, but if the internet is not available, I would like the user to have access to either default or old, downloaded content. It will be XML formatted. I know how to download XML from the web server into my app and I can store the XML-as-string and reload. But, how do I "ship" the product with a default XML data file? I tried to create a new resource with add-to-project, but I cannot find the file in my application's directory.
Is this possible?
Ok, I am back on this task. I have my XML properly download from my webserver with a URL pointing to the server's file, however, when I detect the network is 'unreachable' I simply point the URL to my application's local XML and I get the following error. I cannot find detail description, but I think it is saying that the URL is pointing to an inaccessible location. Am I storing this resource in the wrong location? I think I want it in the HomeDirectory / Library??
Debug output
loadMyXml: /var/mobile/Applications/950569B0-6113-48FC-A184-4F1B67A0510F/MyApp.app/SampleHtml.xml
2009-10-14 22:08:17.257 MyApp[288:207] Wah! It didn't work.
Error Domain=NSXMLParserErrorDomain Code=5 "Operation could not be completed. (NSXMLParserErrorDomain error 5.)"
2009-10-14 22:08:17.270 MyApp[288:207] Operation could not be completed. (NSXMLParserErrorDomain error 5.)
Totally! Just include it into your project and make sure it's included in the "Copy Bundle Resources" phase. Then it will be copied into ./YourApp.app/Contents/Resources/. This will work on both Mac and iPhone.
You can easily retrieve it by doing something like this (assuming your file is named "MyXMLFile.plist"):
NSString * pathToMyXMLFile = [[NSBundle mainBundle] pathForResource:#"MyXMLFile" ofType:#"plist"];