Pass ReadOnlySequence<byte> via in (#11052)
This commit is contained in:
parent
bcb59fa5c9
commit
81b757afcc
|
|
@ -284,7 +284,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
throw new InvalidDataException($"Form value length limit {ValueLengthLimit} exceeded.");
|
||||
}
|
||||
|
||||
private string GetDecodedStringFromReadOnlySequence(ReadOnlySequence<byte> ros)
|
||||
private string GetDecodedStringFromReadOnlySequence(in ReadOnlySequence<byte> ros)
|
||||
{
|
||||
if (ros.IsSingleSegment)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace System.Buffers
|
|||
private static byte[] _numericBytesScratch;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ReadOnlySpan<byte> ToSpan(this ReadOnlySequence<byte> buffer)
|
||||
public static ReadOnlySpan<byte> ToSpan(in this ReadOnlySequence<byte> buffer)
|
||||
{
|
||||
if (buffer.IsSingleSegment)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
_requestBodyPipe.Reset();
|
||||
}
|
||||
|
||||
private void Copy(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer)
|
||||
private void Copy(in ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer)
|
||||
{
|
||||
if (readableBuffer.IsSingleSegment)
|
||||
{
|
||||
|
|
@ -321,10 +321,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
return _mode == Mode.Complete;
|
||||
}
|
||||
|
||||
private void ParseChunkedPrefix(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
private void ParseChunkedPrefix(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.Start;
|
||||
var reader = new SequenceReader<byte>(buffer);
|
||||
|
||||
if (!reader.TryRead(out var ch1) || !reader.TryRead(out var ch2))
|
||||
|
|
@ -383,7 +382,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
// Chunk-extensions not currently parsed
|
||||
// Just drain the data
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.Start;
|
||||
|
||||
do
|
||||
|
|
@ -432,7 +430,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
} while (_mode == Mode.Extension);
|
||||
}
|
||||
|
||||
private void ReadChunkedData(ReadOnlySequence<byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
private void ReadChunkedData(in ReadOnlySequence<byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
var actual = Math.Min(buffer.Length, _inputLength);
|
||||
consumed = buffer.GetPosition(actual);
|
||||
|
|
@ -449,10 +447,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
}
|
||||
|
||||
private void ParseChunkedSuffix(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
private void ParseChunkedSuffix(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.Start;
|
||||
|
||||
if (buffer.Length < 2)
|
||||
{
|
||||
|
|
@ -478,10 +475,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
}
|
||||
|
||||
private void ParseChunkedTrailer(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
private void ParseChunkedTrailer(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.Start;
|
||||
|
||||
if (buffer.Length < 2)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
SendTimeoutResponse();
|
||||
}
|
||||
|
||||
public void ParseRequest(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
public void ParseRequest(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
consumed = buffer.Start;
|
||||
examined = buffer.End;
|
||||
|
|
@ -151,10 +151,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
case RequestProcessingStatus.ParsingRequestLine:
|
||||
if (TakeStartLine(buffer, out consumed, out examined))
|
||||
{
|
||||
buffer = buffer.Slice(consumed, buffer.End);
|
||||
|
||||
_requestProcessingStatus = RequestProcessingStatus.ParsingHeaders;
|
||||
goto case RequestProcessingStatus.ParsingHeaders;
|
||||
TrimAndParseHeaders(buffer, ref consumed, out examined);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -167,24 +165,42 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
void TrimAndParseHeaders(in ReadOnlySequence<byte> buffer, ref SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
var trimmedBuffer = buffer.Slice(consumed, buffer.End);
|
||||
_requestProcessingStatus = RequestProcessingStatus.ParsingHeaders;
|
||||
|
||||
if (TakeMessageHeaders(trimmedBuffer, trailers: false, out consumed, out examined))
|
||||
{
|
||||
_requestProcessingStatus = RequestProcessingStatus.AppStarted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TakeStartLine(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
public bool TakeStartLine(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
var overLength = false;
|
||||
// Make sure the buffer is limited
|
||||
if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize)
|
||||
{
|
||||
buffer = buffer.Slice(buffer.Start, ServerOptions.Limits.MaxRequestLineSize);
|
||||
overLength = true;
|
||||
// Input oversize, cap amount checked
|
||||
return TrimAndTakeStartLine(buffer, out consumed, out examined);
|
||||
}
|
||||
|
||||
var result = _parser.ParseRequestLine(new Http1ParsingHandler(this), buffer, out consumed, out examined);
|
||||
if (!result && overLength)
|
||||
return _parser.ParseRequestLine(new Http1ParsingHandler(this), buffer, out consumed, out examined);
|
||||
|
||||
bool TrimAndTakeStartLine(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
BadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
|
||||
}
|
||||
var trimmedBuffer = buffer.Slice(buffer.Start, ServerOptions.Limits.MaxRequestLineSize);
|
||||
|
||||
return result;
|
||||
if (!_parser.ParseRequestLine(new Http1ParsingHandler(this), trimmedBuffer, out consumed, out examined))
|
||||
{
|
||||
// We read the maximum allowed but didn't complete the start line.
|
||||
BadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TakeMessageHeaders(in ReadOnlySequence<byte> buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined)
|
||||
|
|
@ -192,6 +208,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
// Make sure the buffer is limited
|
||||
if (buffer.Length > _remainingRequestHeadersBytesAllowed)
|
||||
{
|
||||
// Input oversize, cap amount checked
|
||||
return TrimAndTakeMessageHeaders(buffer, trailers, out consumed, out examined);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack
|
|||
_headerValueOctets = new byte[maxRequestHeaderFieldSize];
|
||||
}
|
||||
|
||||
public void Decode(ReadOnlySequence<byte> data, bool endHeaders, IHttpHeadersHandler handler)
|
||||
public void Decode(in ReadOnlySequence<byte> data, bool endHeaders, IHttpHeadersHandler handler)
|
||||
{
|
||||
foreach (var segment in data)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return true;
|
||||
}
|
||||
|
||||
private Task ProcessFrameAsync<TContext>(IHttpApplication<TContext> application, ReadOnlySequence<byte> payload)
|
||||
private Task ProcessFrameAsync<TContext>(IHttpApplication<TContext> application, in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1
|
||||
// Streams initiated by a client MUST use odd-numbered stream identifiers; ...
|
||||
|
|
@ -417,7 +417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
private Task ProcessDataFrameAsync(ReadOnlySequence<byte> payload)
|
||||
private Task ProcessDataFrameAsync(in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
|
|
@ -473,7 +473,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED);
|
||||
}
|
||||
|
||||
private Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext> application, ReadOnlySequence<byte> payload)
|
||||
private Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext> application, in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
|
|
@ -640,7 +640,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task ProcessSettingsFrameAsync(ReadOnlySequence<byte> payload)
|
||||
private Task ProcessSettingsFrameAsync(in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
|
|
@ -711,7 +711,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
private Task ProcessPingFrameAsync(ReadOnlySequence<byte> payload)
|
||||
private Task ProcessPingFrameAsync(in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
|
|
@ -818,7 +818,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task ProcessContinuationFrameAsync(ReadOnlySequence<byte> payload)
|
||||
private Task ProcessContinuationFrameAsync(in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
if (_currentHeadersStream == null)
|
||||
{
|
||||
|
|
@ -857,7 +857,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task DecodeHeadersAsync(bool endHeaders, ReadOnlySequence<byte> payload)
|
||||
private Task DecodeHeadersAsync(bool endHeaders, in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -879,7 +879,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task DecodeTrailersAsync(bool endHeaders, ReadOnlySequence<byte> payload)
|
||||
private Task DecodeTrailersAsync(bool endHeaders, in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
_hpackDecoder.Decode(payload, endHeaders, handler: this);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
public const int SettingSize = 6; // 2 bytes for the id, 4 bytes for the value.
|
||||
|
||||
public static bool ReadFrame(ReadOnlySequence<byte> readableBuffer, Http2Frame frame, uint maxFrameSize, out ReadOnlySequence<byte> framePayload)
|
||||
public static bool ReadFrame(in ReadOnlySequence<byte> readableBuffer, Http2Frame frame, uint maxFrameSize, out ReadOnlySequence<byte> framePayload)
|
||||
{
|
||||
framePayload = ReadOnlySequence<byte>.Empty;
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return true;
|
||||
}
|
||||
|
||||
private static int ReadExtendedFields(Http2Frame frame, ReadOnlySequence<byte> readableBuffer)
|
||||
private static int ReadExtendedFields(Http2Frame frame, in ReadOnlySequence<byte> readableBuffer)
|
||||
{
|
||||
// Copy in any extra fields for the given frame type
|
||||
var extendedHeaderLength = GetPayloadFieldsLength(frame);
|
||||
|
|
@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
public static IList<Http2PeerSetting> ReadSettings(ReadOnlySequence<byte> payload)
|
||||
public static IList<Http2PeerSetting> ReadSettings(in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
var data = payload.ToSpan();
|
||||
Debug.Assert(data.Length % SettingSize == 0, "Invalid settings payload length");
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
public ValueTask<FlushResult> WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence<byte> data, bool endStream)
|
||||
public ValueTask<FlushResult> WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, in ReadOnlySequence<byte> data, bool endStream)
|
||||
{
|
||||
// The Length property of a ReadOnlySequence can be expensive, so we cache the value.
|
||||
var dataLength = data.Length;
|
||||
|
|
@ -270,28 +270,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
| Padding (*) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
private void WriteDataUnsynchronized(int streamId, ReadOnlySequence<byte> data, long dataLength, bool endStream)
|
||||
private void WriteDataUnsynchronized(int streamId, in ReadOnlySequence<byte> data, long dataLength, bool endStream)
|
||||
{
|
||||
Debug.Assert(dataLength == data.Length);
|
||||
|
||||
// Note padding is not implemented
|
||||
_outgoingFrame.PrepareData(streamId);
|
||||
|
||||
var dataPayloadLength = (int)_maxFrameSize; // Minus padding
|
||||
|
||||
while (data.Length > dataPayloadLength)
|
||||
if (dataLength > _maxFrameSize) // Minus padding
|
||||
{
|
||||
var currentData = data.Slice(0, dataPayloadLength);
|
||||
_outgoingFrame.PayloadLength = dataPayloadLength; // Plus padding
|
||||
|
||||
WriteHeaderUnsynchronized();
|
||||
|
||||
foreach (var buffer in currentData)
|
||||
{
|
||||
_outputWriter.Write(buffer.Span);
|
||||
}
|
||||
|
||||
// Plus padding
|
||||
|
||||
data = data.Slice(dataPayloadLength);
|
||||
TrimAndWriteDataUnsynchronized(in data, dataLength, endStream);
|
||||
return;
|
||||
}
|
||||
|
||||
if (endStream)
|
||||
|
|
@ -299,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_outgoingFrame.DataFlags |= Http2DataFrameFlags.END_STREAM;
|
||||
}
|
||||
|
||||
_outgoingFrame.PayloadLength = (int)data.Length; // Plus padding
|
||||
_outgoingFrame.PayloadLength = (int)dataLength; // Plus padding
|
||||
|
||||
WriteHeaderUnsynchronized();
|
||||
|
||||
|
|
@ -309,6 +298,51 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
|
||||
// Plus padding
|
||||
return;
|
||||
|
||||
void TrimAndWriteDataUnsynchronized(in ReadOnlySequence<byte> data, long dataLength, bool endStream)
|
||||
{
|
||||
Debug.Assert(dataLength == data.Length);
|
||||
|
||||
var dataPayloadLength = (int)_maxFrameSize; // Minus padding
|
||||
|
||||
Debug.Assert(dataLength > dataPayloadLength);
|
||||
|
||||
var remainingData = data;
|
||||
do
|
||||
{
|
||||
var currentData = remainingData.Slice(0, dataPayloadLength);
|
||||
_outgoingFrame.PayloadLength = dataPayloadLength; // Plus padding
|
||||
|
||||
WriteHeaderUnsynchronized();
|
||||
|
||||
foreach (var buffer in currentData)
|
||||
{
|
||||
_outputWriter.Write(buffer.Span);
|
||||
}
|
||||
|
||||
// Plus padding
|
||||
dataLength -= dataPayloadLength;
|
||||
remainingData = remainingData.Slice(dataPayloadLength);
|
||||
|
||||
} while (dataLength > dataPayloadLength);
|
||||
|
||||
if (endStream)
|
||||
{
|
||||
_outgoingFrame.DataFlags |= Http2DataFrameFlags.END_STREAM;
|
||||
}
|
||||
|
||||
_outgoingFrame.PayloadLength = (int)dataLength; // Plus padding
|
||||
|
||||
WriteHeaderUnsynchronized();
|
||||
|
||||
foreach (var buffer in remainingData)
|
||||
{
|
||||
_outputWriter.Write(buffer.Span);
|
||||
}
|
||||
|
||||
// Plus padding
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<FlushResult> WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence<byte> data, long dataLength, bool endStream)
|
||||
|
|
@ -498,7 +532,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
| |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public ValueTask<FlushResult> WritePingAsync(Http2PingFrameFlags flags, ReadOnlySequence<byte> payload)
|
||||
public ValueTask<FlushResult> WritePingAsync(Http2PingFrameFlags flags, in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
lock (_writeLock)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
public Task OnDataAsync(Http2Frame dataFrame, ReadOnlySequence<byte> payload)
|
||||
public Task OnDataAsync(Http2Frame dataFrame, in ReadOnlySequence<byte> payload)
|
||||
{
|
||||
// Since padding isn't buffered, immediately count padding bytes as read for flow control purposes.
|
||||
if (dataFrame.DataHasPadding)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
|||
_bufs = handle + requestSize;
|
||||
}
|
||||
|
||||
public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlySequence<byte> buffer)
|
||||
public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, in ReadOnlySequence<byte> buffer)
|
||||
{
|
||||
Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable);
|
||||
return _awaitable;
|
||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
|||
|
||||
private unsafe void Write(
|
||||
UvStreamHandle handle,
|
||||
ReadOnlySequence<byte> buffer,
|
||||
in ReadOnlySequence<byte> buffer,
|
||||
Action<UvWriteReq, int, UvException, object> callback,
|
||||
object state)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
|||
{
|
||||
}
|
||||
|
||||
public SocketAwaitableEventArgs SendAsync(ReadOnlySequence<byte> buffers)
|
||||
public SocketAwaitableEventArgs SendAsync(in ReadOnlySequence<byte> buffers)
|
||||
{
|
||||
if (buffers.IsSingleSegment)
|
||||
{
|
||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
|||
return _awaitableEventArgs;
|
||||
}
|
||||
|
||||
private List<ArraySegment<byte>> GetBufferList(ReadOnlySequence<byte> buffer)
|
||||
private List<ArraySegment<byte>> GetBufferList(in ReadOnlySequence<byte> buffer)
|
||||
{
|
||||
Debug.Assert(!buffer.IsEmpty);
|
||||
Debug.Assert(!buffer.IsSingleSegment);
|
||||
|
|
|
|||
Loading…
Reference in New Issue