The doc of URLComponents.init(url:resolvingAgainstBaseURL:)
says:
Returns the initialized URL components object, or nil if the URL could not be parsed.
Knowing that:
I assume that the initialization of URLComponents
will fail when the URL is conforming to RFC 1808/1738/2732 but not RFC 3986. What kind of URL is that? Any example?
The only hint I have so far as a difference may be related to different reserved characters?
Let's explore it from its source code, as Swift Foundation is open-source.
The URLComponents
initializer is implemented in apple/swift – URLComponents.swift and apple/swift-corelibs-foundation – URLComponents.swift and simply calls the initializer of NSURLComponents
.
The NSURLComponents
initializer is implemented in apple/swift-corelibs-foundation – NSURL.swift and simply calls _CFURLComponentsCreateWithURL
.
_CFURLComponentsCreateWithURL
is implemented in apple/swift-corelibs-foundation – CFURLComponents.c and does:
CFURLCopyAbsoluteURL
_CFURLComponentsCreateWithString
which calls:
_CFURIParserParseURIReference
+ a failable _CFURIParserURLStringIsValid
CFURLCopyAbsoluteURL
is implemented in apple/swift-corelibs-foundation – CFURL.c and only fails for:
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
if ( base && CFURLIsFileReferenceURL(base) && !CFURLHasDirectoryPath(base) ) {
// 16695827 - If the base URL is a file reference URL which doesn't end with a slash, we have to convert it to a file path URL before we can make it absolute.
base = CFURLCreateFilePathURL(alloc, base, NULL);
if ( !base ) {
// could not convert file reference URL to file path URL -- fail will NULL
return NULL;
}
}
#endif
The implementation of CFURLCreateFilePathURL
is in opensource.apple.com/source/CF – CFURL.c, and my understanding is that it will only fail if there is no scheme or no path, which shouldn't be possible as we previously tested for a file scheme or file existence with CFURLIsFileReferenceURL
.
_CFURIParserParseURIReference
is implemented in apple/swift-corelibs-foundation – CFURLComponents_URIParser.c and will only fail if the URL length is more than 2 GB, which I believe is unrelated to RFC specifications.
_CFURIParserURLStringIsValid
will essentially call _CFURIParserValidateComponent
for each component and fail for invalid characters or escape sequences. This is possibly the most relevant part.
Now, with a bit of experiments, we know we need a scheme (for instance, https://
or simply a://
) and we play with the reserved characters to come up with examples such as:
// OK
let url = URL(string: "a://@@")!
// CRASH
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
Trying the alternative initializer of URLComponents
will also fail, so don't try to think it's different:
// CRASH
let components = URLComponents(string: url.absoluteString)!
"a://@@"
is an example of valid NSURL but invalid RFC 3986.
On a side note, some Swift people seem to wish for the future to unify the support of URL and URLComponents (no more RFC differences) as seen in URL.swift:
// Future implementation note:
// NSURL (really CFURL, which provides its implementation) has quite a few quirks in its processing of some more esoteric (and some not so esoteric) strings. We would like to move much of this over to the more modern NSURLComponents, but binary compat concerns have made this difficult.
// Hopefully soon, we can replace some of the below delegation to NSURL with delegation to NSURLComponents instead. It cannot be done piecemeal, because otherwise we will get inconsistent results from the API.
I'm not sure how they plan to do this, as it would mean that either URL(string: "a://@@")
would fail or URLComponents(string: "a://@@")
would succeed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With