@@ -20,21 +20,24 @@ struct HTTPRequestStateMachine {
2020 fileprivate enum State {
2121 /// The initial state machine state. The only valid mutation is `start()`. The state will
2222 /// transitions to:
23- /// - `.waitForChannelToBecomeWritable`
24- /// - `.running(.streaming, .initialized)` (if the Channel is writable and if a request body is expected)
25- /// - `.running(.endSent, .initialized)` (if the Channel is writable and no request body is expected)
23+ /// - `.waitForChannelToBecomeWritable` (if the channel becomes non writable while sending the header)
24+ /// - `.sendingHead` if the channel is writable
2625 case initialized
26+
2727 /// Waiting for the channel to be writable. Valid transitions are:
28- /// - `.running(.streaming, .initialized )` (once the Channel is writable again and if a request body is expected)
29- /// - `.running(.endSent, .initialized )` (once the Channel is writable again and no request body is expected)
28+ /// - `.running(.streaming, .waitingForHead )` (once the Channel is writable again and if a request body is expected)
29+ /// - `.running(.endSent, .waitingForHead )` (once the Channel is writable again and no request body is expected)
3030 /// - `.failed` (if a connection error occurred)
3131 case waitForChannelToBecomeWritable( HTTPRequestHead , RequestFramingMetadata )
32+
3233 /// A request is on the wire. Valid transitions are:
3334 /// - `.finished`
3435 /// - `.failed`
3536 case running( RequestState , ResponseState )
37+
3638 /// The request has completed successfully
3739 case finished
40+
3841 /// The request has failed
3942 case failed( Error )
4043
@@ -93,7 +96,11 @@ struct HTTPRequestStateMachine {
9396 case none
9497 }
9598
96- case sendRequestHead( HTTPRequestHead , startBody: Bool )
99+ case sendRequestHead( HTTPRequestHead , sendEnd: Bool )
100+ case notifyRequestHeadSendSuccessfully(
101+ resumeRequestBodyStream: Bool ,
102+ startIdleTimer: Bool
103+ )
97104 case sendBodyPart( IOData , EventLoopPromise < Void > ? )
98105 case sendRequestEnd( EventLoopPromise < Void > ? )
99106 case failSendBodyPart( Error , EventLoopPromise < Void > ? )
@@ -223,6 +230,7 @@ struct HTTPRequestStateMachine {
223230 // the request failed, before it was sent onto the wire.
224231 self . state = . failed( error)
225232 return . failRequest( error, . none)
233+
226234 case . running:
227235 self . state = . failed( error)
228236 return . failRequest( error, . close( nil ) )
@@ -520,7 +528,7 @@ struct HTTPRequestStateMachine {
520528
521529 switch self . state {
522530 case . initialized, . waitForChannelToBecomeWritable:
523- preconditionFailure ( " How can we receive a response head before sending a request head ourselves " )
531+ preconditionFailure ( " How can we receive a response head before sending a request head ourselves \( self . state ) " )
524532
525533 case . running( . streaming( let expectedBodyLength, let sentBodyBytes, producer: . paused) , . waitingForHead) :
526534 self . state = . running(
@@ -561,7 +569,7 @@ struct HTTPRequestStateMachine {
561569 mutating func receivedHTTPResponseBodyPart( _ body: ByteBuffer ) -> Action {
562570 switch self . state {
563571 case . initialized, . waitForChannelToBecomeWritable:
564- preconditionFailure ( " How can we receive a response head before sending a request head ourselves. Invalid state: \( self . state) " )
572+ preconditionFailure ( " How can we receive a response head before completely sending a request head ourselves. Invalid state: \( self . state) " )
565573
566574 case . running( _, . waitingForHead) :
567575 preconditionFailure ( " How can we receive a response body, if we haven't received a head. Invalid state: \( self . state) " )
@@ -587,7 +595,7 @@ struct HTTPRequestStateMachine {
587595 private mutating func receivedHTTPResponseEnd( ) -> Action {
588596 switch self . state {
589597 case . initialized, . waitForChannelToBecomeWritable:
590- preconditionFailure ( " How can we receive a response head before sending a request head ourselves. Invalid state: \( self . state) " )
598+ preconditionFailure ( " How can we receive a response end before completely sending a request head ourselves. Invalid state: \( self . state) " )
591599
592600 case . running( _, . waitingForHead) :
593601 preconditionFailure ( " How can we receive a response end, if we haven't a received a head. Invalid state: \( self . state) " )
@@ -654,7 +662,7 @@ struct HTTPRequestStateMachine {
654662 case . initialized,
655663 . running( _, . waitingForHead) ,
656664 . waitForChannelToBecomeWritable:
657- preconditionFailure ( " The response is expected to only ask for more data after the response head was forwarded " )
665+ preconditionFailure ( " The response is expected to only ask for more data after the response head was forwarded \( self . state ) " )
658666
659667 case . running( let requestState, . receivingBody( let head, var responseStreamState) ) :
660668 return self . avoidingStateMachineCoW { state -> Action in
@@ -697,18 +705,51 @@ struct HTTPRequestStateMachine {
697705 }
698706
699707 private mutating func startSendingRequest( head: HTTPRequestHead , metadata: RequestFramingMetadata ) -> Action {
700- switch metadata. body {
701- case . stream:
702- self . state = . running( . streaming( expectedBodyLength: nil , sentBodyBytes: 0 , producer: . producing) , . waitingForHead)
703- return . sendRequestHead( head, startBody: true )
704- case . fixedSize( 0 ) :
708+ let length = metadata. body. expectedLength
709+ if length == 0 {
705710 // no body
706711 self . state = . running( . endSent, . waitingForHead)
707- return . sendRequestHead( head, startBody: false )
708- case . fixedSize( let length) :
709- // length is greater than zero and we therefore have a body to send
710- self . state = . running( . streaming( expectedBodyLength: length, sentBodyBytes: 0 , producer: . producing) , . waitingForHead)
711- return . sendRequestHead( head, startBody: true )
712+ return . sendRequestHead( head, sendEnd: true )
713+ } else {
714+ self . state = . running( . streaming( expectedBodyLength: length, sentBodyBytes: 0 , producer: . paused) , . waitingForHead)
715+ return . sendRequestHead( head, sendEnd: false )
716+ }
717+ }
718+
719+ mutating func headSent( ) -> Action {
720+ switch self . state {
721+ case . initialized, . waitForChannelToBecomeWritable, . finished:
722+ preconditionFailure ( " Not a valid transition after `.sendingHeader`: \( self . state) " )
723+
724+ case . running( . streaming( let expectedBodyLength, let sentBodyBytes, producer: . paused) , let responseState) :
725+ let startProducing = self . isChannelWritable && expectedBodyLength != sentBodyBytes
726+ self . state = . running( . streaming(
727+ expectedBodyLength: expectedBodyLength,
728+ sentBodyBytes: sentBodyBytes,
729+ producer: startProducing ? . producing : . paused
730+ ) , responseState)
731+ return . notifyRequestHeadSendSuccessfully(
732+ resumeRequestBodyStream: startProducing,
733+ startIdleTimer: false
734+ )
735+ case . running( . endSent, _) :
736+ return . notifyRequestHeadSendSuccessfully( resumeRequestBodyStream: false , startIdleTimer: true )
737+ case . running( . streaming( _, _, producer: . producing) , _) :
738+ preconditionFailure ( " request body producing can not start before we have successfully send the header \( self . state) " )
739+ case . failed:
740+ return . wait
741+
742+ case . modifying:
743+ preconditionFailure ( " Invalid state: \( self . state) " )
744+ }
745+ }
746+ }
747+
748+ extension RequestFramingMetadata . Body {
749+ var expectedLength : Int ? {
750+ switch self {
751+ case . fixedSize( let length) : return length
752+ case . stream: return nil
712753 }
713754 }
714755}
0 commit comments