Implement MaxFrameSize and HeaderTableSize for HTTP/2

This commit is contained in:
John Luo 2018-08-20 21:13:37 -07:00
parent d318d7b94d
commit 64127e6c76
14 changed files with 280 additions and 72 deletions

View File

@ -575,4 +575,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
<data name="Http2FrameMissingFields" xml:space="preserve"> <data name="Http2FrameMissingFields" xml:space="preserve">
<value>The frame is too short to contain the fields indicated by the given flags.</value> <value>The frame is too short to contain the fields indicated by the given flags.</value>
</data> </data>
<data name="ArgumentOutOfRange" xml:space="preserve">
<value>A value between {min} and {max} is required.</value>
</data>
</root> </root>

View File

@ -11,6 +11,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
public class Http2Limits public class Http2Limits
{ {
private int _maxStreamsPerConnection = 100; private int _maxStreamsPerConnection = 100;
private int _headerTableSize = MaxAllowedHeaderTableSize;
private int _maxFrameSize = MinAllowedMaxFrameSize;
// These are limits defined by the RFC https://tools.ietf.org/html/rfc7540#section-4.2
public const int MaxAllowedHeaderTableSize = 4096;
public const int MinAllowedMaxFrameSize = 16 * 1024;
public const int MaxAllowedMaxFrameSize = 16 * 1024 * 1024 - 1;
/// <summary> /// <summary>
/// Limits the number of concurrent request streams per HTTP/2 connection. Excess streams will be refused. /// Limits the number of concurrent request streams per HTTP/2 connection. Excess streams will be refused.
@ -27,8 +34,49 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
{ {
throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.GreaterThanZeroRequired); throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.GreaterThanZeroRequired);
} }
_maxStreamsPerConnection = value; _maxStreamsPerConnection = value;
} }
} }
/// <summary>
/// Limits the size of the header compression table, in octets, the HPACK decoder on the server can use.
/// <para>
/// Defaults to 4096
/// </para>
/// </summary>
public int HeaderTableSize
{
get => _headerTableSize;
set
{
if (value <= 0 || value > MaxAllowedHeaderTableSize)
{
throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.FormatArgumentOutOfRange(0, MaxAllowedHeaderTableSize));
}
_headerTableSize = value;
}
}
/// <summary>
/// Indicates the size of the largest frame payload that is allowed to be received, in octets. The size must be between 2^14 and 2^24-1.
/// <para>
/// Defaults to 2^14 (16,384)
/// </para>
/// </summary>
public int MaxFrameSize
{
get => _maxFrameSize;
set
{
if (value < MinAllowedMaxFrameSize || value > MaxAllowedMaxFrameSize)
{
throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.FormatArgumentOutOfRange(MinAllowedMaxFrameSize, MaxAllowedMaxFrameSize));
}
_maxFrameSize = value;
}
}
} }
} }

View File

