Skip to content

Commit 305bbfb

Browse files
committed
(138168197) Restore URL.host bracket stripping for compatibility (swiftlang#1008)
1 parent 201e2d2 commit 305bbfb

File tree

2 files changed

+65
-12
lines changed

2 files changed

+65
-12
lines changed

Sources/FoundationEssentials/URL/URL.swift

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,21 +1207,38 @@ public struct URL: Equatable, Sendable, Hashable {
12071207
return nil
12081208
}
12091209
#endif
1210-
guard let encodedHost else { return nil }
1211-
let didPercentEncodeHost = hasAuthority ? _parseInfo.didPercentEncodeHost : _baseParseInfo?.didPercentEncodeHost ?? false
1212-
if percentEncoded {
1213-
if didPercentEncodeHost {
1214-
return String(encodedHost)
1215-
}
1216-
guard let decoded = Parser.IDNADecodeHost(encodedHost) else {
1210+
guard let encodedHost else {
1211+
return nil
1212+
}
1213+
1214+
func requestedHost() -> String? {
1215+
let didPercentEncodeHost = hasAuthority ? _parseInfo.didPercentEncodeHost : _baseParseInfo?.didPercentEncodeHost ?? false
1216+
if percentEncoded {
1217+
if didPercentEncodeHost {
1218+
return encodedHost
1219+
}
1220+
guard let decoded = Parser.IDNADecodeHost(encodedHost) else {
1221+
return encodedHost
1222+
}
1223+
return Parser.percentEncode(decoded, component: .host)
1224+
} else {
1225+
if didPercentEncodeHost {
1226+
return Parser.percentDecode(encodedHost)
1227+
}
12171228
return encodedHost
12181229
}
1219-
return Parser.percentEncode(decoded, component: .host)
1230+
}
1231+
1232+
guard let requestedHost = requestedHost() else {
1233+
return nil
1234+
}
1235+
1236+
let isIPLiteral = hasAuthority ? _parseInfo.isIPLiteral : _baseParseInfo?.isIPLiteral ?? false
1237+
if isIPLiteral {
1238+
// Strip square brackets to be compatible with old URL.host behavior
1239+
return String(requestedHost.utf8.dropFirst().dropLast())
12201240
} else {
1221-
if didPercentEncodeHost {
1222-
return Parser.percentDecode(encodedHost)
1223-
}
1224-
return String(encodedHost)
1241+
return requestedHost
12251242
}
12261243
}
12271244

Tests/FoundationEssentialsTests/URLTests.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,42 @@ final class URLTests : XCTestCase {
642642
XCTAssertEqual(url.host, "*.xn--poema-9qae5a.com.br")
643643
}
644644

645+
func testURLHostIPLiteralCompatibility() throws {
646+
var url = URL(string: "http://[::]")!
647+
XCTAssertEqual(url.host, "::")
648+
XCTAssertEqual(url.host(), "::")
649+
650+
url = URL(string: "https://[::1]:433/")!
651+
XCTAssertEqual(url.host, "::1")
652+
XCTAssertEqual(url.host(), "::1")
653+
654+
url = URL(string: "https://[2001:db8::]/")!
655+
XCTAssertEqual(url.host, "2001:db8::")
656+
XCTAssertEqual(url.host(), "2001:db8::")
657+
658+
url = URL(string: "https://[2001:db8::]:433")!
659+
XCTAssertEqual(url.host, "2001:db8::")
660+
XCTAssertEqual(url.host(), "2001:db8::")
661+
662+
url = URL(string: "http://[fe80::a%25en1]")!
663+
XCTAssertEqual(url.absoluteString, "http://[fe80::a%25en1]")
664+
XCTAssertEqual(url.host, "fe80::a%en1")
665+
XCTAssertEqual(url.host(percentEncoded: true), "fe80::a%25en1")
666+
XCTAssertEqual(url.host(percentEncoded: false), "fe80::a%en1")
667+
668+
url = URL(string: "http://[fe80::a%en1]")!
669+
XCTAssertEqual(url.absoluteString, "http://[fe80::a%25en1]")
670+
XCTAssertEqual(url.host, "fe80::a%en1")
671+
XCTAssertEqual(url.host(percentEncoded: true), "fe80::a%25en1")
672+
XCTAssertEqual(url.host(percentEncoded: false), "fe80::a%en1")
673+
674+
url = URL(string: "http://[fe80::a%100%CustomZone]")!
675+
XCTAssertEqual(url.absoluteString, "http://[fe80::a%25100%25CustomZone]")
676+
XCTAssertEqual(url.host, "fe80::a%100%CustomZone")
677+
XCTAssertEqual(url.host(percentEncoded: true), "fe80::a%25100%25CustomZone")
678+
XCTAssertEqual(url.host(percentEncoded: false), "fe80::a%100%CustomZone")
679+
}
680+
645681
func testURLTildeFilePath() throws {
646682
var url = URL(filePath: "~")
647683
// "~" must either be expanded to an absolute path or resolved against a base URL

0 commit comments

Comments
 (0)