Skip to content

Commit cb0cab2

Browse files
authored
(141584267) URL inits should resolve file reference paths (#1140)
1 parent 8558978 commit cb0cab2

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

Sources/FoundationEssentials/URL/URL.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,8 @@ public struct URL: Equatable, Sendable, Hashable {
634634
}()
635635
#endif
636636

637+
internal static let fileIDPrefix = Array("/.file/id=".utf8)
638+
637639
#if FOUNDATION_FRAMEWORK
638640

639641
private var _url: NSURL
@@ -747,10 +749,7 @@ public struct URL: Equatable, Sendable, Hashable {
747749
if isDirectory {
748750
flags.insert(.isDirectory)
749751
}
750-
751-
let fileIDPrefix = [UInt8(ascii: "/"), UInt8(ascii: "."), UInt8(ascii: "f"), UInt8(ascii: "i"), UInt8(ascii: "l"), UInt8(ascii: "e"), UInt8(ascii: "/"), UInt8(ascii: "i"), UInt8(ascii: "d"), UInt8(ascii: "=")]
752-
753-
if path.starts(with: fileIDPrefix) {
752+
if parseInfo.pathHasFileID {
754753
flags.insert(.pathHasFileID)
755754
}
756755
if !isDirectory && !parseInfo.pathHasPercent {
@@ -784,6 +783,10 @@ public struct URL: Equatable, Sendable, Hashable {
784783
}
785784
#if FOUNDATION_FRAMEWORK
786785
_url = URL._nsURL(from: _parseInfo, baseParseInfo: _baseParseInfo)
786+
if self.isFileURL && _parseInfo.pathHasFileID {
787+
// _baseParseInfo cannot have a file ID because it came from `URL`
788+
self = URL(reference: _url)
789+
}
787790
#endif // FOUNDATION_FRAMEWORK
788791
}
789792

@@ -809,6 +812,9 @@ public struct URL: Equatable, Sendable, Hashable {
809812
}
810813
#if FOUNDATION_FRAMEWORK
811814
_url = URL._nsURL(from: _parseInfo, baseParseInfo: _baseParseInfo)
815+
if self.isFileURL && _parseInfo.pathHasFileID {
816+
self = URL(reference: _url)
817+
}
812818
#endif // FOUNDATION_FRAMEWORK
813819
}
814820

@@ -830,6 +836,9 @@ public struct URL: Equatable, Sendable, Hashable {
830836
_parseInfo = parseInfo
831837
#if FOUNDATION_FRAMEWORK
832838
_url = URL._nsURL(from: _parseInfo, baseParseInfo: _baseParseInfo)
839+
if self.isFileURL && _parseInfo.pathHasFileID {
840+
self = URL(reference: _url)
841+
}
833842
#endif // FOUNDATION_FRAMEWORK
834843
}
835844

@@ -854,6 +863,9 @@ public struct URL: Equatable, Sendable, Hashable {
854863
}
855864
#if FOUNDATION_FRAMEWORK
856865
_url = URL._nsURL(from: _parseInfo, baseParseInfo: _baseParseInfo)
866+
if self.isFileURL && _parseInfo.pathHasFileID {
867+
self = URL(reference: _url)
868+
}
857869
#endif // FOUNDATION_FRAMEWORK
858870
}
859871

@@ -878,6 +890,9 @@ public struct URL: Equatable, Sendable, Hashable {
878890
_parseInfo = parseInfo
879891
#if FOUNDATION_FRAMEWORK
880892
_url = URL._nsURL(from: _parseInfo, baseParseInfo: _baseParseInfo)
893+
if self.isFileURL && _parseInfo.pathHasFileID {
894+
self = URL(reference: _url)
895+
}
881896
#endif // FOUNDATION_FRAMEWORK
882897
}
883898

@@ -2120,9 +2135,9 @@ public struct URL: Equatable, Sendable, Hashable {
21202135
_parseInfo = parseInfo
21212136
} else {
21222137
// Go to compatibility jail (allow `URL` as a dummy string container for `NSURL` instead of crashing)
2123-
_parseInfo = URLParseInfo(urlString: _url.relativeString, urlParser: .RFC3986, schemeRange: nil, userRange: nil, passwordRange: nil, hostRange: nil, portRange: nil, pathRange: nil, queryRange: nil, fragmentRange: nil, isIPLiteral: false, didPercentEncodeHost: false, pathHasPercent: false)
2138+
_parseInfo = URLParseInfo(urlString: _url.relativeString, urlParser: .RFC3986, schemeRange: nil, userRange: nil, passwordRange: nil, hostRange: nil, portRange: nil, pathRange: nil, queryRange: nil, fragmentRange: nil, isIPLiteral: false, didPercentEncodeHost: false, pathHasPercent: false, pathHasFileID: false)
21242139
}
2125-
_baseParseInfo = reference.baseURL?._parseInfo
2140+
_baseParseInfo = reference.baseURL?.absoluteURL._parseInfo
21262141
}
21272142

