@@ -35,7 +35,7 @@ internal abstract partial class HttpProtocol : IDefaultHttpContextContainer, IHt
35
35
private Stack < KeyValuePair < Func < object , Task > , object > > _onCompleted ;
36
36
37
37
private object _abortLock = new object ( ) ;
38
- private volatile bool _requestAborted ;
38
+ private volatile bool _connectionAborted ;
39
39
private bool _preventRequestAbortedCancellation ;
40
40
private CancellationTokenSource _abortedCts ;
41
41
private CancellationToken ? _manuallySetRequestAbortToken ;
@@ -257,7 +257,7 @@ public CancellationToken RequestAborted
257
257
return new CancellationToken ( false ) ;
258
258
}
259
259
260
- if ( _requestAborted )
260
+ if ( _connectionAborted )
261
261
{
262
262
return new CancellationToken ( true ) ;
263
263
}
@@ -375,18 +375,19 @@ public void Reset()
375
375
Scheme = _scheme ;
376
376
377
377
_manuallySetRequestAbortToken = null ;
378
- _preventRequestAbortedCancellation = false ;
379
378
380
- // Lock to prevent CancelRequestAbortedToken from attempting to cancel an disposed CTS.
379
+ // Lock to prevent CancelRequestAbortedToken from attempting to cancel a disposed CTS.
380
+ CancellationTokenSource localAbortCts = null ;
381
+
381
382
lock ( _abortLock )
382
383
{
383
- if ( ! _requestAborted )
384
- {
385
- _abortedCts ? . Dispose ( ) ;
386
- _abortedCts = null ;
387
- }
384
+ _preventRequestAbortedCancellation = false ;
385
+ localAbortCts = _abortedCts ;
386
+ _abortedCts = null ;
388
387
}
389
388
389
+ localAbortCts ? . Dispose ( ) ;
390
+
390
391
if ( _wrapperObjectsToDispose != null )
391
392
{
392
393
foreach ( var disposable in _wrapperObjectsToDispose )
@@ -442,9 +443,20 @@ private void CancelRequestAbortedToken()
442
443
{
443
444
try
444
445
{
445
- _abortedCts . Cancel ( ) ;
446
- _abortedCts . Dispose ( ) ;
447
- _abortedCts = null ;
446
+ CancellationTokenSource localAbortCts = null ;
447
+
448
+ lock ( _abortLock )
449
+ {
450
+ if ( _abortedCts != null && ! _preventRequestAbortedCancellation )
451
+ {
452
+ localAbortCts = _abortedCts ;
453
+ _abortedCts = null ;
454
+ }
455
+ }
456
+
457
+ // If we cancel the cts, we don't dispose as people may still be using
458
+ // the cts. It also isn't necessary to dispose a canceled cts.
459
+ localAbortCts ? . Cancel ( ) ;
448
460
}
449
461
catch ( Exception ex )
450
462
{
@@ -454,17 +466,20 @@ private void CancelRequestAbortedToken()
454
466
455
467
protected void AbortRequest ( )
456
468
{
469
+ var shouldScheduleCancellation = false ;
470
+
457
471
lock ( _abortLock )
458
472
{
459
- if ( _requestAborted )
473
+ if ( _connectionAborted )
460
474
{
461
475
return ;
462
476
}
463
477
464
- _requestAborted = true ;
478
+ shouldScheduleCancellation = _abortedCts != null && ! _preventRequestAbortedCancellation ;
479
+ _connectionAborted = true ;
465
480
}
466
481
467
- if ( _abortedCts != null )
482
+ if ( shouldScheduleCancellation )
468
483
{
469
484
// Potentially calling user code. CancelRequestAbortedToken logs any exceptions.
470
485
ServiceContext . Scheduler . Schedule ( state => ( ( HttpProtocol ) state ) . CancelRequestAbortedToken ( ) , this ) ;
@@ -481,14 +496,12 @@ private void PreventRequestAbortedCancellation()
481
496
{
482
497
lock ( _abortLock )
483
498
{
484
- if ( _requestAborted )
499
+ if ( _connectionAborted )
485
500
{
486
501
return ;
487
502
}
488
503
489
504
_preventRequestAbortedCancellation = true ;
490
- _abortedCts ? . Dispose ( ) ;
491
- _abortedCts = null ;
492
505
}
493
506
}
494
507
@@ -594,7 +607,7 @@ private async Task ProcessRequests<TContext>(IHttpApplication<TContext> applicat
594
607
// Run the application code for this request
595
608
await application . ProcessRequestAsync ( context ) ;
596
609
597
- if ( ! _requestAborted )
610
+ if ( ! _connectionAborted )
598
611
{
599
612
VerifyResponseContentLength ( ) ;
600
613
}
@@ -630,7 +643,7 @@ private async Task ProcessRequests<TContext>(IHttpApplication<TContext> applicat
630
643
// 4XX responses are written by TryProduceInvalidRequestResponse during connection tear down.
631
644
if ( _requestRejectedException == null )
632
645
{
633
- if ( ! _requestAborted )
646
+ if ( ! _connectionAborted )
634
647
{
635
648
// Call ProduceEnd() before consuming the rest of the request body to prevent
636
649
// delaying clients waiting for the chunk terminator:
@@ -662,7 +675,7 @@ private async Task ProcessRequests<TContext>(IHttpApplication<TContext> applicat
662
675
application . DisposeContext ( context , _applicationException ) ;
663
676
664
677
// Even for non-keep-alive requests, try to consume the entire body to avoid RSTs.
665
- if ( ! _requestAborted && _requestRejectedException == null && ! messageBody . IsEmpty )
678
+ if ( ! _connectionAborted && _requestRejectedException == null && ! messageBody . IsEmpty )
666
679
{
667
680
await messageBody . ConsumeAsync ( ) ;
668
681
}
@@ -964,7 +977,7 @@ private void VerifyInitializeState(int firstWriteByteCount)
964
977
protected Task TryProduceInvalidRequestResponse ( )
965
978
{
966
979
// If _requestAborted is set, the connection has already been closed.
967
- if ( _requestRejectedException != null && ! _requestAborted )
980
+ if ( _requestRejectedException != null && ! _connectionAborted )
968
981
{
969
982
return ProduceEnd ( ) ;
970
983
}
0 commit comments