7
7
using System . Net . Http ;
8
8
using System . Net . Http . QPack ;
9
9
using System . Runtime . CompilerServices ;
10
+ using System . Threading . Tasks . Sources ;
10
11
using Microsoft . AspNetCore . Connections ;
11
12
using Microsoft . AspNetCore . Connections . Features ;
12
13
using Microsoft . AspNetCore . Hosting . Server ;
@@ -47,8 +48,7 @@ internal abstract partial class Http3Stream : HttpProtocol, IHttp3Stream, IHttpH
47
48
private int _totalParsedHeaderSize ;
48
49
private bool _isMethodConnect ;
49
50
50
- // TODO: Change to resetable ValueTask source
51
- private TaskCompletionSource ? _appCompleted ;
51
+ private readonly ManualResetValueTaskSource < object ? > _appCompletedTaskSource = new ManualResetValueTaskSource < object ? > ( ) ;
52
52
53
53
private StreamCompletionFlags _completionState ;
54
54
private readonly object _completionLock = new object ( ) ;
@@ -70,8 +70,8 @@ internal abstract partial class Http3Stream : HttpProtocol, IHttp3Stream, IHttpH
70
70
public long StreamId => _streamIdFeature . StreamId ;
71
71
72
72
public long StreamTimeoutTicks { get ; set ; }
73
- public bool IsReceivingHeader => _appCompleted == null ; // TCS is assigned once headers are received
74
- public bool IsDraining => _appCompleted ? . Task . IsCompleted ?? false ; // Draining starts once app is complete
73
+ public bool IsReceivingHeader => _requestHeaderParsingState <= RequestHeaderParsingState . Headers ; // Assigned once headers are received
74
+ public bool IsDraining => _appCompletedTaskSource . GetStatus ( ) != ValueTaskSourceStatus . Pending ; // Draining starts once app is complete
75
75
76
76
public bool IsRequestStream => true ;
77
77
@@ -87,7 +87,7 @@ public void Initialize(Http3StreamContext context)
87
87
_streamIdFeature = _context . ConnectionFeatures . Get < IStreamIdFeature > ( ) ! ;
88
88
_streamAbortFeature = _context . ConnectionFeatures . Get < IStreamAbortFeature > ( ) ! ;
89
89
90
- _appCompleted = null ;
90
+ _appCompletedTaskSource . Reset ( ) ;
91
91
_isClosed = 0 ;
92
92
_requestHeaderParsingState = default ;
93
93
_parsedPseudoHeaderFields = default ;
@@ -403,8 +403,7 @@ private void CompleteStream(bool errored)
403
403
404
404
// Stream will be pooled after app completed.
405
405
// Wait to signal app completed after any potential aborts on the stream.
406
- Debug . Assert ( _appCompleted != null ) ;
407
- _appCompleted . SetResult ( ) ;
406
+ _appCompletedTaskSource . SetResult ( null ) ;
408
407
}
409
408
410
409
private bool TryClose ( )
@@ -492,8 +491,12 @@ public async Task ProcessRequestAsync<TContext>(IHttpApplication<TContext> appli
492
491
493
492
await Input . CompleteAsync ( ) ;
494
493
495
- var appCompleted = _appCompleted ? . Task ?? Task . CompletedTask ;
496
- if ( ! appCompleted . IsCompletedSuccessfully )
494
+ // Once the header is finished being received then the app has started.
495
+ var appCompletedTask = ! IsReceivingHeader
496
+ ? new ValueTask ( _appCompletedTaskSource , _appCompletedTaskSource . Version )
497
+ : ValueTask . CompletedTask ;
498
+
499
+ if ( ! appCompletedTask . IsCompletedSuccessfully )
497
500
{
498
501
// At this point in the stream's read-side is complete. However, with HTTP/3
499
502
// the write-side of the stream can still be aborted by the client on request
@@ -529,7 +532,7 @@ public async Task ProcessRequestAsync<TContext>(IHttpApplication<TContext> appli
529
532
} , this ) ;
530
533
531
534
// Make sure application func is completed before completing writer.
532
- await appCompleted ;
535
+ await appCompletedTask ;
533
536
}
534
537
535
538
try
@@ -630,7 +633,7 @@ private async Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext>
630
633
throw new Http3ConnectionErrorException ( CoreStrings . FormatHttp3StreamErrorFrameReceivedAfterTrailers ( Http3Formatting . ToFormattedType ( Http3FrameType . Headers ) ) , Http3ErrorCode . UnexpectedFrame ) ;
631
634
}
632
635
633
- if ( _requestHeaderParsingState == RequestHeaderParsingState . Headers )
636
+ if ( _requestHeaderParsingState == RequestHeaderParsingState . Body )
634
637
{
635
638
_requestHeaderParsingState = RequestHeaderParsingState . Trailers ;
636
639
}
@@ -679,7 +682,7 @@ private async Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext>
679
682
throw new Http3StreamErrorException ( CoreStrings . HttpErrorMissingMandatoryPseudoHeaderFields , Http3ErrorCode . MessageError ) ;
680
683
}
681
684
682
- _appCompleted = new TaskCompletionSource ( ) ;
685
+ _requestHeaderParsingState = RequestHeaderParsingState . Body ;
683
686
StreamTimeoutTicks = default ;
684
687
_context . StreamLifetimeHandler . OnStreamHeaderReceived ( this ) ;
685
688
@@ -990,6 +993,7 @@ protected enum RequestHeaderParsingState
990
993
Ready ,
991
994
PseudoHeaderFields ,
992
995
Headers ,
996
+ Body ,
993
997
Trailers
994
998
}
995
999
0 commit comments