Question

I want to send imageUrl in POST parameter which can have &.e.g. imageUrl can be http://www.url.com?param1=edfef&param2=erfregreg.

Now If I send this directly to server then it will not consider any params after &. Other answers on SO suggest to replace & with %26. But that is not working. Because when I escape the whole POST param string then it will replace % in %26 with %25. i.e.http://www.url.com?param1=edfef%2526param2=erfregreg which makes url invalid.

Code to escape params :

NSMutableString *postParams = [NSMutableString stringWithFormat:@"imageUrl=%@&realName=%@, imageUrl, realName];
NSMutableString *escapeParams = (NSMutableString*)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,  (CFStringRef)postParams, NULL,(CFStringRef)@" !%?$#[]/+:@;*()'\"",kCFStringEncodingUTF8));   
self.postParameters = escapeParams;

Update : I tried below code, but not working.

// URL
NSString * url = [NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?width=250&height=250", fbId];

NSString *escapedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
    NULL,
   (__bridge CFStringRef) url,
    NULL,
    CFSTR("!*'();:@&=+$,/?%#[]\" "),
    kCFStringEncodingUTF8));

url = escapedString;

// Making REST API call to store user details in table.
NSMutableString *postParams = [NSMutableString stringWithFormat:@"imageUrl=%@&realName=%@", imageUrl, realName];
NSMutableString *escapeParams = (NSMutableString*)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,  (CFStringRef)postParams, NULL,(CFStringRef)@" !%?$#[]/+:@;*()'\"",kCFStringEncodingUTF8));
postParams = escapeParams;
NSString * getParams = ...;

// Code to call API.
.
.   // Setting up url and NSMutableURLRequest
.
NSData *myRequestData = [NSData dataWithBytes:[postParams UTF8String] length:[postParams length]];
[request setHTTPBody:myRequestData];
Was it helpful?

Solution 3

I used a workaround.

I escape the string using answer of alex-i and call API to save in database.

NSString *escapedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
    NULL,
   (__bridge CFStringRef) unescapedURL,
    NULL,
    CFSTR("!*'();:@&=+$,/?%#[]\" "),
    kCFStringEncodingUTF8));

Whenever I get it from database I replace %26 with & in url string.

OTHER TIPS

Here is a copy-paste code snippet that I use in all my projects it encodes perfectly

- (NSString *)urlencode:(NSString *)val {
    NSMutableString *output = [NSMutableString string];
    const unsigned char *source = (const unsigned char *)[val UTF8String];
    int sourceLen = strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (thisChar == ' '){
            [output appendString:@"+"];
        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
                   (thisChar >= 'a' && thisChar <= 'z') ||
                   (thisChar >= 'A' && thisChar <= 'Z') ||
                   (thisChar >= '0' && thisChar <= '9')) {
            [output appendFormat:@"%c", thisChar];
        } else {
            [output appendFormat:@"%%%02X", thisChar];
        }
    }
    return output;
}

I suggest you to use a NSString Categroy

Header

//#import "NSString+UrlEncode.h"
#import <Foundation/Foundation.h>

@interface NSString (UrlEncode)
- (NSString *)urlencode;
@end

Implementation

//#import "NSString+UrlEncode.m"
#import "NSString+UrlEncode.h"

@implementation NSString (UrlEncode)
- (NSString *)urlencode {
    NSMutableString *output = [NSMutableString string];
    const unsigned char *source = (const unsigned char *)[self UTF8String];
    int sourceLen = strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (thisChar == ' '){
            [output appendString:@"+"];
        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
                   (thisChar >= 'a' && thisChar <= 'z') ||
                   (thisChar >= 'A' && thisChar <= 'Z') ||
                   (thisChar >= '0' && thisChar <= '9')) {
            [output appendFormat:@"%c", thisChar];
        } else {
            [output appendFormat:@"%%%02X", thisChar];
        }
    }
    return output;
}
@end

Usage: import the category

#import "NSString+UrlEncode.h"

then

  param.urlencode 

the = needs to be escaped (url encoded) as well.

See this answer on how to encode correctly ("!*'();:@&=+$,/?%#[]\" ").

An easy solution for your problem that might work is not to use an application/x-www-urlformencoded content type, but instead to use JSON. That is, specify application/json as the value for the Content-Type header in your HTTP request and send the parameters as JSON:

So, first create a JSON from your parameters:

[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

NSDictionary* params = @{@"imageUrl": url, @"realName": name};

NSError* error;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];

Pass that JSON data as your request data.

Note:

Sending POST parameters as application/x-www-urlformencoded requires properly encoded parameters. How to precent encode the parameters is likely the most wrongly answered question on SO, though many incorrectly encoded parameters will work anyway on most servers.

The definitive answer how to encode correctly is here:

The algorithm as specified by w3c.

I've put an implementation of the above algorithm in Objective-C based on Core Foundation elsewhere on SO, including a convenient method which converts a NSDictionary to a NSData object, properly percent encoded.

However, given the above specification, it should be easy to implement it yourself - without using Core Foundation or Foundation, and thus becoming dependent on that Core Foundation implementation, which may break that algorithm when Core Foundation changes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top