Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opening a non-standard URL in a Cocoa app

In an application that I'm writing I have some code like this:

NSWorkspace* ws = [NSWorkspace sharedWorkspace];
NSString* myurl = @"http://www.somewebsite.com/method?a=%d";

NSURL* url = [NSURL URLWithString:myurl];

[ws openURL:url];

The main difference being that myurl comes from somewhere outside my control. Note the %d in the URL which isn't entirely correct and means that URLWithString fails, returning nil.

What is the "correct" way of handling this? Do I need to parse the string and properly encode the arguments? Or is there some clever method in Cocoa that does all the hard work for me?

like image 583
Stephen Darlington Avatar asked Sep 05 '08 14:09

Stephen Darlington


3 Answers

I'm not sure if this is exactly what you're looking for, but there is a method in NSString that will sanitize a URL:

stringByAddingPercentEscapesUsingEncoding:

like image 108
amrox Avatar answered Nov 20 '22 06:11

amrox


I think the behaviour here is correct, because %d is not a valid component of a URL (% is the escape, but expects two hex characters to follow it).

You can't just URL encode the URL as given to you, because that would encode the /s and ?s as well, which you don't want.

So, the question is, what's the correct behaviour here?

Perhaps you would want it to be turned into...

http://www.somewebsite.com/method?a=%25d

(i.e. the % is encode to the encoded version of % in a URL, so when method gets the input, it sees a as being set to %d)

I don't think there's any library function which will do that sort of thing for you, since there's no 'correct' way to do it. About he only correct thing you can do is return an error message saying the URL you were given is invalid (just as URLWithString is)


If you wanted to try to handle the input, I guess you would need to search the URL for any % symbols which are not immediately followed by two hex characters, and then replace the % with %25 in that case. That should be quite possible with a regular expression, though I suspect there may be some additional complexities if your URLs start containing encoded versions of characters outside the ASCII character set.

like image 35
Matt Sheppard Avatar answered Nov 20 '22 08:11

Matt Sheppard


Unfortunately you need to be smarter than what is provided by Apple :

stringByAddingPercentEscapesUsingEncoding:

This will escape all invalid URL characters so that "http://foo.com/hey%20dude/", which is valid, becomes "http://foo.com/hey%2520dud/", which is not what we want.

According to apple documentation : http://developer.apple.com/library/mac/documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html#//apple_ref/c/func/CFURLCreateStringByAddingPercentEscapes

I made an NSURL category which does the right thing and works with odd string such as ones with partial encoding (i.e. "http://foo.com/hey dude/i%20do%20it/").

Here is the code:

@interface NSURL (SmartEncoding)
+ (NSURL *)smartURLWithString:(NSString *)str;
@end

@implementation NSURL (SmartEncoding)

+ (NSURL *)smartURLWithString:(NSString *)str
{
    CFStringRef preprocessed = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (CFStringRef)str, CFSTR(""), kCFStringEncodingUTF8);
    if (!preprocessed) 
        preprocessed = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (CFStringRef)str, CFSTR(""), kCFStringEncodingASCII);

    if (!preprocessed)
        return [NSURL URLWithString:str];

    CFStringRef sanitized = CFURLCreateStringByAddingPercentEscapes(NULL, preprocessed, NULL, NULL, kCFStringEncodingUTF8);
    CFRelease(preprocessed);
    NSURL *result = (NSURL*)CFURLCreateWithString(NULL, sanitized, NULL);
    CFRelease(sanitized);
    return [result autorelease];
}

@end

It works fine with UTF8 string encoded and ASCII ones.

like image 1
nverinaud Avatar answered Nov 20 '22 07:11

nverinaud