Use one SequenceReader+Rewind rather than 2 (#8076)
This commit is contained in:
parent
3dc2be22c5
commit
f10680a37a
|
|
@ -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<TRequestHandler>.ParseHeaders(TRequestHandler handler, in System.Buffers.ReadOnlySequence<byte> buffer, out System.SequencePosition consumed, out System.SequencePosition examined, out int consumedBytes) { throw null; }
|
||||
bool Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpParser<TRequestHandler>.ParseRequestLine(TRequestHandler handler, in System.Buffers.ReadOnlySequence<byte> buffer, out System.SequencePosition consumed, out System.SequencePosition examined) { throw null; }
|
||||
public bool ParseHeaders(TRequestHandler handler, in System.Buffers.ReadOnlySequence<byte> buffer, out System.SequencePosition consumed, out System.SequencePosition examined, out int consumedBytes) { throw null; }
|
||||
public bool ParseHeaders(TRequestHandler handler, ref System.Buffers.SequenceReader<byte> reader) { throw null; }
|
||||
public bool ParseRequestLine(TRequestHandler handler, in System.Buffers.ReadOnlySequence<byte> 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<TRequestHandler> 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<byte> buffer, out System.SequencePosition consumed, out System.SequencePosition examined, out int consumedBytes);
|
||||
bool ParseHeaders(TRequestHandler handler, ref System.Buffers.SequenceReader<byte> reader);
|
||||
bool ParseRequestLine(TRequestHandler handler, in System.Buffers.ReadOnlySequence<byte> buffer, out System.SequencePosition consumed, out System.SequencePosition examined);
|
||||
}
|
||||
public partial interface IHttpRequestLineHandler
|
||||
|
|
|
|||
|
|
@ -189,32 +189,77 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
return result;
|
||||
}
|
||||
|
||||
public bool TakeMessageHeaders(ReadOnlySequence<byte> buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined)
|
||||
public bool TakeMessageHeaders(in ReadOnlySequence<byte> 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<byte>(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<byte> buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
var trimmedBuffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed);
|
||||
|
||||
var reader = new SequenceReader<byte>(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<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
|
||||
|
|
|
|||
|
|
@ -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<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
|
||||
public unsafe bool ParseHeaders(TRequestHandler handler, ref SequenceReader<byte> reader)
|
||||
{
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.End;
|
||||
consumedBytes = 0;
|
||||
|
||||
var bufferEnd = buffer.End;
|
||||
|
||||
var reader = new SequenceReader<byte>(buffer);
|
||||
var start = default(SequenceReader<byte>);
|
||||
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<byte>(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<byte> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
bool ParseRequestLine(TRequestHandler handler, in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined);
|
||||
|
||||
bool ParseHeaders(TRequestHandler handler, in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes);
|
||||
bool ParseHeaders(TRequestHandler handler, ref SequenceReader<byte> reader);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
var buffer = new ReadOnlySequence<byte>(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<byte>(buffer);
|
||||
Assert.False(parser.ParseHeaders(requestHandler, ref reader));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -207,11 +208,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
var buffer = new ReadOnlySequence<byte>(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<byte>(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<byte>(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<byte>(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<byte>(Encoding.ASCII.GetBytes("\r\n"));
|
||||
Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes));
|
||||
var reader2 = new SequenceReader<byte>(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<BadHttpRequestException>(() =>
|
||||
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
|
||||
{
|
||||
var reader = new SequenceReader<byte>(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<byte>(Encoding.ASCII.GetBytes("Header: value\n\r\n"));
|
||||
|
||||
exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
|
||||
{
|
||||
var reader = new SequenceReader<byte>(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<byte>(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<byte>(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<byte>(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<byte>(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<string> expectedHeaderNames, IEnumerable<string> expectedHeaderValues)
|
||||
|
|
@ -437,15 +447,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var buffer = new ReadOnlySequence<byte>(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<byte>(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<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log.IsEnabled(LogLevel.Information));
|
||||
|
|
|
|||
|
|
@ -83,8 +83,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
}
|
||||
|
||||
_buffer = _buffer.Slice(consumed, _buffer.End);
|
||||
var reader = new SequenceReader<byte>(_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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<byte>(_buffer);
|
||||
if (!_parser.ParseHeaders(new Adapter(this), ref reader))
|
||||
{
|
||||
ErrorUtilities.ThrowInvalidRequestHeaders();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,17 +21,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
|
||||
public static readonly NullParser<Http1ParsingHandler> Instance = new NullParser<Http1ParsingHandler>();
|
||||
|
||||
public bool ParseHeaders(TRequestHandler handler, in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
|
||||
public bool ParseHeaders(TRequestHandler handler, ref SequenceReader<byte> reader)
|
||||
{
|
||||
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
|
||||
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
|
||||
handler.OnHeader(new Span<byte>(_connectionHeaderName), new Span<byte>(_connectionHeaderValue));
|
||||
handler.OnHeadersComplete();
|
||||
|
||||
consumedBytes = 0;
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.End;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue