how to compress request using ASIFormDataRequest? - iphone

I'm trying to to send some post data to a Apache server from iPad application using the ASIHttp library.
actually I need to send huge data to the server and that means I need to compress the request body so I write some code to send the data and compress the request BUT there are no parameters received on the server !!!
the iOS code is :
NSURL * URL = [NSURL URLWithString:myURL];
ASIFormDataRequest *ASIRequest = [ASIFormDataRequest requestWithURL:URL];
ASIRequest.shouldCompressRequestBody=YES;
ASIRequest setPostValue:data forKey:#"data"];
[ASIRequest startSynchronous];
NSError *error = [ASIRequest error];
if (!error) {
NSString *response = [ASIRequest responseString];
NSLog(#"response %#" , response);
}
PS: if I removed the ASIRequest.shouldCompressRequestBody=YES; everything works fine and I can see the data but when use it I see nothing on the server
the request can be seen on the server but with no parameter
noway to send such data over GET method.
the server configuration are fine.
any solution ? any comment or idea can help ?

By default, most web servers do not support compression on POSTs. The accepted answer here does a really good job explainining it: Why can't browser send gzip request?
According to official documentation, this feature has only been tested with Apache servers.
EDIT:
Here is a code snipt that compresses the actual post data:
if ([self shouldCompressRequestBody]) {
NSError *err = nil;
NSData *compressedBody = [ASIDataCompressor compressData:[self postBody] error:&err];
if (err) {
[self failWithError:err];
return;
}
[self setCompressedPostBody:compressedBody];
[self setPostLength:[[self compressedPostBody] length]];
}
Source: http://forums.three20.info/discussion/77/tturlrequest-vs-asihttprequest/p1

Related

why can't my iphone app connect to my server?

i have a weird problem. so i've been working on an iphone app where a user can login, and upon logging in, the app would authorize the user by making an http GET request to the server. if the username and password is correct it return an authorization token (typical stuff).
the weird part is that when i test this locally, pointing the http request url to my local machine, it works fine. everything authorizes correctly and all data is returned correctly.
but today, i got the app stable enough that i decided to deploy rest api to my server, but when changed the http request url to my server url, the requests fails.
i thought maybe the server wasn't deployed correctly so i tested the http endpoints with the firefox rest client and everything seems to be working, authorization works, and data gets returned.
does anyone have any thoughts? i'm lost as to what the problem might be.
i'm using AFNetworking library to make the requests.
here's my code:
self.apiHttpClient = [[TKRHttpClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://mywebsite.com/api"]];
--------------
NSString *username = [usernameField text];
NSString *password = [passwordField text];
TKRHttpClient *httpClient = [TKRHttpClient sharedInstance];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"/user/auth" parameters:nil];
[request addValue:username forHTTPHeaderField:#"username"];
[request addValue:password forHTTPHeaderField:#"password"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if(response.statusCode == 200){
NSDictionary * headers = [response allHeaderFields];
NSString *token = [headers objectForKey:#"auth_token"];
NSLog(#"token was %#", token);
[[AppController sharedAppController] initializeDataForUserToken:token];
}else{
NSLog(#"upload failed!");
}
} failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , id JSON ) {
NSLog(#"code was: %i", response.statusCode);
if(response.statusCode == 401){
[errorMessage setText:#"Incorrect password or username"];
}
}];
[operation start];
i put in break points, and it seems that the request goes straight to the failure block. the line that says "NSLog(#"code was: %i", response.statusCode);" in the failure block prints out 200. but when i tail the logs on my server, no request was received.
any help would be greatly appreciated. can't figure out for the life of my why it would work against my local tomcat, but won't work when deployed to my server.
thanks in advance!
i found the reason for my problem thanks to #Brad's suggestion.
upon inspecting the request in charles, i found that the request was made as "http://mywebsite.com", then for path it was /user/auth. so the "/api" part was missing.
maybe this is the standard, i don't know, but it appears that AFHTTPClient's (my TKRHttpClient extends AFHTTPClient) initWithBaseURL really means the host URL. the "/api" part gets lopped off.
and the reason why it was working locally is because i deployed the app locally as root, so there was no "/api"
so two ways to fix this. 1. redeploy as app to server as root. or 2. change the line of code from:
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"/user/auth" parameters:nil];
TO:
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"api/user/auth" parameters:nil];
hopefully this helps anyone using AFNetworking in the future.

iPhone objective c Asyncron HTTPS request in NSThread

I need a good solution for my little issue.
What I have at the moment:
My App works with asyncron https request very well. At the moment the app uploads an JSON object, so far so good. After that I save the object in an sqlite database.
Now I have to change to determine what the received server response code is.
I will get an response code like 000 if the uploaded data was valid, and a code like 151 if not. For that I have to wait for the server response to save the response code in the database as well.
I experimented with NSThread, too. But that didn't work out as well as I expected.
Somebody any suggestions? I mean, it should be one of the most common things ;) I just don't see it.
thx, dominik
I usually use an NSOperationQueue to manage my communication. This lets you use a synchronous request instead of asynchronous, and handle the whole shebang in one method.
Example:
-(void)doIt {
NSInvocationOperation *op = [[[NSInvocationOperation alloc] initWithTarget:self selector:#selector(doIt_) object:nil] autorelease];
[opQueue addOperation:op];
}
-(void)doIt_ {
NSData *data;
NSMutableURLRequest *request;
NSURLResponse *response = nil;
NSError *error = nil;
// Build request to spec
data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error];
// do something with data
[self performSelectorOnMainThread:#selector(yadda) withObject:yaddayadda waitUntilDone:NO];
}
If you do use the asynchronous loading methods, you have to implement a delegate to catch the response data as it comes down, and do something with it when finished.
I recommend that you take a look at ASIHTTPRequest which is a wrapper for the CFNetwork API. Particularly look into the mechanism it offers for asynchronous HTTP requests, where you can define blocks to be executed once the request has completed or failed and can you can inspect the response data easily. Your code would be something like this:
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:#"POST"];
// add your json object to the request
[request setCompletionBlock:^{
int responseCode = [request responseStatusCode];
NSData *responseData = [request responseData];
// do whatever you want with this info
}];
[request setFailedBlock:^{
NSError *error = [request error];
// handle the error
}];
[request startAsynchronous];

ASIHTTPRequest with UIWebView

I need to connect to a protected site and try to use ASIHTTPRequest
Here is my code:
url = [NSURL URLWithString:#"http://myurl/page.aspx"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:username];
[request setPassword:password];
[request setDomain:domain];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
[webView loadHTMLString:[request responseString] baseURL:[request url]];
}
When I use NSLog to see [request responseString], I get the correct HTML, but the result is a blank white webview.
From the outgoing request warnings that little snitch displays, I see the initial request and one going to an external resource.
My guess so far is that the inital request correctly uses the authentication from ASIHTTPRequest and fetches the page, but the uiwebview will try to load the included .js files and since uiwebview is not authenticating, it will not render the page at all ...
Anybody knows how to fix my problem?
Have you tried ASIWebPageRequest? My guess is you have resources in that page that are not downloaded, like http://myurl/image.jpg
ASIHttpRequest runs asynchronously. You need to put your webview loading code into the ASIHTTPRequest callbacks. (requestFinished).
Add a method to your class as follows:
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSError *error = [request error];
if (!error) {
[webView loadHTMLString:[request responseString] baseURL:[request url]];
}
}
There is also a requestFailed method that you can use to trap additional errors, you should implement this as well. One or the other of these methods will be called once ASIHttpRequest completes.
Note you will probably also need to set the delegate on the request before making the asynch call. (so same place you set the auth stuff).
request.delegate = self;

Problem sending images POST

For several days, I look for what's wrong in my code but without success, and now I really want to know what's wrong.
The problem is that I want to send an UIImage from my Iphone to my server, but I receive a blank image on my server everytime... I'm not sure, but I think the problem come from the image that I convert. The UIImage come from the method takePicture.
Please check my code :
First I call takePicture and :
- (void)imagePickerController:(UIImagePickerController *)aPicker didFinishPickingMediaWithInfo:(NSDictionary *)info {
self.testImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
}
testImage is a property of my ViewController.
Then I make this to send the UIImage :
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(testImage)];
NSURL *url = [NSURL URLWithString:#"http://myserver/mytest.php"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addData:imageData withFileName:#"tmp.png" andContentType:#"image/png" forKey:#"userfile"];
[request setRequestMethod:#"POST"];
[request setDelegate:self];
[request startAsynchronous];
and to see the result :
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
NSLog(#"response: %#", responseString);
// Use when fetching binary data
NSData *responseData = [request responseData];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Request Failed Error: %#", error);
}
and then I receive a blank image on my server...
Please help me ='(
I think you're actually sending a URL encoded POST body, as opposed to a multi-part POST body, which is required to send data like you want. So you just need to do the following before you start the request:
request.postFormat = ASIMultipartFormDataPostFormat;
The issue came from the high resolution image. My connection was too slow. When I'm using wifi the code works.
Mate,
look at your code here:
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(testImage)];
you can change the picture quality by adding a number in the bracket for the dpi you would like it to be, for example, if i wanted it to be in 90 dpi quality i would have written it like this: [NSData dataWithData:UIImagePNGRepresentation(testImage,90)]
i noticed now that your picture is in .PNG format , i always worked with .JPEG and it worked
so i think you should give it a try...
good luck

Why does the activity indicator never finish when using ASIHTTPRequest?

I use ASIHTTPRequest to do http requests in my iPhone app. ASIHTTPRequet comes with that feature that starts the activity indicator when issuing a request and stops it when finished. The problem is, once I started a request the indicator never stops and keeps spinning as long as my app runs.
Here is my code, a little utility method that fetches some content from the web synchroniously (since it gets started in a different thread):
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL: [NSURL URLWithString: url]];
[request startSynchronous];
NSError *error = [request error];
NSString *response = nil;
if (error) {
NSLog(#"error %#", error);
return nil;
}
int statusCode = [request responseStatusCode];
response = [NSString stringWithString: [request responseString]];
NSLog(#"status code: %d response: %#", statusCode, response);
if (statusCode != 200) {
return nil;
}
return response;
The above code works just fine, I get the contents of the given URL as a NSString only the indicator keeps spinning. My question is: Why does the indicator never stop and how to fix it? Do I have to release some resources here?
This is a bug that was fixed very recently in the development version of ASIHTTPRequest:
http://github.com/pokeb/asi-http-request/commit/35ea592084145b3332861344f36b52dbcaafa351
(It only affects synchronous requests started on a secondary thread)
Can you try the same thing with an asynchronous request and see if that changes it? I use ASIHTTPRequest and I've never noticed this behavior, but I also never use synchronous requests.