diff --git a/benchmarks/Kestrel.Performance/BinaryPrimitivesBenchmark.cs b/benchmarks/Kestrel.Performance/BinaryPrimitivesBenchmark.cs
new file mode 100644
index 0000000000..1761178991
--- /dev/null
+++ b/benchmarks/Kestrel.Performance/BinaryPrimitivesBenchmark.cs
@@ -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;
+ }
+ }
+}
diff --git a/benchmarks/Kestrel.Performance/README.md b/benchmarks/Kestrel.Performance/README.md
index 91991f82ff..50418ef343 100644
--- a/benchmarks/Kestrel.Performance/README.md
+++ b/benchmarks/Kestrel.Performance/README.md
@@ -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
diff --git a/src/Kestrel.Core/CoreStrings.resx b/src/Kestrel.Core/CoreStrings.resx
index f119165500..6d72c97ca4 100644
--- a/src/Kestrel.Core/CoreStrings.resx
+++ b/src/Kestrel.Core/CoreStrings.resx
@@ -564,7 +564,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
More data received than specified in the Content-Length header.
- 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.
A new stream was refused because this connection has reached its stream limit.
@@ -572,4 +572,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
A value greater than zero is required.
+
+ The frame is too short to contain the fields indicated by the given flags.
+
\ No newline at end of file
diff --git a/src/Kestrel.Core/Internal/Http2/Bitshifter.cs b/src/Kestrel.Core/Internal/Http2/Bitshifter.cs
new file mode 100644
index 0000000000..7c3915203f
--- /dev/null
+++ b/src/Kestrel.Core/Internal/Http2/Bitshifter.cs
@@ -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 source)
+ {
+ return (uint)((source[0] << 16) | (source[1] << 8) | source[2]);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void WriteUInt24BigEndian(Span 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 source)
+ {
+ return BinaryPrimitives.ReadUInt32BigEndian(source) & 0x7F_FF_FF_FF;
+ }
+
+ // Does not overwrite the highest order bit
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void WriteUInt31BigEndian(Span 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);
+ }
+ }
+}
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs
index b447fffdf3..3bd7aa7c29 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs
@@ -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);
}
}
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.Continuation.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.Continuation.cs
index d599864b7b..26f3afe92b 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.Continuation.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.Continuation.cs
@@ -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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.Data.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.Data.cs
index 2310db23ad..b2df5c4bfd 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.Data.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.Data.cs
@@ -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 DataPayload => DataHasPadding
- ? new ArraySegment(_data, PayloadOffset + 1, Length - DataPadLength - 1)
- : new ArraySegment(_data, PayloadOffset, Length);
+ public int DataPayloadOffset => DataHasPadding ? 1 : 0;
+
+ private int DataPayloadLength => PayloadLength - DataPayloadOffset - DataPadLength;
+
+ public Span 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);
}
}
}
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.GoAway.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.GoAway.cs
index e3bec2afa2..602c5f1fac 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.GoAway.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.GoAway.cs
@@ -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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.Headers.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.Headers.cs
index 52c20bde94..e89a2e1675 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.Headers.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.Headers.cs
@@ -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 HeadersPayload => new Span(_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 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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.Ping.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.Ping.cs
index cbbdc88d41..239c006c1b 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.Ping.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.Ping.cs
@@ -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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.Priority.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.Priority.cs
index 02f9bf02f9..53f1d9e368 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.Priority.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.Priority.cs
@@ -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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.RstStream.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.RstStream.cs
index 612d778d14..c9c2716f3b 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.RstStream.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.RstStream.cs
@@ -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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.Settings.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.Settings.cs
index c3da784e01..3039ec1b76 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.Settings.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.Settings.cs
@@ -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 GetSettings()
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.WindowUpdate.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.WindowUpdate.cs
index deb06ac02a..098064b3e3 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.WindowUpdate.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.WindowUpdate.cs
@@ -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;
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Frame.cs b/src/Kestrel.Core/Internal/Http2/Http2Frame.cs
index 00e2968de1..f5f447ae7f 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Frame.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Frame.cs
@@ -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 Raw => new Span(_data, 0, HeaderLength + Length);
+ public Span Raw => new Span(_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 Payload => new Span(_data, PayloadOffset, Length);
+ public Span Payload => new Span(_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}";
+ }
+ }
}
}
diff --git a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs
index 4ca9c09aed..15f3d430a6 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs
@@ -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;
}
diff --git a/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs b/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs
index 0a9b62e30e..1d101d1591 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs
@@ -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);
diff --git a/src/Kestrel.Core/Internal/Http2/Http2Stream.cs b/src/Kestrel.Core/Internal/Http2/Http2Stream.cs
index 940fda25a6..9ae576a1b8 100644
--- a/src/Kestrel.Core/Internal/Http2/Http2Stream.cs
+++ b/src/Kestrel.Core/Internal/Http2/Http2Stream.cs
@@ -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);
diff --git a/src/Kestrel.Core/Internal/Infrastructure/KestrelTrace.cs b/src/Kestrel.Core/Internal/Infrastructure/KestrelTrace.cs
index 752759a969..3c269b0ac9 100644
--- a/src/Kestrel.Core/Internal/Infrastructure/KestrelTrace.cs
+++ b/src/Kestrel.Core/Internal/Infrastructure/KestrelTrace.cs
@@ -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(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
diff --git a/src/Kestrel.Core/Properties/CoreStrings.Designer.cs b/src/Kestrel.Core/Properties/CoreStrings.Designer.cs
index 2d24e413e8..77e6f5c678 100644
--- a/src/Kestrel.Core/Properties/CoreStrings.Designer.cs
+++ b/src/Kestrel.Core/Properties/CoreStrings.Designer.cs
@@ -2087,7 +2087,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
=> GetString("Http2StreamErrorMoreDataThanLength");
///
- /// 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.
///
internal static string Http2StreamErrorAfterHeaders
{
@@ -2095,7 +2095,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
}
///
- /// 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.
///
internal static string FormatHttp2StreamErrorAfterHeaders()
=> GetString("Http2StreamErrorAfterHeaders");
@@ -2128,6 +2128,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
internal static string FormatGreaterThanZeroRequired()
=> GetString("GreaterThanZeroRequired");
+ ///
+ /// The frame is too short to contain the fields indicated by the given flags.
+ ///
+ internal static string Http2FrameMissingFields
+ {
+ get => GetString("Http2FrameMissingFields");
+ }
+
+ ///
+ /// The frame is too short to contain the fields indicated by the given flags.
+ ///
+ internal static string FormatHttp2FrameMissingFields()
+ => GetString("Http2FrameMissingFields");
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/test/Kestrel.InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/test/Kestrel.InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
index b1b77db419..c4b6c3ab44 100644
--- a/test/Kestrel.InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
+++ b/test/Kestrel.InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
@@ -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(_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(
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(
+ 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(_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(_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(_helloWorldBytes, 0, initialWindowSize), dataFrame1.DataPayload);
- Assert.Equal(new ArraySegment(_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(_helloWorldBytes, 0, 6), dataFrame1.DataPayload);
- Assert.Equal(new ArraySegment(_helloWorldBytes, 6, 3), dataFrame2.DataPayload);
- Assert.Equal(new ArraySegment(_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]
diff --git a/test/Kestrel.InMemory.FunctionalTests/Http2/Http2StreamTests.cs b/test/Kestrel.InMemory.FunctionalTests/Http2/Http2StreamTests.cs
index f2dfb600b8..6a727466d1 100644
--- a/test/Kestrel.InMemory.FunctionalTests/Http2/Http2StreamTests.cs
+++ b/test/Kestrel.InMemory.FunctionalTests/Http2/Http2StreamTests.cs
@@ -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
diff --git a/test/Kestrel.InMemory.FunctionalTests/Http2/Http2TestBase.cs b/test/Kestrel.InMemory.FunctionalTests/Http2/Http2TestBase.cs
index ec588826c2..4fa61a11df 100644
--- a/test/Kestrel.InMemory.FunctionalTests/Http2/Http2TestBase.cs
+++ b/test/Kestrel.InMemory.FunctionalTests/Http2/Http2TestBase.cs
@@ -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);
diff --git a/test/Kestrel.InMemory.FunctionalTests/Http2/TlsTests.cs b/test/Kestrel.InMemory.FunctionalTests/Http2/TlsTests.cs
index 98d041a09c..fda221726e 100644
--- a/test/Kestrel.InMemory.FunctionalTests/Http2/TlsTests.cs
+++ b/test/Kestrel.InMemory.FunctionalTests/Http2/TlsTests.cs
@@ -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);