NSURL URLWithString:relativeToURL: is clipping relative url

13,753

Solution 1

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 /

Solution 2

You have two problems here:

Firstly, the string /files/search is an absolute path since it starts with a slash. Resolving it against any existing URL will ignore the existing path.

Secondly, https://api.service.com/v1 does not have a trailing slash to indicate it's a directory. Any strings resolved against it will always ignore the v1 portion.

To conclude, you need that combo of a relative path — files/search — and directory base URL — https://api.service.com/v1/.

Share:
13,753

Related videos on Youtube

Pipo
Author by

Pipo

Updated on September 16, 2022

Comments

  • Pipo
    Pipo over 1 year

    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?

  • Daij-Djan
    Daij-Djan almost 11 years
    @downvoter please explain why ... is it because of the leading /? I get that and therefore edited it and up voted mike.. but please leave comment whenever you down vote
  • Daij-Djan
    Daij-Djan almost 10 years
    again: latest down voter would you please leave a comment so I can fix it if needed
  • Johnykutty
    Johnykutty over 8 years
    the baseURL needs to end in a / and the relative url shouldn't start with a / this is absolutely correct:). I was struggling with some problem wrt base url and path. Can you add the link for [RFC1808]