什么样的 URL 不符合 RFC 3986 但符合 RFC 1808、RFC 1738 和 RFC 2732?
Posted
技术标签:
【中文标题】什么样的 URL 不符合 RFC 3986 但符合 RFC 1808、RFC 1738 和 RFC 2732?【英文标题】:What kind of URL is not conforming to RFC 3986 but is conforming to RFC 1808, RFC 1738, and RFC 2732? 【发布时间】:2019-08-31 16:52:49 【问题描述】: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】:让我们从它的源代码来探索它,因为 Swift Foundation 是开源的。
URLComponents
初始化器在 apple/swift – URLComponents.swift 和 apple/swift-corelibs-foundation – URLComponents.swift 中实现,并简单地调用 NSURLComponents
的初始化器。
NSURLComponents
初始化器在 apple/swift-corelibs-foundation – NSURL.swift 中实现,并简单地调用 _CFURLComponentsCreateWithURL
。
_CFURLComponentsCreateWithURL
在apple/swift-corelibs-foundation – CFURLComponents.c 中实现,并且:
CFURLCopyAbsoluteURL
的失败副本
_CFURLComponentsCreateWithString
的失败创建,它调用:
_CFURIParserParseURIReference
+ 一个失败的_CFURIParserURLStringIsValid
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中,我的理解是只有在没有scheme或者没有路径的情况下才会失败,这应该是不可能的,因为我们之前测试过文件scheme或者文件存在CFURLIsFileReferenceURL
。
_CFURIParserParseURIReference
在apple/swift-corelibs-foundation – CFURLComponents_URIParser.c 中实现,只有在 URL 长度超过 2 GB 时才会失败,我认为这与 RFC 规范无关。
_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)!
结论
"a://@@"
是 NSURL 有效但 RFC 3986 无效的示例。
另一方面,一些 Swift 人似乎希望将来统一对 URL 和 URLComponents 的支持(不再有 RFC 差异)as seen in URL.swift:
// 未来实现说明: // NSURL(实际上是 CFURL,它提供了它的实现)在处理一些更深奥(和一些不那么深奥)的字符串时有很多怪癖。我们希望将其中的大部分内容转移到更现代的 NSURLComponents,但二进制兼容性问题让这变得困难。 // 希望很快,我们可以将下面的一些对 NSURL 的委托替换为对 NSURLComponents 的委托。不能零碎完成,否则我们会从 API 中得到不一致的结果。
我不确定他们打算如何做到这一点,因为这意味着URL(string: "a://@@")
将失败或URLComponents(string: "a://@@")
将成功。
【讨论】:
这真的很有趣,谢谢!还帮助我摆脱了在我的代码覆盖率报告中困扰我的一行红色 - 即使是这样一个边缘情况! 聪明的香肠 :-)以上是关于什么样的 URL 不符合 RFC 3986 但符合 RFC 1808、RFC 1738 和 RFC 2732?的主要内容,如果未能解决你的问题,请参考以下文章
Java URL 类 getPath()、getQuery() 和 getFile() 与 RFC3986 URI 语法不一致