@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
private readonly Http2PeerSettings _serverSettings = new Http2PeerSettings(); private readonly Http2PeerSettings _serverSettings = new Http2PeerSettings();
private readonly Http2PeerSettings _clientSettings = new Http2PeerSettings(); private readonly Http2PeerSettings _clientSettings = new Http2PeerSettings();
private readonly Http2Frame _incomingFrame = new Http2Frame(); private readonly Http2Frame _incomingFrame;
private Http2Stream _currentHeadersStream; private Http2Stream _currentHeadersStream;
private RequestHeaderParsingState _requestHeaderParsingState; private RequestHeaderParsingState _requestHeaderParsingState;
@ -87,8 +87,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
_context = context; _context = context;
_frameWriter = new Http2FrameWriter(context.Transport.Output, context.ConnectionContext, _outputFlowControl, this, context.ConnectionId, context.ServiceContext.Log); _frameWriter = new Http2FrameWriter(context.Transport.Output, context.ConnectionContext, _outputFlowControl, this, context.ConnectionId, context.ServiceContext.Log);
_hpackDecoder = new HPackDecoder((int)_serverSettings.HeaderTableSize);
_serverSettings.MaxConcurrentStreams = (uint)context.ServiceContext.ServerOptions.Limits.Http2.MaxStreamsPerConnection; _serverSettings.MaxConcurrentStreams = (uint)context.ServiceContext.ServerOptions.Limits.Http2.MaxStreamsPerConnection;
_serverSettings.MaxFrameSize = (uint)context.ServiceContext.ServerOptions.Limits.Http2.MaxFrameSize;
_serverSettings.HeaderTableSize = (uint)context.ServiceContext.ServerOptions.Limits.Http2.HeaderTableSize;
_hpackDecoder = new HPackDecoder((int)_serverSettings.HeaderTableSize);
_incomingFrame = new Http2Frame(_serverSettings.MaxFrameSize);
} }
public string ConnectionId => _context.ConnectionId; public string ConnectionId => _context.ConnectionId;
@ -601,7 +604,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
return Task.CompletedTask; return Task.CompletedTask;
} }
private Task ProcessSettingsFrameAsync() private async Task ProcessSettingsFrameAsync()
{ {
if (_currentHeadersStream != null) if (_currentHeadersStream != null)
{ {
@ -620,7 +623,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorSettingsAckLengthNotZero, Http2ErrorCode.FRAME_SIZE_ERROR); throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorSettingsAckLengthNotZero, Http2ErrorCode.FRAME_SIZE_ERROR);
} }
return Task.CompletedTask; return;
} }
if (_incomingFrame.PayloadLength % 6 != 0) if (_incomingFrame.PayloadLength % 6 != 0)
@ -632,10 +635,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
// int.MaxValue is the largest allowed windows size. // int.MaxValue is the largest allowed windows size.
var previousInitialWindowSize = (int)_clientSettings.InitialWindowSize; var previousInitialWindowSize = (int)_clientSettings.InitialWindowSize;
var previousMaxFrameSize = _clientSettings.MaxFrameSize;
_clientSettings.Update(_incomingFrame.GetSettings()); _clientSettings.Update(_incomingFrame.GetSettings());
var ackTask = _frameWriter.WriteSettingsAckAsync(); // Ack before we update the windows, they could send data immediately. // Ack before we update the windows, they could send data immediately.
await _frameWriter.WriteSettingsAckAsync();
if (_clientSettings.MaxFrameSize != previousMaxFrameSize)
{
_frameWriter.UpdateMaxFrameSize(_clientSettings.MaxFrameSize);
}
// This difference can be negative. // This difference can be negative.
var windowSizeDifference = (int)_clientSettings.InitialWindowSize - previousInitialWindowSize; var windowSizeDifference = (int)_clientSettings.InitialWindowSize - previousInitialWindowSize;
@ -653,8 +663,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
} }
} }
return ackTask;
} }
catch (Http2SettingsParameterOutOfRangeException ex) catch (Http2SettingsParameterOutOfRangeException ex)
{ {

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public void PrepareContinuation(Http2ContinuationFrameFlags flags, int streamId) public void PrepareContinuation(Http2ContinuationFrameFlags flags, int streamId)
{ {
PayloadLength = MinAllowedMaxFrameSize - HeaderLength; PayloadLength = (int)_maxFrameSize;
Type = Http2FrameType.CONTINUATION; Type = Http2FrameType.CONTINUATION;
ContinuationFlags = flags; ContinuationFlags = flags;
StreamId = streamId; StreamId = streamId;

View File

@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
var padded = padLength != null; var padded = padLength != null;
PayloadLength = MinAllowedMaxFrameSize; PayloadLength = (int)_maxFrameSize;
Type = Http2FrameType.DATA; Type = Http2FrameType.DATA;
DataFlags = padded ? Http2DataFrameFlags.PADDED : Http2DataFrameFlags.NONE; DataFlags = padded ? Http2DataFrameFlags.PADDED : Http2DataFrameFlags.NONE;
StreamId = streamId; StreamId = streamId;

View File

@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public void PrepareHeaders(Http2HeadersFrameFlags flags, int streamId) public void PrepareHeaders(Http2HeadersFrameFlags flags, int streamId)
{ {
PayloadLength = MinAllowedMaxFrameSize - HeaderLength; PayloadLength = (int)_maxFrameSize;
Type = Http2FrameType.HEADERS; Type = Http2FrameType.HEADERS;
HeadersFlags = flags; HeadersFlags = flags;
StreamId = streamId; StreamId = streamId;

View File

@ -18,8 +18,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
*/ */
public partial class Http2Frame public partial class Http2Frame
{ {
public const int MinAllowedMaxFrameSize = 16 * 1024;
public const int MaxAllowedMaxFrameSize = 16 * 1024 * 1024 - 1;
public const int HeaderLength = 9; public const int HeaderLength = 9;
private const int LengthOffset = 0; private const int LengthOffset = 0;
@ -28,7 +26,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
private const int StreamIdOffset = 5; private const int StreamIdOffset = 5;
private const int PayloadOffset = 9; private const int PayloadOffset = 9;
private readonly byte[] _data = new byte[HeaderLength + MinAllowedMaxFrameSize]; private uint _maxFrameSize;
private readonly byte[] _data;
public Http2Frame(uint maxFrameSize)
{
_maxFrameSize = maxFrameSize;
_data = new byte[HeaderLength + _maxFrameSize];
}
public Span<byte> Raw => new Span<byte>(_data, 0, HeaderLength + PayloadLength); public Span<byte> Raw => new Span<byte>(_data, 0, HeaderLength + PayloadLength);

View File

@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.FlowControl; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.FlowControl;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
@ -22,7 +21,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
// Literal Header Field without Indexing - Indexed Name (Index 8 - :status) // Literal Header Field without Indexing - Indexed Name (Index 8 - :status)
private static readonly byte[] _continueBytes = new byte[] { 0x08, 0x03, (byte)'1', (byte)'0', (byte)'0' }; private static readonly byte[] _continueBytes = new byte[] { 0x08, 0x03, (byte)'1', (byte)'0', (byte)'0' };
private readonly Http2Frame _outgoingFrame = new Http2Frame(); private uint _maxFrameSize = Http2Limits.MinAllowedMaxFrameSize;
private Http2Frame _outgoingFrame;
private readonly object _writeLock = new object(); private readonly object _writeLock = new object();
private readonly HPackEncoder _hpackEncoder = new HPackEncoder(); private readonly HPackEncoder _hpackEncoder = new HPackEncoder();
private readonly PipeWriter _outputWriter; private readonly PipeWriter _outputWriter;
@ -49,6 +49,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
_connectionId = connectionId; _connectionId = connectionId;
_log = log; _log = log;
_flusher = new StreamSafePipeFlusher(_outputWriter, timeoutControl); _flusher = new StreamSafePipeFlusher(_outputWriter, timeoutControl);
_outgoingFrame = new Http2Frame(_maxFrameSize);
}
public void UpdateMaxFrameSize(uint maxFrameSize)
{
lock (_writeLock)
{
_maxFrameSize = maxFrameSize;
_outgoingFrame = new Http2Frame(maxFrameSize);
}
} }
public void Complete() public void Complete()

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public const bool DefaultEnablePush = true; public const bool DefaultEnablePush = true;
public const uint DefaultMaxConcurrentStreams = uint.MaxValue; public const uint DefaultMaxConcurrentStreams = uint.MaxValue;
public const uint DefaultInitialWindowSize = 65535; public const uint DefaultInitialWindowSize = 65535;
public const uint DefaultMaxFrameSize = 16384; public const uint DefaultMaxFrameSize = Http2Limits.MinAllowedMaxFrameSize;
public const uint DefaultMaxHeaderListSize = uint.MaxValue; public const uint DefaultMaxHeaderListSize = uint.MaxValue;
public const uint MaxWindowSize = int.MaxValue; public const uint MaxWindowSize = int.MaxValue;
@ -38,6 +38,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
switch (setting.Parameter) switch (setting.Parameter)
{ {
case Http2SettingsParameter.SETTINGS_HEADER_TABLE_SIZE: case Http2SettingsParameter.SETTINGS_HEADER_TABLE_SIZE:
if (value > Http2Limits.MaxAllowedHeaderTableSize)
{
throw new Http2SettingsParameterOutOfRangeException(Http2SettingsParameter.SETTINGS_HEADER_TABLE_SIZE,
lowerBound: 0,
upperBound: Http2Limits.MaxAllowedHeaderTableSize);
}
HeaderTableSize = value; HeaderTableSize = value;
break; break;
case Http2SettingsParameter.SETTINGS_ENABLE_PUSH: case Http2SettingsParameter.SETTINGS_ENABLE_PUSH:
@ -64,11 +70,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
InitialWindowSize = value; InitialWindowSize = value;
break; break;
case Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE: case Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE:
if (value < Http2Frame.MinAllowedMaxFrameSize || value > Http2Frame.MaxAllowedMaxFrameSize) if (value < Http2Limits.MinAllowedMaxFrameSize || value > Http2Limits.MaxAllowedMaxFrameSize)
{ {
throw new Http2SettingsParameterOutOfRangeException(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, throw new Http2SettingsParameterOutOfRangeException(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE,
lowerBound: Http2Frame.MinAllowedMaxFrameSize, lowerBound: Http2Limits.MinAllowedMaxFrameSize,
upperBound: Http2Frame.MaxAllowedMaxFrameSize); upperBound: Http2Limits.MaxAllowedMaxFrameSize);
} }
MaxFrameSize = value; MaxFrameSize = value;

View File

@ -2142,6 +2142,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
internal static string FormatHttp2FrameMissingFields() internal static string FormatHttp2FrameMissingFields()
=> GetString("Http2FrameMissingFields"); => GetString("Http2FrameMissingFields");
/// <summary>
/// A value between {min} and {max} is required.
/// </summary>
internal static string ArgumentOutOfRange
{
get => GetString("ArgumentOutOfRange");
}
/// <summary>
/// A value between {min} and {max} is required.
/// </summary>
internal static string FormatArgumentOutOfRange(object min, object max)
=> string.Format(CultureInfo.CurrentCulture, GetString("ArgumentOutOfRange", "min", "max"), min, max);
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -308,6 +308,37 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(TimeSpan.FromSeconds(5), new KestrelServerLimits().MinResponseDataRate.GracePeriod); Assert.Equal(TimeSpan.FromSeconds(5), new KestrelServerLimits().MinResponseDataRate.GracePeriod);
} }
[Fact]
public void Http2MaxFrameSizeDefault()
{
Assert.Equal(1 << 14, new KestrelServerLimits().Http2.MaxFrameSize);
}
[Theory]
[InlineData(1 << 14 - 1)]
[InlineData(1 << 24)]
[InlineData(-1)]
public void Http2MaxFrameSizeInvalid(int value)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new KestrelServerLimits().Http2.MaxFrameSize = value);
Assert.Contains("A value between", ex.Message);
}
[Fact]
public void Http2HeaderTableSizeDefault()
{
Assert.Equal(4096, new KestrelServerLimits().Http2.HeaderTableSize);
}
[Theory]
[InlineData(4097)]
[InlineData(-1)]
public void Http2HeaderTableSizeInvalid(int value)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new KestrelServerLimits().Http2.MaxFrameSize = value);
Assert.Contains("A value between", ex.Message);
}
public static TheoryData<TimeSpan> TimeoutValidData => new TheoryData<TimeSpan> public static TheoryData<TimeSpan> TimeoutValidData => new TheoryData<TimeSpan>
{ {
TimeSpan.FromTicks(1), TimeSpan.FromTicks(1),

View File

@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private static readonly byte[] _worldBytes = Encoding.ASCII.GetBytes("world"); private static readonly byte[] _worldBytes = Encoding.ASCII.GetBytes("world");
private static readonly byte[] _helloWorldBytes = Encoding.ASCII.GetBytes("hello, world"); private static readonly byte[] _helloWorldBytes = Encoding.ASCII.GetBytes("hello, world");
private static readonly byte[] _noData = new byte[0]; private static readonly byte[] _noData = new byte[0];
private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize)); private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Limits.MinAllowedMaxFrameSize));
[Fact] [Fact]
public async Task Frame_Received_OverMaxSize_FrameError() public async Task Frame_Received_OverMaxSize_FrameError()
@ -85,20 +85,47 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
await InitializeConnectionAsync(_echoApplication); await InitializeConnectionAsync(_echoApplication);
await StartStreamAsync(1, _browserRequestHeaders, endStream: false); await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
// Manually craft a frame where the size is too large. Our own frame class won't allow this. uint length = Http2Limits.MinAllowedMaxFrameSize + 1;
// See Http2Frame.Length await SendDataAsync(1, new byte[length].AsSpan(), endStream: true);
var length = Http2Frame.MinAllowedMaxFrameSize + 1; // Too big
var frame = new byte[9 + length];
frame[0] = (byte)((length & 0x00ff0000) >> 16);
frame[1] = (byte)((length & 0x0000ff00) >> 8);
frame[2] = (byte)(length & 0x000000ff);
await SendAsync(frame);
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>( await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
ignoreNonGoAwayFrames: true, ignoreNonGoAwayFrames: true,
expectedLastStreamId: 1, expectedLastStreamId: 1,
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
expectedErrorMessage: CoreStrings.FormatHttp2ErrorFrameOverLimit(length, Http2Frame.MinAllowedMaxFrameSize)); expectedErrorMessage: CoreStrings.FormatHttp2ErrorFrameOverLimit(length, Http2Limits.MinAllowedMaxFrameSize));
}
[Fact]
public async Task ServerSettings_ChangesRequestMaxFrameSize()
{
var length = Http2Limits.MinAllowedMaxFrameSize + 10;
_connectionContext.ServiceContext.ServerOptions.Limits.Http2.MaxFrameSize = length;
_connection = new Http2Connection(_connectionContext);
await InitializeConnectionAsync(_echoApplication, expectedSettingsLegnth: 12);
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
await SendDataAsync(1, new byte[length].AsSpan(), endStream: true);
await ExpectAsync(Http2FrameType.HEADERS,
withLength: 37,
withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS,
withStreamId: 1);
// The client's settings is still defaulted to Http2PeerSettings.MinAllowedMaxFrameSize so the echo response will come back in two separate frames
await ExpectAsync(Http2FrameType.DATA,
withLength: Http2Limits.MinAllowedMaxFrameSize,
withFlags: (byte)Http2DataFrameFlags.NONE,
withStreamId: 1);
await ExpectAsync(Http2FrameType.DATA,
withLength: length - Http2Limits.MinAllowedMaxFrameSize,
withFlags: (byte)Http2DataFrameFlags.NONE,
withStreamId: 1);
await ExpectAsync(Http2FrameType.DATA,
withLength: 0,
withFlags: (byte)Http2DataFrameFlags.END_STREAM,
withStreamId: 1);
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
} }
[Fact] [Fact]
@ -2042,7 +2069,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
await InitializeConnectionAsync(_noopApplication); await InitializeConnectionAsync(_noopApplication);
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareSettings(Http2SettingsFrameFlags.ACK); frame.PrepareSettings(Http2SettingsFrameFlags.ACK);
await SendAsync(frame.Raw); await SendAsync(frame.Raw);
@ -2073,6 +2100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[InlineData(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, 16 * 1024 - 1, Http2ErrorCode.PROTOCOL_ERROR)] [InlineData(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, 16 * 1024 - 1, Http2ErrorCode.PROTOCOL_ERROR)]
[InlineData(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, 16 * 1024 * 1024, Http2ErrorCode.PROTOCOL_ERROR)] [InlineData(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, 16 * 1024 * 1024, Http2ErrorCode.PROTOCOL_ERROR)]
[InlineData(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, uint.MaxValue, Http2ErrorCode.PROTOCOL_ERROR)] [InlineData(Http2SettingsParameter.SETTINGS_MAX_FRAME_SIZE, uint.MaxValue, Http2ErrorCode.PROTOCOL_ERROR)]
[InlineData(Http2SettingsParameter.SETTINGS_HEADER_TABLE_SIZE, 4097, Http2ErrorCode.PROTOCOL_ERROR)]
public async Task SETTINGS_Received_InvalidParameterValue_ConnectionError(Http2SettingsParameter parameter, uint value, Http2ErrorCode expectedErrorCode) public async Task SETTINGS_Received_InvalidParameterValue_ConnectionError(Http2SettingsParameter parameter, uint value, Http2ErrorCode expectedErrorCode)
{ {
await InitializeConnectionAsync(_noopApplication); await InitializeConnectionAsync(_noopApplication);
@ -2160,6 +2188,60 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
expectedErrorMessage: CoreStrings.Http2ErrorInitialWindowSizeInvalid); expectedErrorMessage: CoreStrings.Http2ErrorInitialWindowSizeInvalid);
} }
[Fact]
public async Task SETTINGS_Received_ChangesAllowedResponseMaxFrameSize()
{
// This includes the default response headers such as :status, etc
var defaultResponseHeaderLength = 37;
var headerValueLength = Http2Limits.MinAllowedMaxFrameSize;
// First byte is always 0
// Second byte is the length of header name which is 1
// Third byte is the header name which is A/B
// Next three bytes are the 7-bit integer encoding representation of the header length which is 16*1024
var encodedHeaderLength = 1 + 1 + 1 + 3 + headerValueLength;
// Adding 10 additional bytes for encoding overhead
var payloadLength = defaultResponseHeaderLength + encodedHeaderLength;
await InitializeConnectionAsync(context =>
{
context.Response.Headers["A"] = new string('a', headerValueLength);
context.Response.Headers["B"] = new string('b', headerValueLength);
return context.Response.Body.WriteAsync(new byte[payloadLength], 0, payloadLength);
});
// Update client settings
_clientSettings.MaxFrameSize = (uint)payloadLength;
await SendSettingsAsync();
// ACK
await ExpectAsync(Http2FrameType.SETTINGS,
withLength: 0,
withFlags: (byte)Http2SettingsFrameFlags.ACK,
withStreamId: 0);
// Start request
await StartStreamAsync(1, _browserRequestHeaders, endStream: true);
await ExpectAsync(Http2FrameType.HEADERS,
withLength: defaultResponseHeaderLength + encodedHeaderLength,
withFlags: (byte)Http2HeadersFrameFlags.NONE,
withStreamId: 1);
await ExpectAsync(Http2FrameType.CONTINUATION,
withLength: encodedHeaderLength,
withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS,
withStreamId: 1);
await ExpectAsync(Http2FrameType.DATA,
withLength: payloadLength,
withFlags: (byte)Http2DataFrameFlags.NONE,
withStreamId: 1);
await ExpectAsync(Http2FrameType.DATA,
withLength: 0,
withFlags: (byte)Http2DataFrameFlags.END_STREAM,
withStreamId: 1);
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
}
[Fact] [Fact]
public async Task PUSH_PROMISE_Received_ConnectionError() public async Task PUSH_PROMISE_Received_ConnectionError()
{ {

View File

@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_echoApplication = async context => _echoApplication = async context =>
{ {
var buffer = new byte[Http2Frame.MinAllowedMaxFrameSize]; var buffer = new byte[Http2Limits.MinAllowedMaxFrameSize];
var received = 0; var received = 0;
while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0)
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_echoWaitForAbortApplication = async context => _echoWaitForAbortApplication = async context =>
{ {
var buffer = new byte[Http2Frame.MinAllowedMaxFrameSize]; var buffer = new byte[Http2Limits.MinAllowedMaxFrameSize];
var received = 0; var received = 0;
while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0) while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0)
@ -307,7 +307,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_decodedHeaders[name.GetAsciiStringNonNullCharacters()] = value.GetAsciiStringNonNullCharacters(); _decodedHeaders[name.GetAsciiStringNonNullCharacters()] = value.GetAsciiStringNonNullCharacters();
} }
protected async Task InitializeConnectionAsync(RequestDelegate application) protected async Task InitializeConnectionAsync(RequestDelegate application, int expectedSettingsLegnth = 6)
{ {
_connectionTask = _connection.ProcessRequestsAsync(new DummyApplication(application)); _connectionTask = _connection.ProcessRequestsAsync(new DummyApplication(application));
@ -315,7 +315,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
await SendSettingsAsync(); await SendSettingsAsync();
await ExpectAsync(Http2FrameType.SETTINGS, await ExpectAsync(Http2FrameType.SETTINGS,
withLength: 6, withLength: expectedSettingsLegnth,
withFlags: 0, withFlags: 0,
withStreamId: 0); withStreamId: 0);
@ -330,7 +330,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously); var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
_runningStreams[streamId] = tcs; _runningStreams[streamId] = tcs;
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId);
var done = _hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length); var done = _hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length);
frame.PayloadLength = length; frame.PayloadLength = length;
@ -367,7 +367,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously); var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
_runningStreams[streamId] = tcs; _runningStreams[streamId] = tcs;
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED, streamId); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED, streamId);
frame.HeadersPadLength = padLength; frame.HeadersPadLength = padLength;
@ -390,7 +390,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously); var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
_runningStreams[streamId] = tcs; _runningStreams[streamId] = tcs;
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PRIORITY, streamId); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PRIORITY, streamId);
frame.HeadersPriorityWeight = priority; frame.HeadersPriorityWeight = priority;
frame.HeadersStreamDependency = streamDependency; frame.HeadersStreamDependency = streamDependency;
@ -412,7 +412,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously); var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
_runningStreams[streamId] = tcs; _runningStreams[streamId] = tcs;
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED | Http2HeadersFrameFlags.PRIORITY, streamId); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED | Http2HeadersFrameFlags.PRIORITY, streamId);
frame.HeadersPadLength = padLength; frame.HeadersPadLength = padLength;
frame.HeadersPriorityWeight = priority; frame.HeadersPriorityWeight = priority;
@ -452,14 +452,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendSettingsAsync() protected Task SendSettingsAsync()
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults()); frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults());
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
} }
protected Task SendSettingsAckWithInvalidLengthAsync(int length) protected Task SendSettingsAckWithInvalidLengthAsync(int length)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareSettings(Http2SettingsFrameFlags.ACK); frame.PrepareSettings(Http2SettingsFrameFlags.ACK);
frame.PayloadLength = length; frame.PayloadLength = length;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
@ -467,7 +467,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendSettingsWithInvalidStreamIdAsync(int streamId) protected Task SendSettingsWithInvalidStreamIdAsync(int streamId)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults()); frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults());
frame.StreamId = streamId; frame.StreamId = streamId;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
@ -475,7 +475,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendSettingsWithInvalidLengthAsync(int length) protected Task SendSettingsWithInvalidLengthAsync(int length)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults()); frame.PrepareSettings(Http2SettingsFrameFlags.NONE, _clientSettings.GetNonProtocolDefaults());
frame.PayloadLength = length; frame.PayloadLength = length;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
@ -483,7 +483,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendSettingsWithInvalidParameterValueAsync(Http2SettingsParameter parameter, uint value) protected Task SendSettingsWithInvalidParameterValueAsync(Http2SettingsParameter parameter, uint value)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareSettings(Http2SettingsFrameFlags.NONE); frame.PrepareSettings(Http2SettingsFrameFlags.NONE);
frame.PayloadLength = 6; frame.PayloadLength = 6;
@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendPushPromiseFrameAsync() protected Task SendPushPromiseFrameAsync()
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PayloadLength = 0; frame.PayloadLength = 0;
frame.Type = Http2FrameType.PUSH_PROMISE; frame.Type = Http2FrameType.PUSH_PROMISE;
frame.StreamId = 1; frame.StreamId = 1;
@ -508,7 +508,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected async Task<bool> SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, IEnumerable<KeyValuePair<string, string>> headers) protected async Task<bool> SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, IEnumerable<KeyValuePair<string, string>> headers)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(flags, streamId); frame.PrepareHeaders(flags, streamId);
var done = _hpackEncoder.BeginEncode(headers, frame.Payload, out var length); var done = _hpackEncoder.BeginEncode(headers, frame.Payload, out var length);
@ -521,7 +521,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, byte[] headerBlock) protected Task SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, byte[] headerBlock)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(flags, streamId); frame.PrepareHeaders(flags, streamId);
frame.PayloadLength = headerBlock.Length; frame.PayloadLength = headerBlock.Length;
@ -534,7 +534,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
Assert.True(padLength >= payloadLength, $"{nameof(padLength)} must be greater than or equal to {nameof(payloadLength)} 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(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(Http2HeadersFrameFlags.PADDED, streamId); frame.PrepareHeaders(Http2HeadersFrameFlags.PADDED, streamId);
frame.Payload[0] = padLength; frame.Payload[0] = padLength;
@ -547,7 +547,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendIncompleteHeadersFrameAsync(int streamId) protected Task SendIncompleteHeadersFrameAsync(int streamId)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS, streamId); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS, streamId);
frame.PayloadLength = 3; frame.PayloadLength = 3;
@ -563,7 +563,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected async Task<bool> SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags) protected async Task<bool> SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareContinuation(flags, streamId); frame.PrepareContinuation(flags, streamId);
var done = _hpackEncoder.Encode(frame.Payload, out var length); var done = _hpackEncoder.Encode(frame.Payload, out var length);
@ -576,7 +576,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected async Task SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags, byte[] payload) protected async Task SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags, byte[] payload)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareContinuation(flags, streamId); frame.PrepareContinuation(flags, streamId);
frame.PayloadLength = payload.Length; frame.PayloadLength = payload.Length;
@ -587,7 +587,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendEmptyContinuationFrameAsync(int streamId, Http2ContinuationFrameFlags flags) protected Task SendEmptyContinuationFrameAsync(int streamId, Http2ContinuationFrameFlags flags)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareContinuation(flags, streamId); frame.PrepareContinuation(flags, streamId);
frame.PayloadLength = 0; frame.PayloadLength = 0;
@ -597,7 +597,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendIncompleteContinuationFrameAsync(int streamId) protected Task SendIncompleteContinuationFrameAsync(int streamId)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareContinuation(Http2ContinuationFrameFlags.END_HEADERS, streamId); frame.PrepareContinuation(Http2ContinuationFrameFlags.END_HEADERS, streamId);
frame.PayloadLength = 3; frame.PayloadLength = 3;
@ -613,7 +613,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendDataAsync(int streamId, Span<byte> data, bool endStream) protected Task SendDataAsync(int streamId, Span<byte> data, bool endStream)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame((uint)data.Length);
frame.PrepareData(streamId); frame.PrepareData(streamId);
frame.PayloadLength = data.Length; frame.PayloadLength = data.Length;
@ -625,7 +625,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendDataWithPaddingAsync(int streamId, Span<byte> data, byte padLength, bool endStream) protected Task SendDataWithPaddingAsync(int streamId, Span<byte> data, byte padLength, bool endStream)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareData(streamId, padLength); frame.PrepareData(streamId, padLength);
frame.PayloadLength = data.Length + 1 + padLength; frame.PayloadLength = data.Length + 1 + padLength;
@ -643,7 +643,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
Assert.True(padLength >= frameLength, $"{nameof(padLength)} must be greater than or equal to {nameof(frameLength)} to create an invalid frame."); Assert.True(padLength >= frameLength, $"{nameof(padLength)} must be greater than or equal to {nameof(frameLength)} to create an invalid frame.");
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareData(streamId); frame.PrepareData(streamId);
frame.DataFlags = Http2DataFrameFlags.PADDED; frame.DataFlags = Http2DataFrameFlags.PADDED;
@ -657,14 +657,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendPingAsync(Http2PingFrameFlags flags) protected Task SendPingAsync(Http2PingFrameFlags flags)
{ {
var pingFrame = new Http2Frame(); var pingFrame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
pingFrame.PreparePing(flags); pingFrame.PreparePing(flags);
return SendAsync(pingFrame.Raw); return SendAsync(pingFrame.Raw);
} }
protected Task SendPingWithInvalidLengthAsync(int length) protected Task SendPingWithInvalidLengthAsync(int length)
{ {
var pingFrame = new Http2Frame(); var pingFrame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
pingFrame.PreparePing(Http2PingFrameFlags.NONE); pingFrame.PreparePing(Http2PingFrameFlags.NONE);
pingFrame.PayloadLength = length; pingFrame.PayloadLength = length;
return SendAsync(pingFrame.Raw); return SendAsync(pingFrame.Raw);
@ -674,7 +674,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
Assert.NotEqual(0, streamId); Assert.NotEqual(0, streamId);
var pingFrame = new Http2Frame(); var pingFrame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
pingFrame.PreparePing(Http2PingFrameFlags.NONE); pingFrame.PreparePing(Http2PingFrameFlags.NONE);
pingFrame.StreamId = streamId; pingFrame.StreamId = streamId;
return SendAsync(pingFrame.Raw); return SendAsync(pingFrame.Raw);
@ -682,14 +682,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendPriorityAsync(int streamId, int streamDependency = 0) protected Task SendPriorityAsync(int streamId, int streamDependency = 0)
{ {
var priorityFrame = new Http2Frame(); var priorityFrame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
priorityFrame.PreparePriority(streamId, streamDependency: streamDependency, exclusive: false, weight: 0); priorityFrame.PreparePriority(streamId, streamDependency: streamDependency, exclusive: false, weight: 0);
return SendAsync(priorityFrame.Raw); return SendAsync(priorityFrame.Raw);
} }
protected Task SendInvalidPriorityFrameAsync(int streamId, int length) protected Task SendInvalidPriorityFrameAsync(int streamId, int length)
{ {
var priorityFrame = new Http2Frame(); var priorityFrame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
priorityFrame.PreparePriority(streamId, streamDependency: 0, exclusive: false, weight: 0); priorityFrame.PreparePriority(streamId, streamDependency: 0, exclusive: false, weight: 0);
priorityFrame.PayloadLength = length; priorityFrame.PayloadLength = length;
return SendAsync(priorityFrame.Raw); return SendAsync(priorityFrame.Raw);
@ -697,14 +697,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendRstStreamAsync(int streamId) protected Task SendRstStreamAsync(int streamId)
{ {
var rstStreamFrame = new Http2Frame(); var rstStreamFrame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
rstStreamFrame.PrepareRstStream(streamId, Http2ErrorCode.CANCEL); rstStreamFrame.PrepareRstStream(streamId, Http2ErrorCode.CANCEL);
return SendAsync(rstStreamFrame.Raw); return SendAsync(rstStreamFrame.Raw);
} }
protected Task SendInvalidRstStreamFrameAsync(int streamId, int length) protected Task SendInvalidRstStreamFrameAsync(int streamId, int length)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareRstStream(streamId, Http2ErrorCode.CANCEL); frame.PrepareRstStream(streamId, Http2ErrorCode.CANCEL);
frame.PayloadLength = length; frame.PayloadLength = length;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
@ -712,14 +712,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendGoAwayAsync() protected Task SendGoAwayAsync()
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareGoAway(0, Http2ErrorCode.NO_ERROR); frame.PrepareGoAway(0, Http2ErrorCode.NO_ERROR);
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
} }
protected Task SendInvalidGoAwayFrameAsync() protected Task SendInvalidGoAwayFrameAsync()
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareGoAway(0, Http2ErrorCode.NO_ERROR); frame.PrepareGoAway(0, Http2ErrorCode.NO_ERROR);
frame.StreamId = 1; frame.StreamId = 1;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
@ -727,14 +727,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendWindowUpdateAsync(int streamId, int sizeIncrement) protected Task SendWindowUpdateAsync(int streamId, int sizeIncrement)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareWindowUpdate(streamId, sizeIncrement); frame.PrepareWindowUpdate(streamId, sizeIncrement);
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
} }
protected Task SendInvalidWindowUpdateAsync(int streamId, int sizeIncrement, int length) protected Task SendInvalidWindowUpdateAsync(int streamId, int sizeIncrement, int length)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.PrepareWindowUpdate(streamId, sizeIncrement); frame.PrepareWindowUpdate(streamId, sizeIncrement);
frame.PayloadLength = length; frame.PayloadLength = length;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
@ -742,16 +742,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected Task SendUnknownFrameTypeAsync(int streamId, int frameType) protected Task SendUnknownFrameTypeAsync(int streamId, int frameType)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
frame.StreamId = streamId; frame.StreamId = streamId;
frame.Type = (Http2FrameType)frameType; frame.Type = (Http2FrameType)frameType;
frame.PayloadLength = 0; frame.PayloadLength = 0;
return SendAsync(frame.Raw); return SendAsync(frame.Raw);
} }
protected async Task<Http2Frame> ReceiveFrameAsync() protected async Task<Http2Frame> ReceiveFrameAsync(uint maxFrameSize = Http2PeerSettings.DefaultMaxFrameSize)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(maxFrameSize);
while (true) while (true)
{ {
@ -764,7 +764,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
Assert.True(buffer.Length > 0); Assert.True(buffer.Length > 0);
if (Http2FrameReader.ReadFrame(buffer, frame, 16_384, out consumed, out examined)) if (Http2FrameReader.ReadFrame(buffer, frame, maxFrameSize, out consumed, out examined))
{ {
return frame; return frame;
} }
@ -783,7 +783,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
protected async Task<Http2Frame> ExpectAsync(Http2FrameType type, int withLength, byte withFlags, int withStreamId) protected async Task<Http2Frame> ExpectAsync(Http2FrameType type, int withLength, byte withFlags, int withStreamId)
{ {
var frame = await ReceiveFrameAsync(); var frame = await ReceiveFrameAsync((uint)withLength);
Assert.Equal(type, frame.Type); Assert.Equal(type, frame.Type);
Assert.Equal(withLength, frame.PayloadLength); Assert.Equal(withLength, frame.PayloadLength);

View File

@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.Http2
private async Task<Http2Frame> ReceiveFrameAsync(PipeReader reader) private async Task<Http2Frame> ReceiveFrameAsync(PipeReader reader)
{ {
var frame = new Http2Frame(); var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize);
while (true) while (true)
{ {