diff --git a/Sources/NIOHTTPClient/HTTPHandler.swift b/Sources/NIOHTTPClient/HTTPHandler.swift index 9482fd8de..6ae5c1e54 100644 --- a/Sources/NIOHTTPClient/HTTPHandler.swift +++ b/Sources/NIOHTTPClient/HTTPHandler.swift @@ -228,7 +228,8 @@ extension HTTPClientResponseDelegate { internal extension URL { var uri: String { - return path.isEmpty ? "/" : path + (query.map { "?" + $0 } ?? "") + let urlEncodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? path + return path.isEmpty ? "/" : urlEncodedPath + (query.map { "?" + $0 } ?? "") } func hasTheSameOrigin(as other: URL) -> Bool { diff --git a/Tests/NIOHTTPClientTests/HTTPClientTestUtils.swift b/Tests/NIOHTTPClientTests/HTTPClientTestUtils.swift index 99f4aedea..cfc405acd 100644 --- a/Tests/NIOHTTPClientTests/HTTPClientTestUtils.swift +++ b/Tests/NIOHTTPClientTests/HTTPClientTestUtils.swift @@ -246,6 +246,14 @@ internal final class HttpBinHandler: ChannelInboundHandler { headers.add(name: "Location", value: "http://127.0.0.1:\(port)/echohostheader") self.resps.append(HTTPResponseBuilder(status: .found, headers: headers)) return + // Since this String is taken from URL.path, the percent encoding has been removed + case "/percent encoded": + if req.method != .GET { + self.resps.append(HTTPResponseBuilder(status: .methodNotAllowed)) + return + } + self.resps.append(HTTPResponseBuilder(status: .ok)) + return case "/echohostheader": var builder = HTTPResponseBuilder(status: .ok) let hostValue = req.headers["Host"].first ?? "" diff --git a/Tests/NIOHTTPClientTests/HTTPClientTests+XCTest.swift b/Tests/NIOHTTPClientTests/HTTPClientTests+XCTest.swift index e7af2c153..78348f157 100644 --- a/Tests/NIOHTTPClientTests/HTTPClientTests+XCTest.swift +++ b/Tests/NIOHTTPClientTests/HTTPClientTests+XCTest.swift @@ -32,6 +32,7 @@ extension HTTPClientTests { ("testPostHttps", testPostHttps), ("testHttpRedirect", testHttpRedirect), ("testHttpHostRedirect", testHttpHostRedirect), + ("testPercentEncoded", testPercentEncoded), ("testMultipleContentLengthHeaders", testMultipleContentLengthHeaders), ("testStreaming", testStreaming), ("testRemoteClose", testRemoteClose), diff --git a/Tests/NIOHTTPClientTests/HTTPClientTests.swift b/Tests/NIOHTTPClientTests/HTTPClientTests.swift index bf04070ba..72b26f54b 100644 --- a/Tests/NIOHTTPClientTests/HTTPClientTests.swift +++ b/Tests/NIOHTTPClientTests/HTTPClientTests.swift @@ -135,6 +135,18 @@ class HTTPClientTests: XCTestCase { let hostName = try decoder.decode([String: String].self, from: responseData)["data"] XCTAssert(hostName == "127.0.0.1") } + + func testPercentEncoded() throws { + let httpBin = HttpBin() + let httpClient = HTTPClient(eventLoopGroupProvider: .createNew) + defer { + try! httpClient.syncShutdown() + httpBin.shutdown() + } + + let response = try httpClient.get(url: "http://localhost:\(httpBin.port)/percent%20encoded").wait() + XCTAssertEqual(.ok, response.status) + } func testMultipleContentLengthHeaders() throws { let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)