NSURL URLWithString:relativeToURL: is clipping relative url

Pipo picture Pipo · May 16, 2013 · Viewed 13.5k times · Source

I'm trying to implement an iOS app, which uses RestKit. In all examples I've seen so far the following code is used to create the URLs:

NSURL *baseURL = [NSURL URLWithString:@"https://api.service.com/v1"];
NSURL *relativeURL = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL];

But then [relativeURL absoluteString] will return https://api.service.com/files/search.

So I tried a few examples:

NSURL *baseURL1 = [NSURL URLWithString:@"https://api.service.com/v1/"];
NSURL *baseURL2 = [NSURL URLWithString:@"https://api.service.com/v1"];
NSURL *baseURL3 = [NSURL URLWithString:@"/v1" relativeToURL:[NSURL URLWithString:@"https://api.service.com"]];

NSURL *relativeURL1 = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL1];
NSURL *relativeURL2 = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL2];
NSURL *relativeURL3 = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL3];
NSURL *relativeURL4 = [NSURL URLWithString:@"files/search" relativeToURL:baseURL1];
NSURL *relativeURL5 = [NSURL URLWithString:@"files/search" relativeToURL:baseURL2];
NSURL *relativeURL6 = [NSURL URLWithString:@"files/search" relativeToURL:baseURL3];

NSLog(@"1: %@", [relativeURL1 absoluteString]);
NSLog(@"2: %@", [relativeURL2 absoluteString]);
NSLog(@"3: %@", [relativeURL3 absoluteString]);
NSLog(@"4: %@", [relativeURL4 absoluteString]);
NSLog(@"5: %@", [relativeURL5 absoluteString]);
NSLog(@"6: %@", [relativeURL6 absoluteString]);

And this is the output:

1: https://api.service.com/files/search
2: https://api.service.com/files/search
3: https://api.service.com/files/search
4: https://api.service.com/v1/files/search
5: https://api.service.com/files/search
6: https://api.service.com/files/search

So the only example returning what I want is #4. Can anyone explain why?

Answer

Daij-Djan picture Daij-Djan · May 16, 2013

I read [RFC1808] which defines the normative algorithm for resolving relative URLs

2 issues:

  1. the relative url may not start with a / or it is considered to be absolute:

    Step 4: If the embedded URL path is preceded by a slash "/", the
       path is not relative and we skip to Step 7."
    
  2. when the base url ends with a non-slash. everything from the last slash on is skipped

    Step 6: The last segment of the base URL's path (anything
       following the rightmost slash "/", or the entire path if no
       slash is present) is removed and the embedded URL's path is
       appended in its place.  The following operations are
       then applied, in order, to the new path:"
    

so that explains it. the baseURL needs to end in a / and the relative url shouldn't start with a /