From f10680a37ab34c2b92829bc5135dde253260614a Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Fri, 7 Jun 2019 21:15:27 +0100 Subject: [PATCH] Use one SequenceReader+Rewind rather than 2 (#8076) --- ...tCore.Server.Kestrel.Core.netcoreapp3.0.cs | 5 +- .../Core/src/Internal/Http/Http1Connection.cs | 77 ++++-- .../Core/src/Internal/Http/HttpParser.cs | 244 ++++++++---------- .../Core/src/Internal/Http/IHttpParser.cs | 2 +- .../Kestrel/Core/test/HttpParserTests.cs | 56 ++-- .../Http1ConnectionBenchmark.cs | 3 +- .../HttpParserBenchmark.cs | 3 +- .../Kestrel.Performance/Mocks/NullParser.cs | 6 +- 8 files changed, 210 insertions(+), 186 deletions(-) diff --git a/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs b/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs index 8891d7feb7..5e480488d6 100644 --- a/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs +++ b/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs @@ -228,9 +228,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { public HttpParser() { } public HttpParser(bool showErrorDetails) { } - bool Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpParser.ParseHeaders(TRequestHandler handler, in System.Buffers.ReadOnlySequence buffer, out System.SequencePosition consumed, out System.SequencePosition examined, out int consumedBytes) { throw null; } bool Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpParser.ParseRequestLine(TRequestHandler handler, in System.Buffers.ReadOnlySequence buffer, out System.SequencePosition consumed, out System.SequencePosition examined) { throw null; } - public bool ParseHeaders(TRequestHandler handler, in System.Buffers.ReadOnlySequence buffer, out System.SequencePosition consumed, out System.SequencePosition examined, out int consumedBytes) { throw null; } + public bool ParseHeaders(TRequestHandler handler, ref System.Buffers.SequenceReader reader) { throw null; } public bool ParseRequestLine(TRequestHandler handler, in System.Buffers.ReadOnlySequence buffer, out System.SequencePosition consumed, out System.SequencePosition examined) { throw null; } } public enum HttpScheme @@ -253,7 +252,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } public partial interface IHttpParser where TRequestHandler : Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpHeadersHandler, Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpRequestLineHandler { - bool ParseHeaders(TRequestHandler handler, in System.Buffers.ReadOnlySequence buffer, out System.SequencePosition consumed, out System.SequencePosition examined, out int consumedBytes); + bool ParseHeaders(TRequestHandler handler, ref System.Buffers.SequenceReader reader); bool ParseRequestLine(TRequestHandler handler, in System.Buffers.ReadOnlySequence buffer, out System.SequencePosition consumed, out System.SequencePosition examined); } public partial interface IHttpRequestLineHandler diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index 6a54f47e28..0427ecd902 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -189,32 +189,77 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return result; } - public bool TakeMessageHeaders(ReadOnlySequence buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined) + public bool TakeMessageHeaders(in ReadOnlySequence buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined) { // Make sure the buffer is limited - bool overLength = false; - if (buffer.Length >= _remainingRequestHeadersBytesAllowed) + if (buffer.Length > _remainingRequestHeadersBytesAllowed) { - buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed); - - // If we sliced it means the current buffer bigger than what we're - // allowed to look at - overLength = true; + return TrimAndTakeMessageHeaders(buffer, trailers, out consumed, out examined); } - var result = _parser.ParseHeaders(new Http1ParsingHandler(this, trailers), buffer, out consumed, out examined, out var consumedBytes); - _remainingRequestHeadersBytesAllowed -= consumedBytes; + var reader = new SequenceReader(buffer); + var result = false; + try + { + result = _parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref reader); - if (!result && overLength) - { - BadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize); + if (result) + { + TimeoutControl.CancelTimeout(); + } + + return result; } - if (result) + finally { - TimeoutControl.CancelTimeout(); + consumed = reader.Position; + _remainingRequestHeadersBytesAllowed -= (int)reader.Consumed; + + if (result) + { + examined = consumed; + } + else + { + examined = buffer.End; + } } - return result; + bool TrimAndTakeMessageHeaders(in ReadOnlySequence buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined) + { + var trimmedBuffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed); + + var reader = new SequenceReader(trimmedBuffer); + var result = false; + try + { + result = _parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref reader); + + if (!result) + { + // We read the maximum allowed but didn't complete the headers. + BadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize); + } + + TimeoutControl.CancelTimeout(); + + return result; + } + finally + { + consumed = reader.Position; + _remainingRequestHeadersBytesAllowed -= (int)reader.Consumed; + + if (result) + { + examined = consumed; + } + else + { + examined = trimmedBuffer.End; + } + } + } } public void OnStartLine(HttpMethod method, HttpVersion version, Span target, Span path, Span query, Span customMethod, bool pathEncoded) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs index d55706d827..b8486621db 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http @@ -174,149 +175,128 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded); } - public unsafe bool ParseHeaders(TRequestHandler handler, in ReadOnlySequence buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes) + public unsafe bool ParseHeaders(TRequestHandler handler, ref SequenceReader reader) { - consumed = buffer.Start; - examined = buffer.End; - consumedBytes = 0; - - var bufferEnd = buffer.End; - - var reader = new SequenceReader(buffer); - var start = default(SequenceReader); - var done = false; - - try + while (!reader.End) { - while (!reader.End) + var span = reader.UnreadSpan; + while (span.Length > 0) { - var span = reader.CurrentSpan; - var remaining = span.Length - reader.CurrentSpanIndex; + var ch1 = (byte)0; + var ch2 = (byte)0; + var readAhead = 0; - fixed (byte* pBuffer = span) + // Fast path, we're still looking at the same span + if (span.Length >= 2) { - while (remaining > 0) + ch1 = span[0]; + ch2 = span[1]; + } + else if (reader.TryRead(out ch1)) // Possibly split across spans + { + // Note if we read ahead by 1 or 2 bytes + readAhead = (reader.TryRead(out ch2)) ? 2 : 1; + } + + if (ch1 == ByteCR) + { + // Check for final CRLF. + if (ch2 == ByteLF) { - var index = reader.CurrentSpanIndex; - byte ch1; - byte ch2; - var readAhead = false; - var readSecond = true; - - // Fast path, we're still looking at the same span - if (remaining >= 2) + // If we got 2 bytes from the span directly so skip ahead 2 so that + // the reader's state matches what we expect + if (readAhead == 0) { - ch1 = pBuffer[index]; - ch2 = pBuffer[index + 1]; - } - else - { - // Store the reader before we look ahead 2 bytes (probably straddling - // spans) - start = reader; - - // Possibly split across spans - reader.TryRead(out ch1); - readSecond = reader.TryRead(out ch2); - - readAhead = true; + reader.Advance(2); } - if (ch1 == ByteCR) + // Double CRLF found, so end of headers. + handler.OnHeadersComplete(); + return true; + } + else if (readAhead == 1) + { + // Didn't read 2 bytes, reset the reader so we don't consume anything + reader.Rewind(1); + return false; + } + + Debug.Assert(readAhead == 0 || readAhead == 2); + // Headers don't end in CRLF line. + BadHttpRequestException.Throw(RequestRejectionReason.InvalidRequestHeadersNoCRLF); + } + + var length = 0; + // We only need to look for the end if we didn't read ahead; otherwise there isn't enough in + // in the span to contain a header. + if (readAhead == 0) + { + length = span.IndexOf(ByteLF) + 1; + if (length > 0) + { + // Potentially found the end, or an invalid header. + fixed (byte* pHeader = span) { - // Check for final CRLF. - if (!readSecond) - { - // Reset the reader so we don't consume anything - reader = start; - return false; - } - else if (ch2 == ByteLF) - { - // If we got 2 bytes from the span directly so skip ahead 2 so that - // the reader's state matches what we expect - if (!readAhead) - { - reader.Advance(2); - } - - done = true; - handler.OnHeadersComplete(); - return true; - } - - // Headers don't end in CRLF line. - BadHttpRequestException.Throw(RequestRejectionReason.InvalidRequestHeadersNoCRLF); - } - - // We moved the reader so look ahead 2 bytes so reset both the reader - // and the index - if (readAhead) - { - reader = start; - index = reader.CurrentSpanIndex; - } - - var endIndex = new Span(pBuffer + index, remaining).IndexOf(ByteLF); - var length = 0; - - if (endIndex != -1) - { - length = endIndex + 1; - var pHeader = pBuffer + index; - TakeSingleHeader(pHeader, length, handler); } - else - { - var current = reader.Position; - var currentSlice = buffer.Slice(current, bufferEnd); - - var lineEndPosition = currentSlice.PositionOf(ByteLF); - // Split buffers - if (lineEndPosition == null) - { - // Not there - return false; - } - - var lineEnd = lineEndPosition.Value; - - // Make sure LF is included in lineEnd - lineEnd = buffer.GetPosition(1, lineEnd); - var headerSpan = buffer.Slice(current, lineEnd).ToSpan(); - length = headerSpan.Length; - - fixed (byte* pHeader = headerSpan) - { - TakeSingleHeader(pHeader, length, handler); - } - - // We're going to the next span after this since we know we crossed spans here - // so mark the remaining as equal to the headerSpan so that we end up at 0 - // on the next iteration - remaining = length; - } - - // Skip the reader forward past the header line + // Read the header sucessfully, skip the reader forward past the header line. reader.Advance(length); - remaining -= length; + span = span.Slice(length); } } - } - return false; + // End not found in current span + if (length <= 0) + { + // We moved the reader to look ahead 2 bytes so rewind the reader + if (readAhead > 0) + { + reader.Rewind(readAhead); + } + + length = ParseMultiSpanHeader(handler, ref reader); + if (length < 0) + { + // Not there + return false; + } + + reader.Advance(length); + // As we crossed spans set the current span to default + // so we move to the next span on the next iteration + span = default; + } + } } - finally + + return false; + } + + private unsafe int ParseMultiSpanHeader(TRequestHandler handler, ref SequenceReader reader) + { + var buffer = reader.Sequence; + var currentSlice = buffer.Slice(reader.Position, reader.Remaining); + var lineEndPosition = currentSlice.PositionOf(ByteLF); + // Split buffers + if (lineEndPosition == null) { - consumed = reader.Position; - consumedBytes = (int)reader.Consumed; - - if (done) - { - examined = consumed; - } + // Not there + return -1; } + + var lineEnd = lineEndPosition.Value; + + // Make sure LF is included in lineEnd + lineEnd = buffer.GetPosition(1, lineEnd); + var headerSpan = buffer.Slice(reader.Position, lineEnd).ToSpan(); + var length = headerSpan.Length; + + fixed (byte* pHeader = headerSpan) + { + TakeSingleHeader(pHeader, length, handler); + } + + return length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -339,7 +319,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (index == length || sawWhitespace) { - RejectRequestHeader(headerLine, length); + // Set to -1 to indicate invalid. + index = -1; } return index; @@ -352,17 +333,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var valueEnd = length - 3; var nameEnd = FindEndOfName(headerLine, length); - // Header name is empty - if (nameEnd == 0) - { - RejectRequestHeader(headerLine, length); - } - - if (headerLine[valueEnd + 2] != ByteLF) - { - RejectRequestHeader(headerLine, length); - } - if (headerLine[valueEnd + 1] != ByteCR) + // Header name is empty, invalid, or doesn't end in CRLF + if (nameEnd <= 0 || headerLine[valueEnd + 2] != ByteLF || headerLine[valueEnd + 1] != ByteCR) { RejectRequestHeader(headerLine, length); } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/IHttpParser.cs b/src/Servers/Kestrel/Core/src/Internal/Http/IHttpParser.cs index efd8e9445b..18837ccd0a 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/IHttpParser.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/IHttpParser.cs @@ -10,6 +10,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { bool ParseRequestLine(TRequestHandler handler, in ReadOnlySequence buffer, out SequencePosition consumed, out SequencePosition examined); - bool ParseHeaders(TRequestHandler handler, in ReadOnlySequence buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes); + bool ParseHeaders(TRequestHandler handler, ref SequenceReader reader); } } diff --git a/src/Servers/Kestrel/Core/test/HttpParserTests.cs b/src/Servers/Kestrel/Core/test/HttpParserTests.cs index 0c7abe1b60..7ce8587743 100644 --- a/src/Servers/Kestrel/Core/test/HttpParserTests.cs +++ b/src/Servers/Kestrel/Core/test/HttpParserTests.cs @@ -182,7 +182,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); - Assert.False(parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes)); + var reader = new SequenceReader(buffer); + Assert.False(parser.ParseHeaders(requestHandler, ref reader)); } [Theory] @@ -207,11 +208,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); - parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); + var reader = new SequenceReader(buffer); - Assert.Equal(buffer.Length, buffer.Slice(consumed).Length); - Assert.True(buffer.Slice(examined).IsEmpty); - Assert.Equal(0, consumedBytes); + Assert.False(parser.ParseHeaders(requestHandler, ref reader)); + + Assert.Equal(buffer.Length, buffer.Slice(reader.Consumed).Length); + Assert.Equal(0, reader.Consumed); } [Fact] @@ -297,18 +299,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests const string headerLine = "Header: value\r\n\r"; var buffer1 = new ReadOnlySequence(Encoding.ASCII.GetBytes(headerLine)); var requestHandler = new RequestHandler(); - Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes)); + var reader1 = new SequenceReader(buffer1); + Assert.False(parser.ParseHeaders(requestHandler, ref reader1)); - Assert.Equal(buffer1.GetPosition(headerLine.Length - 1), consumed); - Assert.Equal(buffer1.End, examined); - Assert.Equal(headerLine.Length - 1, consumedBytes); + Assert.Equal(buffer1.GetPosition(headerLine.Length - 1), reader1.Position); + Assert.Equal(headerLine.Length - 1, reader1.Consumed); var buffer2 = new ReadOnlySequence(Encoding.ASCII.GetBytes("\r\n")); - Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes)); + var reader2 = new SequenceReader(buffer2); + Assert.True(parser.ParseHeaders(requestHandler, ref reader2)); - Assert.True(buffer2.Slice(consumed).IsEmpty); - Assert.True(buffer2.Slice(examined).IsEmpty); - Assert.Equal(2, consumedBytes); + Assert.True(buffer2.Slice(reader2.Position).IsEmpty); + Assert.Equal(2, reader2.Consumed); } [Theory] @@ -325,7 +327,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var requestHandler = new RequestHandler(); var exception = Assert.Throws(() => - parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes)); + { + var reader = new SequenceReader(buffer); + parser.ParseHeaders(requestHandler, ref reader); + }); Assert.Equal(expectedExceptionMessage, exception.Message); Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); @@ -364,7 +369,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes("Header: value\n\r\n")); exception = Assert.Throws(() => - parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes)); + { + var reader = new SequenceReader(buffer); + parser.ParseHeaders(requestHandler, ref reader); + }); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestHeader_Detail(string.Empty), exception.Message); Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); @@ -393,7 +401,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var buffer = BytePerSegmentTestSequenceFactory.Instance.CreateWithContent("Host:\r\nConnection: keep-alive\r\n\r\n"); var requestHandler = new RequestHandler(); - var result = parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out _); + var reader = new SequenceReader(buffer); + var result = parser.ParseHeaders(requestHandler, ref reader); Assert.True(result); } @@ -405,7 +414,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var buffer = BytePerSegmentTestSequenceFactory.Instance.CreateWithContent("A:B\r\nB: C\r\n\r\n"); var requestHandler = new RequestHandler(); - var result = parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out _); + var reader = new SequenceReader(buffer); + var result = parser.ParseHeaders(requestHandler, ref reader); Assert.True(result); } @@ -419,14 +429,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); var requestHandler = new RequestHandler(); - parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); + var reader = new SequenceReader(buffer); + Assert.False(parser.ParseHeaders(requestHandler, ref reader)); var pairs = requestHandler.Headers.ToArray(); Assert.Single(pairs); Assert.Equal(headerName, pairs[0].Key); Assert.Equal(expectedHeaderValue, pairs[0].Value); - Assert.True(buffer.Slice(consumed).IsEmpty); - Assert.True(buffer.Slice(examined).IsEmpty); + Assert.True(buffer.Slice(reader.Position).IsEmpty); } private void VerifyRawHeaders(string rawHeaders, IEnumerable expectedHeaderNames, IEnumerable expectedHeaderValues) @@ -437,15 +447,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); - parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); + var reader = new SequenceReader(buffer); + Assert.True(parser.ParseHeaders(requestHandler,ref reader)); var parsedHeaders = requestHandler.Headers.ToArray(); Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length); Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key)); Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value)); - Assert.True(buffer.Slice(consumed).IsEmpty); - Assert.True(buffer.Slice(examined).IsEmpty); + Assert.True(buffer.Slice(reader.Position).IsEmpty); } private IHttpParser CreateParser(IKestrelTrace log) => new HttpParser(log.IsEnabled(LogLevel.Information)); diff --git a/src/Servers/Kestrel/perf/Kestrel.Performance/Http1ConnectionBenchmark.cs b/src/Servers/Kestrel/perf/Kestrel.Performance/Http1ConnectionBenchmark.cs index d7bdd0a709..290c63f2f2 100644 --- a/src/Servers/Kestrel/perf/Kestrel.Performance/Http1ConnectionBenchmark.cs +++ b/src/Servers/Kestrel/perf/Kestrel.Performance/Http1ConnectionBenchmark.cs @@ -83,8 +83,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance } _buffer = _buffer.Slice(consumed, _buffer.End); + var reader = new SequenceReader(_buffer); - if (!_parser.ParseHeaders(new Adapter(this), _buffer, out consumed, out examined, out var consumedBytes)) + if (!_parser.ParseHeaders(new Adapter(this), ref reader)) { ErrorUtilities.ThrowInvalidRequestHeaders(); } diff --git a/src/Servers/Kestrel/perf/Kestrel.Performance/HttpParserBenchmark.cs b/src/Servers/Kestrel/perf/Kestrel.Performance/HttpParserBenchmark.cs index a542f905b5..c5eb24baf8 100644 --- a/src/Servers/Kestrel/perf/Kestrel.Performance/HttpParserBenchmark.cs +++ b/src/Servers/Kestrel/perf/Kestrel.Performance/HttpParserBenchmark.cs @@ -58,7 +58,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance _buffer = _buffer.Slice(consumed, _buffer.End); - if (!_parser.ParseHeaders(new Adapter(this), _buffer, out consumed, out examined, out var consumedBytes)) + var reader = new SequenceReader(_buffer); + if (!_parser.ParseHeaders(new Adapter(this), ref reader)) { ErrorUtilities.ThrowInvalidRequestHeaders(); } diff --git a/src/Servers/Kestrel/perf/Kestrel.Performance/Mocks/NullParser.cs b/src/Servers/Kestrel/perf/Kestrel.Performance/Mocks/NullParser.cs index 2a3069823a..288588f3b1 100644 --- a/src/Servers/Kestrel/perf/Kestrel.Performance/Mocks/NullParser.cs +++ b/src/Servers/Kestrel/perf/Kestrel.Performance/Mocks/NullParser.cs @@ -21,17 +21,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public static readonly NullParser Instance = new NullParser(); - public bool ParseHeaders(TRequestHandler handler, in ReadOnlySequence buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes) + public bool ParseHeaders(TRequestHandler handler, ref SequenceReader reader) { handler.OnHeader(new Span(_hostHeaderName), new Span(_hostHeaderValue)); handler.OnHeader(new Span(_acceptHeaderName), new Span(_acceptHeaderValue)); handler.OnHeader(new Span(_connectionHeaderName), new Span(_connectionHeaderValue)); handler.OnHeadersComplete(); - consumedBytes = 0; - consumed = buffer.Start; - examined = buffer.End; - return true; }