Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/AsyncHTTPClient/HTTPHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ extension URL {
if self.path.isEmpty {
return "/"
}
return self.path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? self.path
return URLComponents(url: self, resolvingAgainstBaseURL: false)?.percentEncodedPath ?? self.path
}

var pathHasTrailingSlash: Bool {
Expand Down
18 changes: 12 additions & 6 deletions Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,8 @@ internal final class HttpBinHandler: ChannelInboundHandler {
switch self.unwrapInboundIn(data) {
case .head(let req):
self.parseAndSetOptions(from: req)
let url = URL(string: req.uri)!
switch url.path {
let urlComponents = URLComponents(string: req.uri)!
switch urlComponents.percentEncodedPath {
case "/":
var headers = HTTPHeaders()
headers.add(name: "X-Is-This-Slash", value: "Yes")
Expand Down Expand Up @@ -429,13 +429,13 @@ internal final class HttpBinHandler: ChannelInboundHandler {
self.resps.append(HTTPResponseBuilder(status: .found, headers: headers))
return
case "/redirect/https":
let port = self.value(for: "port", from: url.query!)
let port = self.value(for: "port", from: urlComponents.query!)
var headers = HTTPHeaders()
headers.add(name: "Location", value: "https://localhost:\(port)/ok")
self.resps.append(HTTPResponseBuilder(status: .found, headers: headers))
return
case "/redirect/loopback":
let port = self.value(for: "port", from: url.query!)
let port = self.value(for: "port", from: urlComponents.query!)
var headers = HTTPHeaders()
headers.add(name: "Location", value: "http://127.0.0.1:\(port)/echohostheader")
self.resps.append(HTTPResponseBuilder(status: .found, headers: headers))
Expand All @@ -450,8 +450,14 @@ internal final class HttpBinHandler: ChannelInboundHandler {
headers.add(name: "Location", value: "/redirect/infinite1")
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":
case "/percent%20encoded":
if req.method != .GET {
self.resps.append(HTTPResponseBuilder(status: .methodNotAllowed))
return
}
self.resps.append(HTTPResponseBuilder(status: .ok))
return
case "/percent%2Fencoded/hello":
if req.method != .GET {
self.resps.append(HTTPResponseBuilder(status: .methodNotAllowed))
return
Expand Down
1 change: 1 addition & 0 deletions Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extension HTTPClientTests {
("testHttpRedirect", testHttpRedirect),
("testHttpHostRedirect", testHttpHostRedirect),
("testPercentEncoded", testPercentEncoded),
("testPercentEncodedBackslash", testPercentEncodedBackslash),
("testMultipleContentLengthHeaders", testMultipleContentLengthHeaders),
("testStreaming", testStreaming),
("testRemoteClose", testRemoteClose),
Expand Down
12 changes: 12 additions & 0 deletions Tests/AsyncHTTPClientTests/HTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,18 @@ class HTTPClientTests: XCTestCase {
XCTAssertEqual(.ok, response.status)
}

func testPercentEncodedBackslash() throws {
let httpBin = HTTPBin()
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
defer {
XCTAssertNoThrow(try httpClient.syncShutdown(requiresCleanClose: true))
XCTAssertNoThrow(try httpBin.shutdown())
}

let response = try httpClient.get(url: "http://localhost:\(httpBin.port)/percent%2Fencoded/hello").wait()
XCTAssertEqual(.ok, response.status)
}

func testMultipleContentLengthHeaders() throws {
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
defer {
Expand Down