Uploading Photo with ASIHTTPRequest - file-upload

I'm using ASIHTTPRequest to upload a photo with PHP. The PHP side is proven to work(I'm using it for android), and I'm trying to get the iOS component to work.
Here is my upload:
NSString *myurl = #"http://mydomain.tld/php/upload.php?casenum=";
myurl = [myurl stringByAppendingFormat: casenumber];
NSString *fixedURL = [myurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSString stringWithFormat:#"%#",fixedURL];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSData *imageData = UIImageJPEGRepresentation(image1.image, 90);
[request setData:imageData withFileName:#"myphoto.jpg" andContentType:#"image/jpeg" forKey:#"file"];
[request setCompletionBlock:^{
NSString *responseString = [request responseString];
NSLog(#"Response: %#", responseString);
}];
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Error: %#", error.localizedDescription);
}];
[request startAsynchronous];
Ive found this on the internet and when I run it, it fails with the error 2012-01-17 10:52:16.939 MyApp[30373:707] Error: NSInvalidArgumentException
From many of the documentation and examples I've found online, this should work, but it isn't, as you can see with the exception. Any help at ironing out the kinks? If you need any other information, I'll gladly post it.

There would appear to be a couple of errors in the way that you're producing the NSURL. Firstly, it's only the parameters that need escaping, not the whole URL, so
NSString *myurl = #"http://mydomain.tld/php/upload.php?casenum=";
myurl = [myurl stringByAppendingFormat: casenumber];
NSString *fixedURL = [myurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
should be
NSString *myurl = #"http://mydomain.tld/php/upload.php?casenum=";
NSString *escapedCasenumber = [casenumber stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
myurl = [myurl stringByAppendingFormat:escapedCasenumber];
Secondly, you're then trying to assign an NSString to an NSURL, so
NSURL *url = [NSString stringWithFormat:#"%#",fixedURL];
should be
NSURL *url = [NSURL urlWithString:myurl];
Finally, the second argument passed to UIImageJPEGRepresentation should be a float value between 0.0 and 1.0, so I'm guessing
NSData *imageData = UIImageJPEGRepresentation(image1.image, 90);
should be
NSData *imageData = UIImageJPEGRepresentation(image1.image, 0.9);
If it still doesn't work after these changes, then do as JosephH suggests and use the debugger to identify exactly which line is causing the exception

Related

Reddit API ios modhash/cookie issue

Im' trying to submit to Reddit via my iOS app. I can login fine and am sent back a modhash and a cookie which I save via NSUserDefaults.
The issue is when I post the data I keep getting "USER_REQUIRED" as the response, even though I have included the modhash in the post and set my session cookie. I have even included the following in my app delegate:
[[NSHTTPCookieStorage sharedHTTPCookieStorage]
setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
But it still doesn't work. Here is my code:
-(void) post {
NSString *modhash2 = [[NSUserDefaults standardUserDefaults]
objectForKey:#"modhash"];
NSString *urlString = [NSString
stringWithFormat:#"https://ssl.reddit.com/api/submit"];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *contentType = [NSString stringWithFormat:#"application/x-www-form-urlencoded;"];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
[request addValue:redditCookie forHTTPHeaderField:#"Cookie"];
[request setHTTPMethod:#"POST"];
NSString *httpBody = [NSString stringWithFormat
:#" ?uh=%#&kind=link&url=%#&sr=%#&title=%#&r=%#&api_type=json",
modhash2,
#"www.google.com",
#"test",
#"Google.com",
#"test"];
[request setHTTPBody:[httpBody dataUsingEncoding:NSASCIIStringEncoding]];
NSURLResponse* response;
NSError* error = nil;
NSData* result = [NSURLConnection
sendSynchronousRequest:request
returningResponse:&response
error:&error];
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:result
options:NSJSONReadingMutableContainers
error:nil];
NSDictionary *responseJSON = [json valueForKey:#"json"];
NSLog(#"RETURN: %#",responseJSON);
}
Any ideas?

Posting an url i"m getting Invalid request

What would be the reason for getting Invalid Request when we are posting an URL to server in iOS SDK. the URL what i am sending is correct and the data what I'm posting is also correct.
I tried in RestClient also even though I'm getting same error Invalid Request in that also.
Can any one help me what would be the reason for it.
Thanks in advance.
- (NSURLConnection *) executeAsyncHttpPost :(NSString *) baseURL :(NSString *) method
:(id) jsonParams :(int)callerTag
{
NSLog(#"jsonParams: %#", jsonParams);
NSString *urlstr = [NSString stringWithFormat:#"%#", baseURL];
urlstr = [urlstr stringByAppendingFormat:method];
NSLog(#"urlstr: %#", urlstr);
NSString *postLength = [NSString stringWithFormat:#"%d", [jsonParams length]];
NSURL *pUrl = [NSURL URLWithString:urlstr];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:pUrl];
NSData *requestData = [[NSData alloc] initWithData:[jsonParams dataUsingEncoding:NSASCIIStringEncoding]];
NSString* myString;
myString = [[NSString alloc] initWithData:requestData encoding:NSASCIIStringEncoding];
NSLog(#"myString: %#", myString);
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody: requestData];
self.tag = callerTag;
return [super initWithRequest:request delegate:delegateResponder];
}
The JSON you are posting might be invalid. Please validate it using this. There should be no character outside the { }.
Just post the following string instead of the current JSON
EDIT:
{"jsonRequest" :{"methodName":"CheckUserExist","username":"giriraj.vyas#dotsquares‌​.com","password":"233444"}}

EXC_BAD_ACCESS error occured when using stringWithFormat

this is my header section:
#interface RootViewController : UIViewController
{
NSString *status_id;
}
in the controller file, i am assigning the variable:
- (void)updateStatus
{
NSURL *url = [NSURL URLWithString:#"http://localhost/RightNow/API/status.json"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
NSString *response = [NSString alloc];
NSError *error2;
NSData* data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error2];
status_id = [json objectForKey:#"id"];
}
now, when i try to use the status_id again, i get the error
- (IBAction)likeClick:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://localhost/RightNow/API/vote"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setRequestMethod:#"POST"];
[request setPostValue:status_id forKey:#"id"]; //The error comes here
[request setPostValue:#"like" forKey:#"vote"];
[request startSynchronous];
}
sorry about my bad english.
please help me, thank you!
[json objectForKey:#"id"]; will return the object in autorelease pool. You either need to send a copy message to it like
status_id = [[json objectForKey:#"id"] copy];
and release it when appropriate (if not using ARC)

NSURLConnection closes early on GET

I'm working on a method to centralize my URL connections for sending and receiving JSON data from a server. It works with POST, but not GET. I'm using a Google App Engine server and on my computer it'll handle the POST requests and return proper results (and log appropriately), but I get the following error when I try the request with a GET method:
Error Domain=kCFErrorDomainCFNetwork Code=303 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)" UserInfo=0xd57e400 {NSErrorFailingURLKey=http://localhost:8080/api/login, NSErrorFailingURLStringKey=http://localhost:8080/api/login}
In addition, the GAE dev server shows a "broken pipe" error, indicating that the client closed the connection before the server was finished sending all data.
Here's the method:
/* Connects to a given URL and sends JSON data via HTTP request and returns the result of the request as a dict */
- (id) sendRequestToModule:(NSString*) module ofType:(NSString*) type function:(NSString*) func params:(NSDictionary*) params {
NSString *str_params = [NSDictionary dictionaryWithObjectsAndKeys:func, #"function", params, #"params", nil];
NSString *str_url = [NSString stringWithFormat:#"%#%#", lds_url, module];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str_url]];
NSData *data = [[NSString stringWithFormat:#"action=%#", [str_params JSONString]] dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:type];
[request setHTTPBody:data];
[request setValue:[NSString stringWithFormat:#"%d", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Error: %#", error);
NSLog(#"Result: %#", [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]);
return [result objectFromJSONData];
}
A sample call would be:
NSDictionary *response = [fetcher sendRequestToModule:#"login" ofType:#"GET" function:#"validate_email" params:dict];
Again, this works with a POST but not a GET. How can I fix this?
In my case i was not calling [request setHTTPMethod: #"POST" ]
I think the root cause is you have an invalid URL.
JSON encoding will include things like '{', '}', '[' and ']'. All of these need to be URL encoded before being added to a URL.
NSString *query = [NSString stringWithFormat:#"?action=%#", [str_params JSONString]];
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", str_url, query]];
To directly answer your question:
According to CFNetwork Error Codes Reference the error is kCFErrorHTTPParseFailure. This means the client failed to correctly parse the HTTP response.
The reason why is that a GET doesn't include a body. Why would you want to submit JSON in a GET anyways?
If the target api returns data only you pass it in the url params.
If you want to send data and "get" a response use a post and examine the body on return.
Sample Post:
NSError *error;
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#:%#/XXXX/MVC Controller Method/%#",self.ServerName, self.Port, sessionId ];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
// hydrate the remote object
NSString *returnString = [rdc JSONRepresentation];
NSData *s10 = [returnString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:s10];
NSURLResponse *theResponse = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&error];
NSString *message = [[NSString alloc] initWithFormat: #"nothing"];
if (error) {
message = [[NSString alloc] initWithFormat:#"Error: %#", error];
} else {
message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
NSLog(#"%#", message);
return message;

What's the equivlent code for stringWithContentsOfURL using a NSURLRequest?

NSURL *url = [NSURL URLWithString:escapedUrlString];
NSString *responseString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
But, I was reading online that I should probably be using an NSURLRequest instead if I want to add a timeout. The first code works fine, but the second code always returns #"" (not nil, just ""). Anyone have any suggestions?
I also read that the NSURLConnection takes care of any sort of web compression that might be done whereas NSURLRequest won't handle that, so I thought I better just go for the more well rounded solution.
http://lists.apple.com/archives/cocoa-dev/2009/Oct/msg01921.html
NSString *escapedUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *responseString;
NSURLResponse *response;
NSError *error;
NSURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL URLWithString:escapedUrlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:5]; // 5 second timeout?
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]){
NSLog(#"Recieved String Result: %#", responseString);
} else {
NSLog(#"Response String is null!");
}
Thanks for the good suggestions. The code magically worked this morning, so I'm guessing my webserver went down or something last night.