@@ -183,23 +183,7 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
183
183
private func run( _ action: HTTP1ConnectionStateMachine . Action , context: ChannelHandlerContext ) {
184
184
switch action {
185
185
case . sendRequestHead( let head, startBody: let startBody) :
186
- if startBody {
187
- context. write ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
188
- context. flush ( )
189
-
190
- self . request!. requestHeadSent ( )
191
- self . request!. resumeRequestBodyStream ( )
192
- } else {
193
- context. write ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
194
- context. write ( self . wrapOutboundOut ( . end( nil ) ) , promise: nil )
195
- context. flush ( )
196
-
197
- self . request!. requestHeadSent ( )
198
-
199
- if let timeoutAction = self . idleReadTimeoutStateMachine? . requestEndSent ( ) {
200
- self . runTimeoutAction ( timeoutAction, context: context)
201
- }
202
- }
186
+ self . sendRequestHead ( head, startBody: startBody, context: context)
203
187
204
188
case . sendBodyPart( let part) :
205
189
context. writeAndFlush ( self . wrapOutboundOut ( . body( part) ) , promise: nil )
@@ -212,9 +196,13 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
212
196
}
213
197
214
198
case . pauseRequestBodyStream:
199
+ // We can force unwrap the request here, as we have just validated in the state machine,
200
+ // that the request is neither failed nor finished yet
215
201
self . request!. pauseRequestBodyStream ( )
216
202
217
203
case . resumeRequestBodyStream:
204
+ // We can force unwrap the request here, as we have just validated in the state machine,
205
+ // that the request is neither failed nor finished yet
218
206
self . request!. resumeRequestBodyStream ( )
219
207
220
208
case . fireChannelActive:
@@ -239,15 +227,25 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
239
227
break
240
228
241
229
case . forwardResponseHead( let head, let pauseRequestBodyStream) :
230
+ // We can force unwrap the request here, as we have just validated in the state machine,
231
+ // that the request is neither failed nor finished yet
242
232
self . request!. receiveResponseHead ( head)
243
- if pauseRequestBodyStream {
244
- self . request!. pauseRequestBodyStream ( )
233
+ if pauseRequestBodyStream, let request = self . request {
234
+ // The above response head forward might lead the request to mark itself as
235
+ // cancelled, which in turn might pop the request of the handler. For this reason we
236
+ // must check if the request is still present here.
237
+ request. pauseRequestBodyStream ( )
245
238
}
246
239
247
240
case . forwardResponseBodyParts( let buffer) :
241
+ // We can force unwrap the request here, as we have just validated in the state machine,
242
+ // that the request is neither failed nor finished yet
248
243
self . request!. receiveResponseBodyParts ( buffer)
249
244
250
245
case . succeedRequest( let finalAction, let buffer) :
246
+ // We can force unwrap the request here, as we have just validated in the state machine,
247
+ // that the request is neither failed nor finished yet
248
+
251
249
// The order here is very important...
252
250
// We first nil our own task property! `taskCompleted` will potentially lead to
253
251
// situations in which we get a new request right away. We should finish the task
@@ -293,6 +291,33 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
293
291
}
294
292
}
295
293
294
+ private func sendRequestHead( _ head: HTTPRequestHead , startBody: Bool , context: ChannelHandlerContext ) {
295
+ if startBody {
296
+ context. writeAndFlush ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
297
+
298
+ // The above write might trigger an error, which may lead to a call to `errorCaught`,
299
+ // which in turn, may fail the request and pop it from the handler. For this reason
300
+ // we must check if the request is still present here.
301
+ guard let request = self . request else { return }
302
+ request. requestHeadSent ( )
303
+ request. resumeRequestBodyStream ( )
304
+ } else {
305
+ context. write ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
306
+ context. write ( self . wrapOutboundOut ( . end( nil ) ) , promise: nil )
307
+ context. flush ( )
308
+
309
+ // The above write might trigger an error, which may lead to a call to `errorCaught`,
310
+ // which in turn, may fail the request and pop it from the handler. For this reason
311
+ // we must check if the request is still present here.
312
+ guard let request = self . request else { return }
313
+ request. requestHeadSent ( )
314
+
315
+ if let timeoutAction = self . idleReadTimeoutStateMachine? . requestEndSent ( ) {
316
+ self . runTimeoutAction ( timeoutAction, context: context)
317
+ }
318
+ }
319
+ }
320
+
296
321
private func runTimeoutAction( _ action: IdleReadStateMachine . Action , context: ChannelHandlerContext ) {
297
322
switch action {
298
323
case . startIdleReadTimeoutTimer( let timeAmount) :
0 commit comments