@@ -19,31 +19,38 @@ public import GRPCHTTP2Core // should be @usableFromInline
19
19
public import NIOCore
20
20
public import NIOPosix // has to be public because of default argument value in init
21
21
22
+ #if canImport(NIOSSL)
23
+ import NIOSSL
24
+ #endif
25
+
22
26
@available ( macOS 15 . 0 , iOS 18 . 0 , watchOS 11 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , * )
23
27
extension HTTP2ClientTransport {
24
- /// A `ClientTransport` using HTTP/2 built on top of `NIOPosix`.
28
+ /// A ``GRPCCore/ ClientTransport` ` using HTTP/2 built on top of `NIOPosix`.
25
29
///
26
30
/// This transport builds on top of SwiftNIO's Posix networking layer and is suitable for use
27
31
/// on Linux and Darwin based platform (macOS, iOS, etc.) However, it's *strongly* recommended
28
32
/// that if you are targeting Darwin platforms then you should use the `NIOTS` variant of
29
- /// the `HTTP2ClientTransport`.
33
+ /// the ``GRPCHTTP2Core/ HTTP2ClientTransport` `.
30
34
///
31
35
/// To use this transport you need to provide a 'target' to connect to which will be resolved
32
36
/// by an appropriate resolver from the resolver registry. By default the resolver registry can
33
37
/// resolve DNS targets, IPv4 and IPv6 targets, Unix domain socket targets, and Virtual Socket
34
38
/// targets. If you use a custom target you must also provide an appropriately configured
35
39
/// registry.
36
40
///
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
39
43
/// the ``ServiceConfig`` (if it isn't provided by a resolver).
40
44
///
41
45
/// Beyond creating the transport you don't need to interact with it directly, instead, pass it
42
46
/// to a `GRPCClient`:
43
47
///
44
48
/// ```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
+ /// )
47
54
/// let client = GRPCClient(transport: transport)
48
55
/// group.addTask {
49
56
/// try await client.run()
@@ -87,7 +94,7 @@ extension HTTP2ClientTransport {
87
94
// Configure a connector.
88
95
self . channel = GRPCChannel (
89
96
resolver: resolver,
90
- connector: Connector ( eventLoopGroup: eventLoopGroup, config: config) ,
97
+ connector: try Connector ( eventLoopGroup: eventLoopGroup, config: config) ,
91
98
config: GRPCChannel . Config ( posix: config) ,
92
99
defaultServiceConfig: serviceConfig
93
100
)
@@ -125,9 +132,33 @@ extension HTTP2ClientTransport.Posix {
125
132
private let config : HTTP2ClientTransport . Posix . Config
126
133
private let eventLoopGroup : any EventLoopGroup
127
134
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 {
129
141
self . eventLoopGroup = eventLoopGroup
130
142
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
131
162
}
132
163
133
164
func establishConnection(
@@ -137,7 +168,18 @@ extension HTTP2ClientTransport.Posix {
137
168
group: self . eventLoopGroup
138
169
) . connect ( to: address) { channel in
139
170
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 (
141
183
channel: channel,
142
184
config: GRPCChannel . Config ( posix: self . config)
143
185
)
@@ -164,31 +206,48 @@ extension HTTP2ClientTransport.Posix {
164
206
/// Compression configuration.
165
207
public var compression : HTTP2ClientTransport . Config . Compression
166
208
209
+ /// The transport's security.
210
+ public var transportSecurity : TransportSecurity
211
+
167
212
/// Creates a new connection configuration.
168
213
///
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(_:)``.
170
222
public init (
171
223
http2: HTTP2ClientTransport . Config . HTTP2 ,
172
224
backoff: HTTP2ClientTransport . Config . Backoff ,
173
225
connection: HTTP2ClientTransport . Config . Connection ,
174
- compression: HTTP2ClientTransport . Config . Compression
226
+ compression: HTTP2ClientTransport . Config . Compression ,
227
+ transportSecurity: TransportSecurity
175
228
) {
176
229
self . http2 = http2
177
230
self . connection = connection
178
231
self . backoff = backoff
179
232
self . compression = compression
233
+ self . transportSecurity = transportSecurity
180
234
}
181
235
182
236
/// Default values.
183
237
///
184
238
/// - Parameters:
239
+ /// - transportSecurity: The security settings applied to the transport.
185
240
/// - 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 {
187
245
var config = Self (
188
246
http2: . defaults,
189
247
backoff: . defaults,
190
248
connection: . defaults,
191
- compression: . defaults
249
+ compression: . defaults,
250
+ transportSecurity: transportSecurity
192
251
)
193
252
configure ( & config)
194
253
return config
0 commit comments