@@ -108,16 +108,24 @@ struct HTTPRequestStateMachine {
108108 }
109109
110110 mutating func startRequest( head: HTTPRequestHead , metadata: RequestFramingMetadata ) -> Action {
111- guard case . initialized = self . state else {
112- preconditionFailure ( " `start()` must be called first, and exactly once. Invalid state: \( self . state) " )
113- }
111+ switch self . state {
112+ case . initialized:
113+ guard self . isChannelWritable else {
114+ self . state = . waitForChannelToBecomeWritable( head, metadata)
115+ return . wait
116+ }
117+ return self . startSendingRequest ( head: head, metadata: metadata)
114118
115- guard self . isChannelWritable else {
116- self . state = . waitForChannelToBecomeWritable( head, metadata)
119+ case . failed:
120+ // The request state machine is marked as failed before the request is started, if
121+ // the request was cancelled before hitting the channel handler. Before `startRequest`
122+ // is called on the state machine, `willExecuteRequest` is called on
123+ // `HTTPExecutableRequest`, which might loopback to state machines cancel method.
117124 return . wait
118- }
119125
120- return self . startSendingRequest ( head: head, metadata: metadata)
126+ case . running, . finished, . waitForChannelToBecomeWritable, . modifying:
127+ preconditionFailure ( " `startRequest()` must be called first, and exactly once. Invalid state: \( self . state) " )
128+ }
121129 }
122130
123131 mutating func writabilityChanged( writable: Bool ) -> Action {
@@ -381,6 +389,10 @@ struct HTTPRequestStateMachine {
381389 case . initialized, . waitForChannelToBecomeWritable:
382390 let error = HTTPClientError . cancelled
383391 self . state = . failed( error)
392+ // Okay, this has different semantics for HTTP/1 and HTTP/2. In HTTP/1 we don't want to
393+ // close the connection, if we haven't sent anything yet, to reuse the connection for
394+ // another request. In HTTP/2 we must close the channel to ensure it is released from
395+ // HTTP/2 multiplexer.
384396 return . failRequest( error, . none)
385397
386398 case . running:
0 commit comments