@@ -122,46 +122,24 @@ final class HTTP2Connection {
122
122
return connection. start ( ) . map { _ in connection }
123
123
}
124
124
125
- func execute( request: HTTPExecutableRequest ) {
126
- let createStreamChannelPromise = self . channel. eventLoop. makePromise ( of: Channel . self)
127
-
128
- self . multiplexer. createStreamChannel ( promise: createStreamChannelPromise) { channel -> EventLoopFuture < Void > in
129
- do {
130
- // We only support http/2 over an https connection – using the Application-Layer
131
- // Protocol Negotiation (ALPN). For this reason it is safe to fix this to `.https`.
132
- let translate = HTTP2FramePayloadToHTTP1ClientCodec ( httpProtocol: . https)
133
- let handler = HTTP2ClientRequestHandler ( eventLoop: channel. eventLoop)
134
-
135
- try channel. pipeline. syncOperations. addHandler ( translate)
136
- try channel. pipeline. syncOperations. addHandler ( handler)
137
-
138
- // We must add the new channel to the list of open channels BEFORE we write the
139
- // request to it. In case of an error, we are sure that the channel was added
140
- // before.
141
- let box = ChannelBox ( channel)
142
- self . openStreams. insert ( box)
143
- self . channel. closeFuture. whenComplete { _ in
144
- self . openStreams. remove ( box)
145
- }
146
-
147
- channel. write ( request, promise: nil )
148
- return channel. eventLoop. makeSucceededVoidFuture ( )
149
- } catch {
150
- return channel. eventLoop. makeFailedFuture ( error)
125
+ func executeRequest( _ request: HTTPExecutableRequest ) {
126
+ if self . channel. eventLoop. inEventLoop {
127
+ self . executeRequest0 ( request)
128
+ } else {
129
+ self . channel. eventLoop. execute {
130
+ self . executeRequest0 ( request)
151
131
}
152
132
}
153
-
154
- createStreamChannelPromise. futureResult. whenFailure { error in
155
- request. fail ( error)
156
- }
157
133
}
158
134
159
- func cancel( ) {
135
+ /// shuts down the connection by cancelling all running tasks and closing the connection once
136
+ /// all child streams/channels are closed.
137
+ func shutdown( ) {
160
138
if self . channel. eventLoop. inEventLoop {
161
- self . cancel0 ( )
139
+ self . shutdown0 ( )
162
140
} else {
163
141
self . channel. eventLoop. execute {
164
- self . cancel0 ( )
142
+ self . shutdown0 ( )
165
143
}
166
144
}
167
145
}
@@ -203,7 +181,60 @@ final class HTTP2Connection {
203
181
return readyToAcceptConnectionsPromise. futureResult
204
182
}
205
183
206
- private func cancel0( ) {
184
+ private func executeRequest0( _ request: HTTPExecutableRequest ) {
185
+ self . channel. eventLoop. assertInEventLoop ( )
186
+
187
+ switch self . state {
188
+ case . initialized, . starting:
189
+ preconditionFailure ( " Invalid state: \( self . state) . Sending requests is not allowed before we are started. " )
190
+
191
+ case . active:
192
+ let createStreamChannelPromise = self . channel. eventLoop. makePromise ( of: Channel . self)
193
+ self . multiplexer. createStreamChannel ( promise: createStreamChannelPromise) { channel -> EventLoopFuture < Void > in
194
+ do {
195
+ // the connection may have been asked to shutdown while we created the child. in
196
+ // this
197
+ // channel.
198
+ guard case . active = self . state else {
199
+ throw HTTPClientError . cancelled
200
+ }
201
+
202
+ // We only support http/2 over an https connection – using the Application-Layer
203
+ // Protocol Negotiation (ALPN). For this reason it is safe to fix this to `.https`.
204
+ let translate = HTTP2FramePayloadToHTTP1ClientCodec ( httpProtocol: . https)
205
+ let handler = HTTP2ClientRequestHandler ( eventLoop: channel. eventLoop)
206
+
207
+ try channel. pipeline. syncOperations. addHandler ( translate)
208
+ try channel. pipeline. syncOperations. addHandler ( handler)
209
+
210
+ // We must add the new channel to the list of open channels BEFORE we write the
211
+ // request to it. In case of an error, we are sure that the channel was added
212
+ // before.
213
+ let box = ChannelBox ( channel)
214
+ self . openStreams. insert ( box)
215
+ self . channel. closeFuture. whenComplete { _ in
216
+ self . openStreams. remove ( box)
217
+ }
218
+
219
+ channel. write ( request, promise: nil )
220
+ return channel. eventLoop. makeSucceededVoidFuture ( )
221
+ } catch {
222
+ return channel. eventLoop. makeFailedFuture ( error)
223
+ }
224
+ }
225
+
226
+ createStreamChannelPromise. futureResult. whenFailure { error in
227
+ request. fail ( error)
228
+ }
229
+
230
+ case . closing, . closed:
231
+ // Because of race conditions requests might reach this point, even though the
232
+ // connection is already closing
233
+ return request. fail ( HTTPClientError . cancelled)
234
+ }
235
+ }
236
+
237
+ private func shutdown0( ) {
207
238
self . channel. eventLoop. assertInEventLoop ( )
208
239
209
240
self . state = . closing
0 commit comments