From bb56586c4cab9a79dce6ec4738baddb5802c5de7 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Tue, 11 Aug 2020 10:10:17 +0100 Subject: [PATCH] Avoid crashing when connecting to empty host. (#103) Motivation: Network.framework will crash when we attempt to connect to the host string "". That's not ideal, so we should detect that case and avoid it. Modifications: - Add code to detect the empty host string. Result: No crashes when accidentally connecting to "". --- .../NIOTransportServices/NIOTSConnectionChannel.swift | 10 ++++++++++ Sources/NIOTransportServices/NIOTSErrors.swift | 5 +++++ .../NIOTSConnectionChannelTests.swift | 7 +++++++ 3 files changed, 22 insertions(+) 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