Ampersand in POST request causing havoc - iphone

I have a simple POST coming from my iphone app. Its working fine, except passing an ampersand causes the backend to break - it's almost like its treating it like a GET request (ampersands seperate the variable names). Do I need to do some kind of encoding first? Here is the code:
NSString *content = [[NSString alloc] initWithFormat:#"data=%#&email=%#", str, emailAddress.text];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.myurl.com/myscript.php"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[content dataUsingEncoding:NSISOLatin1StringEncoding]];
// generates an autoreleased NSURLConnection
[NSURLConnection connectionWithRequest:request delegate:self];

I had this issue in iOS7 and the accepted answer didn't work at all (actually, that is my standard when sending data to the backend). The ampersand was breaking in the backend side, so I had to replace the & by %26. The backend was being done in python and the code was legacy and was using ASI.
Essentially I have done the following:
NSString *dataContent = [NSString stringWithFormat:#"text=%#",
[json stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
dataContent = [dataContent stringByReplacingOccurrencesOfString:#"&"
withString:#"%26"];

ByAddingPercent....... will not work as & is a valid URL character.
I needed to send a JSON with & in it, it is the same idea though;
NSString *post = [NSString stringWithFormat:#"JSON=%#", (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)jsonString, NULL, CFSTR(":/?#[]#!$&’()*+,;="), kCFStringEncodingUTF8))];
"jsonString" towards the end is what is converted.

Edit: As stringByAddingPercentEscapesUsingEncoding: should be used to encode parts of the query, not the whole one, you should be using another method instead.
Unfortunately, Foundation doesn't provide such a method, so you need to reach to CoreFoundation:
- (NSString *)stringByURLEncodingString:(NSString *)string {
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)string,
NULL, // or (__bridge CFStringRef)(#"[].")
(__bridge CFStringRef)(#":/?&=;+!##$()',*"),
kCFStringEncodingUTF8
);
}
You can use
- stringByAddingPercentEscapesUsingEncoding:
In your case it will look like this:
NSString * content = [[NSString alloc] initWithFormat:#"data=%#&email=%#", [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], [emailAddress.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
You can do this in this way, too:
NSString *dataStr = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *emailStr = [emailAddress.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *content = [[NSString alloc] initWithFormat:#"data=%#&email=%#", dataStr, emailStr];

I'm not sure if this will work in your case, but you could try %38 to try and encode the ampersand.

Related

How do I post images to reddit in iOS / Objective C?

I am trying to post an image to reddit; however, I only kind of know what I am doing. I am using objective c for my iphone app.
Prior to the code listed below I obtain a modhash and cookie by logging in prior to the upload and use NSLog to determine that I truly am receiving them. Then I use a JSON Parser to separate them into separate variables.
I was not sure what all of the POST argument values were supposed to be so I kind of guessed. The necessary arguments are uh, file, formid, header, ing_type, name, and sponsor.
The documentation for reddit api is http://www.reddit.com/dev/api I believe that I want to use the POST /api/upload_sr_img method...
NSURL *url = [NSURL URLWithString:#"http://www.reddit.com/api/upload_sr_img"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
NSString *httpBody = [NSString stringWithFormat:#"?uh=%#&file=%#&formid=''header=%#&img_type=%#&name=%#&sponsor=%#",modhash,UIImagePNGRepresentation(self.memeImage.image),#"test",#"png",#"Drew",#"Drew'sApp"];
[request setHTTPBody:[httpBody dataUsingEncoding:NSASCIIStringEncoding]];
NSURLResponse *response = NULL;
NSError *imgError = NULL;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&imgError];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingMutableContainers error:nil];
NSDictionary *responseJson = [json valueForKey:#"json"];
NSLog(#"response is: %#",response);
NSLog(#"imgError is: %#",imgError);
NSLog(#"result is: %#",result);
NSLog(#"json is: %#",json);
NSLog(#"responseJson is: %#",responseJson);
Could use any help I can get.
Also, I was not sure if I needed to send a content-type or even what it would be.
Thanks for your help.
Check this library: https://github.com/MattFoley/MFRedditPostController
You can use the provided UI or create your own.

iphone url escaping problems

Hi I have to send data to server via JSON and usually I do it like that:
NSMutableString * temp=[[NSMutableString alloc] initWithString:service_registra_inc];
//here I add more staff to temp
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:temp]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
but I get some error message that the url is wrong: something like url length but I have searched around and it means I have to escape my url si I have found this fonction that doesn't work for me:
NSString *temp2=(__bridge_transfer NSString*)CFURLCreateStringByAddingPercentEscapes(NULL,((CFStringRef)temp.UTF8String),NULL,NULL,kCFStringEncodingUTF8);
and there the program just stops and it says signal EXC_BAD_ACCess.
Well I don't really know how to transform mutable strings into CFStringRef so xcode just suggested the corrections for me but I don't really understand what is happening. Please help.... I have read the doc but it doesn't say how to cast NSSMutableString to CFStringRef and back or how to use the whole thing to create an NSURL object directly. Thks
Why are you using CFURL & CFStringRef functions here?
You could do what you are trying to do via NSString's stringByAddingPercentEscapesUsingEncoding: method. I've linked the documentation for you.
Something like:
NSMutableString * temp=[[NSMutableString alloc] initWithString:service_registra_inc];
// append your staff... errr, stuff here.
NSString * temp2 = [temp stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:temp2]];
[NSURLConnection alloc] initWithRequest:request delegate:self];
(don't forget to release things if you're not using ARC)
An NSString * is also a CFStringRef through a mechanism known as toll-free bridging and an NSMutableString * is also an NSString * through inheritance. So your second line of code should be:
NSString *temp2 = (__bridge_transfer NSString *)
CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)temp,
NULL,
NULL,
kCFStringEncodingUTF8);
Though in practice you might prefer:
NSString *temp2 =
[temp stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Which has the secondary advantage of returning an object with a non-owning reference, so you don't need to worry about releasing it even if you're not using ARC.

Problem creating url

I want to create a url as below
http://maps.googleapis.com/maps/api/directions/json?origin=Adelaide,SA&destination=Adelaide,SA&waypoints=optimize:true|Barossa+Valley,SA|Clare,SA|Connawarra,SA|McLaren+Vale,SA&sensor=false
I used the following code to create this
NSURL *jsonURL;
NSString *strurl = [[NSString alloc]initWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=Adelaide,SA&destination=Adelaide,SA&waypoints=optimize:true|Barossa+Valley,SA|Clare,SA|Connawarra,SA|McLaren+Vale,SA&sensor=false"];
jsonURL = [NSURL URLWithString:strurl];
[strurl release];
NSLog(#"json Url%#",jsonURL);
NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL];
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
if(jsonData == nil){
//NSLog(#"Data NIL .....");
}
else{
SBJSON *json = [[SBJSON alloc] init];
NSError *error = nil;
dic = [json objectWithString:jsonData error:&error];
[json release];
}
But every time I get jsonURL to be nil .
I think the problem is due to "|". Has someone come across same issue? If yes, can you help me out?
Try
[NSURL URLWithString:[strurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]
The documentation for URLWithString says:
The string with which to initialize the NSURL object. Must conform to RFC 2396.
... which e.g. mentions:
Other characters are excluded because
gateways and other transport agents
are known to sometimes modify such
characters, or they are used as
delimiters.
unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
Data corresponding to excluded
characters must be escaped in order to
be properly represented within a URI.
Thus escape them properly as slf suggested.
Also, just use a string constant for predefined strings:
NSString *strurl = #"http://....";
As for your URL issue, Georg is right:
NSURL *jsonURL = [NSURL URLWithString:#"http://maps.googleapis.com/maps/api/directions/json?origin=Adelaide,SA&destination=Adelaide,SA&waypoints=optimize%3Atrue%7CBarossa+Valley,SA%7CClare,SA%7CConnawarra,SA%7CMcLaren+Vale,SA&sensor=false"];
Fixed that issue for me.
However, the next bit:
NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL];
Is deeply troubling. You should never do synchronous data reads on the main thread. initWithContentsOfURL is going to spawn a synchronous NSURLConnection to go fetch that data and might return sometime before sunday, but you never know. (This method is ok for filesystem loads, where things are much more deterministic)
Look into an asynchronous loading API like NSURLConnection from Apple, or better yet ASIHTTPRequest, about which there is ample documentation online.
Happy webservicing!
I think, the root of cause is your string creating method.
NSString *strurl = [[NSString alloc]initWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=Adelaide,SA&destination=Adelaide,SA&waypoints=optimize:true|Barossa+Valley,SA|Clare,SA|Connawarra,SA|McLaren+Vale,SA&sensor=false"];
Try with ...
NSString *strurl = [[NSString alloc]initWithString:#"http://maps.googleapis.com/maps/api/directions/json?origin=Adelaide,SA&destination=Adelaide,SA&waypoints=optimize:true|Barossa+Valley,SA|Clare,SA|Connawarra,SA|McLaren+Vale,SA&sensor=false"];

iPhone encoding of non latin characters

I am trying to parse a JSON response of a GET request. When the characters, are latin no problem.
However when they are not latin the message doesn't come out correctly. I tried greek and instead of "πανος" i get "& pi; & alpha; & nu; & omicron; & sigmaf;"
The code I use for parsing the response is:
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"response %#", responseString);
// array from the JSON string
NSArray *results = [responseString JSONValue];
When I try to read the response from a website using ajax, everything is fine. The same applies when trying to send a GET request to the application servers with data from iphone. So when i transmit data to the server and read it from the website everything is fine. When i try to show the same data in the app, "Houston we have a problem".
Any clues?
EDIT: To avoid misunderstandings, it's not an issue of HTML, I just point out that for some readon utf-8 characters here are encoded correctly and automatically eg. "&pi" will be converted to "π", however objective c doesn't seem to do this on its own
There is a confusion I think.
π is an HTML entity which is unrelated to text encoding like UTF8 / Latin.
Read wikipedia for details about...
You need a parser to decode these entities like the one previously mentioned by Chiefly Izzy:
NSString+HTML category and method stringByReplacingHTMLEntities
Look at Cocoanetics NSString+HTML category and method stringByReplacingHTMLEntities method. You can find it at:
https://github.com/Cocoanetics/NSAttributedString-Additions-for-HTML/blob/master/Classes/NSString%2BHTML.m
Here's a pretty decent list of lot of HTML entities and their corresponding unicode characters.
Try to use this snippet of code:
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSString *decodedString = [NSString stringWithUTF8String:[responseString cStringUsingEncoding:[NSString defaultCStringEncoding]]];
NSLog(#"response %#", decodedString);
// array from the JSON string
NSArray *results = [decodedString JSONValue];
I have faced the same problem, but I solved it by changing the JSON parser. I have started using the SBJSONParser, and now I am getting the appropriate results. This is the code snippet, I have used
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"POST"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
SBJSON *parser=[[SBJSON alloc]init];
NSArray *JSONData = (NSArray*)[parser objectWithString:returnString error:nil];

iphone: NSMutableURLRequest returns strange characters for MS Word style apostrophe

We are pulling content off our website using XML/NSMutableURLRequest and sometimes it pulls through the "curly" style apostrophe and quotes, ’ rather than '. NSMutableURLRequest seems to hate these and turns them into the strange \U00e2\U0080\U0099 string.
Is there something that I can to do prevent this? I am using the GET method, so should I be somehow telling it to use UTF-8? Or, am I missing something?
UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
NSString *urlStr = [NSString stringWithFormat:#"%#",url];
NSURL *serviceUrl = [NSURL URLWithString:urlStr];
NSMutableURLRequest *serviceRequest = [NSMutableURLRequest requestWithURL:serviceUrl];
[serviceRequest setHTTPMethod:#"GET"];
NSURLResponse *serviceResponse;
NSError *serviceError;
app.networkActivityIndicatorVisible = NO;
return [NSURLConnection sendSynchronousRequest:serviceRequest returningResponse:&serviceResponse error:&serviceError];
NSURLConnection returns an NSData response. You can take that NSData response and turn it into a string. Then take this string, turn it back into a NSData object, properly UTF-8 encoding it along the way, and feed it to NSXMLParser.
Example: (Assuming response is the NSData response from your request)
// long variable names for descriptive purposes
NSString* xmlDataAsAString = [[[NSString alloc] initWithData:response] autorelease];
NSData* toFeedToXMLParser = [xmDataAsAString dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser* parser = [[[NSXMLParser alloc] initWithData:toFeedToXMLParser] autorelease];
// now utilize parser...
I would suggest replacing those characters using stringByReplacingCharactersInRange:withString: to replace the unwanted strings.
NSString *currentTitle = #"Some string with a bunch of stuff in it.";
//Create a new range for each character.
NSRange rangeOfDash = [currentTitle rangeOfString:#"character to replace"];
NSString *location = (rangeOfDash.location != NSNotFound) ? [currentTitle substringToIndex:rangeOfDash.location] : nil;
if(location){
currentTitle = [[currentTitle stringByReplacingOccurrencesOfString:location withString:#""] mutableCopy];
}
I've done this in the past to handle the same problem you describe.
Try using the stringByReplacingPercentEscapesUsingEncoding: