@@ -30,19 +30,29 @@ struct HTTP1ConnectionStateMachine {
30
30
/// A action to execute, when we consider a request "done".
31
31
enum FinalStreamAction {
32
32
/// Close the connection
33
- case close
33
+ ///
34
+ /// The promise is an optional write promise.
35
+ case close( EventLoopPromise < Void > ? )
34
36
/// If the server has replied, with a status of 200...300 before all data was sent, a request is considered succeeded,
35
37
/// as soon as we wrote the request end onto the wire.
36
- case sendRequestEnd
38
+ ///
39
+ /// The promise is an optional write promise.
40
+ case sendRequestEnd( EventLoopPromise < Void > ? )
37
41
/// Inform an observer that the connection has become idle
38
- case informConnectionIsIdle
42
+ ///
43
+ /// The promise is an optional write promise.
44
+ case informConnectionIsIdle( EventLoopPromise < Void > ? )
39
45
/// Do nothing.
40
- case none
46
+ ///
47
+ /// The promise is an optional write promise.
48
+ case none( EventLoopPromise < Void > ? )
41
49
}
42
50
43
51
case sendRequestHead( HTTPRequestHead , startBody: Bool )
44
- case sendBodyPart( IOData )
45
- case sendRequestEnd
52
+ case sendBodyPart( IOData , EventLoopPromise < Void > ? )
53
+ case sendRequestEnd( EventLoopPromise < Void > ? )
54
+ case failSendBodyPart( Error , EventLoopPromise < Void > ? )
55
+ case failSendStreamFinished( Error , EventLoopPromise < Void > ? )
46
56
47
57
case pauseRequestBodyStream
48
58
case resumeRequestBodyStream
@@ -173,7 +183,7 @@ struct HTTP1ConnectionStateMachine {
173
183
// as closed.
174
184
//
175
185
// TODO: AHC should support a fast rescheduling mechanism here.
176
- return . failRequest( HTTPClientError . remoteConnectionClosed, . none)
186
+ return . failRequest( HTTPClientError . remoteConnectionClosed, . none( nil ) )
177
187
178
188
case . idle:
179
189
var requestStateMachine = HTTPRequestStateMachine ( isChannelWritable: self . isChannelWritable)
@@ -189,25 +199,25 @@ struct HTTP1ConnectionStateMachine {
189
199
}
190
200
}
191
201
192
- mutating func requestStreamPartReceived( _ part: IOData ) -> Action {
202
+ mutating func requestStreamPartReceived( _ part: IOData , promise : EventLoopPromise < Void > ? ) -> Action {
193
203
guard case . inRequest( var requestStateMachine, let close) = self . state else {
194
204
preconditionFailure ( " Invalid state: \( self . state) " )
195
205
}
196
206
197
207
return self . avoidingStateMachineCoW { state -> Action in
198
- let action = requestStateMachine. requestStreamPartReceived ( part)
208
+ let action = requestStateMachine. requestStreamPartReceived ( part, promise : promise )
199
209
state = . inRequest( requestStateMachine, close: close)
200
210
return state. modify ( with: action)
201
211
}
202
212
}
203
213
204
- mutating func requestStreamFinished( ) -> Action {
214
+ mutating func requestStreamFinished( promise : EventLoopPromise < Void > ? ) -> Action {
205
215
guard case . inRequest( var requestStateMachine, let close) = self . state else {
206
216
preconditionFailure ( " Invalid state: \( self . state) " )
207
217
}
208
218
209
219
return self . avoidingStateMachineCoW { state -> Action in
210
- let action = requestStateMachine. requestStreamFinished ( )
220
+ let action = requestStateMachine. requestStreamFinished ( promise : promise )
211
221
state = . inRequest( requestStateMachine, close: close)
212
222
return state. modify ( with: action)
213
223
}
@@ -377,10 +387,10 @@ extension HTTP1ConnectionStateMachine.State {
377
387
return . pauseRequestBodyStream
378
388
case . resumeRequestBodyStream:
379
389
return . resumeRequestBodyStream
380
- case . sendBodyPart( let part) :
381
- return . sendBodyPart( part)
382
- case . sendRequestEnd:
383
- return . sendRequestEnd
390
+ case . sendBodyPart( let part, let writePromise ) :
391
+ return . sendBodyPart( part, writePromise )
392
+ case . sendRequestEnd( let writePromise ) :
393
+ return . sendRequestEnd( writePromise )
384
394
case . forwardResponseHead( let head, let pauseRequestBodyStream) :
385
395
return . forwardResponseHead( head, pauseRequestBodyStream: pauseRequestBodyStream)
386
396
case . forwardResponseBodyParts( let parts) :
@@ -392,39 +402,63 @@ extension HTTP1ConnectionStateMachine.State {
392
402
393
403
let newFinalAction : HTTP1ConnectionStateMachine . Action . FinalStreamAction
394
404
switch finalAction {
395
- case . close:
405
+ case . close( let writePromise ) :
396
406
self = . closing
397
- newFinalAction = . close
398
- case . sendRequestEnd:
399
- newFinalAction = . sendRequestEnd
407
+ newFinalAction = . close( writePromise )
408
+ case . sendRequestEnd( let writePromise ) :
409
+ newFinalAction = . sendRequestEnd( writePromise )
400
410
case . none:
401
411
self = . idle
402
- newFinalAction = close ? . close : . informConnectionIsIdle
412
+ newFinalAction = close ? . close( nil ) : . informConnectionIsIdle( nil )
403
413
}
404
414
return . succeedRequest( newFinalAction, finalParts)
405
415
406
416
case . failRequest( let error, let finalAction) :
407
- switch self {
408
- case . initialized:
417
+ switch ( self , finalAction ) {
418
+ case ( . initialized, _ ) :
409
419
preconditionFailure ( " Invalid state: \( self ) " )
410
- case . idle:
420
+
421
+ case ( . idle, _) :
411
422
preconditionFailure ( " How can we fail a task, if we are idle " )
412
- case . inRequest( _, close: let close) :
413
- if close || finalAction == . close {
414
- self = . closing
415
- return . failRequest( error, . close)
416
- } else {
417
- self = . idle
418
- return . failRequest( error, . informConnectionIsIdle)
419
- }
420
423
421
- case . closing:
422
- return . failRequest( error, . none)
423
- case . closed:
424
+ // If we are either in .inRequest(_, close: true) or the final action is .close
425
+ // we have to fail the request with .close()
426
+ case ( . inRequest( _, let close) , . sendRequestEnd( let writePromise) ) where close:
427
+ self = . closing
428
+ return . failRequest( error, . close( writePromise) )
429
+
430
+ case ( . inRequest( _, let close) , . none) where close:
431
+ self = . closing
432
+ return . failRequest( error, . close( nil ) )
433
+
434
+ case ( . inRequest( _, _) , . close( let writePromise) ) :
435
+ self = . closing
436
+ return . failRequest( error, . close( writePromise) )
437
+
438
+ // otherwise we fail with .informConnectionIsIdle
439
+ case ( . inRequest( _, _) , . sendRequestEnd( let writePromise) ) :
440
+ self = . idle
441
+ return . failRequest( error, . informConnectionIsIdle( writePromise) )
442
+
443
+ case ( . inRequest( _, _) , . none) :
444
+ self = . idle
445
+ return . failRequest( error, . informConnectionIsIdle( nil ) )
446
+
447
+ case ( . closing, . close( let writePromise) ) , ( . closing, . sendRequestEnd( let writePromise) ) :
448
+ return . failRequest( error, . none( writePromise) )
449
+
450
+ case ( . closing, . none) :
451
+ return . failRequest( error, . none( nil ) )
452
+
453
+ case ( . closed, . close( let writePromise) ) , ( . closed, . sendRequestEnd( let writePromise) ) :
424
454
// this state can be reached, if the connection was unexpectedly closed by remote
425
- return . failRequest( error, . none)
455
+ return . failRequest( error, . none( writePromise ) )
426
456
427
- case . modifying:
457
+ case ( . closed, . none) :
458
+ // this state can be reached, if the connection was unexpectedly closed by remote
459
+ return . failRequest( error, . none( nil ) )
460
+
461
+ case ( . modifying, _) :
428
462
preconditionFailure ( " Invalid state: \( self ) " )
429
463
}
430
464
@@ -433,6 +467,12 @@ extension HTTP1ConnectionStateMachine.State {
433
467
434
468
case . wait:
435
469
return . wait
470
+
471
+ case . failSendBodyPart( let error, let writePromise) :
472
+ return . failSendBodyPart( error, writePromise)
473
+
474
+ case . failSendStreamFinished( let error, let writePromise) :
475
+ return . failSendStreamFinished( error, writePromise)
436
476
}
437
477
}
438
478
}
0 commit comments