Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ extension HTTPClientRequest {
newRequest.headers = headers
newRequest.body = body
newRequest.localAddress = self.localAddress
newRequest.tlsConfiguration = self.tlsConfiguration
return newRequest
}
}
3 changes: 2 additions & 1 deletion Sources/AsyncHTTPClient/HTTPHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,8 @@ internal struct RedirectHandler<ResponseType: Sendable> {
url: redirectURL,
method: method,
headers: headers,
body: body
body: body,
tlsConfiguration: self.request.tlsConfiguration
)

let newTask = self.execute(newRequest, redirectState)
Expand Down
26 changes: 26 additions & 0 deletions Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,32 @@ final class AsyncAwaitEndToEndTests: XCTestCase {
}
}

func testRedirectPreservesPerRequestTLSConfiguration() {
XCTAsyncTest {
let bin = HTTPBin(.http2(compress: false))
defer { XCTAssertNoThrow(try bin.shutdown()) }
// No client-level TLS configuration: default verification rejects HTTPBin's self-signed certificate,
// so the redirected request only succeeds if the per-request configuration is carried over.
let client = HTTPClient(eventLoopGroupProvider: .singleton)
defer { XCTAssertNoThrow(try client.syncShutdown()) }
let logger = Logger(label: "HTTPClient", factory: StreamLogHandler.standardOutput(label:))

var request = HTTPClientRequest(url: "https://localhost:\(bin.port)/redirect/302")
var tlsConfiguration = TLSConfiguration.makeClientConfiguration()
tlsConfiguration.certificateVerification = .none
request.tlsConfiguration = tlsConfiguration

guard
let response = await XCTAssertNoThrowWithResult(
try await client.execute(request, deadline: .now() + .seconds(10), logger: logger)
)
else { return }

XCTAssertEqual(response.status, .ok)
XCTAssertEqual(response.history.count, 2)
}
}

// MARK: - Integration tests: local address binding

func testLocalAddressBinding_configLevel() async throws {
Expand Down
26 changes: 26 additions & 0 deletions Tests/AsyncHTTPClientTests/HTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,32 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass {
)
}

func testHttpRedirectPreservesPerRequestTLSConfiguration() throws {
let httpsBin = HTTPBin(.http1_1(ssl: true))
// No client-level TLS configuration: default verification rejects HTTPBin's self-signed certificate,
// so the redirected request only succeeds if the per-request configuration is carried over.
let localClient = HTTPClient(
eventLoopGroupProvider: .shared(self.clientGroup),
configuration: HTTPClient.Configuration(redirectConfiguration: .follow(max: 10, allowCycles: true))
)

defer {
XCTAssertNoThrow(try localClient.syncShutdown())
XCTAssertNoThrow(try httpsBin.shutdown())
}

var tlsConfiguration = TLSConfiguration.makeClientConfiguration()
tlsConfiguration.certificateVerification = .none
let request = try HTTPClient.Request(
url: "https://localhost:\(httpsBin.port)/redirect/302",
tlsConfiguration: tlsConfiguration
)

let response = try localClient.execute(request: request).wait()
XCTAssertEqual(response.status, .ok)
XCTAssertEqual(response.history.count, 2)
}

func testHttpHostRedirect() {
let localClient = HTTPClient(
eventLoopGroupProvider: .shared(self.clientGroup),
Expand Down
Loading