@@ -14,6 +14,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
1414 /// </summary>
1515 internal sealed class Http1UpgradeMessageBody : Http1MessageBody
1616 {
17+ private int _userCanceled ;
18+
1719 public Http1UpgradeMessageBody ( Http1Connection context , bool keepAlive )
1820 : base ( context , keepAlive )
1921 {
@@ -23,13 +25,26 @@ public Http1UpgradeMessageBody(Http1Connection context, bool keepAlive)
2325 // This returns IsEmpty so we can avoid draining the body (since it's basically an endless stream)
2426 public override bool IsEmpty => true ;
2527
28+ public override ValueTask < ReadResult > ReadAsync ( CancellationToken cancellationToken = default )
29+ {
30+ ThrowIfReaderCompleted ( ) ;
31+ return ReadAsyncInternal ( cancellationToken ) ;
32+ }
33+
34+ public override bool TryRead ( out ReadResult result )
35+ {
36+ ThrowIfReaderCompleted ( ) ;
37+ return TryReadInternal ( out result ) ;
38+ }
39+
2640 public override void AdvanceTo ( SequencePosition consumed , SequencePosition examined )
2741 {
2842 _context . Input . AdvanceTo ( consumed , examined ) ;
2943 }
3044
3145 public override void CancelPendingRead ( )
3246 {
47+ Interlocked . Exchange ( ref _userCanceled , 1 ) ;
3348 _context . Input . CancelPendingRead ( ) ;
3449 }
3550
@@ -45,12 +60,49 @@ public override ValueTask StopAsync()
4560
4661 public override bool TryReadInternal ( out ReadResult readResult )
4762 {
48- return _context . Input . TryRead ( out readResult ) ;
63+ // Ignore the canceled readResult unless it was canceled by the user.
64+ do
65+ {
66+ if ( ! _context . Input . TryRead ( out readResult ) )
67+ {
68+ return false ;
69+ }
70+ } while ( readResult . IsCanceled && Interlocked . Exchange ( ref _userCanceled , 0 ) == 0 ) ;
71+
72+ return true ;
4973 }
5074
5175 public override ValueTask < ReadResult > ReadAsyncInternal ( CancellationToken cancellationToken = default )
5276 {
53- return _context . Input . ReadAsync ( cancellationToken ) ;
77+ ReadResult readResult ;
78+
79+ // Ignore the canceled readResult unless it was canceled by the user.
80+ do
81+ {
82+ var readTask = _context . Input . ReadAsync ( cancellationToken ) ;
83+
84+ if ( ! readTask . IsCompletedSuccessfully )
85+ {
86+ return ReadAsyncInternalAwaited ( readTask , cancellationToken ) ;
87+ }
88+
89+ readResult = readTask . GetAwaiter ( ) . GetResult ( ) ;
90+ } while ( readResult . IsCanceled && Interlocked . Exchange ( ref _userCanceled , 0 ) == 0 ) ;
91+
92+ return new ValueTask < ReadResult > ( readResult ) ;
93+ }
94+
95+ private async ValueTask < ReadResult > ReadAsyncInternalAwaited ( ValueTask < ReadResult > readTask , CancellationToken cancellationToken = default )
96+ {
97+ var readResult = await readTask ;
98+
99+ // Ignore the canceled readResult unless it was canceled by the user.
100+ while ( readResult . IsCanceled && Interlocked . Exchange ( ref _userCanceled , 0 ) == 0 )
101+ {
102+ readResult = await _context . Input . ReadAsync ( cancellationToken ) ;
103+ }
104+
105+ return readResult ;
54106 }
55107 }
56108}
0 commit comments