@@ -5239,10 +5239,10 @@ await InitializeConnectionAsync(async context =>
5239
5239
5240
5240
await context . Response . CompleteAsync ( ) . DefaultTimeout ( ) ;
5241
5241
5242
- Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
5243
-
5244
5242
// Make sure the client gets our results from CompleteAsync instead of from the request delegate exiting.
5245
5243
await clientTcs . Task . DefaultTimeout ( ) ;
5244
+
5245
+ Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
5246
5246
appTcs . SetResult ( ) ;
5247
5247
}
5248
5248
catch ( Exception ex )
@@ -5432,6 +5432,7 @@ await WaitForStreamErrorAsync(1, Http2ErrorCode.INTERNAL_ERROR,
5432
5432
public async Task AbortAfterCompleteAsync_GETWithResponseBodyAndTrailers_ResetsAfterResponse ( )
5433
5433
{
5434
5434
var startingTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5435
+ var trailersTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5435
5436
var appTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5436
5437
var clientTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5437
5438
var headers = new [ ]
@@ -5453,6 +5454,9 @@ await InitializeConnectionAsync(async context =>
5453
5454
context . Response . AppendTrailer ( "CustomName" , "Custom Value" ) ;
5454
5455
5455
5456
await context . Response . CompleteAsync ( ) . DefaultTimeout ( ) ;
5457
+ // Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5458
+ // That something is the client side receiving the trailers.
5459
+ await trailersTcs . Task ;
5456
5460
5457
5461
Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
5458
5462
@@ -5484,6 +5488,7 @@ await InitializeConnectionAsync(async context =>
5484
5488
withLength : 25 ,
5485
5489
withFlags : ( byte ) ( Http2HeadersFrameFlags . END_HEADERS | Http2HeadersFrameFlags . END_STREAM ) ,
5486
5490
withStreamId : 1 ) ;
5491
+ trailersTcs . SetResult ( ) ;
5487
5492
// Stream should return an INTERNAL_ERROR. If there is an unexpected exception from app TCS instead, then throw it here to avoid timeout waiting for the stream error.
5488
5493
await Task . WhenAny ( WaitForStreamErrorAsync ( 1 , Http2ErrorCode . INTERNAL_ERROR , expectedErrorMessage : null ) , appTcs . Task ) . Unwrap ( ) ;
5489
5494
@@ -5512,6 +5517,7 @@ await InitializeConnectionAsync(async context =>
5512
5517
public async Task AbortAfterCompleteAsync_POSTWithResponseBodyAndTrailers_RequestBodyThrows ( )
5513
5518
{
5514
5519
var startingTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5520
+ var trailersTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5515
5521
var appTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5516
5522
var clientTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5517
5523
var headers = new [ ]
@@ -5535,7 +5541,10 @@ await InitializeConnectionAsync(async context =>
5535
5541
context . Response . AppendTrailer ( "CustomName" , "Custom Value" ) ;
5536
5542
5537
5543
await context . Response . CompleteAsync ( ) . DefaultTimeout ( ) ;
5538
-
5544
+ // Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5545
+ // That something is the client side receiving the trailers.
5546
+ await trailersTcs . Task ;
5547
+
5539
5548
Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
5540
5549
5541
5550
// RequestAborted will no longer fire after CompleteAsync.
@@ -5569,6 +5578,7 @@ await InitializeConnectionAsync(async context =>
5569
5578
withLength : 25 ,
5570
5579
withFlags : ( byte ) ( Http2HeadersFrameFlags . END_HEADERS | Http2HeadersFrameFlags . END_STREAM ) ,
5571
5580
withStreamId : 1 ) ;
5581
+ trailersTcs . SetResult ( ) ;
5572
5582
await WaitForStreamErrorAsync ( 1 , Http2ErrorCode . INTERNAL_ERROR , expectedErrorMessage : null ) ;
5573
5583
5574
5584
clientTcs . SetResult ( ) ;
@@ -5596,6 +5606,7 @@ await InitializeConnectionAsync(async context =>
5596
5606
public async Task ResetAfterCompleteAsync_GETWithResponseBodyAndTrailers_ResetsAfterResponse ( )
5597
5607
{
5598
5608
var startingTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5609
+ var trailersTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5599
5610
var appTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5600
5611
var clientTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5601
5612
var headers = new [ ]
@@ -5617,6 +5628,9 @@ await InitializeConnectionAsync(async context =>
5617
5628
context . Response . AppendTrailer ( "CustomName" , "Custom Value" ) ;
5618
5629
5619
5630
await context . Response . CompleteAsync ( ) . DefaultTimeout ( ) ;
5631
+ // Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5632
+ // That something is the client side receiving the trailers.
5633
+ await trailersTcs . Task ;
5620
5634
5621
5635
Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
5622
5636
@@ -5650,6 +5664,7 @@ await InitializeConnectionAsync(async context =>
5650
5664
withLength : 25 ,
5651
5665
withFlags : ( byte ) ( Http2HeadersFrameFlags . END_HEADERS | Http2HeadersFrameFlags . END_STREAM ) ,
5652
5666
withStreamId : 1 ) ;
5667
+ trailersTcs . SetResult ( ) ;
5653
5668
await WaitForStreamErrorAsync ( 1 , Http2ErrorCode . NO_ERROR , expectedErrorMessage :
5654
5669
"The HTTP/2 stream was reset by the application with error code NO_ERROR." ) ;
5655
5670
@@ -5678,6 +5693,7 @@ await WaitForStreamErrorAsync(1, Http2ErrorCode.NO_ERROR, expectedErrorMessage:
5678
5693
public async Task ResetAfterCompleteAsync_POSTWithResponseBodyAndTrailers_RequestBodyThrows ( )
5679
5694
{
5680
5695
var startingTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5696
+ var trailersTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5681
5697
var appTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5682
5698
var clientTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
5683
5699
var headers = new [ ]
@@ -5701,6 +5717,9 @@ await InitializeConnectionAsync(async context =>
5701
5717
context . Response . AppendTrailer ( "CustomName" , "Custom Value" ) ;
5702
5718
5703
5719
await context . Response . CompleteAsync ( ) . DefaultTimeout ( ) ;
5720
+ // Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5721
+ // That something is the client side receiving the trailers.
5722
+ await trailersTcs . Task ;
5704
5723
5705
5724
Assert . True ( context . Features . Get < IHttpResponseTrailersFeature > ( ) . Trailers . IsReadOnly ) ;
5706
5725
@@ -5737,6 +5756,7 @@ await InitializeConnectionAsync(async context =>
5737
5756
withLength : 25 ,
5738
5757
withFlags : ( byte ) ( Http2HeadersFrameFlags . END_HEADERS | Http2HeadersFrameFlags . END_STREAM ) ,
5739
5758
withStreamId : 1 ) ;
5759
+ trailersTcs . SetResult ( ) ;
5740
5760
await WaitForStreamErrorAsync ( 1 , Http2ErrorCode . NO_ERROR , expectedErrorMessage :
5741
5761
"The HTTP/2 stream was reset by the application with error code NO_ERROR." ) ;
5742
5762
0 commit comments