@@ -28,6 +28,7 @@ extension Transaction {
2828 private enum State {
2929 case initialized( CheckedContinuation < HTTPClientResponse , Error > )
3030 case queued( CheckedContinuation < HTTPClientResponse , Error > , HTTPRequestScheduler )
31+ case deadlineExceededWhileQueued( CheckedContinuation < HTTPClientResponse , Error > )
3132 case executing( ExecutionContext , RequestStreamState , ResponseStreamState )
3233 case finished( error: Error ? , HTTPClientResponse . Body . IteratorStream . ID ? )
3334 }
@@ -105,7 +106,20 @@ extension Transaction {
105106 case . queued( let continuation, let scheduler) :
106107 self . state = . finished( error: error, nil )
107108 return . failResponseHead( continuation, error, scheduler, nil , bodyStreamContinuation: nil )
108-
109+ case . deadlineExceededWhileQueued( let continuation) :
110+ let realError : Error = {
111+ if ( error as? HTTPClientError ) == . cancelled {
112+ /// if we just get a `HTTPClientError.cancelled` we can use the original cancellation reason
113+ /// to give a more descriptive error to the user.
114+ return HTTPClientError . deadlineExceeded
115+ } else {
116+ /// otherwise we already had an intermediate connection error which we should present to the user instead
117+ return error
118+ }
119+ } ( )
120+
121+ self . state = . finished( error: realError, nil )
122+ return . failResponseHead( continuation, realError, nil , nil , bodyStreamContinuation: nil )
109123 case . executing( let context, let requestStreamState, . waitingForResponseHead) :
110124 switch requestStreamState {
111125 case . paused( continuation: . some( let continuation) ) :
@@ -178,6 +192,7 @@ extension Transaction {
178192
179193 enum StartExecutionAction {
180194 case cancel( HTTPRequestExecutor )
195+ case cancelAndFail( HTTPRequestExecutor , CheckedContinuation < HTTPClientResponse , Error > , with: Error )
181196 case none
182197 }
183198
@@ -191,6 +206,8 @@ extension Transaction {
191206 )
192207 self . state = . executing( context, . requestHeadSent, . waitingForResponseHead)
193208 return . none
209+ case . deadlineExceededWhileQueued( let continuation) :
210+ return . cancelAndFail( executor, continuation, with: HTTPClientError . deadlineExceeded)
194211
195212 case . finished( error: . some, . none) :
196213 return . cancel( executor)
@@ -210,7 +227,7 @@ extension Transaction {
210227
211228 mutating func resumeRequestBodyStream( ) -> ResumeProducingAction {
212229 switch self . state {
213- case . initialized, . queued:
230+ case . initialized, . queued, . deadlineExceededWhileQueued :
214231 preconditionFailure ( " Received a resumeBodyRequest on a request, that isn't executing. Invalid state: \( self . state) " )
215232
216233 case . executing( let context, . requestHeadSent, let responseState) :
@@ -246,6 +263,7 @@ extension Transaction {
246263 switch self . state {
247264 case . initialized,
248265 . queued,
266+ . deadlineExceededWhileQueued,
249267 . executing( _, . requestHeadSent, _) :
250268 preconditionFailure ( " A request stream can only be resumed, if the request was started " )
251269
@@ -271,6 +289,7 @@ extension Transaction {
271289 switch self . state {
272290 case . initialized,
273291 . queued,
292+ . deadlineExceededWhileQueued,
274293 . executing( _, . requestHeadSent, _) :
275294 preconditionFailure ( " A request stream can only produce, if the request was started. Invalid state: \( self . state) " )
276295
@@ -301,6 +320,7 @@ extension Transaction {
301320 switch self . state {
302321 case . initialized,
303322 . queued,
323+ . deadlineExceededWhileQueued,
304324 . executing( _, . requestHeadSent, _) ,
305325 . executing( _, . finished, _) :
306326 preconditionFailure ( " A request stream can only produce, if the request was started. Invalid state: \( self . state) " )
@@ -334,6 +354,7 @@ extension Transaction {
334354 switch self . state {
335355 case . initialized,
336356 . queued,
357+ . deadlineExceededWhileQueued,
337358 . executing( _, . finished, _) :
338359 preconditionFailure ( " Invalid state: \( self . state) " )
339360
@@ -372,6 +393,7 @@ extension Transaction {
372393 switch self . state {
373394 case . initialized,
374395 . queued,
396+ . deadlineExceededWhileQueued,
375397 . executing( _, _, . waitingForResponseIterator) ,
376398 . executing( _, _, . buffering) ,
377399 . executing( _, _, . waitingForRemote) :
@@ -401,7 +423,7 @@ extension Transaction {
401423
402424 mutating func receiveResponseBodyParts( _ buffer: CircularBuffer < ByteBuffer > ) -> ReceiveResponsePartAction {
403425 switch self . state {
404- case . initialized, . queued:
426+ case . initialized, . queued, . deadlineExceededWhileQueued :
405427 preconditionFailure ( " Received a response body part, but request hasn't started yet. Invalid state: \( self . state) " )
406428
407429 case . executing( _, _, . waitingForResponseHead) :
@@ -457,6 +479,7 @@ extension Transaction {
457479 switch self . state {
458480 case . initialized,
459481 . queued,
482+ . deadlineExceededWhileQueued,
460483 . executing( _, _, . waitingForResponseHead) :
461484 preconditionFailure ( " Got notice about a deinited response, before we even received a response. Invalid state: \( self . state) " )
462485
@@ -486,7 +509,7 @@ extension Transaction {
486509
487510 mutating func responseBodyIteratorDeinited( streamID: HTTPClientResponse . Body . IteratorStream . ID ) -> FailAction {
488511 switch self . state {
489- case . initialized, . queued, . executing( _, _, . waitingForResponseHead) :
512+ case . initialized, . queued, . deadlineExceededWhileQueued , . executing( _, _, . waitingForResponseHead) :
490513 preconditionFailure ( " Got notice about a deinited response body iterator, before we even received a response. Invalid state: \( self . state) " )
491514
492515 case . executing( _, _, . buffering( let registeredStreamID, _, next: _) ) ,
@@ -516,6 +539,7 @@ extension Transaction {
516539 switch self . state {
517540 case . initialized,
518541 . queued,
542+ . deadlineExceededWhileQueued,
519543 . executing( _, _, . waitingForResponseHead) :
520544 preconditionFailure ( " If we receive a response body, we must have received a head before " )
521545
@@ -635,6 +659,7 @@ extension Transaction {
635659 switch self . state {
636660 case . initialized,
637661 . queued,
662+ . deadlineExceededWhileQueued,
638663 . executing( _, _, . waitingForResponseHead) :
639664 preconditionFailure ( " Received no response head, but received a response end. Invalid state: \( self . state) " )
640665
@@ -677,6 +702,7 @@ extension Transaction {
677702
678703 enum DeadlineExceededAction {
679704 case none
705+ case cancelSchedulerOnly( scheduler: HTTPRequestScheduler )
680706 /// fail response before head received. scheduler and executor are exclusive here.
681707 case cancel(
682708 requestContinuation: CheckedContinuation < HTTPClientResponse , Error > ,
@@ -699,14 +725,12 @@ extension Transaction {
699725 )
700726
701727 case . queued( let continuation, let scheduler) :
702- self . state = . finished( error: error, nil )
703- return . cancel(
704- requestContinuation: continuation,
705- scheduler: scheduler,
706- executor: nil ,
707- bodyStreamContinuation: nil
728+ self . state = . deadlineExceededWhileQueued( continuation)
729+ return . cancelSchedulerOnly(
730+ scheduler: scheduler
708731 )
709-
732+ case . deadlineExceededWhileQueued:
733+ return . none
710734 case . executing( let context, let requestStreamState, . waitingForResponseHead) :
711735 switch requestStreamState {
712736 case . paused( continuation: . some( let continuation) ) :
0 commit comments