swift 什么样的URL不符合RFC 3986,但符合RFC 1808,RFC 1738和RFC 2732?

bjg7j2ky  于 5个月前  发布在  Swift
关注(0)|答案(1)|浏览(66)

URLComponents.init(url:resolvingAgainstBaseURL:)的文档说:
返回初始化的URL组件对象,如果无法解析URL,则返回nil。
知道:

我假设当URL符合RFC 1808/1738/2732但不符合RFC 3986时,URLComponents的初始化将失败。这是什么类型的URL?任何示例?
唯一的提示,我迄今为止的差异可能与不同的保留字符?

628mspwn

628mspwn1#

[更新自iOS 17和macOS 14]

自iOS 17以来,URL/NSURL现在符合RFC 3986,不再符合过时的RFC 1738/1808。因此,不再有URL成功构建但URLComponents失败的示例。

iOS 17 / macOS 14之前版本的答案

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

  1. URLComponents初始化器在apple/swift - URLComponents.swift和apple/swift-corelibs-foundation - URLComponents.swift中实现,并简单地调用NSURLComponents的初始化器。
  2. NSURLComponents初始化器是在apple/swift-corelibs-foundation - NSURL.swift中实现的,它只调用_CFURLComponentsCreateWithURL
  3. _CFURLComponentsCreateWithURL在apple/swift-corelibs-foundation -CFURLclassifients.c中实现,并执行以下操作:
  • 使用CFURLCopyAbsoluteURL的可失败副本
  • 使用_CFURLComponentsCreateWithString创建一个可失败的创建,它调用:
  • _CFURIParserParseURIReference + a failable _CFURIParserURLStringIsValid
  1. CFURLCopyAbsoluteURL在apple/swift-corelibs-foundation - CFURL.c中实现,仅在以下情况下失败:
#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

字符串
CFURLCreateFilePathURL的实现是在opensource.apple.com/source/CF – CFURL.c中实现的,我的理解是,只有在没有模式或没有路径的情况下,它才会失败,这是不可能的,因为我们之前用CFURLIsFileReferenceURL测试了文件模式或文件存在。

  1. _CFURIParserParseURIReference是在apple/swift-corelibs-foundation -CFURLparents_URIParser. c中实现的,只有在URL长度超过2 GB时才会失败,我相信这与RFC规范无关。
  2. _CFURIParserURLStringIsValid本质上会为每个组件调用_CFURIParserValidateComponent,并因无效字符或转义序列而失败。这可能是最相关的部分。
    现在,通过一些实验,我们知道我们需要一个方案(例如,https://或简单的a://),我们使用保留字符来提出这样的例子:
// OK
let url = URL(string: "a://@@")!
// CRASH
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!


尝试URLComponents的替代初始化器也会失败,所以不要试图认为它是不同的:

// CRASH
let components = URLComponents(string: url.absoluteString)!

总结(iOS 17之前)

"a://@@"是一个有效NSURL但无效RFC 3986的例子。
顺便说一下,一些Swift人似乎希望将来统一URL和URLComponents的支持(没有更多的RFC差异),如URL.swift中所示:
//未来实现说明:
// NSURL(实际上是CFURL,它提供了它的实现)在处理一些更深奥(和一些不那么深奥)的字符串时有很多怪癖。我们想把这些大部分移到更现代的NSURLComponents上,但是二进制compat问题使这变得困难。
//希望很快,我们可以将下面的一些NSURL委托替换为NSURLComponents委托。它不能逐个完成,因为否则我们将从API获得不一致的结果。
我不确定他们计划如何做到这一点,因为这意味着要么URL(string: "a://@@")失败,要么URLComponents(string: "a://@@")成功。
历史显示,自iOS 17以来,URL(string: "a://@@")现在返回nil

相关问题