@@ -94,7 +94,7 @@ public override int Read(Span<byte> buffer)
94
94
}
95
95
96
96
// We're only here if we need more data to make forward progress.
97
- _connection . Fill ( ) ;
97
+ Fill ( ) ;
98
98
99
99
// Now that we have more, see if we can get any response data, and if
100
100
// we can we're done.
@@ -210,7 +210,7 @@ private async ValueTask<int> ReadAsyncCore(Memory<byte> buffer, CancellationToke
210
210
}
211
211
212
212
// We're only here if we need more data to make forward progress.
213
- await _connection . FillAsync ( async : true ) . ConfigureAwait ( false ) ;
213
+ await FillAsync ( ) . ConfigureAwait ( false ) ;
214
214
215
215
// Now that we have more, see if we can get any response data, and if
216
216
// we can we're done.
@@ -273,7 +273,7 @@ private async Task CopyToAsyncCore(Stream destination, CancellationToken cancell
273
273
return ;
274
274
}
275
275
276
- await _connection . FillAsync ( async : true ) . ConfigureAwait ( false ) ;
276
+ await FillAsync ( ) . ConfigureAwait ( false ) ;
277
277
}
278
278
}
279
279
catch ( Exception exc ) when ( CancellationHelper . ShouldWrapInOperationCanceledException ( exc , cancellationToken ) )
@@ -323,7 +323,7 @@ private int ReadChunksFromConnectionBuffer(Span<byte> buffer, CancellationTokenR
323
323
Debug . Assert ( _chunkBytesRemaining == 0 , $ "Expected { nameof ( _chunkBytesRemaining ) } == 0, got { _chunkBytesRemaining } ") ;
324
324
325
325
// Read the chunk header line.
326
- if ( ! _connection . TryReadNextChunkedLine ( readingHeader : false , out currentLine ) )
326
+ if ( ! _connection . TryReadNextChunkedLine ( out currentLine ) )
327
327
{
328
328
// Could not get a whole line, so we can't parse the chunk header.
329
329
return default ;
@@ -379,7 +379,7 @@ private int ReadChunksFromConnectionBuffer(Span<byte> buffer, CancellationTokenR
379
379
case ParsingState . ExpectChunkTerminator :
380
380
Debug . Assert ( _chunkBytesRemaining == 0 , $ "Expected { nameof ( _chunkBytesRemaining ) } == 0, got { _chunkBytesRemaining } ") ;
381
381
382
- if ( ! _connection . TryReadNextChunkedLine ( readingHeader : false , out currentLine ) )
382
+ if ( ! _connection . TryReadNextChunkedLine ( out currentLine ) )
383
383
{
384
384
return default ;
385
385
}
@@ -395,38 +395,23 @@ private int ReadChunksFromConnectionBuffer(Span<byte> buffer, CancellationTokenR
395
395
case ParsingState . ConsumeTrailers :
396
396
Debug . Assert ( _chunkBytesRemaining == 0 , $ "Expected { nameof ( _chunkBytesRemaining ) } == 0, got { _chunkBytesRemaining } ") ;
397
397
398
- while ( true )
398
+ // Consume the receive buffer. If the stream is disposed, pass a null response to avoid
399
+ // processing headers for a connection returned to the pool.
400
+ if ( _connection . ParseHeaders ( IsDisposed ? null : _response , isFromTrailer : true ) )
399
401
{
400
- if ( ! _connection . TryReadNextChunkedLine ( readingHeader : true , out currentLine ) )
401
- {
402
- break ;
403
- }
404
-
405
- if ( currentLine . IsEmpty )
406
- {
407
- // Dispose of the registration and then check whether cancellation has been
408
- // requested. This is necessary to make deterministic a race condition between
409
- // cancellation being requested and unregistering from the token. Otherwise,
410
- // it's possible cancellation could be requested just before we unregister and
411
- // we then return a connection to the pool that has been or will be disposed
412
- // (e.g. if a timer is used and has already queued its callback but the
413
- // callback hasn't yet run).
414
- cancellationRegistration . Dispose ( ) ;
415
- CancellationHelper . ThrowIfCancellationRequested ( cancellationRegistration . Token ) ;
416
-
417
- _state = ParsingState . Done ;
418
- _connection . CompleteResponse ( ) ;
419
- _connection = null ;
420
-
421
- break ;
422
- }
423
- // Parse the trailer.
424
- else if ( ! IsDisposed )
425
- {
426
- // Make sure that we don't inadvertently consume trailing headers
427
- // while draining a connection that's being returned back to the pool.
428
- HttpConnection . ParseHeaderNameValue ( _connection , currentLine , _response , isFromTrailer : true ) ;
429
- }
402
+ // Dispose of the registration and then check whether cancellation has been
403
+ // requested. This is necessary to make deterministic a race condition between
404
+ // cancellation being requested and unregistering from the token. Otherwise,
405
+ // it's possible cancellation could be requested just before we unregister and
406
+ // we then return a connection to the pool that has been or will be disposed
407
+ // (e.g. if a timer is used and has already queued its callback but the
408
+ // callback hasn't yet run).
409
+ cancellationRegistration . Dispose ( ) ;
410
+ CancellationHelper . ThrowIfCancellationRequested ( cancellationRegistration . Token ) ;
411
+
412
+ _state = ParsingState . Done ;
413
+ _connection . CompleteResponse ( ) ;
414
+ _connection = null ;
430
415
}
431
416
432
417
return default ;
@@ -528,7 +513,7 @@ public override async ValueTask<bool> DrainAsync(int maxDrainBytes)
528
513
}
529
514
}
530
515
531
- await _connection . FillAsync ( async : true ) . ConfigureAwait ( false ) ;
516
+ await FillAsync ( ) . ConfigureAwait ( false ) ;
532
517
}
533
518
}
534
519
finally
@@ -537,6 +522,24 @@ public override async ValueTask<bool> DrainAsync(int maxDrainBytes)
537
522
cts ? . Dispose ( ) ;
538
523
}
539
524
}
525
+
526
+ private void Fill ( )
527
+ {
528
+ Debug . Assert ( _connection is not null ) ;
529
+ ValueTask fillTask = _state == ParsingState . ConsumeTrailers
530
+ ? _connection . FillForHeadersAsync ( async: false )
531
+ : _connection . FillAsync ( async: false ) ;
532
+ Debug . Assert ( fillTask . IsCompleted ) ;
533
+ fillTask . GetAwaiter ( ) . GetResult ( ) ;
534
+ }
535
+
536
+ private ValueTask FillAsync ( )
537
+ {
538
+ Debug . Assert ( _connection is not null ) ;
539
+ return _state == ParsingState . ConsumeTrailers
540
+ ? _connection . FillForHeadersAsync ( async: true )
541
+ : _connection . FillAsync ( async: true ) ;
542
+ }
540
543
}
541
544
}
542
545
}
0 commit comments