@@ -183,23 +183,7 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
183183 private func run( _ action: HTTP1ConnectionStateMachine . Action , context: ChannelHandlerContext ) {
184184 switch action {
185185 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)
203187
204188 case . sendBodyPart( let part) :
205189 context. writeAndFlush ( self . wrapOutboundOut ( . body( part) ) , promise: nil )
@@ -212,9 +196,13 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
212196 }
213197
214198 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
215201 self . request!. pauseRequestBodyStream ( )
216202
217203 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
218206 self . request!. resumeRequestBodyStream ( )
219207
220208 case . fireChannelActive:
@@ -239,15 +227,25 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
239227 break
240228
241229 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
242232 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 ( )
245238 }
246239
247240 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
248243 self . request!. receiveResponseBodyParts ( buffer)
249244
250245 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+
251249 // The order here is very important...
252250 // We first nil our own task property! `taskCompleted` will potentially lead to
253251 // situations in which we get a new request right away. We should finish the task
@@ -293,6 +291,33 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler {
293291 }
294292 }
295293
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+
296321 private func runTimeoutAction( _ action: IdleReadStateMachine . Action , context: ChannelHandlerContext ) {
297322 switch action {
298323 case . startIdleReadTimeoutTimer( let timeAmount) :
0 commit comments