diff --git a/Sources/NIOTransportServices/NIOTSConnectionChannel.swift b/Sources/NIOTransportServices/NIOTSConnectionChannel.swift index 9b80ba4..53836d8 100644 --- a/Sources/NIOTransportServices/NIOTSConnectionChannel.swift +++ b/Sources/NIOTransportServices/NIOTSConnectionChannel.swift @@ -500,6 +500,16 @@ extension NIOTSConnectionChannel: StateManagedChannel { internal func beginActivating0(to target: NWEndpoint, promise: EventLoopPromise?) { assert(self.nwConnection == nil) assert(self.connectPromise == nil) + + // Before we start, we validate that the target won't cause a crash: see + // https://github.com/apple/swift-nio/issues/1617. + if case .hostPort(host: let host, port: _) = target, host == "" { + // We don't pass the promise in here because we'll actually not complete it. We complete it manually ourselves. + self.close0(error: NIOTSErrors.InvalidHostname(), mode: .all, promise: nil) + promise?.fail(NIOTSErrors.InvalidHostname()) + return + } + self.connectPromise = promise let parameters = NWParameters(tls: self.tlsOptions, tcp: self.tcpOptions) diff --git a/Sources/NIOTransportServices/NIOTSErrors.swift b/Sources/NIOTransportServices/NIOTSErrors.swift index bc55a41..e35a4d1 100644 --- a/Sources/NIOTransportServices/NIOTSErrors.swift +++ b/Sources/NIOTransportServices/NIOTSErrors.swift @@ -69,5 +69,10 @@ public enum NIOTSErrors { self.timeout = timeout } } + + /// `InvalidHostname` is thrown when attempting to connect to an invalid host. + public struct InvalidHostname: NIOTSError { + public init() { } + } } #endif diff --git a/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift b/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift index 1476e02..3f896d7 100644 --- a/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift +++ b/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift @@ -778,5 +778,12 @@ class NIOTSConnectionChannelTests: XCTestCase { // throw XCTAssertNoThrow(try eventPromise.futureResult.wait()) } + + func testConnectingToEmptyStringErrors() throws { + let connectBootstrap = NIOTSConnectionBootstrap(group: self.group) + XCTAssertThrowsError(try connectBootstrap.connect(host: "", port: 80).wait()) { error in + XCTAssertTrue(error is NIOTSErrors.InvalidHostname) + } + } } #endif