iPhone ASIHttpRequest - can't POST variables asynchronously - iphone

Greetings,
I'm trying to simply POST data to a url using ASIHttpRequest.
Here is my code:
__block ASIHTTPRequest *request=[ASIHTTPRequest requestWithURL:url];
[request setPostBody:[NSMutableData dataWithData:[#"uname=Hello" dataUsingEncoding:NSUTF8StringEncoding]]];
[request setDelegate:self];
[request setCompletionBlock:^{
NSString *response=[request responseString];
UIAlertView *msg=[[UIAlertView alloc] initWithTitle:#"Response" message:response delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[msg show];
[msg release];
}];
[request setFailedBlock:^{
NSError *error =[request error];
}];
[request startAsynchronous];
Basically, my url is xxx.xxx.xxx.xxx/login.php, when I dump the PHP $_POST variable, I just get an empty array - i.e. no POST parameters are sent! The rest of the PHP is tested and working fine.
I've looked through the allseeing-i.com documentation and examples and can't seem to resolve this problem.
Any insight greatly appreciated.
Many thanks in advance,

I am having the exact same problem. I am using ASIHTTPRequest and trying to set my own POST data. I have tried both [request setPostBody:] and [request appendPostData:].
When I run these lines just before I start the request, I find that both the method and the data are what I expect.
NSLog(#"%#", [request requestMethod]);
NSLog(#"%#", [[[NSString alloc] initWithBytes:[[request postBody] bytes]
length:[[request postBody] length]
encoding:NSUTF8StringEncoding] autorelease]);
When I send it to the server, however, the request is made and logged but the POST data is empty.
I have, however, gotten my code working by switching to ASIFormDataRequest.
Reading the documentation, however, suggests to me that what you and I are doing should be working, so I suspect that is a bug in ASIHTTPRequest and I will contact the author to see if this is the case.
Update
One possibility is that the code is redirecting to another URL. In that case, the post data may be dropped. If that is the case, you can try using
[request setShouldUseRFC2616RedirectBehaviour:YES];⠀⠀⠀
which will allow the request to send the post data to the redirected URL.

I believe you need to setup the callback functions for async.
-(void)requestFinished:(ASIHTTPRequest *)request{
NSLog([request responseString]);
}
edit: looking again, u had some completion block code there... never seen that before, but maybe that takes care of what i posted above

Related

ASIDownloadCache security

I am caching some data using ASIDownloadCache as shown below.
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[request setSecondsToCache:60*60*24*30]; // Cache for 30 days, this will change to a db version check.
[request setDelegate:self]; // this calls the delegate function requestFinished
[request startAsynchronous];
I was wondering how secure that data was? for instance I know that someone with a jailbroken phone can access coredata sotrage.. but what about ASIDownloadCache? what would someone need to do to get to it? how can I protect it?
You don't even have to jailbreak to access it, see:
http://www.macroplant.com/iexplorer/
If you want to protect it, you'll need to encrypt it, and you will have to do this yourself or modify ASIDownloadCache to do it.
Given the decryption key will need to be present in your application this would really just be obfuscation though.

when is a response code received during a request for an image using ASIHTTPRequest?

When do I actually get my response code 200 for a valid request for an image? Is it after all of the data has been downloaded to my browser or which ever device is requesting the image?
I am using the library http://allseeing-i.com/ASIHTTPRequest/ to download images in my iPad app and using the download directly to a file option and then deleting the file if it was a 404 error or any other status code than 200.
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadDestinationPath:#"/Users/ben/Desktop/my_file.jpg"];
Problem is partial responses seem to be getting saved during slow connections so I end up with blank or corrupt images.
I decided instead to save the data stream to disk only after I received a status code of 200:
NSURL *url = [NSURL URLWithString: [[NSString stringWithFormat:kProductImagesURL, fileName] stringByAppendingString:tStamp]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setTimeOutSeconds:10];
[request startSynchronous];
int statusCode = [request responseStatusCode];
if (statusCode==200) {
NSData *responseData = [request responseData];
[responseData writeToFile:[savePath stringByReplacingOccurrencesOfString:#"%20" withString:#" "] atomically:YES];
}
I just want to make sure that the response code only comes back after the request has been completed and all of the data has been downloaded. I am 99% sure that is the case but can't afford another app release with an image bug like this in it.
There are two reasons you should probably consider switching to an asynchronous request. The first is, it frees up your main thread to interact with the user (even a modal spinner would be nice--otherwise it looks like your app has frozen).
Second, it gives you callbacks that only happen once the whole request is finished. I can't really explain only having gotten partial data with the code you showed, but I've never once had that problem using ASI's asynchronous methods.

iOS Development: Why do I always get the "A connection failure occurred" on the 1st attempt, but success on the next?

I'm using the ASIHTTPRequest lib in my iOS app to make RESTful requests to my Rails 3 web app. I seeing a weird and somewhat consistent error the 1st time I try to make a POST request to my web app, but then the POST request works fine the on the second attempt. The exact error is...
Error Domain=ASIHTTPRequestErrorDomain Code=1 "A connection failure occurred" UserInfo=0xb513740 {NSUnderlyingError=0xb5135a0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1005.)", NSLocalizedDescription=A connection failure occurred}
And here's my ASIHTTPRequest code for making the POST request...
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://myrails3app.heroku.com/tournaments/%d/register.json", tid]];
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setRequestMethod:#"POST"];
[request addPostValue:username forKey:#"username"];
[request setCompletionBlock:^
{
NSData *responseData = [request responseData];
NSLog(#"Success!");
}];
// Set the code to be called when the request fails
[request setFailedBlock:^
{
NSError *error = [request error];
NSLog(#"Error: %#", [error localizedDescription]);
}];
// Start the request
[request startAsynchronous];
It's worth mentioning that when it errors out, it errors out incredibly quickly! Also, for what it's worth, my Rail 3 app that I'm making the POST request to is hosted on Heroku. Your thoughts?
Thanks so much for your wisdom!
This issue I had a lot of hard time to figure out why. The problem resides in ASIHTTPRequest itself (iOS), not the rails code.
To make a long story short, the problem is specific to the use of persistent connection for every request sent by ASIHTTPRequest.
While this is good for GET requests, most server implementation does not allow persistent connection to be used with POST request.
I didn't really have time to investigate it deeply on the server side of things but I think that the problem resides with the 100-Continue header that should be sent (and which isn't) with request that has body attached to it (hence PUT/POST). If you want to have a deeper look at what I'm talking about go have a read at the spec sheet: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html
So the persistent connection used by ASIHTTPRequest wait for a 100 response to be sent, which is never sent. so it ends up being timed out.
A fix is to set persistentConnection to NO with your post requests like the following:
ASIHTTPRequest *req = [ASIHTTPRequest requestWithURL:url];
req.shouldAttemptPersistentConnection = NO;
Secure Connection Failed
An error occurred during a connection to login.yahoo.com.
SSL received a record with an incorrect Message Authentication Code.
(Error code: ssl_error_bad_mac_read)
The page you are trying to view can not be shown because the authenticity of the received data could not be verified.
Please contact the web site owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.
On iOS 5.1, even after upgrading ASIHTTPRequest to ASIHTTPRequestVersion = #"v1.8.1-61 2011-09-19" still needed:
ASIHTTPRequest *req = [ASIHTTPRequest requestWithURL:url];
req.shouldAttemptPersistentConnection = NO;
i also had to set response setHeader Connection to "close" in by Java servlet
response.setHeader("Connection", "close");

Twitter profile image upload in objective-c

I want to upload an image to my twitter profile using objective-c. I saw in the twitter API that I need to send a HTML post to http://twitter.com/account/update_profile_image.format and send the picture as a parameter. I am done with the authentication. I am stuck with the uploading. Maybe somebody can help me with sending the picture as a parameter?
You should be using NSURLRequests and NSURLConnection to perform the API requests. If this is true, all you need to do is create an NSMutableURLRequest, set it's URL to the Twitter image upload API URL, set the method to POST.
Then you'll need to create an NSData object to represent your image, which you can do using
NSData *myImageData = [[NSData alloc] initWithData:[myImage CGImage]];
I don't know what the parameter name is for Twitter's upload API, so for arguments sake, lets call it "image". The next thing you need to do is set the image data as the request's body for the "image" parameter, like this
NSString *bodyString = [NSString stringWithFormat:#"image=%#", [[[NSString alloc] initWithData:myImageData encoding:NSStringUTF8Encoding] autorelease]];
[myRequest setBody:bodyString];
Then you can just start your NSURLConnection with the request and it should upload.
If you’ve managed to get started, then this post on CocoaDev should help you set the uploading up. There’s a sample linked at the top too.
I recommend using ASIHTTPRequest
What is ASIHTTPRequest?
ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier. It is written in Objective-C and works in both Mac OS X and iPhone applications.
It is suitable performing basic HTTP requests and interacting with REST-based services (GET / POST / PUT / DELETE). The included ASIFormDataRequest subclass makes it easy to submit POST data and files using multipart/form-data.
See this blog post for an example
Somthing like this
// See http://groups.google.com/group/twitter-development-talk/browse_thread/thread/df7102654c3077be/163abfbdcd24b8bf
NSString *postUrl = #"http://api.twitter.com/1/account/update_profile_image.json";
ASIFormDataRequest *req = [[ASIFormDataRequest alloc] initWithURL:[NSURL
URLWithString:postUrl]];
[req addRequestHeader:#"Authorization" value:[oAuth oAuthHeaderForMethod:#"POST"
andUrl:postUrl andParams:nil]];
[req setData:UIImageJPEGRepresentation(imageView.image, 0.8)
withFileName:#"myProfileImage.jpg"
andContentType:#"image/jpeg" forKey:#"image"];
[req startSynchronous];
NSLog(#"Got HTTP status code from Twitter after posting profile image: %d", [req
responseStatusCode]);
NSLog(#"Response string: %#", [req responseString]);
[req release];

iPhone and ASIHTTPRequest - Unable to start HTTP connection

I am using the ASIHTTPRequest class in order to communicate with a web service and get a response. This is how I send a request to the server
NSString *str = [NSString stringWithFormat:#"%#verifyLogin.json", serverUrl];
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[request addRequestHeader:#"Content-Type" value:#"text/x-gwt-rpc; charset=utf-8"];
NSDictionary* data = [NSDictionary dictionaryWithObjectsAndKeys:emailId, #"username", pwd, #"password", nil];
[request appendPostData: [[data JSONFragment] dataUsingEncoding: NSUTF8StringEncoding]];
[request setRequestMethod:#"POST"];
[request setDelegate:self];
[request setDidFinishSelector: #selector(gotLoginResponse:)];
[request setDidFailSelector: #selector(loginRequestFailed:)];
[networkQueue addOperation: request];
[networkQueue go];
The control immediately goes to the error routine and the error description and domain are
Unable to start HTTP connection and ASIHTTPRequestErrorDomain
I can get the same request to work via a desktop tool for checking HTTP requests so I know the settings are all correct.
Can someone please tell me what I am missing here while sending the request?
Thanks.
As I commented earlier;
in your first line it says
"%verifyLogin.json". Shouldn't that
be; "%#verifyLogin.json" ????
For me I forgot to add http:// as i was testing locally. But after adding http it ran successfully
Can you check the status code of the request when it fails? I recently dealt with a JSON user authentication issue with ASI-HTTP-Request where the first request would always fail with Status Code 0 and some sort of underlying network connection failure (as if it wasn't connected to the internet, but clearly was).
I was able to solve it by setting that particular request to not attempt to use a persistent connection.
So try that first!