AFNetworking Overload a Post Parameter - objective-c

I am migrating from ASIHTTPRequest to AFNetworking and have run into an issue.
I am trying to hit an API with a request that overloads the post parameter. I was previously using ASIFormDataRequest for this and used this code to update 3 ids at the same time.
// ASIHTTPRequestCode
[request addPostValue:#"value1" forKey:#"id"];
[request addPostValue:#"value2" forKey:#"id"];
[request addPostValue:#"value3" forKey:#"id"];
Since AFNetworking uses an NSDictionary to store key value pairs, it doesn't seem straight forward how to do this. Any ideas?

I can't immediately see a direct way to do this with AFNetworking, but it is possible to do.
If you look at the code for AFHTTPClient requestWithMethod, you'll see this line, which is the one that sets up the request body to contain the parameters:
[request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]];
Basically you could pass an empty dictionary to requestWithMethod for the parameters, then it returns, call request setHTTPBody yourself, making up the query string yourself in a similar way to the way AFQueryStringFromParametersWithEncoding does it.

You can build the request this way:
NSURL *url = [NSURL URLWithString:#"http://www.mydomain.com/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *postValues = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%#,%#,%#",#"value1",#"value2",#"value3"] forKey:#"id"];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"/path/to/your/page.php" postValues];

I was facing a similar issue but solved it by updating the url. I added the parameters i need to send with the url and set the "parameters to nil"
so the url became something like
server\url.htm?data=param1&data=param2&data=param3
and sent nil as paramDictionary
[request setHTTPBody:[AFQueryStringFromParametersWithEncoding(nil, self.stringEncoding) dataUsingEncoding:self.stringEncoding]];

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.

NSURLRequest doesn't send cookies

I'm developing a newsstand application and use NSURLRequest to download issue assets.
NSArray *contents = [issue.tableOfContents objectForKey:kSNTableOfContentsContents];
NSHTTPCookie *cookie;
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSLog(#"HERE GO MY COOKIES");
for (cookie in [cookieJar cookies]) {
NSLog(#"%#", cookie);
}
for (NSDictionary *contentItem in contents) {
NSString *contentURL_string = [contentItem objectForKey:kSNTableOfContentsRemoteURL];
NSURL *contentURL = [NSURL URLWithString:contentURL_string];
NSString *fileName = [contentItem objectForKey:kSNTableOfContentsContentsURL];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:contentURL];
NKAssetDownload *asset = [newsstandIssue addAssetWithRequest:request];
[request release];
....
[asset downloadWithDelegate:self];
....
}
When the first for loop is executed my cookies appear to be in NSHTTPCookieStorage, but when actual requests are sent, there are no cookie information in headers. I use CharlesProxy to look that up. Could anyone please give some advice what might be causing this issue?
From this thread, the magic incantation appears to be:
NSDictionary * headers = [NSHTTPCookie requestHeaderFieldsWithCookies:
[cookieJar cookies]];
[request setAllHTTPHeaderFields:headers];
(Warning: untested code.)
This will convert your cookie jar into an array of cookies, then to an NSDictionary of headers, and finally, staple those headers to your request. This is comparable to doing it manually, as Adam Shiemke linked in the question errata, but much cleaner in my opinion.
As per the documentation, you may also want to check HTTPShouldHandleCookies to see if your default cookie policy is being used properly.
On iOS projects I found the ASIHTTPRequest very useful for this kind of problems. It does things like authentication and cookies a lot better that the build-in functions:
http://allseeing-i.com/ASIHTTPRequest/

How to use the token given from google reader api to view unread list in objective c

I am making a Google Reader App and so far I have been able to receive the sid, auth, and use those to get a token from http://www.google.com/reader/api/0/token?client=clientName.
My next step if I am correct is to send a GET request using this token to a url that will return me a list of unread messages.
Problem is I do not know what url to use or how to send this GET request using the ID's i have.
Can someone please show me some code that actually does this correctly in objective c.
Assuming you're using a NSURLRequest in Objective-C you can set a custom header like this:
NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] initWithURL:url]
autorelease];
[request setValue:[NSString stringWithFormat:#"GoogleLogin auth=#%", token]
forHTTPHeaderField:#"Authorization"];
This is assuming you have two strings defined already, the URL and the token.
The URL you want is http://www.google.com/reader/atom/user/-/state/com.google/read
I've written a PHP library to interact with Google Reader's API feel free to dig around there. Specifically line 523 is relevent to this question. The library is up to date with their latest authorization changes.
NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] initWithURL:url]autorelease];
[request setValue:[NSString stringWithFormat:#"GoogleLogin auth=#%", token]
forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"GET"];
responseStr = [[NSString alloc]initWithData:recieveData encoding:NSASCIIStringEncoding];
NSLog(#"message %#", responseStr);