@@ -468,6 +468,101 @@ public async Task Request_EscapedControlCharacters_400()
468
468
}
469
469
}
470
470
471
+ [ ConditionalFact ]
472
+ public async Task RequestAborted_AfterAccessingProperty_Notified ( )
473
+ {
474
+ var registered = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
475
+ var result = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
476
+ using var server = Utilities . CreateHttpServerReturnRoot ( "/" , out var address , async httpContext =>
477
+ {
478
+ var ct = httpContext . RequestAborted ;
479
+
480
+ if ( ! ct . CanBeCanceled || ct . IsCancellationRequested )
481
+ {
482
+ result . SetException ( new Exception ( "The CT isn't valid." ) ) ;
483
+ return ;
484
+ }
485
+
486
+ ct . Register ( ( ) => result . SetResult ( ) ) ;
487
+
488
+ registered . SetResult ( ) ;
489
+
490
+ // Don't exit until it fires or else it could be disposed.
491
+ await result . Task . DefaultTimeout ( ) ;
492
+ } ) ;
493
+
494
+ // Send a request and then abort.
495
+
496
+ var uri = new Uri ( address ) ;
497
+ StringBuilder builder = new StringBuilder ( ) ;
498
+ builder . AppendLine ( "POST / HTTP/1.1" ) ;
499
+ builder . AppendLine ( "Connection: close" ) ;
500
+ builder . AppendLine ( "Content-Length: 10" ) ;
501
+ builder . Append ( "HOST: " ) ;
502
+ builder . AppendLine ( uri . Authority ) ;
503
+ builder . AppendLine ( ) ;
504
+
505
+ byte [ ] request = Encoding . ASCII . GetBytes ( builder . ToString ( ) ) ;
506
+
507
+ using var socket = new Socket ( SocketType . Stream , ProtocolType . Tcp ) ;
508
+
509
+ await socket . ConnectAsync ( uri . Host , uri . Port ) ;
510
+ socket . Send ( request ) ;
511
+
512
+ // Wait for the token to be setup before aborting.
513
+ await registered . Task . DefaultTimeout ( ) ;
514
+
515
+ socket . Close ( ) ;
516
+
517
+ await result . Task . DefaultTimeout ( ) ;
518
+ }
519
+
520
+ [ ConditionalFact ]
521
+ public async Task RequestAbortedDurringRead_BeforeAccessingProperty_TokenAlreadyCanceled ( )
522
+ {
523
+ var requestAborted = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
524
+ var result = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
525
+ using var server = Utilities . CreateHttpServerReturnRoot ( "/" , out var address , async httpContext =>
526
+ {
527
+ await requestAborted . Task . DefaultTimeout ( ) ;
528
+ try
529
+ {
530
+ await httpContext . Request . Body . ReadAsync ( new byte [ 10 ] ) . DefaultTimeout ( ) ;
531
+ result . SetException ( new Exception ( "This should have aborted" ) ) ;
532
+ return ;
533
+ }
534
+ catch ( IOException )
535
+ {
536
+ }
537
+
538
+ result . SetResult ( httpContext . RequestAborted . IsCancellationRequested ) ;
539
+ } ) ;
540
+
541
+ // Send a request and then abort.
542
+
543
+ var uri = new Uri ( address ) ;
544
+ StringBuilder builder = new StringBuilder ( ) ;
545
+ builder . AppendLine ( "POST / HTTP/1.1" ) ;
546
+ builder . AppendLine ( "Connection: close" ) ;
547
+ builder . AppendLine ( "Content-Length: 10" ) ;
548
+ builder . Append ( "HOST: " ) ;
549
+ builder . AppendLine ( uri . Authority ) ;
550
+ builder . AppendLine ( ) ;
551
+
552
+ byte [ ] request = Encoding . ASCII . GetBytes ( builder . ToString ( ) ) ;
553
+
554
+ using var socket = new Socket ( SocketType . Stream , ProtocolType . Tcp ) ;
555
+
556
+ await socket . ConnectAsync ( uri . Host , uri . Port ) ;
557
+ socket . Send ( request ) ;
558
+ socket . Close ( ) ;
559
+
560
+ requestAborted . SetResult ( ) ;
561
+
562
+ var wasCancelled = await result . Task ;
563
+ Assert . True ( wasCancelled ) ;
564
+ }
565
+
471
566
private IServer CreateServer ( out string root , RequestDelegate app )
472
567
{
473
568
// TODO: We're just doing this to get a dynamic port. This can be removed later when we add support for hot-adding prefixes.
0 commit comments