@@ -19,31 +19,38 @@ public import GRPCHTTP2Core // should be @usableFromInline
1919public import NIOCore
2020public import NIOPosix // has to be public because of default argument value in init
2121
22+ #if canImport(NIOSSL)
23+ import NIOSSL
24+ #endif
25+
2226@available ( macOS 15 . 0 , iOS 18 . 0 , watchOS 11 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , * )
2327extension HTTP2ClientTransport {
24- /// A `ClientTransport` using HTTP/2 built on top of `NIOPosix`.
28+ /// A ``GRPCCore/ ClientTransport` ` using HTTP/2 built on top of `NIOPosix`.
2529 ///
2630 /// This transport builds on top of SwiftNIO's Posix networking layer and is suitable for use
2731 /// on Linux and Darwin based platform (macOS, iOS, etc.) However, it's *strongly* recommended
2832 /// that if you are targeting Darwin platforms then you should use the `NIOTS` variant of
29- /// the `HTTP2ClientTransport`.
33+ /// the ``GRPCHTTP2Core/ HTTP2ClientTransport` `.
3034 ///
3135 /// To use this transport you need to provide a 'target' to connect to which will be resolved
3236 /// by an appropriate resolver from the resolver registry. By default the resolver registry can
3337 /// resolve DNS targets, IPv4 and IPv6 targets, Unix domain socket targets, and Virtual Socket
3438 /// targets. If you use a custom target you must also provide an appropriately configured
3539 /// registry.
3640 ///
37- /// You can control various aspects of connection creation, management and RPC behavior via the
38- /// ``Config``. Load balancing policies and other RPC specific behavior can be configured via
41+ /// You can control various aspects of connection creation, management, security and RPC behavior via
42+ /// the ``Config``. Load balancing policies and other RPC specific behavior can be configured via
3943 /// the ``ServiceConfig`` (if it isn't provided by a resolver).
4044 ///
4145 /// Beyond creating the transport you don't need to interact with it directly, instead, pass it
4246 /// to a `GRPCClient`:
4347 ///
4448 /// ```swift
45- /// try await withThrowingDiscardingTaskGroup {
46- /// let transport = try HTTP2ClientTransport.Posix(target: .dns(host: "example.com"))
49+ /// try await withThrowingDiscardingTaskGroup { group in
50+ /// let transport = try HTTP2ClientTransport.Posix(
51+ /// target: .ipv4(host: "example.com"),
52+ /// config: .defaults(transportSecurity: .plaintext)
53+ /// )
4754 /// let client = GRPCClient(transport: transport)
4855 /// group.addTask {
4956 /// try await client.run()
@@ -87,7 +94,7 @@ extension HTTP2ClientTransport {
8794 // Configure a connector.
8895 self . channel = GRPCChannel (
8996 resolver: resolver,
90- connector: Connector ( eventLoopGroup: eventLoopGroup, config: config) ,
97+ connector: try Connector ( eventLoopGroup: eventLoopGroup, config: config) ,
9198 config: GRPCChannel . Config ( posix: config) ,
9299 defaultServiceConfig: serviceConfig
93100 )
@@ -125,9 +132,33 @@ extension HTTP2ClientTransport.Posix {
125132 private let config : HTTP2ClientTransport . Posix . Config
126133 private let eventLoopGroup : any EventLoopGroup
127134
128- init ( eventLoopGroup: any EventLoopGroup , config: HTTP2ClientTransport . Posix . Config ) {
135+ #if canImport(NIOSSL)
136+ private let nioSSLContext : NIOSSLContext ?
137+ private let serverHostname : String ?
138+ #endif
139+
140+ init ( eventLoopGroup: any EventLoopGroup , config: HTTP2ClientTransport . Posix . Config ) throws {
129141 self . eventLoopGroup = eventLoopGroup
130142 self . config = config
143+
144+ #if canImport(NIOSSL)
145+ switch self . config. transportSecurity. wrapped {
146+ case . plaintext:
147+ self . nioSSLContext = nil
148+ self . serverHostname = nil
149+ case . tls( let tlsConfig) :
150+ do {
151+ self . nioSSLContext = try NIOSSLContext ( configuration: TLSConfiguration ( tlsConfig) )
152+ self . serverHostname = tlsConfig. serverHostname
153+ } catch {
154+ throw RuntimeError (
155+ code: . transportError,
156+ message: " Couldn't create SSL context, check your TLS configuration. " ,
157+ cause: error
158+ )
159+ }
160+ }
161+ #endif
131162 }
132163
133164 func establishConnection(
@@ -137,7 +168,18 @@ extension HTTP2ClientTransport.Posix {
137168 group: self . eventLoopGroup
138169 ) . connect ( to: address) { channel in
139170 channel. eventLoop. makeCompletedFuture {
140- try channel. pipeline. syncOperations. configureGRPCClientPipeline (
171+ #if canImport(NIOSSL)
172+ if let nioSSLContext = self . nioSSLContext {
173+ try channel. pipeline. syncOperations. addHandler (
174+ NIOSSLClientHandler (
175+ context: nioSSLContext,
176+ serverHostname: self . serverHostname
177+ )
178+ )
179+ }
180+ #endif
181+
182+ return try channel. pipeline. syncOperations. configureGRPCClientPipeline (
141183 channel: channel,
142184 config: GRPCChannel . Config ( posix: self . config)
143185 )
@@ -164,31 +206,48 @@ extension HTTP2ClientTransport.Posix {
164206 /// Compression configuration.
165207 public var compression : HTTP2ClientTransport . Config . Compression
166208
209+ /// The transport's security.
210+ public var transportSecurity : TransportSecurity
211+
167212 /// Creates a new connection configuration.
168213 ///
169- /// See also ``defaults``.
214+ /// - Parameters:
215+ /// - http2: HTTP2 configuration.
216+ /// - backoff: Backoff configuration.
217+ /// - connection: Connection configuration.
218+ /// - compression: Compression configuration.
219+ /// - transportSecurity: The transport's security configuration.
220+ ///
221+ /// - SeeAlso: ``defaults(_:)``.
170222 public init (
171223 http2: HTTP2ClientTransport . Config . HTTP2 ,
172224 backoff: HTTP2ClientTransport . Config . Backoff ,
173225 connection: HTTP2ClientTransport . Config . Connection ,
174- compression: HTTP2ClientTransport . Config . Compression
226+ compression: HTTP2ClientTransport . Config . Compression ,
227+ transportSecurity: TransportSecurity
175228 ) {
176229 self . http2 = http2
177230 self . connection = connection
178231 self . backoff = backoff
179232 self . compression = compression
233+ self . transportSecurity = transportSecurity
180234 }
181235
182236 /// Default values.
183237 ///
184238 /// - Parameters:
239+ /// - transportSecurity: The security settings applied to the transport.
185240 /// - configure: A closure which allows you to modify the defaults before returning them.
186- public static func defaults( _ configure: ( _ config: inout Self ) -> Void = { _ in } ) -> Self {
241+ public static func defaults(
242+ transportSecurity: TransportSecurity ,
243+ configure: ( _ config: inout Self ) -> Void = { _ in }
244+ ) -> Self {
187245 var config = Self (
188246 http2: . defaults,
189247 backoff: . defaults,
190248 connection: . defaults,
191- compression: . defaults
249+ compression: . defaults,
250+ transportSecurity: transportSecurity
192251 )
193252 configure ( & config)
194253 return config
0 commit comments