@@ -3712,6 +3712,87 @@ await ExpectAsync(Http2FrameType.DATA,
3712
3712
Assert . Equal ( "Hello World" , Encoding . UTF8 . GetString ( bodyFrame . Payload . Span ) ) ;
3713
3713
}
3714
3714
3715
+ [ Fact ]
3716
+ public async Task CompleteAsync_AfterPipeWrite_WithTrailers_SendsBodyAndTrailersWithEndStream ( )
3717
+ {
3718
+ var startingTcs = new TaskCompletionSource < int > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
3719
+ var appTcs = new TaskCompletionSource < int > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
3720
+ var clientTcs = new TaskCompletionSource < int > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
3721
+ var headers = new [ ]
3722
+ {
3723
+ new KeyValuePair < string , string > ( HeaderNames . Method , "GET" ) ,
3724
+ new KeyValuePair < string , string > ( HeaderNames . Path , "/" ) ,
3725
+ new KeyValuePair < string , string > ( HeaderNames . Scheme , "http" ) ,
3726
+ } ;
3727
+ await InitializeConnectionAsync ( async context =>
3728
+ {
3729
+ try
3730
+ {
3731
+ context . Response . OnStarting ( ( ) => { startingTcs . SetResult ( 0 ) ; return Task . CompletedTask ; } ) ;
3732
+ var completionFeature = context . Features . Get < IHttpResponseCompletionFeature > ( ) ;
3733
+ Assert . NotNull ( completionFeature ) ;
3734
+
3735
+ var buffer = context . Response . BodyWriter . GetMemory ( ) ;
3736
+ var length = Encoding . UTF8 . GetBytes ( "Hello World" , buffer . Span ) ;
3737
+ context . Response . BodyWriter . Advance ( length ) ;
3738
+
3739
+ Assert . False ( startingTcs . Task . IsCompletedSuccessfully ) ; // OnStarting did not get called.
3740
+ Assert . False ( context . Response . Headers . IsReadOnly ) ;
3741
+
3742
+ context . Response . AppendTrailer ( "CustomName" , "Custom Value" ) ;
3743
+
3744
+ await completionFeature . CompleteAsync ( ) . DefaultTimeout ( ) ;
3745
+ Assert . True ( startingTcs . Task . IsCompletedSuccessfully ) ; // OnStarting got called.
3746
+ Assert . True ( context . Response . Headers . IsReadOnly ) ;
3747
+
3748
+ Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
3749
+
3750
+ // Make sure the client gets our results from CompleteAsync instead of from the request delegate exiting.
3751
+ await clientTcs . Task . DefaultTimeout ( ) ;
3752
+ appTcs . SetResult ( 0 ) ;
3753
+ }
3754
+ catch ( Exception ex )
3755
+ {
3756
+ appTcs . SetException ( ex ) ;
3757
+ }
3758
+ } ) ;
3759
+
3760
+ await StartStreamAsync ( 1 , headers , endStream : true ) ;
3761
+
3762
+ var headersFrame = await ExpectAsync ( Http2FrameType . HEADERS ,
3763
+ withLength : 37 ,
3764
+ withFlags : ( byte ) ( Http2HeadersFrameFlags . END_HEADERS ) ,
3765
+ withStreamId : 1 ) ;
3766
+ var bodyFrame = await ExpectAsync ( Http2FrameType . DATA ,
3767
+ withLength : 11 ,
3768
+ withFlags : ( byte ) ( Http2HeadersFrameFlags . NONE ) ,
3769
+ withStreamId : 1 ) ;
3770
+ var trailersFrame = await ExpectAsync ( Http2FrameType . HEADERS ,
3771
+ withLength : 25 ,
3772
+ withFlags : ( byte ) ( Http2HeadersFrameFlags . END_HEADERS | Http2HeadersFrameFlags . END_STREAM ) ,
3773
+ withStreamId : 1 ) ;
3774
+
3775
+ clientTcs . SetResult ( 0 ) ;
3776
+ await appTcs . Task ;
3777
+
3778
+ await StopConnectionAsync ( expectedLastStreamId : 1 , ignoreNonGoAwayFrames : false ) ;
3779
+
3780
+ _hpackDecoder . Decode ( headersFrame . PayloadSequence , endHeaders : false , handler : this ) ;
3781
+
3782
+ Assert . Equal ( 2 , _decodedHeaders . Count ) ;
3783
+ Assert . Contains ( "date" , _decodedHeaders . Keys , StringComparer . OrdinalIgnoreCase ) ;
3784
+ Assert . Equal ( "200" , _decodedHeaders [ HeaderNames . Status ] ) ;
3785
+
3786
+ Assert . Equal ( "Hello World" , Encoding . UTF8 . GetString ( bodyFrame . Payload . Span ) ) ;
3787
+
3788
+ _decodedHeaders . Clear ( ) ;
3789
+
3790
+ _hpackDecoder . Decode ( trailersFrame . PayloadSequence , endHeaders : true , handler : this ) ;
3791
+
3792
+ Assert . Single ( _decodedHeaders ) ;
3793
+ Assert . Equal ( "Custom Value" , _decodedHeaders [ "CustomName" ] ) ;
3794
+ }
3795
+
3715
3796
[ Fact ]
3716
3797
public async Task CompleteAsync_AfterBodyStarted_WithTrailers_SendsBodyAndTrailersWithEndStream ( )
3717
3798
{
0 commit comments