@@ -3712,6 +3712,87 @@ await ExpectAsync(Http2FrameType.DATA,
37123712 Assert . Equal ( "Hello World" , Encoding . UTF8 . GetString ( bodyFrame . Payload . Span ) ) ;
37133713 }
37143714
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+
37153796 [ Fact ]
37163797 public async Task CompleteAsync_AfterBodyStarted_WithTrailers_SendsBodyAndTrailersWithEndStream ( )
37173798 {
0 commit comments