Skip to content

Commit d14ef7e

Browse files
authored
(138168197) Restore URL.host bracket stripping for compatibility (#1008)
1 parent 5a497cc commit d14ef7e

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
@@ -1213,21 +1213,38 @@ public struct URL: Equatable, Sendable, Hashable {
12131213
return nil
12141214
}
12151215
#endif
1216-
guard let encodedHost else { return nil }
1217-
let didPercentEncodeHost = hasAuthority ? _parseInfo.didPercentEncodeHost : _baseParseInfo?.didPercentEncodeHost ?? false
1218-
if percentEncoded {
1219-
if didPercentEncodeHost {
1220-
return String(encodedHost)
1221-
}
1222-
guard let decoded = Parser.IDNADecodeHost(encodedHost) else {
1216+
guard let encodedHost else {
1217+
return nil
1218+
}
1219+
1220+
func requestedHost() -> String? {
1221+
let didPercentEncodeHost = hasAuthority ? _parseInfo.didPercentEncodeHost : _baseParseInfo?.didPercentEncodeHost ?? false
1222+
if percentEncoded {
1223+
if didPercentEncodeHost {
1224+
return encodedHost
1225+
}
1226+
guard let decoded = Parser.IDNADecodeHost(encodedHost) else {
1227+
return encodedHost
1228+
}
1229+
return Parser.percentEncode(decoded, component: .host)
1230+
} else {
1231+
if didPercentEncodeHost {
1232+
return Parser.percentDecode(encodedHost)
1233+
}
12231234
return encodedHost
12241235
}
1225-
return Parser.percentEncode(decoded, component: .host)
1236+
}
1237+
1238+
guard let requestedHost = requestedHost() else {
1239+
return nil
1240+
}
1241+
1242+
let isIPLiteral = hasAuthority ? _parseInfo.isIPLiteral : _baseParseInfo?.isIPLiteral ?? false
1243+
if isIPLiteral {
1244+
// Strip square brackets to be compatible with old URL.host behavior
1245+
return String(requestedHost.utf8.dropFirst().dropLast())
12261246
} else {
1227-
if didPercentEncodeHost {
1228-
return Parser.percentDecode(encodedHost)
1229-
}
1230-
return String(encodedHost)
1247+
return requestedHost
12311248
}
12321249
}
12331250

Tests/FoundationEssentialsTests/URLTests.swift

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

795+
func testURLHostIPLiteralCompatibility() throws {
796+
var url = URL(string: "http://[::]")!
797+
XCTAssertEqual(url.host, "::")
798+
XCTAssertEqual(url.host(), "::")
799+
800+
url = URL(string: "https://[::1]:433/")!
801+
XCTAssertEqual(url.host, "::1")
802+
XCTAssertEqual(url.host(), "::1")
803+
804+
url = URL(string: "https://[2001:db8::]/")!
805+
XCTAssertEqual(url.host, "2001:db8::")
806+
XCTAssertEqual(url.host(), "2001:db8::")
807+
808+
url = URL(string: "https://[2001:db8::]:433")!
809+
XCTAssertEqual(url.host, "2001:db8::")
810+
XCTAssertEqual(url.host(), "2001:db8::")
811+
812+
url = URL(string: "http://[fe80::a%25en1]")!
813+
XCTAssertEqual(url.absoluteString, "http://[fe80::a%25en1]")
814+
XCTAssertEqual(url.host, "fe80::a%en1")
815+
XCTAssertEqual(url.host(percentEncoded: true), "fe80::a%25en1")
816+
XCTAssertEqual(url.host(percentEncoded: false), "fe80::a%en1")
817+
818+
url = URL(string: "http://[fe80::a%en1]")!
819+
XCTAssertEqual(url.absoluteString, "http://[fe80::a%25en1]")
820+
XCTAssertEqual(url.host, "fe80::a%en1")
821+
XCTAssertEqual(url.host(percentEncoded: true), "fe80::a%25en1")
822+
XCTAssertEqual(url.host(percentEncoded: false), "fe80::a%en1")
823+
824+
url = URL(string: "http://[fe80::a%100%CustomZone]")!
825+
XCTAssertEqual(url.absoluteString, "http://[fe80::a%25100%25CustomZone]")
826+
XCTAssertEqual(url.host, "fe80::a%100%CustomZone")
827+
XCTAssertEqual(url.host(percentEncoded: true), "fe80::a%25100%25CustomZone")
828+
XCTAssertEqual(url.host(percentEncoded: false), "fe80::a%100%CustomZone")
829+
}
830+
795831
func testURLTildeFilePath() throws {
796832
func urlIsAbsolute(_ url: URL) -> Bool {
797833
if url.relativePath.utf8.first == ._slash {

0 commit comments

Comments
 (0)