ASIFormDataRequest has empty POST body - objective-c

I had a working MacOS application that was making a POST to a server. I changed the URL of the POST and things stopped working.
I downloaded Tuffcode (a sniffer), which shows me that when using the new URL, the POST BODY is empty!
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:#"url1"];
//NSURL *url = [NSURL URLWithString:#"url2"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setDelegate:self];
[request addRequestHeader:#"Content-Language" value:#"en"];
[request addRequestHeader:#"Content-Type" value:#"application/x-www-form-urlencoded"];
[request addRequestHeader:#"Connection" value:#"keep-alive"];
[request addRequestHeader:#"Cookie" value: [NSString stringWithFormat:#"botcust2=%#", sn]];
[request setShouldAttemptPersistentConnection:NO];
[request addPostValue:[input stringValue] forKey:#"input"];
[input setStringValue:#""];
[request startAsynchronous];
}
Switching from url1 to url2 goes from a well formed POST BODY to an empty POST BODY. How could that be? How can the URL determine what gets sent?
At first I thought it was the new server that did not interpret the POST correctly, but if Tuffcode is correct, the application doesn't even send the data??
Or maybe there is something I don't know about how HTTP works? I am confused...
Some logs:
2011-07-29 12:28:36.018 ChatBot[6764:707] [STATUS] Starting asynchronous request <ASIFormDataRequest: 0x10188d420>
2011-07-29 12:28:36.021 ChatBot[6764:6403]
==== Building an application/x-www-form-urlencoded body ====
input=hello
==== End of application/x-www-form-urlencoded body ====
2011-07-29 12:28:36.027 ChatBot[6764:6403] [CONNECTION] Request <ASIFormDataRequest: 0x10188d420> will not use a persistent connection
2011-07-29 12:28:36.280 ChatBot[6764:6403] [STATUS] Request <ASIFormDataRequest: 0x10188d420> finished uploading data
2011-07-29 12:28:36.374 ChatBot[6764:6403] [STATUS] Request <ASIFormDataRequest: 0x10188d420> received response headers
2011-07-29 12:28:36.375 ChatBot[6764:6403] [STATUS] Request <ASIFormDataRequest: 0x10188d420> finished downloading data (0 bytes)
2011-07-29 12:28:36.376 ChatBot[6764:6403] [STATUS] Request finished: <ASIFormDataRequest: 0x10188d420>

Why are you setting the string to null right after you post?
[request addPostValue:[input stringValue] forKey:#"input"];
[input setStringValue:#""];
It's possible that the compiler is switching the order of those two lines and you are submitting that null string. Why don't you try running it with the 2nd line removed?

A little after the fact, but I've just run into something similar. Like you I had a ASIHTTPRequest setup to work with a previous instance of an application but in the new version the POST was empty (no data sent); I knew the server on the other end was working fine (same code, but new hosting/URL) so I knew it couldn't be that.
After playing with it for a bit I remembered that the old URL was submission.php, but this time it was it's own folder (so just /submission/), adding index.php to the end of my new URL magically made things work again; so I guess it just didn't like not having a file at the end of the URL.
tl;dr - make sure your submission URL's end with a file name (ie: index.php or similar)
nbsp

Related

Server not properly receiving POST request from ASIFormDataRequest in Objective-C

I'm trying to use an ASIFormDataRequest in my iPhone application to send a video I have just recorded to a server, along with a string that I can use to ID who the video belongs to. The code for doing so is here:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *urlvideo = [info objectForKey:UIImagePickerControllerMediaURL];
NSString *urlString=[urlvideo path];
NSLog(#"urlString=%#",urlString);
NSString *str = [NSString stringWithFormat:#"http://www.mysite.com/videodata.php"];
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSData *patientData = [_patientCode dataUsingEncoding:NSUTF8StringEncoding];
[request setFile:urlString forKey:#"video"];
[request setData:patientData forKey:#"patientcode"];
[request setRequestMethod:#"POST"];
[request setDelegate:self];
[request startSynchronous];
NSLog(#"responseStatusCode: %i",[request responseStatusCode]);
NSLog(#"responseString: %#",[request responseString]);
[picker dismissViewControllerAnimated:YES completion:nil];
}
Everything seems to work correctly, I get back a status code of 200 and the method finishes as expected. However, nothing seems to be received by the php file on the server. I added this line to my server-side php code:
echo(count($_POST));
This returns 0, so it seems as though nothing is actually getting posted by the ASIFormDataRequest. I feel like there might be some simple step I am missing as I have never used the ASIFormDataRequest before, but any help would be greatly appreciated.
EDIT: I changed the setData:patientData to setPostValue:_patientCode and now that part of the post is getting sent correctly, so it seems as though setPostValue works but setData and setFile do not.
You should use -addData:forKey: and -addFile:forKey: instead of -setData:forKey: and -setFile:forKey:.
Other than that, check the debug output when you compile with DEBUG_FORM_DATA_REQUEST.
You should be sending a multipart/form-data request when using -addFile:forKey: and a application/x-www-form-urlencoded request when using -addPostValue:forKey:.
Does your server handle multipart/form-data requests?
I ended up finding the answer while reading something else and noticing that they did something interesting: The file I uploaded was simply going into the $_FILES array, not the $_POST array. I also changed [request setData:patientData forKey:#"patientcode"]; to [request setPostValue:_patientCode forKey:#"patientCode"]; and then that appeared in the $_POST array as I wanted so I was able to get both the string I was sending and the file I was sending in my php script.

ASIFormDataRequest: unable to send file to server using asynchronous request

I would like to send a file asynchronously to the server; however, it seems like when I do send the request to the server. The server gives me a HTTP code: 200, which is OK but no file is being uploaded to the server.
However, when I leave it to synchronous... it works perfectly. Weird..
Any ideas would be greatly appreciated,
- (void) sendCSVtoServer: ( Session * ) archive_session {
NSLog(#"file name: %#", [archive_session getFile]);
NSURL *url = [NSURL URLWithString:#"http://xx.x.xxx.xxx:3000/xxx/xxxxxxxx"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue: [archive_session getEmail] forKey:#"email"];
[request addFile: [archive_session getFile] forKey:#"csv"];
[request setDelegate:self];
[request startSynchronous];
}
Thanks!
You are setting a delegate, but you mention you did not implement any of those methods. ASIFormDataRequest extends ASIHTTPResquest, and therefore inherits all its properties.
You will have to implement methods decalred in ASIHTTPRequestDelegate, at least
- (void)requestFinished:(ASIHTTPRequest *)request;
and
- (void)requestFailed:(ASIHTTPRequest *)request;
Maybe others depending on your needs.
Your upload is probably still working (can you check your server?), but, when you send the request asynchronously, you don't have any way to determine if the request has succeeded or failed; right now you are just sedning and forgetting.
All the methods declared in ASIHTTPRequestDelegate.h are marked as optional, which is why the debugger, compiler, and runtime is not complaining.

NSMutableURLRequest http status code 413

I have a web service. I use it to accept a base 64 string representation of a small (thumbnail size) image. This web service works awesome when using it with Fiddler and manually posting the request. When I run the same request with NSMutableURLRequest (or ASIHTTPRequest), it always returns a 413 status code (413 is Request Entity is Too Large).
Why would NSMutableURLRequest cause it to come up with a 413, whereas Fiddler returns 200 every time?
Here is my NSMutableURLRequest code. I could really use a push, if anybody has any ideas.
//the image request
NSMutableURLRequest *imageRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:POST_IMAGE_API_URL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:240.0];
//the post parameters
[imageRequest setHTTPMethod:#"POST"];
[imageRequest setHTTPBody:[imageMessage dataUsingEncoding:NSUTF8StringEncoding]];
[imageRequest setValue:#"text/xml" forHTTPHeaderField:#"Content-Type"];
//a few other things
NSURLResponse* imageresponse;
NSError *imageerror;
NSData* imageresult = [NSURLConnection sendSynchronousRequest:imageRequest returningResponse:&imageresponse error:&imageerror];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)imageresponse;
NSLog(#"imageresponse: %d", httpResponse.statusCode);
When I see this bit of your code:
//the image request
NSMutableURLRequest *imageRequest =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:POST_IMAGE_API_URL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:240.0];
I'm guessing you have some whacky characters in your "POST_IMAGE_API_URL" #define, most likely in the parameters that you're passing along.
You need to URL encode the URL string you pass to your URL request.
Try doing:
// assuming POST_IMAGE_API_URL starts with a "#" character
NSString * yourURLAsString = [NSString stringWithString: POST_IMAGE_API_URL];
NSURL * yourEncodedURL = [yourURL stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
and pass "yourEncodedURL" in as a parameter to the URLRequest.
I found a solution for this. The issue was not on the Apple end, but on the IIS end. There is an additional parameter for IIS hosted applications (one of which being my WCF service) beyond what is specified in the WCF's web.config file that specifies the "uploadReadAheadSize" for each service. I increased this and the 413 went away. Interestingly enough, I didn't get this error when sending the HTTP request from Fiddler on a desktop client on the same network as the server where the service resides. Basically, I had the solution to this guy's problem but not his context. My solution was his context.

ASIHTTPRequest how to recognize finished request and failed request?

In my application, i have a button wich calls an ASIHTTPRequest. The request goes fine and i receive an response string. But when the request finishes, it always goes to the method: requestFinished. And i also got a requestFailed method. But even when i give a wrong link, the request finsihes and never fails.. Why is this? This is my code:
-(void)fetchForm:(id)sender {
NSURL *URL=[NSURL URLWithString:#"http://www.mydomain.nl/testGet.php"];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:URL] autorelease];
[request setDelegate:self];
[request setDidFailSelector:#selector(requestFailed:)];
[request startAsynchronous];
}
-(void)requestFinished:(ASIHTTPRequest *)request {
NSLog(#"Request Success!");
}
-(void)requestFailed:(ASIHTTPRequest *)request {
NSLog(#"Request Failed!");
}
EDIT:
I read a little documentation on the ASIHTTPRequest website. And i came to the conclusion that i need to see for myself if there is an error code. i do this with:
int statusCode = [request responseStatusCode];
if (statusCode == 404) {
NSLog(#"Statuscode 404 has occured!");
}
There are several conditions that might affect error reporting with HTTP requests. From ASIHTTP's viewpoint, if the request object can be successfully built, sent, and a some kind of response is received, then everything is ok.
In my case, for example, my ISP has a proxy that will return an error page with many not existing URLs and sometimes even with ill-formed URLs. In such cases, ASIHTTP will not fail. I don't know if this is also your case, but it was for me.
If you look at the file ASIHTTPRequest.m and search for failWithError, you will see all the cases where ASIHTTP will trigger the mechanism that leads to the didFailSelector to be called. You might even set a breakpoint in the failWithError method to see if it is called.
EDIT:
In a sense ASIHTTPRequest mechanism is very basic and covers failures at the network level. If you receive a response then it is an application level failure and you have to deal with it.
First thing is checking the HTTP status code:
int statusCode = [request responseStatusCode];
NSString *statusMessage = [request responseStatusMessage];
This will allow you to identify 404, 500, and so on.
If this does not work and the server does not send an error code, then the only way to go about it is parsing the response you receive and, if it does not contain the data you were waiting for, fail.
try this one -
[request setDidFailSelector:#selector(requestFailed:)];
try this:-
[request setDidFinishSelector:#selector(requestFinished:)];
[request setDidFailSelector:#selector(requestFailed:)];
Write these two lines and then try.

Getting SHOUTcast metadata on the Mac

I'm creating an application in Objective-C and I need to get the metadata from a SHOUTcast stream. I tried this:
NSURL *URL = [NSURL URLWithString:#"http://202.4.100.2:8000/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request addValue:#"1" forHTTPHeaderField:#"icy-metadata"];
[request addValue:#"Winamp 5/3" forHTTPHeaderField:#"User-Agent"];
[request addValue:#"audio/mpeg" forHTTPHeaderField:#"Content-Type"];
[NSURLConnection connectionWithRequest:request delegate:self];
I would have to get the headers from this request in order to get the information, right? Unfortunately it keeps returning these headers:
Date = "17 Apr 2010 21:57:14 -0200";
"Max-Age" = 0;
What I'm doing wrong?
I found an answer to this question. Simply append a 7.html at the end of the URL and parse the file.
I.E.
http://38.96.148.138:7534/7.html
Fernando Valente's solution for this problem
http://www.fvalente.org/blog/2012/03/15/shoutcast-metadata-the-easy-way/
It seems that shoutcast does not follow HTTP exchange standards and its response headers and body are not separated by two newlines. NSURLConnection/NSURLResponse are unable to parse out the headers; however, connection:didReceiveResponse: is still fired, just with an empty NSURLResponse. This becomes clear if we take a look at data coming in connection:didReceiveData:. The first chunk received will contain metadata headers.