0

I tried to pass these characters to server, for example *()$

I have coded the NSUrl this way:

NSString *partialURL = [NSString stringWithFormat:@"/%@", commentBody];
NSString *fullURL = [NSString stringWithFormat:@"%@%@", CONST_URL, partialURL];
NSString *encStr = [fullURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:encStr];

But then, the commentBody passed in the url still has *()$ things and not encoded into utf8.

What is the correct way to do it? Thanks!

Rendy
  • 5,572
  • 15
  • 52
  • 95
  • Rendy, you imply here, that you want to percent encode the URL. Generally you only want to percent encode the parameters that you later add to a URL, not the whole URL. For example, `?` or `&` are valid URL characters, but are not valid (unless percent encoded) a parameter of a URL, you really should percent encode them. I only mention it because your above code suggests you're percent encoding the whole URL, which you probably don't want to do (unless the URL in question is, itself, a parameter to some other URL, which I assume is unlikely in this case). – Rob Feb 04 '13 at 05:52
  • Yes Rob, you are correct, I just realized that I only need to encode the parameter, not whole URL. I will update my post :) – Rendy Feb 04 '13 at 06:57

1 Answers1

1
NSString * test = (NSString *) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 
                                                                            (CFStringRef)validUrl,
                                                                            NULL, 
                                                                            (CFStringRef)@";/?:@&=$+{}<>,",
                                                                            kCFStringEncodingUTF8);

UPDATE

Hi @Rendy. Sorry for the quickie reply yesterday. I only had time to past a 1-liner before jumping off and had hoped it would be enough for you to correct the issue you were having.

You always want to encode the parameters of the URL. IF you have a URL that is a parameter to another URL or embedded in some XML; you'll want to encode the entire url (which means parameters get double-encoded - because you take a "valid" URL and escape it so it becomes a valid parameter in another URL (ie, : and & get escaped, so parameters don't mix together.)

If you like, you can add additional chars to the string below and they'll be replaced with percent-encoded values. I believe the string below already has you covered for the invalid values.

Here's a category on NSString:

@implementation NSString (encode)

+ (NSString*)stringEncodedAsUrlParameter:(NSString *)string
{
    NSString *newString = NSMakeCollectable(
                [(NSString *)CFURLCreateStringByAddingPercentEscapes(
                                                                     kCFAllocatorDefault,
                                                                     (CFStringRef)string,
                                                                     NULL, /* charactersToLeaveUnescaped */
                                                                     CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"),
                                                                     kCFStringEncodingUTF8
                                                                     ) autorelease]
                );

    if (newString) {
        return newString;
    }
    return @"";
}


- (NSString*)stringByEncodingAsUrlParameter
{
    return [NSString stringEncodedAsUrlParameter:self];
}

@end

Call it like this:

NSString * escapedParameters = [NSString stringEncodedAsUrlParameter:unescapedParameters];

Or:

NSString * escapedParameters = [unescapedParameters stringByEncodingAsUrlParameter];

Then add your properly escaped parameters to the end of your URL. If you encode the whole URL, you'll encode the "http://" portion and it won't work.

I originally copied the above from ASIHttpRequest, but any bugs added are mine.

Hope that helps! Best of luck!!

Dave
  • 7,552
  • 4
  • 22
  • 26
  • 1
    Don't forget `CFBridgingRelease` (or `__bridge_transfer`). – Rob Feb 04 '13 at 03:18
  • +1 for @Rob's `__bridge_transfer`. It takes me two weeks to discover that `__bridge` (as suggested by Xcode when I copy my non-ARC code to ARC-enabled project) cause memory leaks in this case. – howanghk Feb 04 '13 at 03:21
  • Thx, but one of my question is, for all characters I want to escape I need to list it here: `(CFStringRef)@";/?:@&=$+{}<>,"` ? So there is no othery way to automatically escape all those characters? – Rendy Feb 04 '13 at 03:59
  • @Rendy No, a call to `CFURLCreateStringByAddingPercentEscapes`, including that fourth parameter (the subset of valid RFC3986 characters that you want to encode because you're using them within a parameter) is the way to go. Note, you don't have to worry about other characters, because if they're not RFC3986 valid, they're already percent encoded. See the [`CFURLCreateStringByAddingPercentEscapes` documentation](https://developer.apple.com/library/ios/documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html#//apple_ref/doc/uid/20001206-CH1g-F16659). – Rob Feb 04 '13 at 05:59
  • Hi Rob, I tried to have this `Test !.'` but it gives me `Test%20!'.` instead.. The exclamation mark, full stop and apostrophe is not encoded. – Rendy Feb 04 '13 at 15:16
  • @Rendy The exclamation mark and full stop (period) don't need to be percent encoded, though you can have them encoded by adding them to that string. Personally, I include the apostrophe in the list of characters to encode. My list of "acceptable URL characters to encode" is `@"!*'();:@&=+$,/?%#[]"`, though I freely admit that this what I picked up from a random S.O. post. Looks like everyone uses their own. – Rob Feb 04 '13 at 15:41
  • @Dave I don't think that `NSMakeCollectable` reference is right (because we're not in GC). The preferred technique to transfer ownership to Objective-C object is `CFBridgingRelease` (previously `__bridge_transfer` was recommended). – Rob Feb 04 '13 at 15:43
  • Yup, the snippet is pre-arc, but will work; and if he can always tweak to suit his needs. – Dave Feb 04 '13 at 15:46
  • Hi all, bunch of thanks, now I can fully understand this function. @Rob: I still need to encode . and !, not sure why. – Rendy Feb 04 '13 at 16:01
  • @Rendy If you want to encode `.` and `!`, then just add those to your fourth parameter, if they're not there already. All I know that I just did a iOS request of PHP service and then parsed the responses from the server, and my web server parsed parameters with values containing periods and exclamation marks without escaping. But escaping is always safer than not, so go ahead and percent escape them if you need. In terms of why you need to encode `.` and `!`, neither is strictly required for parsing URLs, but there could be something in your server's code that requires it. – Rob Feb 04 '13 at 19:37
  • 1
    Hi Rob, yes I believe there is something in the server that needs both characters to be encoded. I can't check the code there because I don't have access. – Rendy Feb 05 '13 at 09:44