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.");
|
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)
|
if (ros.IsSingleSegment)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace System.Buffers
|
||||||
private static byte[] _numericBytesScratch;
|
private static byte[] _numericBytesScratch;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)
|
if (buffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_requestBodyPipe.Reset();
|
_requestBodyPipe.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Copy(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer)
|
private void Copy(in ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer)
|
||||||
{
|
{
|
||||||
if (readableBuffer.IsSingleSegment)
|
if (readableBuffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
|
|
@ -321,10 +321,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return _mode == Mode.Complete;
|
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;
|
consumed = buffer.Start;
|
||||||
examined = buffer.Start;
|
|
||||||
var reader = new SequenceReader<byte>(buffer);
|
var reader = new SequenceReader<byte>(buffer);
|
||||||
|
|
||||||
if (!reader.TryRead(out var ch1) || !reader.TryRead(out var ch2))
|
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
|
// Chunk-extensions not currently parsed
|
||||||
// Just drain the data
|
// Just drain the data
|
||||||
consumed = buffer.Start;
|
|
||||||
examined = buffer.Start;
|
examined = buffer.Start;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
|
@ -432,7 +430,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
} while (_mode == Mode.Extension);
|
} 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);
|
var actual = Math.Min(buffer.Length, _inputLength);
|
||||||
consumed = buffer.GetPosition(actual);
|
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;
|
consumed = buffer.Start;
|
||||||
examined = buffer.Start;
|
|
||||||
|
|
||||||
if (buffer.Length < 2)
|
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;
|
consumed = buffer.Start;
|
||||||
examined = buffer.Start;
|
|
||||||
|
|
||||||
if (buffer.Length < 2)
|
if (buffer.Length < 2)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
SendTimeoutResponse();
|
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;
|
consumed = buffer.Start;
|
||||||
examined = buffer.End;
|
examined = buffer.End;
|
||||||
|
|
@ -151,10 +151,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
case RequestProcessingStatus.ParsingRequestLine:
|
case RequestProcessingStatus.ParsingRequestLine:
|
||||||
if (TakeStartLine(buffer, out consumed, out examined))
|
if (TakeStartLine(buffer, out consumed, out examined))
|
||||||
{
|
{
|
||||||
buffer = buffer.Slice(consumed, buffer.End);
|
TrimAndParseHeaders(buffer, ref consumed, out examined);
|
||||||
|
return;
|
||||||
_requestProcessingStatus = RequestProcessingStatus.ParsingHeaders;
|
|
||||||
goto case RequestProcessingStatus.ParsingHeaders;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -167,24 +165,42 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
break;
|
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)
|
if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize)
|
||||||
{
|
{
|
||||||
buffer = buffer.Slice(buffer.Start, ServerOptions.Limits.MaxRequestLineSize);
|
// Input oversize, cap amount checked
|
||||||
overLength = true;
|
return TrimAndTakeStartLine(buffer, out consumed, out examined);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = _parser.ParseRequestLine(new Http1ParsingHandler(this), buffer, out consumed, out examined);
|
return _parser.ParseRequestLine(new Http1ParsingHandler(this), buffer, out consumed, out examined);
|
||||||
if (!result && overLength)
|
|
||||||
|
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)
|
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
|
// Make sure the buffer is limited
|
||||||
if (buffer.Length > _remainingRequestHeadersBytesAllowed)
|
if (buffer.Length > _remainingRequestHeadersBytesAllowed)
|
||||||
{
|
{
|
||||||
|
// Input oversize, cap amount checked
|
||||||
return TrimAndTakeMessageHeaders(buffer, trailers, out consumed, out examined);
|
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];
|
_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)
|
foreach (var segment in data)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return true;
|
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
|
// http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1
|
||||||
// Streams initiated by a client MUST use odd-numbered stream identifiers; ...
|
// 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)
|
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);
|
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)
|
if (_currentHeadersStream != null)
|
||||||
{
|
{
|
||||||
|
|
@ -640,7 +640,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task ProcessSettingsFrameAsync(ReadOnlySequence<byte> payload)
|
private Task ProcessSettingsFrameAsync(in ReadOnlySequence<byte> payload)
|
||||||
{
|
{
|
||||||
if (_currentHeadersStream != null)
|
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)
|
if (_currentHeadersStream != null)
|
||||||
{
|
{
|
||||||
|
|
@ -818,7 +818,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task ProcessContinuationFrameAsync(ReadOnlySequence<byte> payload)
|
private Task ProcessContinuationFrameAsync(in ReadOnlySequence<byte> payload)
|
||||||
{
|
{
|
||||||
if (_currentHeadersStream == null)
|
if (_currentHeadersStream == null)
|
||||||
{
|
{
|
||||||
|
|
@ -857,7 +857,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task DecodeHeadersAsync(bool endHeaders, ReadOnlySequence<byte> payload)
|
private Task DecodeHeadersAsync(bool endHeaders, in ReadOnlySequence<byte> payload)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -879,7 +879,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return Task.CompletedTask;
|
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);
|
_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 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;
|
framePayload = ReadOnlySequence<byte>.Empty;
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return true;
|
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
|
// Copy in any extra fields for the given frame type
|
||||||
var extendedHeaderLength = GetPayloadFieldsLength(frame);
|
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();
|
var data = payload.ToSpan();
|
||||||
Debug.Assert(data.Length % SettingSize == 0, "Invalid settings payload length");
|
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.
|
// The Length property of a ReadOnlySequence can be expensive, so we cache the value.
|
||||||
var dataLength = data.Length;
|
var dataLength = data.Length;
|
||||||
|
|
@ -270,28 +270,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
| Padding (*) ...
|
| 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
|
// Note padding is not implemented
|
||||||
_outgoingFrame.PrepareData(streamId);
|
_outgoingFrame.PrepareData(streamId);
|
||||||
|
|
||||||
var dataPayloadLength = (int)_maxFrameSize; // Minus padding
|
if (dataLength > _maxFrameSize) // Minus padding
|
||||||
|
|
||||||
while (data.Length > dataPayloadLength)
|
|
||||||
{
|
{
|
||||||
var currentData = data.Slice(0, dataPayloadLength);
|
TrimAndWriteDataUnsynchronized(in data, dataLength, endStream);
|
||||||
_outgoingFrame.PayloadLength = dataPayloadLength; // Plus padding
|
return;
|
||||||
|
|
||||||
WriteHeaderUnsynchronized();
|
|
||||||
|
|
||||||
foreach (var buffer in currentData)
|
|
||||||
{
|
|
||||||
_outputWriter.Write(buffer.Span);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plus padding
|
|
||||||
|
|
||||||
data = data.Slice(dataPayloadLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endStream)
|
if (endStream)
|
||||||
|
|
@ -299,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
_outgoingFrame.DataFlags |= Http2DataFrameFlags.END_STREAM;
|
_outgoingFrame.DataFlags |= Http2DataFrameFlags.END_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outgoingFrame.PayloadLength = (int)data.Length; // Plus padding
|
_outgoingFrame.PayloadLength = (int)dataLength; // Plus padding
|
||||||
|
|
||||||
WriteHeaderUnsynchronized();
|
WriteHeaderUnsynchronized();
|
||||||
|
|
||||||
|
|
@ -309,6 +298,51 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plus padding
|
// 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)
|
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)
|
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.
|
// Since padding isn't buffered, immediately count padding bytes as read for flow control purposes.
|
||||||
if (dataFrame.DataHasPadding)
|
if (dataFrame.DataHasPadding)
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
||||||
_bufs = handle + requestSize;
|
_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);
|
Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable);
|
||||||
return _awaitable;
|
return _awaitable;
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
||||||
|
|
||||||
private unsafe void Write(
|
private unsafe void Write(
|
||||||
UvStreamHandle handle,
|
UvStreamHandle handle,
|
||||||
ReadOnlySequence<byte> buffer,
|
in ReadOnlySequence<byte> buffer,
|
||||||
Action<UvWriteReq, int, UvException, object> callback,
|
Action<UvWriteReq, int, UvException, object> callback,
|
||||||
object state)
|
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)
|
if (buffers.IsSingleSegment)
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
return _awaitableEventArgs;
|
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.IsEmpty);
|
||||||
Debug.Assert(!buffer.IsSingleSegment);
|
Debug.Assert(!buffer.IsSingleSegment);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue