Fix Kestrel HTTP/2 debug assert failure (#23062)
This commit is contained in:
parent
7e6b5d5fea
commit
6abc3c759f
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
public override void AdvanceTo(SequencePosition consumed, SequencePosition examined)
|
||||
{
|
||||
OnAdvance(_readResult, consumed, examined);
|
||||
TrackConsumedAndExaminedBytes(_readResult, consumed, examined);
|
||||
_requestBodyPipe.Reader.AdvanceTo(consumed, examined);
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +351,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
consumed = reader.Position;
|
||||
examined = reader.Position;
|
||||
|
||||
AddAndCheckConsumedBytes(reader.Consumed);
|
||||
AddAndCheckObservedBytes(reader.Consumed);
|
||||
_inputLength = chunkSize;
|
||||
_mode = Mode.Extension;
|
||||
return;
|
||||
|
|
@ -370,7 +370,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
consumed = reader.Position;
|
||||
|
||||
AddAndCheckConsumedBytes(reader.Consumed);
|
||||
AddAndCheckObservedBytes(reader.Consumed);
|
||||
_inputLength = chunkSize;
|
||||
_mode = chunkSize > 0 ? Mode.Data : Mode.Trailer;
|
||||
return;
|
||||
|
|
@ -398,7 +398,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
// End marker not found yet
|
||||
consumed = buffer.End;
|
||||
examined = buffer.End;
|
||||
AddAndCheckConsumedBytes(buffer.Length);
|
||||
AddAndCheckObservedBytes(buffer.Length);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
consumed = extensionCursor;
|
||||
examined = buffer.End;
|
||||
AddAndCheckConsumedBytes(charsToByteCRExclusive);
|
||||
AddAndCheckObservedBytes(charsToByteCRExclusive);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -424,14 +424,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
consumed = suffixBuffer.End;
|
||||
examined = suffixBuffer.End;
|
||||
AddAndCheckConsumedBytes(charsToByteCRExclusive + 2);
|
||||
AddAndCheckObservedBytes(charsToByteCRExclusive + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't consume suffixSpan[1] in case it is also a \r.
|
||||
buffer = buffer.Slice(charsToByteCRExclusive + 1);
|
||||
consumed = extensionCursor;
|
||||
AddAndCheckConsumedBytes(charsToByteCRExclusive + 1);
|
||||
AddAndCheckObservedBytes(charsToByteCRExclusive + 1);
|
||||
}
|
||||
} while (_mode == Mode.Extension);
|
||||
}
|
||||
|
|
@ -445,7 +445,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
Copy(buffer.Slice(0, actual), writableBuffer);
|
||||
|
||||
_inputLength -= actual;
|
||||
AddAndCheckConsumedBytes(actual);
|
||||
AddAndCheckObservedBytes(actual);
|
||||
|
||||
if (_inputLength == 0)
|
||||
{
|
||||
|
|
@ -472,7 +472,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n')
|
||||
{
|
||||
consumed = suffixBuffer.End;
|
||||
AddAndCheckConsumedBytes(2);
|
||||
AddAndCheckObservedBytes(2);
|
||||
_mode = Mode.Prefix;
|
||||
}
|
||||
else
|
||||
|
|
@ -500,7 +500,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
if (trailerSpan[0] == '\r' && trailerSpan[1] == '\n')
|
||||
{
|
||||
consumed = trailerBuffer.End;
|
||||
AddAndCheckConsumedBytes(2);
|
||||
AddAndCheckObservedBytes(2);
|
||||
_mode = Mode.Complete;
|
||||
// No trailers
|
||||
_context.OnTrailersComplete();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
private ReadResult _readResult;
|
||||
private readonly long _contentLength;
|
||||
private long _inputLength;
|
||||
private long _unexaminedInputLength;
|
||||
private bool _readCompleted;
|
||||
private bool _isReading;
|
||||
private int _userCanceled;
|
||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
RequestKeepAlive = keepAlive;
|
||||
_contentLength = contentLength;
|
||||
_inputLength = _contentLength;
|
||||
_unexaminedInputLength = _contentLength;
|
||||
}
|
||||
|
||||
public override ValueTask<ReadResult> ReadAsync(CancellationToken cancellationToken = default)
|
||||
|
|
@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
private long CreateReadResultFromConnectionReadResult()
|
||||
{
|
||||
var initialLength = _readResult.Buffer.Length;
|
||||
var maxLength = _inputLength + _examinedUnconsumedBytes;
|
||||
var maxLength = _unexaminedInputLength + _examinedUnconsumedBytes;
|
||||
|
||||
if (initialLength < maxLength)
|
||||
{
|
||||
|
|
@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
return;
|
||||
}
|
||||
|
||||
_inputLength -= OnAdvance(_readResult, consumed, examined);
|
||||
_unexaminedInputLength -= TrackConsumedAndExaminedBytes(_readResult, consumed, examined);
|
||||
_context.Input.AdvanceTo(consumed, examined);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
private readonly HttpProtocol _context;
|
||||
|
||||
private bool _send100Continue = true;
|
||||
private long _consumedBytes;
|
||||
private long _observedBytes;
|
||||
private bool _stopped;
|
||||
|
||||
protected bool _timingEnabled;
|
||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
public virtual void Reset()
|
||||
{
|
||||
_send100Continue = true;
|
||||
_consumedBytes = 0;
|
||||
_observedBytes = 0;
|
||||
_stopped = false;
|
||||
_timingEnabled = false;
|
||||
_backpressure = false;
|
||||
|
|
@ -160,15 +160,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
}
|
||||
|
||||
protected virtual void OnDataRead(long bytesRead)
|
||||
protected void AddAndCheckObservedBytes(long observedBytes)
|
||||
{
|
||||
}
|
||||
_observedBytes += observedBytes;
|
||||
|
||||
protected void AddAndCheckConsumedBytes(long consumedBytes)
|
||||
{
|
||||
_consumedBytes += consumedBytes;
|
||||
|
||||
if (_consumedBytes > _context.MaxRequestBodySize)
|
||||
if (_observedBytes > _context.MaxRequestBodySize)
|
||||
{
|
||||
KestrelBadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
|
||||
}
|
||||
|
|
@ -209,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
}
|
||||
|
||||
protected long OnAdvance(ReadResult readResult, SequencePosition consumed, SequencePosition examined)
|
||||
protected long TrackConsumedAndExaminedBytes(ReadResult readResult, SequencePosition consumed, SequencePosition examined)
|
||||
{
|
||||
// This code path is fairly hard to understand so let's break it down with an example
|
||||
// ReadAsync returns a ReadResult of length 50.
|
||||
|
|
@ -252,18 +248,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
totalLength = readResult.Buffer.Length;
|
||||
}
|
||||
|
||||
var newlyExamined = examinedLength - _examinedUnconsumedBytes;
|
||||
|
||||
if (newlyExamined > 0)
|
||||
{
|
||||
OnDataRead(newlyExamined);
|
||||
_examinedUnconsumedBytes += newlyExamined;
|
||||
}
|
||||
|
||||
_examinedUnconsumedBytes -= consumedLength;
|
||||
var newlyExaminedBytes = examinedLength - _examinedUnconsumedBytes;
|
||||
_examinedUnconsumedBytes += newlyExaminedBytes - consumedLength;
|
||||
_alreadyTimedBytes = totalLength - consumedLength;
|
||||
|
||||
return newlyExamined;
|
||||
return newlyExaminedBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,13 +39,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnDataRead(long bytesRead)
|
||||
{
|
||||
// The HTTP/2 flow control window cannot be larger than 2^31-1 which limits bytesRead.
|
||||
_context.OnDataRead((int)bytesRead);
|
||||
AddAndCheckConsumedBytes(bytesRead);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
|
@ -59,8 +52,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
public override void AdvanceTo(SequencePosition consumed, SequencePosition examined)
|
||||
{
|
||||
OnAdvance(_readResult, consumed, examined);
|
||||
var newlyExaminedBytes = TrackConsumedAndExaminedBytes(_readResult, consumed, examined);
|
||||
|
||||
// Ensure we consume data from the RequestBodyPipe before sending WINDOW_UPDATES to the client.
|
||||
_context.RequestBodyPipe.Reader.AdvanceTo(consumed, examined);
|
||||
|
||||
// The HTTP/2 flow control window cannot be larger than 2^31-1 which limits bytesRead.
|
||||
_context.OnDataRead((int)newlyExaminedBytes);
|
||||
AddAndCheckObservedBytes(newlyExaminedBytes);
|
||||
}
|
||||
|
||||
public override bool TryRead(out ReadResult readResult)
|
||||
|
|
|
|||
|
|
@ -446,7 +446,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
var flushTask = RequestBodyPipe.Writer.FlushAsync();
|
||||
// It shouldn't be possible for the RequestBodyPipe to fill up an return an incomplete task if
|
||||
// _inputFlowControl.Advance() didn't throw.
|
||||
Debug.Assert(flushTask.IsCompleted);
|
||||
Debug.Assert(flushTask.IsCompletedSuccessfully);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3
|
|||
{
|
||||
}
|
||||
|
||||
protected override void OnDataRead(long bytesRead)
|
||||
{
|
||||
AddAndCheckConsumedBytes(bytesRead);
|
||||
}
|
||||
|
||||
public static MessageBody For(Http3Stream context)
|
||||
{
|
||||
return new Http3MessageBody(context);
|
||||
|
|
@ -50,8 +45,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3
|
|||
|
||||
public override void AdvanceTo(SequencePosition consumed, SequencePosition examined)
|
||||
{
|
||||
OnAdvance(_readResult, consumed, examined);
|
||||
var newlyExaminedBytes = TrackConsumedAndExaminedBytes(_readResult, consumed, examined);
|
||||
|
||||
_context.RequestBodyPipe.Reader.AdvanceTo(consumed, examined);
|
||||
|
||||
AddAndCheckObservedBytes(newlyExaminedBytes);
|
||||
}
|
||||
|
||||
public override bool TryRead(out ReadResult readResult)
|
||||
|
|
|
|||
Loading…
Reference in New Issue