@@ -139,30 +139,13 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
139
139
// MARK: Run Actions
140
140
141
141
private func run( _ action: HTTPRequestStateMachine . Action , context: ChannelHandlerContext ) {
142
- // NOTE: We can bang the request in the following actions, since the `HTTPRequestStateMachine`
143
- // ensures, that actions that require a request are only called, if the request is
144
- // still present. The request is only nilled as a response to a state machine action
145
- // (.failRequest or .succeedRequest).
146
-
147
142
switch action {
148
143
case . sendRequestHead( let head, let startBody) :
149
- if startBody {
150
- context. writeAndFlush ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
151
- self . request!. requestHeadSent ( )
152
- self . request!. resumeRequestBodyStream ( )
153
- } else {
154
- context. write ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
155
- context. write ( self . wrapOutboundOut ( . end( nil ) ) , promise: nil )
156
- context. flush ( )
157
-
158
- self . request!. requestHeadSent ( )
159
-
160
- if let timeoutAction = self . idleReadTimeoutStateMachine? . requestEndSent ( ) {
161
- self . runTimeoutAction ( timeoutAction, context: context)
162
- }
163
- }
144
+ self . sendRequestHead ( head, startBody: startBody, context: context)
164
145
165
146
case . pauseRequestBodyStream:
147
+ // We can force unwrap the request here, as we have just validated in the state machine,
148
+ // that the request is neither failed nor finished yet
166
149
self . request!. pauseRequestBodyStream ( )
167
150
168
151
case . sendBodyPart( let data) :
@@ -182,18 +165,29 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
182
165
break
183
166
184
167
case . resumeRequestBodyStream:
168
+ // We can force unwrap the request here, as we have just validated in the state machine,
169
+ // that the request is neither failed nor finished yet
185
170
self . request!. resumeRequestBodyStream ( )
186
171
187
172
case . forwardResponseHead( let head, pauseRequestBodyStream: let pauseRequestBodyStream) :
173
+ // We can force unwrap the request here, as we have just validated in the state machine,
174
+ // that the request is neither failed nor finished yet
188
175
self . request!. receiveResponseHead ( head)
189
- if pauseRequestBodyStream {
190
- self . request!. pauseRequestBodyStream ( )
176
+ if pauseRequestBodyStream, let request = self . request {
177
+ // The above response head forward might lead the request to mark itself as
178
+ // cancelled, which in turn might pop the request of the handler. For this reason we
179
+ // must check if the request is still present here.
180
+ request. pauseRequestBodyStream ( )
191
181
}
192
182
193
183
case . forwardResponseBodyParts( let parts) :
184
+ // We can force unwrap the request here, as we have just validated in the state machine,
185
+ // that the request is neither failed nor finished yet
194
186
self . request!. receiveResponseBodyParts ( parts)
195
187
196
188
case . failRequest( let error, _) :
189
+ // We can force unwrap the request here, as we have just validated in the state machine,
190
+ // that the request object is still present.
197
191
self . request!. fail ( error)
198
192
self . request = nil
199
193
self . runTimeoutAction ( . clearIdleReadTimeoutTimer, context: context)
@@ -204,13 +198,42 @@ final class HTTP2ClientRequestHandler: ChannelDuplexHandler {
204
198
self . runFinalAction ( . close, context: context)
205
199
206
200
case . succeedRequest( let finalAction, let finalParts) :
201
+ // We can force unwrap the request here, as we have just validated in the state machine,
202
+ // that the request object is still present.
207
203
self . request!. succeedRequest ( finalParts)
208
204
self . request = nil
209
205
self . runTimeoutAction ( . clearIdleReadTimeoutTimer, context: context)
210
206
self . runFinalAction ( finalAction, context: context)
211
207
}
212
208
}
213
209
210
+ private func sendRequestHead( _ head: HTTPRequestHead , startBody: Bool , context: ChannelHandlerContext ) {
211
+ if startBody {
212
+ context. writeAndFlush ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
213
+
214
+ // The above write might trigger an error, which may lead to a call to `errorCaught`,
215
+ // which in turn, may fail the request and pop it from the handler. For this reason
216
+ // we must check if the request is still present here.
217
+ guard let request = self . request else { return }
218
+ request. requestHeadSent ( )
219
+ request. resumeRequestBodyStream ( )
220
+ } else {
221
+ context. write ( self . wrapOutboundOut ( . head( head) ) , promise: nil )
222
+ context. write ( self . wrapOutboundOut ( . end( nil ) ) , promise: nil )
223
+ context. flush ( )
224
+
225
+ // The above write might trigger an error, which may lead to a call to `errorCaught`,
226
+ // which in turn, may fail the request and pop it from the handler. For this reason
227
+ // we must check if the request is still present here.
228
+ guard let request = self . request else { return }
229
+ request. requestHeadSent ( )
230
+
231
+ if let timeoutAction = self . idleReadTimeoutStateMachine? . requestEndSent ( ) {
232
+ self . runTimeoutAction ( timeoutAction, context: context)
233
+ }
234
+ }
235
+ }
236
+
214
237
private func runFinalAction( _ action: HTTPRequestStateMachine . Action . FinalStreamAction , context: ChannelHandlerContext ) {
215
238
switch action {
216
239
case . close:
0 commit comments