Skip to content

Instantly share code, notes, and snippets.

@Andrewpk
Last active June 27, 2016 16:19
Show Gist options
  • Save Andrewpk/5d5159c60f6401b17e456103b430f061 to your computer and use it in GitHub Desktop.
Save Andrewpk/5d5159c60f6401b17e456103b430f061 to your computer and use it in GitHub Desktop.
//
// main.m
// NSURLWeirdness
//
// Created by Andrew Kehrig on 6/24/16.
// Copyright © 2016 dudid llc. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSURL (BetterRelativeToURLSupport)
+(instancetype)betterURLWithString:(NSString*)relativeString relativeToURL:(NSURL*)baseURL;
@end
@implementation NSURL (BetterRelativeToURLSupport)
+(instancetype)betterURLWithString:(NSString*)relativeString relativeToURL:(NSURL*)baseURL
{
//It's called 'relativeToURL' for a reason right? Even if this baseURL doesn't end in a /
//we should fix it because the developer said this is the base URL so the entire URL
//should be treated as the base.
if ([baseURL.absoluteString characterAtIndex:(baseURL.absoluteString.length - 1)] != '/' ) {
baseURL = [NSURL URLWithString:[baseURL.absoluteString stringByAppendingString:@"/"]];
}
//So this is an interesting part.
//The only requirements are that the string conform to RFC2396, that it not be nil,
//and that it will be interpreted relative to the baseURL. So why, if the baseURL
//has additional path components, do we nix those and interpret it, in a more absolute
//style? We probably shouldn't - the user asked for a baseURL with additional path
//components, so if they exist, we should interpret the relativeString relative
//with the entire baseURL and all included path components.
if ([baseURL pathComponents].count > 1 && [relativeString characterAtIndex:0] == '/') {
relativeString = [@"." stringByAppendingString:relativeString];
}
return [NSURL URLWithString:relativeString relativeToURL:baseURL];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *basePath = @"https://some.awesome.host.com:9999/api/v1";
NSString *relativePath = @"/account/user/1";
NSURL *baseURL = [NSURL URLWithString:basePath];
NSURL *unexpectedURL = [NSURL URLWithString:relativePath relativeToURL:baseURL];
NSRange range = NSMakeRange(0, 1);
NSString *moreRelativePath = [relativePath stringByReplacingCharactersInRange:range withString:@"./"];
NSURL *potentiallyExpectedURL = [NSURL URLWithString:moreRelativePath relativeToURL:baseURL];
NSLog(@"\n---------\n\nunexpected URL absoluteString: %@\n", unexpectedURL.absoluteString);
NSLog(@"potentially \"expected\" URL absoluteString: %@\n", potentiallyExpectedURL.absoluteString);
NSLog(@"expected URL absoluteString: %@\n", [NSURL betterURLWithString:relativePath relativeToURL:baseURL].absoluteString);
/** example output
---------
unexpected URL absoluteString: https://some.awesome.host.com:9999/account/user/1
2016-06-24 02:28:09.283 NSURLBugXcode7[29155:385606] potentially "expected" URL absoluteString: https://some.awesome.host.com:9999/api/account/user/1
2016-06-24 02:28:09.283 NSURLBugXcode7[29155:385606] expected URL absoluteString: https://some.awesome.host.com:9999/api/v1/account/user/1
Program ended with exit code: 0
*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment