哪种URL不符合RFC 3986标准,但符合RFC 1808、RFC 1738和RFC 2732标准?

9
URLComponents.init(url:resolvingAgainstBaseURL:)的文档说明如下:
返回初始化的URL组件对象,如果无法解析URL则返回nil。
需要知道的是:
Swift URL / NSURL用于基于RFC 1808、RFC 1738和RFC 2732的URL:https://developer.apple.com/documentation/foundation/nsurl Swift URLComponents / NSURLComponents用于基于RFC 3986的URL:https://developer.apple.com/documentation/foundation/nsurlcomponents 我认为当URL符合RFC 1808/1738/2732但不符合RFC 3986时,URLComponents的初始化将失败。这种类型的URL是什么?有示例吗?
到目前为止,唯一的提示可能与不同的保留字符有关。
1个回答

12

让我们从源代码开始探索吧,因为Swift Foundation是开源的。

  1. The URLComponents initializer is implemented in apple/swift – URLComponents.swift and apple/swift-corelibs-foundation – URLComponents.swift and simply calls the initializer of NSURLComponents.

  2. The NSURLComponents initializer is implemented in apple/swift-corelibs-foundation – NSURL.swift and simply calls _CFURLComponentsCreateWithURL.

  3. _CFURLComponentsCreateWithURL is implemented in apple/swift-corelibs-foundation – CFURLComponents.c and does:

    • a failable copy with CFURLCopyAbsoluteURL
    • a failable creation with _CFURLComponentsCreateWithString which calls:
      • _CFURIParserParseURIReference + a failable _CFURIParserURLStringIsValid
  4. 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.

  5. _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.

  6. _CFURIParserURLStringIsValid will essentially call _CFURIParserValidateComponent for each component and fail for invalid characters or escape sequences. This is possibly the most relevant part.

现在,经过一些实验,我们知道需要一个方案(例如,https://或简单地说是a://),并且我们使用保留字符来创建如下示例:
// OK
let url = URL(string: "a://@@")!
// CRASH
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!

尝试使用URLComponents的替代初始化程序也会失败,因此不要尝试认为它与原来的不同:
// CRASH
let components = URLComponents(string: url.absoluteString)!

结论

"a://@@" 是一个有效的 NSURL 例子,但是无效的RFC 3986。


值得一提的是,一些 Swift 开发人员似乎希望将 URL 和 URLComponents 的支持统一起来(不再有 RFC 差异),可以在 URL.swift 中看到:

// 未来实现说明:
//NSURL(实际上是提供其实现的CFURL)在处理某些更为奇特(以及一些不那么奇特)的字符串时会有相当多的怪癖。我们希望将其中很多转移到更现代的NSURLComponents上,但是二进制兼容性问题使这很难实现。
//希望不久之后,我们可以用 NSURLComponents 代替部分 NSURL 的委托,而不是分别使用它们。否则,API 将产生不一致的结果。

我不确定他们计划如何实现这一点,因为这意味着要么 URL(string: "a://@@") 将失败,要么 URLComponents(string: "a://@@") 将成功。


6
真的很有趣,谢谢!这也帮助我解决了一个在我的代码覆盖率报告中一直困扰我的红线——尽管这是一个非常特殊的情况! - Tim
聪明的香肠 :-) - pikuseru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接