Skip to content

Commit 9074ebe

Browse files
committed
Fixed testProxyTLS()
The ssl handler has to be added after the proxy handler has run. Resurrected handshakePromise.
1 parent f97d226 commit 9074ebe

File tree

3 files changed

+74
-16
lines changed

3 files changed

+74
-16
lines changed

Sources/AsyncHTTPClient/ConnectionPool.swift

+42-6
Original file line numberDiff line numberDiff line change
@@ -373,15 +373,42 @@ final class ConnectionPool {
373373
}
374374
}
375375

376+
// if the configuration includes a proxy and requires TLS, TLS will not have been enabled yet. This
377+
// returns whether we need to call addSSLHandlerIfNeeded().
378+
private func requiresSSLHandler(on eventLoop: EventLoop) -> Bool {
379+
// if a proxy is not set return false, otherwise for non-TS situation return true, if TS is available and
380+
// either we don't have an NIOTSEventLoop or the scheme is HTTPS then return true
381+
if self.configuration.proxy != nil {
382+
#if canImport(Network)
383+
if #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
384+
{
385+
if !(eventLoop is NIOTSEventLoop) {
386+
return true
387+
}
388+
if self.key.scheme == .https {
389+
return true
390+
}
391+
} else {
392+
return true
393+
}
394+
#else
395+
return true
396+
#endif
397+
}
398+
return false
399+
}
400+
376401
private func makeConnection(on eventLoop: EventLoop) -> EventLoopFuture<Connection> {
377402
self.activityPrecondition(expected: [.opened])
378403
let address = HTTPClient.resolveAddress(host: self.key.host, port: self.key.port, proxy: self.configuration.proxy)
404+
let requiresTLS = self.key.scheme == .https
379405
let bootstrap : NIOClientTCPBootstrap
380406
do {
381-
bootstrap = try NIOClientTCPBootstrap.makeHTTPClientBootstrapBase(on: eventLoop, host: key.host, port: key.port, requiresTLS: self.key.scheme == .https, configuration: self.configuration)
407+
bootstrap = try NIOClientTCPBootstrap.makeHTTPClientBootstrapBase(on: eventLoop, host: key.host, port: key.port, requiresTLS: requiresTLS, configuration: self.configuration)
382408
} catch {
383409
return eventLoop.makeFailedFuture(error)
384410
}
411+
let handshakePromise = eventLoop.makePromise(of: Void.self)
385412

386413
let channel: EventLoopFuture<Channel>
387414
switch self.key.scheme {
@@ -392,16 +419,25 @@ final class ConnectionPool {
392419
}
393420

394421
return channel.flatMap { channel -> EventLoopFuture<ConnectionPool.Connection> in
395-
396-
channel.pipeline.addHTTPClientHandlers(leftOverBytesStrategy: .forwardBytes).map {
397-
let connection = Connection(key: self.key, channel: channel, parentPool: self.parentPool)
398-
connection.isLeased = true
399-
return connection
422+
if self.requiresSSLHandler(on: eventLoop) {
423+
channel.pipeline.addSSLHandlerIfNeeded(for: self.key, tlsConfiguration: self.configuration.tlsConfiguration, handshakePromise: handshakePromise)
424+
} else {
425+
handshakePromise.succeed(())
426+
}
427+
return handshakePromise.futureResult.flatMap {
428+
channel.pipeline.addHTTPClientHandlers(leftOverBytesStrategy: .forwardBytes)
429+
}.map {
430+
let connection = Connection(key: self.key, channel: channel, parentPool: self.parentPool)
431+
connection.isLeased = true
432+
return connection
400433
}
401434
}.map { connection in
402435
self.configureCloseCallback(of: connection)
403436
return connection
404437
}.flatMapError { error in
438+
// This promise may not have been completed if we reach this
439+
// so we fail it to avoid any leak
440+
handshakePromise.fail(error)
405441
let action = self.parentPool.connectionProvidersLock.withLock {
406442
self.stateLock.withLock {
407443
self.state.failedConnectionAction()

Sources/AsyncHTTPClient/Utils.swift

+32-7
Original file line numberDiff line numberDiff line change
@@ -49,36 +49,61 @@ public final class HTTPClientCopyingDelegate: HTTPClientResponseDelegate {
4949
}
5050

5151
extension ClientBootstrap {
52-
fileprivate static func makeBootstrap(on eventLoop: EventLoop, host: String, requiresTLS: Bool, configuration: HTTPClient.Configuration) throws -> NIOClientTCPBootstrap {
52+
fileprivate static func makeBootstrap(
53+
on eventLoop: EventLoop,
54+
host: String,
55+
requiresTLS: Bool,
56+
configuration: HTTPClient.Configuration
57+
) throws -> NIOClientTCPBootstrap {
5358
let tlsConfiguration = configuration.tlsConfiguration ?? TLSConfiguration.forClient()
5459
let sslContext = try NIOSSLContext(configuration: tlsConfiguration)
55-
let tlsProvider = try NIOSSLClientTLSProvider<ClientBootstrap>(context: sslContext, serverHostname: (!requiresTLS || host.isIPAddress) ? nil : host)
60+
let hostname = (!requiresTLS || host.isIPAddress) ? nil : host
61+
let tlsProvider = try NIOSSLClientTLSProvider<ClientBootstrap>(context: sslContext, serverHostname: hostname)
5662
return NIOClientTCPBootstrap(ClientBootstrap(group: eventLoop), tls: tlsProvider)
5763
}
5864
}
5965

6066
extension NIOClientTCPBootstrap {
6167
/// create a TCP Bootstrap based off what type of `EventLoop` has been passed to the function.
62-
fileprivate static func makeBootstrap(on eventLoop: EventLoop, host: String, requiresTLS: Bool, configuration: HTTPClient.Configuration) throws -> NIOClientTCPBootstrap {
68+
fileprivate static func makeBootstrap(
69+
on eventLoop: EventLoop,
70+
host: String,
71+
requiresTLS: Bool,
72+
configuration: HTTPClient.Configuration
73+
) throws -> NIOClientTCPBootstrap {
6374
let bootstrap: NIOClientTCPBootstrap
6475
#if canImport(Network)
6576
if #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *), eventLoop is NIOTSEventLoop {
66-
let tlsProvider = NIOTSClientTLSProvider(tlsOptions: .init())
67-
bootstrap = NIOClientTCPBootstrap(NIOTSConnectionBootstrap(group: eventLoop), tls: tlsProvider)
77+
if configuration.proxy != nil, requiresTLS {
78+
let tlsConfiguration = configuration.tlsConfiguration ?? TLSConfiguration.forClient()
79+
let sslContext = try NIOSSLContext(configuration: tlsConfiguration)
80+
let hostname = (!requiresTLS || host.isIPAddress) ? nil : host
81+
bootstrap = try NIOClientTCPBootstrap(NIOTSConnectionBootstrap(group: eventLoop), tls: NIOSSLClientTLSProvider(context: sslContext, serverHostname: hostname))
82+
} else {
83+
let tlsProvider = NIOTSClientTLSProvider(tlsOptions: .init())
84+
bootstrap = NIOClientTCPBootstrap(NIOTSConnectionBootstrap(group: eventLoop), tls: tlsProvider)
85+
}
6886
} else {
6987
bootstrap = try ClientBootstrap.makeBootstrap(on: eventLoop, host: host, requiresTLS: requiresTLS, configuration: configuration)
7088
}
7189
#else
7290
bootstrap = try ClientBootstrap.makeBootstrap(on: eventLoop, host: host, requiresTLS: requiresTLS, configuration: configuration)
7391
#endif
7492

75-
if requiresTLS {
93+
// don't enable TLS if we have a proxy, this will be enabled later on
94+
if requiresTLS, configuration.proxy == nil {
7695
return bootstrap.enableTLS()
7796
}
7897
return bootstrap
7998
}
8099

81-
static func makeHTTPClientBootstrapBase(on eventLoop: EventLoop, host: String, port: Int, requiresTLS: Bool, configuration: HTTPClient.Configuration) throws -> NIOClientTCPBootstrap {
100+
static func makeHTTPClientBootstrapBase(
101+
on eventLoop: EventLoop,
102+
host: String,
103+
port: Int,
104+
requiresTLS: Bool,
105+
configuration: HTTPClient.Configuration
106+
) throws -> NIOClientTCPBootstrap {
82107
return try makeBootstrap(on: eventLoop, host: host, requiresTLS: requiresTLS, configuration: configuration)
83108
.channelOption(ChannelOptions.socket(SocketOptionLevel(IPPROTO_TCP), TCP_NODELAY), value: 1)
84109
.channelInitializer { channel in

Tests/AsyncHTTPClientTests/HTTPClientTests.swift

-3
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,6 @@ class HTTPClientTests: XCTestCase {
384384
}
385385

386386
func testProxyTLS() throws {
387-
XCTFail("Disabled test as it crashes");
388-
return
389-
390387
let httpBin = HTTPBin(simulateProxy: .tls)
391388
let httpClient = HTTPClient(
392389
eventLoopGroupProvider: .shared(self.clientGroup),

0 commit comments

Comments
 (0)