diff --git a/Sources/AsyncHTTPClient/HTTPHandler.swift b/Sources/AsyncHTTPClient/HTTPHandler.swift index b81a2c7a5..c13d1accd 100644 --- a/Sources/AsyncHTTPClient/HTTPHandler.swift +++ b/Sources/AsyncHTTPClient/HTTPHandler.swift @@ -662,7 +662,7 @@ extension URL { if self.path.isEmpty { return "/" } - return URLComponents(url: self, resolvingAgainstBaseURL: false)?.percentEncodedPath ?? self.path + return URLComponents(url: self, resolvingAgainstBaseURL: true)?.percentEncodedPath ?? self.path } var uri: String { diff --git a/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift index 80446251c..a3246dde0 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift @@ -142,6 +142,25 @@ class HTTPClientInternalTests: XCTestCase { XCTAssertEqual(request12.url.uri, "/some%2Fpathsegment1/pathsegment2") } + func testURIOfRelativeURLRequest() throws { + let requestNoLeadingSlash = try Request( + url: URL( + string: "percent%2Fencoded/hello", + relativeTo: URL(string: "http://127.0.0.1")! + )! + ) + + let requestWithLeadingSlash = try Request( + url: URL( + string: "/percent%2Fencoded/hello", + relativeTo: URL(string: "http://127.0.0.1")! + )! + ) + + XCTAssertEqual(requestNoLeadingSlash.url.uri, "/percent%2Fencoded/hello") + XCTAssertEqual(requestWithLeadingSlash.url.uri, "/percent%2Fencoded/hello") + } + func testChannelAndDelegateOnDifferentEventLoops() throws { class Delegate: HTTPClientResponseDelegate { typealias Response = ([Message], [Message]) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index c733d0497..2a30a07ca 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -495,6 +495,20 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { XCTAssertEqual(.ok, response.status) } + func testLeadingSlashRelativeURL() throws { + let noLeadingSlashURL = URL(string: "percent%2Fencoded/hello", relativeTo: URL(string: self.defaultHTTPBinURLPrefix)!)! + let withLeadingSlashURL = URL(string: "/percent%2Fencoded/hello", relativeTo: URL(string: self.defaultHTTPBinURLPrefix)!)! + + let noLeadingSlashURLRequest = try HTTPClient.Request(url: noLeadingSlashURL, method: .GET) + let withLeadingSlashURLRequest = try HTTPClient.Request(url: withLeadingSlashURL, method: .GET) + + let noLeadingSlashURLResponse = try self.defaultClient.execute(request: noLeadingSlashURLRequest).wait() + let withLeadingSlashURLResponse = try self.defaultClient.execute(request: withLeadingSlashURLRequest).wait() + + XCTAssertEqual(noLeadingSlashURLResponse.status, .ok) + XCTAssertEqual(withLeadingSlashURLResponse.status, .ok) + } + func testMultipleContentLengthHeaders() throws { let body = ByteBuffer(string: "hello world!")