21282143
private var reference: NSURL {

Sources/FoundationEssentials/URL/URLParser.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ final class URLParseInfo: Sendable {
3131
let isIPLiteral: Bool
3232
let didPercentEncodeHost: Bool
3333
let pathHasPercent: Bool
34+
let pathHasFileID: Bool
3435

35-
init(urlString: String, urlParser: URLParserKind, schemeRange: Range<String.Index>?, userRange: Range<String.Index>?, passwordRange: Range<String.Index>?, hostRange: Range<String.Index>?, portRange: Range<String.Index>?, pathRange: Range<String.Index>?, queryRange: Range<String.Index>?, fragmentRange: Range<String.Index>?, isIPLiteral: Bool, didPercentEncodeHost: Bool, pathHasPercent: Bool) {
36+
init(urlString: String, urlParser: URLParserKind, schemeRange: Range<String.Index>?, userRange: Range<String.Index>?, passwordRange: Range<String.Index>?, hostRange: Range<String.Index>?, portRange: Range<String.Index>?, pathRange: Range<String.Index>?, queryRange: Range<String.Index>?, fragmentRange: Range<String.Index>?, isIPLiteral: Bool, didPercentEncodeHost: Bool, pathHasPercent: Bool, pathHasFileID: Bool) {
3637
self.urlString = urlString
3738
self.urlParser = urlParser
3839
self.schemeRange = schemeRange
@@ -46,6 +47,7 @@ final class URLParseInfo: Sendable {
4647
self.isIPLiteral = isIPLiteral
4748
self.didPercentEncodeHost = didPercentEncodeHost
4849
self.pathHasPercent = pathHasPercent
50+
self.pathHasFileID = pathHasFileID
4951
}
5052

5153
var hasAuthority: Bool {
@@ -131,6 +133,7 @@ fileprivate struct URLBufferParseInfo {
131133
var isIPLiteral: Bool = false
132134
var didPercentEncodeHost: Bool = false
133135
var pathHasPercent: Bool = false
136+
var pathHasFileID: Bool = false
134137
}
135138

136139
internal enum URLParserKind {
@@ -735,7 +738,8 @@ internal struct RFC3986Parser: URLParserProtocol {
735738
fragmentRange: convert(bufferParseInfo.fragmentRange),
736739
isIPLiteral: bufferParseInfo.isIPLiteral,
737740
didPercentEncodeHost: bufferParseInfo.didPercentEncodeHost,
738-
pathHasPercent: bufferParseInfo.pathHasPercent
741+
pathHasPercent: bufferParseInfo.pathHasPercent,
742+
pathHasFileID: bufferParseInfo.pathHasFileID
739743
)
740744
}
741745

@@ -851,6 +855,10 @@ internal struct RFC3986Parser: URLParserProtocol {
851855

852856
let pathStartIndex = currentIndex
853857
var sawPercent = false
858+
if buffer[pathStartIndex...].starts(with: URL.fileIDPrefix) {
859+
parseInfo.pathHasFileID = true
860+
currentIndex = buffer.index(pathStartIndex, offsetBy: URL.fileIDPrefix.count)
861+
}
854862
while currentIndex != buffer.endIndex {
855863
let v = buffer[currentIndex]
856864
if v == UInt8(ascii: "?") || v == UInt8(ascii: "#") {

0 commit comments

Comments
 (0)