Extract bitshift helper code, Frame cleanup #2773
This commit is contained in:
parent
ff52525134
commit
aa9dde2457
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||
{
|
||||
public class BinaryPrimitivesBenchmark
|
||||
{
|
||||
private const int Iterations = 100;
|
||||
|
||||
private byte[] _data;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_data = new byte[4];
|
||||
}
|
||||
|
||||
[Benchmark(Baseline = true, OperationsPerInvoke = Iterations)]
|
||||
public uint GetUInt32AsBitwise()
|
||||
{
|
||||
var v = 0u;
|
||||
for (int i = 0; i < 1_000_000; i++)
|
||||
{
|
||||
v = (uint)((_data[0] << 24) | (_data[1] << 16) | (_data[2] << 8) | _data[3]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = Iterations)]
|
||||
public unsafe uint GetUInt32AsBinary()
|
||||
{
|
||||
var v = 0u;
|
||||
for (int i = 0; i < 1_000_000; i++)
|
||||
{
|
||||
v = BinaryPrimitives.ReadUInt32BigEndian(_data.AsSpan());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
Compile the solution in Release mode (so Kestrel is available in release)
|
||||
|
||||
```
|
||||
build /t:compile /p:Configuration=Release
|
||||
```
|
||||
To run a specific benchmark add it as parameter
|
||||
```
|
||||
dotnet run -f netcoreapp2.0 -c Release RequestParsing
|
||||
|
|
|
|||
|
|
@ -564,7 +564,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
|
|||
<value>More data received than specified in the Content-Length header.</value>
|
||||
</data>
|
||||
<data name="Http2StreamErrorAfterHeaders" xml:space="preserve">
|
||||
<value>An error occured after the response headers were sent, a reset is being sent.</value>
|
||||
<value>An error occurred after the response headers were sent, a reset is being sent.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorMaxStreams" xml:space="preserve">
|
||||
<value>A new stream was refused because this connection has reached its stream limit.</value>
|
||||
|
|
@ -572,4 +572,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
|
|||
<data name="GreaterThanZeroRequired" xml:space="preserve">
|
||||
<value>A value greater than zero is required.</value>
|
||||
</data>
|
||||
<data name="Http2FrameMissingFields" xml:space="preserve">
|
||||
<value>The frame is too short to contain the fields indicated by the given flags.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
// Mimics BinaryPrimities with oddly sized units
|
||||
internal class Bitshifter
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint ReadUInt24BigEndian(ReadOnlySpan<byte> source)
|
||||
{
|
||||
return (uint)((source[0] << 16) | (source[1] << 8) | source[2]);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteUInt24BigEndian(Span<byte> destination, uint value)
|
||||
{
|
||||
Debug.Assert(value <= 0xFF_FF_FF, value.ToString());
|
||||
destination[0] = (byte)((value & 0xFF_00_00) >> 16);
|
||||
destination[1] = (byte)((value & 0x00_FF_00) >> 8);
|
||||
destination[2] = (byte)(value & 0x00_00_FF);
|
||||
}
|
||||
|
||||
// Drops the highest order bit
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint ReadUInt31BigEndian(ReadOnlySpan<byte> source)
|
||||
{
|
||||
return BinaryPrimitives.ReadUInt32BigEndian(source) & 0x7F_FF_FF_FF;
|
||||
}
|
||||
|
||||
// Does not overwrite the highest order bit
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteUInt31BigEndian(Span<byte> destination, uint value)
|
||||
{
|
||||
Debug.Assert(value <= 0x7F_FF_FF_FF, value.ToString());
|
||||
// Keep the highest bit
|
||||
var reserved = (destination[0] & 0x80u) << 24;
|
||||
BinaryPrimitives.WriteUInt32BigEndian(destination, value | reserved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -417,7 +417,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.DataHasPadding && _incomingFrame.DataPadLength >= _incomingFrame.Length)
|
||||
// The Padding field is missing
|
||||
if (_incomingFrame.DataPayloadOffset > _incomingFrame.PayloadLength)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2FrameMissingFields, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.DataHasPadding && _incomingFrame.DataPadLength >= _incomingFrame.PayloadLength)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorPaddingTooLong(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
|
@ -467,7 +473,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.HeadersHasPadding && _incomingFrame.HeadersPadLength >= _incomingFrame.Length)
|
||||
// Padding or priority fields are missing
|
||||
if (_incomingFrame.HeadersPayloadOffset > _incomingFrame.PayloadLength)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2FrameMissingFields, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.HeadersHasPadding && _incomingFrame.HeadersPadLength >= _incomingFrame.PayloadLength - 1)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorPaddingTooLong(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
|
@ -492,7 +504,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
|
||||
// This is the last chance for the client to send END_STREAM
|
||||
if ((_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == 0)
|
||||
if (!_incomingFrame.HeadersEndStream)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorHeadersWithTrailersNoEndStream, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
|
@ -501,8 +513,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_currentHeadersStream = stream;
|
||||
_requestHeaderParsingState = RequestHeaderParsingState.Trailers;
|
||||
|
||||
var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
|
||||
await DecodeTrailersAsync(endHeaders, _incomingFrame.HeadersPayload);
|
||||
await DecodeTrailersAsync(_incomingFrame.HeadersEndHeaders, _incomingFrame.HeadersPayload);
|
||||
}
|
||||
else if (_incomingFrame.StreamId <= _highestOpenedStreamId)
|
||||
{
|
||||
|
|
@ -538,8 +549,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_currentHeadersStream.Reset();
|
||||
_headerFlags = _incomingFrame.HeadersFlags;
|
||||
|
||||
var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
|
||||
await DecodeHeadersAsync(application, endHeaders, _incomingFrame.HeadersPayload);
|
||||
await DecodeHeadersAsync(application, _incomingFrame.HeadersEndHeaders, _incomingFrame.HeadersPayload);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -560,7 +570,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamSelfDependency(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 5)
|
||||
if (_incomingFrame.PayloadLength != 5)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 5), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
|
@ -580,7 +590,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 4)
|
||||
if (_incomingFrame.PayloadLength != 4)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 4), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
|
@ -603,9 +613,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdNotZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if ((_incomingFrame.SettingsFlags & Http2SettingsFrameFlags.ACK) == Http2SettingsFrameFlags.ACK)
|
||||
if (_incomingFrame.SettingsAck)
|
||||
{
|
||||
if (_incomingFrame.Length != 0)
|
||||
if (_incomingFrame.PayloadLength != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorSettingsAckLengthNotZero, Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
|
@ -613,7 +623,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length % 6 != 0)
|
||||
if (_incomingFrame.PayloadLength % 6 != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorSettingsLengthNotMultipleOfSix, Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
|
@ -666,12 +676,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdNotZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 8)
|
||||
if (_incomingFrame.PayloadLength != 8)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 8), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
if ((_incomingFrame.PingFlags & Http2PingFrameFlags.ACK) == Http2PingFrameFlags.ACK)
|
||||
if (_incomingFrame.PingAck)
|
||||
{
|
||||
// TODO: verify that payload is equal to the outgoing PING frame
|
||||
return Task.CompletedTask;
|
||||
|
|
@ -704,7 +714,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 4)
|
||||
if (_incomingFrame.PayloadLength != 4)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 4), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
|
@ -767,15 +777,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
var endHeaders = (_incomingFrame.ContinuationFlags & Http2ContinuationFrameFlags.END_HEADERS) == Http2ContinuationFrameFlags.END_HEADERS;
|
||||
|
||||
if (_requestHeaderParsingState == RequestHeaderParsingState.Trailers)
|
||||
{
|
||||
return DecodeTrailersAsync(endHeaders, _incomingFrame.Payload);
|
||||
return DecodeTrailersAsync(_incomingFrame.ContinuationEndHeaders, _incomingFrame.Payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DecodeHeadersAsync(application, endHeaders, _incomingFrame.Payload);
|
||||
return DecodeHeadersAsync(application, _incomingFrame.ContinuationEndHeaders, _incomingFrame.Payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.10
|
||||
+---------------------------------------------------------------+
|
||||
| Header Block Fragment (*) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public Http2ContinuationFrameFlags ContinuationFlags
|
||||
|
|
@ -12,9 +17,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
set => Flags = (byte)value;
|
||||
}
|
||||
|
||||
public bool ContinuationEndHeaders => (ContinuationFlags & Http2ContinuationFrameFlags.END_HEADERS) == Http2ContinuationFrameFlags.END_HEADERS;
|
||||
|
||||
public void PrepareContinuation(Http2ContinuationFrameFlags flags, int streamId)
|
||||
{
|
||||
Length = MinAllowedMaxFrameSize - HeaderLength;
|
||||
PayloadLength = MinAllowedMaxFrameSize - HeaderLength;
|
||||
Type = Http2FrameType.CONTINUATION;
|
||||
ContinuationFlags = flags;
|
||||
StreamId = streamId;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,18 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/*
|
||||
+---------------+
|
||||
|Pad Length? (8)|
|
||||
+---------------+-----------------------------------------------+
|
||||
| Data (*) ...
|
||||
+---------------------------------------------------------------+
|
||||
| Padding (*) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public Http2DataFrameFlags DataFlags
|
||||
|
|
@ -14,23 +22,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
set => Flags = (byte)value;
|
||||
}
|
||||
|
||||
public bool DataEndStream => (DataFlags & Http2DataFrameFlags.END_STREAM) == Http2DataFrameFlags.END_STREAM;
|
||||
|
||||
public bool DataHasPadding => (DataFlags & Http2DataFrameFlags.PADDED) == Http2DataFrameFlags.PADDED;
|
||||
|
||||
public byte DataPadLength
|
||||
{
|
||||
get => DataHasPadding ? _data[PayloadOffset] : (byte)0;
|
||||
set => _data[PayloadOffset] = value;
|
||||
get => DataHasPadding ? Payload[0] : (byte)0;
|
||||
set => Payload[0] = value;
|
||||
}
|
||||
|
||||
public ArraySegment<byte> DataPayload => DataHasPadding
|
||||
? new ArraySegment<byte>(_data, PayloadOffset + 1, Length - DataPadLength - 1)
|
||||
: new ArraySegment<byte>(_data, PayloadOffset, Length);
|
||||
public int DataPayloadOffset => DataHasPadding ? 1 : 0;
|
||||
|
||||
private int DataPayloadLength => PayloadLength - DataPayloadOffset - DataPadLength;
|
||||
|
||||
public Span<byte> DataPayload => Payload.Slice(DataPayloadOffset, DataPayloadLength);
|
||||
|
||||
public void PrepareData(int streamId, byte? padLength = null)
|
||||
{
|
||||
var padded = padLength != null;
|
||||
|
||||
Length = MinAllowedMaxFrameSize;
|
||||
PayloadLength = MinAllowedMaxFrameSize;
|
||||
Type = Http2FrameType.DATA;
|
||||
DataFlags = padded ? Http2DataFrameFlags.PADDED : Http2DataFrameFlags.NONE;
|
||||
StreamId = streamId;
|
||||
|
|
@ -38,40 +50,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
if (padded)
|
||||
{
|
||||
DataPadLength = padLength.Value;
|
||||
Payload.Slice(Length - padLength.Value).Fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void DataTraceFrame(ILogger logger)
|
||||
{
|
||||
logger.LogTrace("'DATA' Frame. Flags = {DataFlags}, PadLength = {PadLength}, PayloadLength = {PayloadLength}", DataFlags, DataPadLength, DataPayload.Count);
|
||||
}
|
||||
|
||||
internal object ShowFlags()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case Http2FrameType.CONTINUATION:
|
||||
return ContinuationFlags;
|
||||
case Http2FrameType.DATA:
|
||||
return DataFlags;
|
||||
case Http2FrameType.HEADERS:
|
||||
return HeadersFlags;
|
||||
case Http2FrameType.SETTINGS:
|
||||
return SettingsFlags;
|
||||
case Http2FrameType.PING:
|
||||
return PingFlags;
|
||||
|
||||
// Not Implemented
|
||||
case Http2FrameType.PUSH_PROMISE:
|
||||
|
||||
// No flags defined
|
||||
case Http2FrameType.PRIORITY:
|
||||
case Http2FrameType.RST_STREAM:
|
||||
case Http2FrameType.GOAWAY:
|
||||
case Http2FrameType.WINDOW_UPDATE:
|
||||
default:
|
||||
return $"0x{Flags:x}";
|
||||
Payload.Slice(PayloadLength - padLength.Value).Fill(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,38 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Buffers.Binary;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.8
|
||||
+-+-------------------------------------------------------------+
|
||||
|R| Last-Stream-ID (31) |
|
||||
+-+-------------------------------------------------------------+
|
||||
| Error Code (32) |
|
||||
+---------------------------------------------------------------+
|
||||
| Additional Debug Data (*) |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
private const int ErrorCodeOffset = 4;
|
||||
|
||||
public int GoAwayLastStreamId
|
||||
{
|
||||
get => (Payload[0] << 24) | (Payload[1] << 16) | (Payload[2] << 8) | Payload[3];
|
||||
set
|
||||
{
|
||||
Payload[0] = (byte)((value >> 24) & 0xff);
|
||||
Payload[1] = (byte)((value >> 16) & 0xff);
|
||||
Payload[2] = (byte)((value >> 8) & 0xff);
|
||||
Payload[3] = (byte)(value & 0xff);
|
||||
}
|
||||
get => (int)Bitshifter.ReadUInt31BigEndian(Payload);
|
||||
set => Bitshifter.WriteUInt31BigEndian(Payload, (uint)value);
|
||||
}
|
||||
|
||||
public Http2ErrorCode GoAwayErrorCode
|
||||
{
|
||||
get => (Http2ErrorCode)((Payload[4] << 24) | (Payload[5] << 16) | (Payload[6] << 8) | Payload[7]);
|
||||
set
|
||||
{
|
||||
Payload[4] = (byte)(((uint)value >> 24) & 0xff);
|
||||
Payload[5] = (byte)(((uint)value >> 16) & 0xff);
|
||||
Payload[6] = (byte)(((uint)value >> 8) & 0xff);
|
||||
Payload[7] = (byte)((uint)value & 0xff);
|
||||
}
|
||||
get => (Http2ErrorCode)BinaryPrimitives.ReadUInt32BigEndian(Payload.Slice(ErrorCodeOffset));
|
||||
set => BinaryPrimitives.WriteUInt32BigEndian(Payload.Slice(ErrorCodeOffset), (uint)value);
|
||||
}
|
||||
|
||||
public void PrepareGoAway(int lastStreamId, Http2ErrorCode errorCode)
|
||||
{
|
||||
Length = 8;
|
||||
PayloadLength = 8;
|
||||
Type = Http2FrameType.GOAWAY;
|
||||
Flags = 0;
|
||||
StreamId = 0;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,19 @@ using System;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.2
|
||||
+---------------+
|
||||
|Pad Length? (8)|
|
||||
+-+-------------+-----------------------------------------------+
|
||||
|E| Stream Dependency? (31) |
|
||||
+-+-------------+-----------------------------------------------+
|
||||
| Weight? (8) |
|
||||
+-+-------------+-----------------------------------------------+
|
||||
| Header Block Fragment (*) ...
|
||||
+---------------------------------------------------------------+
|
||||
| Padding (*) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public Http2HeadersFrameFlags HeadersFlags
|
||||
|
|
@ -13,57 +26,45 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
set => Flags = (byte)value;
|
||||
}
|
||||
|
||||
public bool HeadersHasPadding => (HeadersFlags & Http2HeadersFrameFlags.PADDED) == Http2HeadersFrameFlags.PADDED;
|
||||
public bool HeadersEndHeaders => (HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
|
||||
|
||||
public byte HeadersPadLength
|
||||
{
|
||||
get => HeadersHasPadding ? _data[HeaderLength] : (byte)0;
|
||||
set => _data[HeaderLength] = value;
|
||||
}
|
||||
public bool HeadersEndStream => (HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == Http2HeadersFrameFlags.END_STREAM;
|
||||
|
||||
public bool HeadersHasPadding => (HeadersFlags & Http2HeadersFrameFlags.PADDED) == Http2HeadersFrameFlags.PADDED;
|
||||
|
||||
public bool HeadersHasPriority => (HeadersFlags & Http2HeadersFrameFlags.PRIORITY) == Http2HeadersFrameFlags.PRIORITY;
|
||||
|
||||
public byte HeadersPriority
|
||||
public byte HeadersPadLength
|
||||
{
|
||||
get => _data[HeadersPriorityOffset];
|
||||
set => _data[HeadersPriorityOffset] = value;
|
||||
get => HeadersHasPadding ? Payload[0] : (byte)0;
|
||||
set => Payload[0] = value;
|
||||
}
|
||||
|
||||
private int HeadersPriorityOffset => PayloadOffset + (HeadersHasPadding ? 1 : 0) + 4;
|
||||
private int HeadersStreamDependencyOffset => HeadersHasPadding ? 1 : 0;
|
||||
|
||||
public int HeadersStreamDependency
|
||||
{
|
||||
get
|
||||
{
|
||||
var offset = HeadersStreamDependencyOffset;
|
||||
|
||||
return (int)((uint)((_data[offset] << 24)
|
||||
| (_data[offset + 1] << 16)
|
||||
| (_data[offset + 2] << 8)
|
||||
| _data[offset + 3]) & 0x7fffffff);
|
||||
}
|
||||
set
|
||||
{
|
||||
var offset = HeadersStreamDependencyOffset;
|
||||
|
||||
_data[offset] = (byte)((value & 0xff000000) >> 24);
|
||||
_data[offset + 1] = (byte)((value & 0x00ff0000) >> 16);
|
||||
_data[offset + 2] = (byte)((value & 0x0000ff00) >> 8);
|
||||
_data[offset + 3] = (byte)(value & 0x000000ff);
|
||||
}
|
||||
get => (int)Bitshifter.ReadUInt31BigEndian(Payload.Slice(HeadersStreamDependencyOffset));
|
||||
set => Bitshifter.WriteUInt31BigEndian(Payload.Slice(HeadersStreamDependencyOffset), (uint)value);
|
||||
}
|
||||
|
||||
private int HeadersStreamDependencyOffset => PayloadOffset + (HeadersHasPadding ? 1 : 0);
|
||||
private int HeadersPriorityWeightOffset => HeadersStreamDependencyOffset + 4;
|
||||
|
||||
public Span<byte> HeadersPayload => new Span<byte>(_data, HeadersPayloadOffset, HeadersPayloadLength);
|
||||
public byte HeadersPriorityWeight
|
||||
{
|
||||
get => Payload[HeadersPriorityWeightOffset];
|
||||
set => Payload[HeadersPriorityWeightOffset] = value;
|
||||
}
|
||||
|
||||
private int HeadersPayloadOffset => PayloadOffset + (HeadersHasPadding ? 1 : 0) + (HeadersHasPriority ? 5 : 0);
|
||||
public int HeadersPayloadOffset => (HeadersHasPadding ? 1 : 0) + (HeadersHasPriority ? 5 : 0);
|
||||
|
||||
private int HeadersPayloadLength => Length - ((HeadersHasPadding ? 1 : 0) + (HeadersHasPriority ? 5 : 0)) - HeadersPadLength;
|
||||
private int HeadersPayloadLength => PayloadLength - HeadersPayloadOffset - HeadersPadLength;
|
||||
|
||||
public Span<byte> HeadersPayload => Payload.Slice(HeadersPayloadOffset, HeadersPayloadLength);
|
||||
|
||||
public void PrepareHeaders(Http2HeadersFrameFlags flags, int streamId)
|
||||
{
|
||||
Length = MinAllowedMaxFrameSize - HeaderLength;
|
||||
PayloadLength = MinAllowedMaxFrameSize - HeaderLength;
|
||||
Type = Http2FrameType.HEADERS;
|
||||
HeadersFlags = flags;
|
||||
StreamId = streamId;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.7
|
||||
+---------------------------------------------------------------+
|
||||
| |
|
||||
| Opaque Data (64) |
|
||||
| |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public Http2PingFrameFlags PingFlags
|
||||
|
|
@ -12,9 +19,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
set => Flags = (byte)value;
|
||||
}
|
||||
|
||||
public bool PingAck => (PingFlags & Http2PingFrameFlags.ACK) == Http2PingFrameFlags.ACK;
|
||||
|
||||
public void PreparePing(Http2PingFrameFlags flags)
|
||||
{
|
||||
Length = 8;
|
||||
PayloadLength = 8;
|
||||
Type = Http2FrameType.PING;
|
||||
PingFlags = flags;
|
||||
StreamId = 0;
|
||||
|
|
|
|||
|
|
@ -3,50 +3,49 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.3
|
||||
+-+-------------------------------------------------------------+
|
||||
|E| Stream Dependency (31) |
|
||||
+-+-------------+-----------------------------------------------+
|
||||
| Weight (8) |
|
||||
+-+-------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
private const int PriorityWeightOffset = 4;
|
||||
|
||||
public int PriorityStreamDependency
|
||||
{
|
||||
get => ((_data[PayloadOffset] << 24)
|
||||
| (_data[PayloadOffset + 1] << 16)
|
||||
| (_data[PayloadOffset + 2] << 8)
|
||||
| _data[PayloadOffset + 3]) & 0x7fffffff;
|
||||
set
|
||||
{
|
||||
_data[PayloadOffset] = (byte)((value & 0x7f000000) >> 24);
|
||||
_data[PayloadOffset + 1] = (byte)((value & 0x00ff0000) >> 16);
|
||||
_data[PayloadOffset + 2] = (byte)((value & 0x0000ff00) >> 8);
|
||||
_data[PayloadOffset + 3] = (byte)(value & 0x000000ff);
|
||||
}
|
||||
get => (int)Bitshifter.ReadUInt31BigEndian(Payload);
|
||||
set => Bitshifter.WriteUInt31BigEndian(Payload, (uint)value);
|
||||
}
|
||||
|
||||
|
||||
public bool PriorityIsExclusive
|
||||
{
|
||||
get => (_data[PayloadOffset] & 0x80000000) != 0;
|
||||
get => (Payload[0] & 0x80) != 0;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_data[PayloadOffset] |= 0x80;
|
||||
Payload[0] |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data[PayloadOffset] &= 0x7f;
|
||||
Payload[0] &= 0x7f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte PriorityWeight
|
||||
{
|
||||
get => _data[PayloadOffset + 4];
|
||||
set => _data[PayloadOffset] = value;
|
||||
get => Payload[PriorityWeightOffset];
|
||||
set => Payload[PriorityWeightOffset] = value;
|
||||
}
|
||||
|
||||
|
||||
public void PreparePriority(int streamId, int streamDependency, bool exclusive, byte weight)
|
||||
{
|
||||
Length = 5;
|
||||
PayloadLength = 5;
|
||||
Type = Http2FrameType.PRIORITY;
|
||||
StreamId = streamId;
|
||||
PriorityStreamDependency = streamDependency;
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Buffers.Binary;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.4
|
||||
+---------------------------------------------------------------+
|
||||
| Error Code (32) |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public Http2ErrorCode RstStreamErrorCode
|
||||
{
|
||||
get => (Http2ErrorCode)((Payload[0] << 24) | (Payload[1] << 16) | (Payload[2] << 8) | Payload[3]);
|
||||
set
|
||||
{
|
||||
Payload[0] = (byte)(((uint)value >> 24) & 0xff);
|
||||
Payload[1] = (byte)(((uint)value >> 16) & 0xff);
|
||||
Payload[2] = (byte)(((uint)value >> 8) & 0xff);
|
||||
Payload[3] = (byte)((uint)value & 0xff);
|
||||
}
|
||||
get => (Http2ErrorCode)BinaryPrimitives.ReadUInt32BigEndian(Payload);
|
||||
set => BinaryPrimitives.WriteUInt32BigEndian(Payload, (uint)value);
|
||||
}
|
||||
|
||||
public void PrepareRstStream(int streamId, Http2ErrorCode errorCode)
|
||||
{
|
||||
Length = 4;
|
||||
PayloadLength = 4;
|
||||
Type = Http2FrameType.RST_STREAM;
|
||||
Flags = 0;
|
||||
StreamId = streamId;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,17 @@
|
|||
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.5.1
|
||||
List of:
|
||||
+-------------------------------+
|
||||
| Identifier (16) |
|
||||
+-------------------------------+-------------------------------+
|
||||
| Value (32) |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
private const int SettingSize = 6; // 2 bytes for the id, 4 bytes for the value.
|
||||
|
|
@ -17,10 +24,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
set => Flags = (byte)value;
|
||||
}
|
||||
|
||||
public bool SettingsAck => (SettingsFlags & Http2SettingsFrameFlags.ACK) == Http2SettingsFrameFlags.ACK;
|
||||
|
||||
public int SettingsCount
|
||||
{
|
||||
get => Length / SettingSize;
|
||||
set => Length = value * SettingSize;
|
||||
get => PayloadLength / SettingSize;
|
||||
set => PayloadLength = value * SettingSize;
|
||||
}
|
||||
|
||||
public IList<Http2PeerSetting> GetSettings()
|
||||
|
|
|
|||
|
|
@ -3,23 +3,22 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-6.9
|
||||
+-+-------------------------------------------------------------+
|
||||
|R| Window Size Increment (31) |
|
||||
+-+-------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public int WindowUpdateSizeIncrement
|
||||
{
|
||||
get => ((Payload[0] << 24) | (Payload[1] << 16) | (Payload[2] << 8) | Payload[3]) & 0x7fffffff;
|
||||
set
|
||||
{
|
||||
Payload[0] = (byte)(((uint)value >> 24) & 0x7f);
|
||||
Payload[1] = (byte)(((uint)value >> 16) & 0xff);
|
||||
Payload[2] = (byte)(((uint)value >> 8) & 0xff);
|
||||
Payload[3] = (byte)((uint)value & 0xff);
|
||||
}
|
||||
get => (int)Bitshifter.ReadUInt31BigEndian(Payload);
|
||||
set => Bitshifter.WriteUInt31BigEndian(Payload, (uint)value);
|
||||
}
|
||||
|
||||
public void PrepareWindowUpdate(int streamId, int sizeIncrement)
|
||||
{
|
||||
Length = 4;
|
||||
PayloadLength = 4;
|
||||
Type = Http2FrameType.WINDOW_UPDATE;
|
||||
Flags = 0;
|
||||
StreamId = streamId;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,17 @@ using System;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc7540#section-4.1
|
||||
+-----------------------------------------------+
|
||||
| Length (24) |
|
||||
+---------------+---------------+---------------+
|
||||
| Type (8) | Flags (8) |
|
||||
+-+-------------+---------------+-------------------------------+
|
||||
|R| Stream Identifier (31) |
|
||||
+=+=============================================================+
|
||||
| Frame Payload (0...) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
public const int MinAllowedMaxFrameSize = 16 * 1024;
|
||||
|
|
@ -19,52 +30,60 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
private readonly byte[] _data = new byte[HeaderLength + MinAllowedMaxFrameSize];
|
||||
|
||||
public Span<byte> Raw => new Span<byte>(_data, 0, HeaderLength + Length);
|
||||
public Span<byte> Raw => new Span<byte>(_data, 0, HeaderLength + PayloadLength);
|
||||
|
||||
public int Length
|
||||
public int PayloadLength
|
||||
{
|
||||
get => (_data[LengthOffset] << 16) | (_data[LengthOffset + 1] << 8) | _data[LengthOffset + 2];
|
||||
set
|
||||
{
|
||||
_data[LengthOffset] = (byte)((value & 0x00ff0000) >> 16);
|
||||
_data[LengthOffset + 1] = (byte)((value & 0x0000ff00) >> 8);
|
||||
_data[LengthOffset + 2] = (byte)(value & 0x000000ff);
|
||||
}
|
||||
get => (int)Bitshifter.ReadUInt24BigEndian(_data.AsSpan(LengthOffset));
|
||||
set => Bitshifter.WriteUInt24BigEndian(_data.AsSpan(LengthOffset), (uint)value);
|
||||
}
|
||||
|
||||
public Http2FrameType Type
|
||||
{
|
||||
get => (Http2FrameType)_data[TypeOffset];
|
||||
set
|
||||
{
|
||||
_data[TypeOffset] = (byte)value;
|
||||
}
|
||||
set => _data[TypeOffset] = (byte)value;
|
||||
}
|
||||
|
||||
public byte Flags
|
||||
{
|
||||
get => _data[FlagsOffset];
|
||||
set
|
||||
{
|
||||
_data[FlagsOffset] = value;
|
||||
}
|
||||
set => _data[FlagsOffset] = value;
|
||||
}
|
||||
|
||||
public int StreamId
|
||||
{
|
||||
get => (int)((uint)((_data[StreamIdOffset] << 24)
|
||||
| (_data[StreamIdOffset + 1] << 16)
|
||||
| (_data[StreamIdOffset + 2] << 8)
|
||||
| _data[StreamIdOffset + 3]) & 0x7fffffff);
|
||||
set
|
||||
{
|
||||
_data[StreamIdOffset] = (byte)((value & 0xff000000) >> 24);
|
||||
_data[StreamIdOffset + 1] = (byte)((value & 0x00ff0000) >> 16);
|
||||
_data[StreamIdOffset + 2] = (byte)((value & 0x0000ff00) >> 8);
|
||||
_data[StreamIdOffset + 3] = (byte)(value & 0x000000ff);
|
||||
}
|
||||
get => (int)Bitshifter.ReadUInt31BigEndian(_data.AsSpan(StreamIdOffset));
|
||||
set => Bitshifter.WriteUInt31BigEndian(_data.AsSpan(StreamIdOffset), (uint)value);
|
||||
}
|
||||
|
||||
public Span<byte> Payload => new Span<byte>(_data, PayloadOffset, Length);
|
||||
public Span<byte> Payload => new Span<byte>(_data, PayloadOffset, PayloadLength);
|
||||
|
||||
internal object ShowFlags()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case Http2FrameType.CONTINUATION:
|
||||
return ContinuationFlags;
|
||||
case Http2FrameType.DATA:
|
||||
return DataFlags;
|
||||
case Http2FrameType.HEADERS:
|
||||
return HeadersFlags;
|
||||
case Http2FrameType.SETTINGS:
|
||||
return SettingsFlags;
|
||||
case Http2FrameType.PING:
|
||||
return PingFlags;
|
||||
|
||||
// Not Implemented
|
||||
case Http2FrameType.PUSH_PROMISE:
|
||||
|
||||
// No flags defined
|
||||
case Http2FrameType.PRIORITY:
|
||||
case Http2FrameType.RST_STREAM:
|
||||
case Http2FrameType.GOAWAY:
|
||||
case Http2FrameType.WINDOW_UPDATE:
|
||||
default:
|
||||
return $"0x{Flags:x}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
|
|
@ -22,18 +21,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
var headerSlice = readableBuffer.Slice(0, Http2Frame.HeaderLength);
|
||||
headerSlice.CopyTo(frame.Raw);
|
||||
|
||||
if (frame.Length > maxFrameSize)
|
||||
var payloadLength = frame.PayloadLength;
|
||||
if (payloadLength > maxFrameSize)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorFrameOverLimit(frame.Length, maxFrameSize), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorFrameOverLimit(payloadLength, maxFrameSize), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
if (readableBuffer.Length < Http2Frame.HeaderLength + frame.Length)
|
||||
var frameLength = Http2Frame.HeaderLength + payloadLength;
|
||||
if (readableBuffer.Length < frameLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload);
|
||||
consumed = examined = readableBuffer.GetPosition(Http2Frame.HeaderLength + frame.Length);
|
||||
readableBuffer.Slice(Http2Frame.HeaderLength, payloadLength).CopyTo(frame.Payload);
|
||||
consumed = examined = readableBuffer.GetPosition(frameLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
lock (_writeLock)
|
||||
{
|
||||
_outgoingFrame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS, streamId);
|
||||
_outgoingFrame.Length = _continueBytes.Length;
|
||||
_outgoingFrame.PayloadLength = _continueBytes.Length;
|
||||
_continueBytes.CopyTo(_outgoingFrame.HeadersPayload);
|
||||
|
||||
return WriteFrameUnsynchronizedAsync();
|
||||
|
|
@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_outgoingFrame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId);
|
||||
|
||||
var done = _hpackEncoder.BeginEncode(statusCode, EnumerateHeaders(headers), _outgoingFrame.Payload, out var payloadLength);
|
||||
_outgoingFrame.Length = payloadLength;
|
||||
_outgoingFrame.PayloadLength = payloadLength;
|
||||
|
||||
if (done)
|
||||
{
|
||||
|
|
@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_outgoingFrame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId);
|
||||
|
||||
done = _hpackEncoder.Encode(_outgoingFrame.Payload, out var length);
|
||||
_outgoingFrame.Length = length;
|
||||
_outgoingFrame.PayloadLength = length;
|
||||
|
||||
if (done)
|
||||
{
|
||||
|
|
@ -207,7 +207,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_outgoingFrame.DataFlags = Http2DataFrameFlags.END_STREAM;
|
||||
}
|
||||
|
||||
_outgoingFrame.Length = unwrittenPayloadLength;
|
||||
_outgoingFrame.PayloadLength = unwrittenPayloadLength;
|
||||
|
||||
_log.Http2FrameSending(_connectionId, _outgoingFrame);
|
||||
_outputWriter.Write(_outgoingFrame.Raw);
|
||||
|
|
|
|||
|
|
@ -274,9 +274,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
|
||||
var payload = dataFrame.DataPayload;
|
||||
var endStream = (dataFrame.DataFlags & Http2DataFrameFlags.END_STREAM) == Http2DataFrameFlags.END_STREAM;
|
||||
var endStream = dataFrame.DataEndStream;
|
||||
|
||||
if (payload.Count > 0)
|
||||
if (payload.Length > 0)
|
||||
{
|
||||
RequestBodyStarted = true;
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_inputFlowControl.StopWindowUpdates();
|
||||
}
|
||||
|
||||
_inputFlowControl.Advance(payload.Count);
|
||||
_inputFlowControl.Advance(payload.Length);
|
||||
|
||||
if (IsAborted)
|
||||
{
|
||||
|
|
@ -300,12 +300,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
if (InputRemaining.HasValue)
|
||||
{
|
||||
// https://tools.ietf.org/html/rfc7540#section-8.1.2.6
|
||||
if (payload.Count > InputRemaining.Value)
|
||||
if (payload.Length > InputRemaining.Value)
|
||||
{
|
||||
throw new Http2StreamErrorException(StreamId, CoreStrings.Http2StreamErrorMoreDataThanLength, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
InputRemaining -= payload.Count;
|
||||
InputRemaining -= payload.Length;
|
||||
}
|
||||
|
||||
RequestBodyPipe.Writer.Write(payload);
|
||||
|
|
|
|||
|
|
@ -256,12 +256,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
public void Http2FrameReceived(string connectionId, Http2Frame frame)
|
||||
{
|
||||
_http2FrameReceived(_logger, connectionId, frame.Type, frame.StreamId, frame.Length, frame.ShowFlags(), null);
|
||||
_http2FrameReceived(_logger, connectionId, frame.Type, frame.StreamId, frame.PayloadLength, frame.ShowFlags(), null);
|
||||
}
|
||||
|
||||
public void Http2FrameSending(string connectionId, Http2Frame frame)
|
||||
{
|
||||
_http2FrameSending(_logger, connectionId, frame.Type, frame.StreamId, frame.Length, frame.ShowFlags(), null);
|
||||
_http2FrameSending(_logger, connectionId, frame.Type, frame.StreamId, frame.PayloadLength, frame.ShowFlags(), null);
|
||||
}
|
||||
|
||||
public virtual void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
|
|
|
|||
|
|
@ -2087,7 +2087,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
=> GetString("Http2StreamErrorMoreDataThanLength");
|
||||
|
||||
/// <summary>
|
||||
/// An error occured after the response headers were sent, a reset is being sent.
|
||||
/// An error occurred after the response headers were sent, a reset is being sent.
|
||||
/// </summary>
|
||||
internal static string Http2StreamErrorAfterHeaders
|
||||
{
|
||||
|
|
@ -2095,7 +2095,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error occured after the response headers were sent, a reset is being sent.
|
||||
/// An error occurred after the response headers were sent, a reset is being sent.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2StreamErrorAfterHeaders()
|
||||
=> GetString("Http2StreamErrorAfterHeaders");
|
||||
|
|
@ -2128,6 +2128,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
internal static string FormatGreaterThanZeroRequired()
|
||||
=> GetString("GreaterThanZeroRequired");
|
||||
|
||||
/// <summary>
|
||||
/// The frame is too short to contain the fields indicated by the given flags.
|
||||
/// </summary>
|
||||
internal static string Http2FrameMissingFields
|
||||
{
|
||||
get => GetString("Http2FrameMissingFields");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The frame is too short to contain the fields indicated by the given flags.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2FrameMissingFields()
|
||||
=> GetString("Http2FrameMissingFields");
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(_helloWorldBytes, dataFrame.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan().SequenceEqual(dataFrame.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(_maxData, dataFrame.DataPayload);
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -223,10 +223,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(_maxData, dataFrame1.DataPayload);
|
||||
Assert.Equal(_maxData, dataFrame2.DataPayload);
|
||||
Assert.Equal(_maxData, dataFrame3.DataPayload);
|
||||
Assert.Equal(_maxData, dataFrame4.DataPayload);
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame1.DataPayload));
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame2.DataPayload));
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame3.DataPayload));
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame4.DataPayload));
|
||||
Assert.Equal(_maxData.Length * 2, streamWindowUpdateFrame1.WindowUpdateSizeIncrement);
|
||||
Assert.Equal(_maxData.Length * 2, connectionWindowUpdateFrame1.WindowUpdateSizeIncrement);
|
||||
Assert.Equal(_maxData.Length * 2, connectionWindowUpdateFrame2.WindowUpdateSizeIncrement);
|
||||
|
|
@ -261,7 +261,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(_helloWorldBytes, dataFrame.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan().SequenceEqual(dataFrame.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -324,10 +324,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 3, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(stream1DataFrame1.DataPayload, _helloBytes);
|
||||
Assert.Equal(stream1DataFrame2.DataPayload, _worldBytes);
|
||||
Assert.Equal(stream3DataFrame1.DataPayload, _helloBytes);
|
||||
Assert.Equal(stream3DataFrame2.DataPayload, _worldBytes);
|
||||
Assert.True(_helloBytes.AsSpan().SequenceEqual(stream1DataFrame1.DataPayload));
|
||||
Assert.True(_worldBytes.AsSpan().SequenceEqual(stream1DataFrame2.DataPayload));
|
||||
Assert.True(_helloBytes.AsSpan().SequenceEqual(stream3DataFrame1.DataPayload));
|
||||
Assert.True(_worldBytes.AsSpan().SequenceEqual(stream3DataFrame2.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -417,16 +417,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 3, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(_maxData, dataFrame1.DataPayload);
|
||||
Assert.Equal(_maxData, dataFrame2.DataPayload);
|
||||
Assert.Equal(_maxData, dataFrame3.DataPayload);
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame1.DataPayload));
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame2.DataPayload));
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame3.DataPayload));
|
||||
Assert.Equal(_maxData.Length * 2, streamWindowUpdateFrame.WindowUpdateSizeIncrement);
|
||||
Assert.Equal(_maxData.Length * 2, connectionWindowUpdateFrame1.WindowUpdateSizeIncrement);
|
||||
|
||||
Assert.Equal(_maxData, dataFrame4.DataPayload);
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame4.DataPayload));
|
||||
Assert.Equal(_maxData.Length * 2, connectionWindowUpdateFrame2.WindowUpdateSizeIncrement);
|
||||
|
||||
Assert.Equal(_maxData, dataFrame5.DataPayload);
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame5.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -521,7 +521,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(_helloWorldBytes, dataFrame.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan().SequenceEqual(dataFrame.DataPayload));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -533,12 +533,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// _maxData should be 1/4th of the default initial window size + 1.
|
||||
Assert.Equal(Http2PeerSettings.DefaultInitialWindowSize + 1, (uint)_maxData.Length * 4);
|
||||
|
||||
var maxDataMinusPadding = new ArraySegment<byte>(_maxData, 0, _maxData.Length - padLength - 1);
|
||||
var maxDataMinusPadding = _maxData.AsMemory(0, _maxData.Length - padLength - 1);
|
||||
|
||||
await InitializeConnectionAsync(_echoApplication);
|
||||
|
||||
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
|
||||
await SendDataWithPaddingAsync(1, maxDataMinusPadding, padLength, endStream: false);
|
||||
await SendDataWithPaddingAsync(1, maxDataMinusPadding.Span, padLength, endStream: false);
|
||||
|
||||
await ExpectAsync(Http2FrameType.HEADERS,
|
||||
withLength: 37,
|
||||
|
|
@ -546,7 +546,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
withStreamId: 1);
|
||||
|
||||
var dataFrame1 = await ExpectAsync(Http2FrameType.DATA,
|
||||
withLength: maxDataMinusPadding.Count,
|
||||
withLength: maxDataMinusPadding.Length,
|
||||
withFlags: (byte)Http2DataFrameFlags.NONE,
|
||||
withStreamId: 1);
|
||||
|
||||
|
|
@ -569,8 +569,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(maxDataMinusPadding, dataFrame1.DataPayload);
|
||||
Assert.Equal(_maxData, dataFrame2.DataPayload);
|
||||
Assert.True(maxDataMinusPadding.Span.SequenceEqual(dataFrame1.DataPayload));
|
||||
Assert.True(_maxData.AsSpan().SequenceEqual(dataFrame2.DataPayload));
|
||||
|
||||
Assert.Equal(_maxData.Length * 2, connectionWindowUpdateFrame.WindowUpdateSizeIncrement);
|
||||
}
|
||||
|
|
@ -678,7 +678,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.DATA));
|
||||
expectedErrorMessage: CoreStrings.Http2FrameMissingFields);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1303,14 +1303,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(255)]
|
||||
public async Task HEADERS_Received_PaddingEqualToFramePayloadLength_ConnectionError(byte padLength)
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendInvalidHeadersFrameAsync(1, frameLength: padLength, padLength: padLength);
|
||||
// The payload length includes the pad length field
|
||||
await SendInvalidHeadersFrameAsync(1, payloadLength: padLength, padLength: padLength);
|
||||
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
|
|
@ -1319,8 +1319,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.HEADERS));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HEADERS_Received_PaddingFieldMissing_ConnectionError()
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendInvalidHeadersFrameAsync(1, payloadLength: 0, padLength: 1);
|
||||
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2FrameMissingFields);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 1)]
|
||||
[InlineData(1, 2)]
|
||||
[InlineData(254, 255)]
|
||||
public async Task HEADERS_Received_PaddingGreaterThanFramePayloadLength_ConnectionError(int frameLength, byte padLength)
|
||||
|
|
@ -1825,7 +1838,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
withFlags: (byte)Http2DataFrameFlags.NONE,
|
||||
withStreamId: streamId);
|
||||
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, 0, initialWindowSize), dataFrame.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan(0, initialWindowSize).SequenceEqual(dataFrame.DataPayload));
|
||||
Assert.False(writeTasks[streamId].IsCompleted);
|
||||
}
|
||||
|
||||
|
|
@ -2445,7 +2458,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
withFlags: (byte)Http2DataFrameFlags.NONE,
|
||||
withStreamId: streamId);
|
||||
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, 0, initialWindowSize), dataFrame.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan(0, initialWindowSize).SequenceEqual(dataFrame.DataPayload));
|
||||
Assert.False(writeTasks[streamId].IsCompleted);
|
||||
}
|
||||
|
||||
|
|
@ -2749,8 +2762,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, 0, initialWindowSize), dataFrame1.DataPayload);
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, initialWindowSize, initialWindowSize), dataFrame2.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan(0, initialWindowSize).SequenceEqual(dataFrame1.DataPayload));
|
||||
Assert.True(_helloWorldBytes.AsSpan(initialWindowSize, initialWindowSize).SequenceEqual(dataFrame2.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -2804,9 +2817,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, 0, 6), dataFrame1.DataPayload);
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, 6, 3), dataFrame2.DataPayload);
|
||||
Assert.Equal(new ArraySegment<byte>(_helloWorldBytes, 9, 3), dataFrame3.DataPayload);
|
||||
Assert.True(_helloWorldBytes.AsSpan(0, 6).SequenceEqual(dataFrame1.DataPayload));
|
||||
Assert.True(_helloWorldBytes.AsSpan(6, 3).SequenceEqual(dataFrame2.DataPayload));
|
||||
Assert.True(_helloWorldBytes.AsSpan(9, 3).SequenceEqual(dataFrame3.DataPayload));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
|||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId);
|
||||
var done = _hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
|
||||
if (done)
|
||||
{
|
||||
|
|
@ -351,7 +351,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId);
|
||||
done = _hpackEncoder.Encode(frame.HeadersPayload, out length);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
|
||||
if (done)
|
||||
{
|
||||
|
|
@ -374,7 +374,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
_hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length);
|
||||
|
||||
frame.Length = 1 + length + padLength;
|
||||
frame.PayloadLength = 1 + length + padLength;
|
||||
frame.Payload.Slice(1 + length).Fill(0);
|
||||
|
||||
if (endStream)
|
||||
|
|
@ -392,12 +392,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
var frame = new Http2Frame();
|
||||
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PRIORITY, streamId);
|
||||
frame.HeadersPriority = priority;
|
||||
frame.HeadersPriorityWeight = priority;
|
||||
frame.HeadersStreamDependency = streamDependency;
|
||||
|
||||
_hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length);
|
||||
|
||||
frame.Length = 5 + length;
|
||||
frame.PayloadLength = 5 + length;
|
||||
|
||||
if (endStream)
|
||||
{
|
||||
|
|
@ -415,12 +415,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED | Http2HeadersFrameFlags.PRIORITY, streamId);
|
||||
frame.HeadersPadLength = padLength;
|
||||
frame.HeadersPriority = priority;
|
||||
frame.HeadersPriorityWeight = priority;
|
||||
frame.HeadersStreamDependency = streamDependency;
|
||||
|
||||
_hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length);
|
||||
|
||||
frame.Length = 6 + length + padLength;
|
||||
frame.PayloadLength = 6 + length + padLength;
|
||||
frame.Payload.Slice(6 + length).Fill(0);
|
||||
|
||||
if (endStream)
|
||||
|
|
@ -461,7 +461,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.PrepareSettings(Http2SettingsFrameFlags.ACK);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -477,7 +477,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults());
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -485,7 +485,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.PrepareSettings(Http2SettingsFrameFlags.NONE);
|
||||
frame.Length = 6;
|
||||
frame.PayloadLength = 6;
|
||||
|
||||
frame.Payload[0] = (byte)((ushort)parameter >> 8);
|
||||
frame.Payload[1] = (byte)(ushort)parameter;
|
||||
|
|
@ -500,7 +500,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
protected Task SendPushPromiseFrameAsync()
|
||||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.Length = 0;
|
||||
frame.PayloadLength = 0;
|
||||
frame.Type = Http2FrameType.PUSH_PROMISE;
|
||||
frame.StreamId = 1;
|
||||
return SendAsync(frame.Raw);
|
||||
|
|
@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
frame.PrepareHeaders(flags, streamId);
|
||||
var done = _hpackEncoder.BeginEncode(headers, frame.Payload, out var length);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
|
||||
await SendAsync(frame.Raw);
|
||||
|
||||
|
|
@ -524,15 +524,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareHeaders(flags, streamId);
|
||||
frame.Length = headerBlock.Length;
|
||||
frame.PayloadLength = headerBlock.Length;
|
||||
headerBlock.CopyTo(frame.HeadersPayload);
|
||||
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
protected Task SendInvalidHeadersFrameAsync(int streamId, int frameLength, byte padLength)
|
||||
protected Task SendInvalidHeadersFrameAsync(int streamId, int payloadLength, byte padLength)
|
||||
{
|
||||
Assert.True(padLength >= frameLength, $"{nameof(padLength)} must be greater than or equal to {nameof(frameLength)} to create an invalid frame.");
|
||||
Assert.True(padLength >= payloadLength, $"{nameof(padLength)} must be greater than or equal to {nameof(payloadLength)} to create an invalid frame.");
|
||||
|
||||
var frame = new Http2Frame();
|
||||
|
||||
|
|
@ -540,7 +540,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
frame.Payload[0] = padLength;
|
||||
|
||||
// Set length last so .Payload can be written to
|
||||
frame.Length = frameLength;
|
||||
frame.PayloadLength = payloadLength;
|
||||
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
|
@ -550,7 +550,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS, streamId);
|
||||
frame.Length = 3;
|
||||
frame.PayloadLength = 3;
|
||||
|
||||
// Set up an incomplete Literal Header Field w/ Incremental Indexing frame,
|
||||
// with an incomplete new name
|
||||
|
|
@ -567,7 +567,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
frame.PrepareContinuation(flags, streamId);
|
||||
var done = _hpackEncoder.Encode(frame.Payload, out var length);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
|
||||
await SendAsync(frame.Raw);
|
||||
|
||||
|
|
@ -579,7 +579,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareContinuation(flags, streamId);
|
||||
frame.Length = payload.Length;
|
||||
frame.PayloadLength = payload.Length;
|
||||
payload.CopyTo(frame.Payload);
|
||||
|
||||
await SendAsync(frame.Raw);
|
||||
|
|
@ -590,7 +590,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareContinuation(flags, streamId);
|
||||
frame.Length = 0;
|
||||
frame.PayloadLength = 0;
|
||||
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
|
@ -600,7 +600,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareContinuation(Http2ContinuationFrameFlags.END_HEADERS, streamId);
|
||||
frame.Length = 3;
|
||||
frame.PayloadLength = 3;
|
||||
|
||||
// Set up an incomplete Literal Header Field w/ Incremental Indexing frame,
|
||||
// with an incomplete new name
|
||||
|
|
@ -616,7 +616,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareData(streamId);
|
||||
frame.Length = data.Length;
|
||||
frame.PayloadLength = data.Length;
|
||||
frame.DataFlags = endStream ? Http2DataFrameFlags.END_STREAM : Http2DataFrameFlags.NONE;
|
||||
data.CopyTo(frame.DataPayload);
|
||||
|
||||
|
|
@ -628,7 +628,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
|
||||
frame.PrepareData(streamId, padLength);
|
||||
frame.Length = data.Length + 1 + padLength;
|
||||
frame.PayloadLength = data.Length + 1 + padLength;
|
||||
data.CopyTo(frame.DataPayload);
|
||||
|
||||
if (endStream)
|
||||
|
|
@ -650,7 +650,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
frame.Payload[0] = padLength;
|
||||
|
||||
// Set length last so .Payload can be written to
|
||||
frame.Length = frameLength;
|
||||
frame.PayloadLength = frameLength;
|
||||
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
|
@ -666,7 +666,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var pingFrame = new Http2Frame();
|
||||
pingFrame.PreparePing(Http2PingFrameFlags.NONE);
|
||||
pingFrame.Length = length;
|
||||
pingFrame.PayloadLength = length;
|
||||
return SendAsync(pingFrame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -691,7 +691,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var priorityFrame = new Http2Frame();
|
||||
priorityFrame.PreparePriority(streamId, streamDependency: 0, exclusive: false, weight: 0);
|
||||
priorityFrame.Length = length;
|
||||
priorityFrame.PayloadLength = length;
|
||||
return SendAsync(priorityFrame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -706,7 +706,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.PrepareRstStream(streamId, Http2ErrorCode.CANCEL);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -736,7 +736,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.PrepareWindowUpdate(streamId, sizeIncrement);
|
||||
frame.Length = length;
|
||||
frame.PayloadLength = length;
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -745,7 +745,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = new Http2Frame();
|
||||
frame.StreamId = streamId;
|
||||
frame.Type = (Http2FrameType)frameType;
|
||||
frame.Length = 0;
|
||||
frame.PayloadLength = 0;
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
|
|
@ -786,7 +786,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = await ReceiveFrameAsync();
|
||||
|
||||
Assert.Equal(type, frame.Type);
|
||||
Assert.Equal(withLength, frame.Length);
|
||||
Assert.Equal(withLength, frame.PayloadLength);
|
||||
Assert.Equal(withFlags, frame.Flags);
|
||||
Assert.Equal(withStreamId, frame.StreamId);
|
||||
|
||||
|
|
@ -808,7 +808,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
protected void VerifyGoAway(Http2Frame frame, int expectedLastStreamId, Http2ErrorCode expectedErrorCode)
|
||||
{
|
||||
Assert.Equal(Http2FrameType.GOAWAY, frame.Type);
|
||||
Assert.Equal(8, frame.Length);
|
||||
Assert.Equal(8, frame.PayloadLength);
|
||||
Assert.Equal(0, frame.Flags);
|
||||
Assert.Equal(0, frame.StreamId);
|
||||
Assert.Equal(expectedLastStreamId, frame.GoAwayLastStreamId);
|
||||
|
|
@ -845,7 +845,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var frame = await ReceiveFrameAsync();
|
||||
|
||||
Assert.Equal(Http2FrameType.RST_STREAM, frame.Type);
|
||||
Assert.Equal(4, frame.Length);
|
||||
Assert.Equal(4, frame.PayloadLength);
|
||||
Assert.Equal(0, frame.Flags);
|
||||
Assert.Equal(expectedStreamId, frame.StreamId);
|
||||
Assert.Equal(expectedErrorCode, frame.RstStreamErrorCode);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.Http2
|
|||
}
|
||||
|
||||
Assert.Equal(Http2FrameType.GOAWAY, frame.Type);
|
||||
Assert.Equal(8, frame.Length);
|
||||
Assert.Equal(8, frame.PayloadLength);
|
||||
Assert.Equal(0, frame.Flags);
|
||||
Assert.Equal(0, frame.StreamId);
|
||||
Assert.Equal(expectedLastStreamId, frame.GoAwayLastStreamId);
|
||||
|
|
|
|||
Loading…
Reference in New Issue