diff --git a/Sources/RediStack/RedisConnection+Configuration.swift b/Sources/RediStack/RedisConnection+Configuration.swift index f32c097..91cf464 100644 --- a/Sources/RediStack/RedisConnection+Configuration.swift +++ b/Sources/RediStack/RedisConnection+Configuration.swift @@ -16,6 +16,7 @@ import Atomics import NIOCore import NIOConcurrencyHelpers import NIOPosix +import NIOSSL import Logging import struct Foundation.URL import protocol Foundation.LocalizedError @@ -52,13 +53,15 @@ extension RedisConnection { public var port: Int? { self.address.port } /// The user name used to authenticate connections with. /// - Warning: This property should only be provided if you are running against Redis 6 or higher. - public let username: String? + public var username: String? /// The password used to authenticate the connection. - public let password: String? + public var password: String? /// The initial database index that the connection should use. - public let initialDatabase: Int? + public var initialDatabase: Int? /// The logger prototype that will be used by the connection by default when generating logs. - public let defaultLogger: Logger + public var defaultLogger: Logger + + public var tlsConfiguration: TLSConfiguration? internal let address: SocketAddress @@ -186,12 +189,16 @@ extension RedisConnection { let databaseID = Int(url.lastPathComponent) - try self.init( + var config = try Self( address: try .makeAddressResolvingHost(host, port: url.port ?? Self.defaultPort), password: url.password, initialDatabase: databaseID, defaultLogger: defaultLogger ) + + config.tlsConfiguration = .clientDefault + + self = config } private static func validateRedisURL(_ url: URL) throws { @@ -200,7 +207,7 @@ extension RedisConnection { !scheme.isEmpty else { throw ValidationError.missingURLScheme } - guard scheme == "redis" else { throw ValidationError.invalidURLScheme } + guard scheme == "redis" || scheme == "rediss" else { throw ValidationError.invalidURLScheme } } } } diff --git a/Sources/RediStack/RedisConnection.swift b/Sources/RediStack/RedisConnection.swift index c6584bf..70be26d 100644 --- a/Sources/RediStack/RedisConnection.swift +++ b/Sources/RediStack/RedisConnection.swift @@ -19,6 +19,7 @@ import Logging import Metrics import NIOCore import NIOConcurrencyHelpers +import NIOSSL import NIOPosix extension RedisConnection { @@ -55,9 +56,34 @@ extension RedisConnection { boundEventLoop eventLoop: EventLoop, configuredTCPClient client: ClientBootstrap? = nil ) -> EventLoopFuture { - let client = client ?? .makeRedisTCPClient(group: eventLoop) + let bootstrap: ClientBootstrap + if let client { + bootstrap = client + } else if let tlsConfiguration = config.tlsConfiguration { + bootstrap = ClientBootstrap(group: eventLoop) + .channelOption( + ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), + value: 1 + ) + .channelInitializer { channel in + do { + try channel.pipeline.syncOperations.addHandler( + NIOSSLClientHandler( + context: NIOSSLContext(configuration: tlsConfiguration), + serverHostname: config.hostname + ) + ) + } catch { + return eventLoop.makeFailedFuture(error) + } + + return channel.pipeline.addBaseRedisHandlers() + } + } else { + bootstrap = .makeRedisTCPClient(group: eventLoop) + } - return client + return bootstrap .connect(to: config.address) .flatMap { let connection = RedisConnection(configuredRESPChannel: $0, backgroundLogger: config.defaultLogger)