HTTP/2: add exception error messages and log them.
This commit is contained in:
parent
fdb4184dbf
commit
deed6c9780
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
@ -40,5 +42,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
public void RequestBodyDone(string connectionId, string traceIdentifier) { }
|
||||
public void RequestBodyMininumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate) { }
|
||||
public void ResponseMininumDataRateNotSatisfied(string connectionId, string traceIdentifier) { }
|
||||
public void Http2ConnectionError(string connectionId, Http2ConnectionErrorException ex) { }
|
||||
public void Http2StreamError(string connectionId, Http2StreamErrorException ex) { }
|
||||
public void HPackDecodingError(string connectionId, int streamId, HPackDecodingException ex) { }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
|
@ -384,4 +384,82 @@
|
|||
<data name="HPackErrorIncompleteHeaderBlock" xml:space="preserve">
|
||||
<value>The header block was incomplete and could not be fully decoded.</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="Http2ErrorStreamIdEven" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame with even stream ID {streamId}.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorPushPromiseReceived" xml:space="preserve">
|
||||
<value>The client sent a A PUSH_PROMISE frame.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorHeadersInterleaved" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame to stream ID {streamId} before signaling of the header block for stream ID {headersStreamId}.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorStreamIdZero" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame with stream ID 0.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorStreamIdNotZero" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame with stream ID different than 0.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorPaddingTooLong" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame with padding longer than or with the same length as the sent data.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorStreamClosed" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame to closed stream ID {streamId}.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorStreamHalfClosedRemote" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame to stream ID {streamId} which is in the "half-closed (remote) state".</value>
|
||||
</data>
|
||||
<data name="Http2ErrorStreamSelfDependency" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame with dependency information that would cause stream ID {streamId} to depend on itself.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorUnexpectedFrameLength" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame with length different than {expectedLength}.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorSettingsLengthNotMultipleOfSix" xml:space="preserve">
|
||||
<value>The client sent a SETTINGS frame with a length that is not a multiple of 6.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorSettingsAckLengthNotZero" xml:space="preserve">
|
||||
<value>The client sent a SETTINGS frame with ACK set and length different than 0.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorSettingsParameterOutOfRange" xml:space="preserve">
|
||||
<value>The client sent a SETTINGS frame with a value for parameter {parameter} that is out of range.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorWindowUpdateIncrementZero" xml:space="preserve">
|
||||
<value>The client sent a WINDOW_UPDATE frame with a window size increment of 0.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorContinuationWithNoHeaders" xml:space="preserve">
|
||||
<value>The client sent a CONTINUATION frame not preceded by a HEADERS frame.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorStreamIdle" xml:space="preserve">
|
||||
<value>The client sent a {frameType} frame to idle stream ID {streamId}.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorTrailersContainPseudoHeaderField" xml:space="preserve">
|
||||
<value>The client sent trailers containing one or more pseudo-header fields.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorHeaderNameUppercase" xml:space="preserve">
|
||||
<value>The client sent a header with uppercase characters in its name.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorTrailerNameUppercase" xml:space="preserve">
|
||||
<value>The client sent a trailer with uppercase characters in its name.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorHeadersWithTrailersNoEndStream" xml:space="preserve">
|
||||
<value>The client sent a HEADERS frame containing trailers without setting the END_STREAM flag.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorMissingMandatoryPseudoHeaderFields" xml:space="preserve">
|
||||
<value>Request headers missing one or more mandatory pseudo-header fields.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorPseudoHeaderFieldAfterRegularHeaders" xml:space="preserve">
|
||||
<value>Pseudo-header field found in request headers after regular header fields.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorUnknownPseudoHeaderField" xml:space="preserve">
|
||||
<value>Request headers contain unknown pseudo-header field.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorResponsePseudoHeaderField" xml:space="preserve">
|
||||
<value>Request headers contain response-specific pseudo-header field.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorDuplicatePseudoHeaderField" xml:space="preserve">
|
||||
<value>Request headers contain duplicate pseudo-header field.</value>
|
||||
</data>
|
||||
<data name="Http2ErrorConnectionSpecificHeaderField" xml:space="preserve">
|
||||
<value>Request headers contain connection-specific header field.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
|||
|
|
@ -166,28 +166,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (ConnectionAbortedException ex)
|
||||
catch (ConnectionResetException ex)
|
||||
{
|
||||
// TODO: log
|
||||
// Don't log ECONNRESET errors when there are no active streams on the connection. Browsers like IE will reset connections regularly.
|
||||
if (_streams.Count > 0)
|
||||
{
|
||||
Log.RequestProcessingError(ConnectionId, ex);
|
||||
}
|
||||
|
||||
error = ex;
|
||||
}
|
||||
catch (Http2ConnectionErrorException ex)
|
||||
{
|
||||
// TODO: log
|
||||
Log.Http2ConnectionError(ConnectionId, ex);
|
||||
error = ex;
|
||||
errorCode = ex.ErrorCode;
|
||||
}
|
||||
catch (HPackDecodingException ex)
|
||||
{
|
||||
// TODO: log
|
||||
Log.HPackDecodingError(ConnectionId, _currentHeadersStream.StreamId, ex);
|
||||
error = ex;
|
||||
errorCode = Http2ErrorCode.COMPRESSION_ERROR;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TODO: log
|
||||
error = ex;
|
||||
errorCode = Http2ErrorCode.INTERNAL_ERROR;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -242,7 +247,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
// a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
||||
if (_incomingFrame.StreamId != 0 && (_incomingFrame.StreamId & 1) == 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdEven(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
switch (_incomingFrame.Type)
|
||||
|
|
@ -258,7 +263,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
case Http2FrameType.SETTINGS:
|
||||
return ProcessSettingsFrameAsync();
|
||||
case Http2FrameType.PUSH_PROMISE:
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorPushPromiseReceived, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
case Http2FrameType.PING:
|
||||
return ProcessPingFrameAsync();
|
||||
case Http2FrameType.GOAWAY:
|
||||
|
|
@ -276,35 +281,39 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId == 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.DataHasPadding && _incomingFrame.DataPadLength >= _incomingFrame.Length)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorPaddingTooLong(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
ThrowIfIncomingFrameSentToIdleStream();
|
||||
|
||||
if (_streams.TryGetValue(_incomingFrame.StreamId, out var stream) && !stream.EndStreamReceived)
|
||||
if (_streams.TryGetValue(_incomingFrame.StreamId, out var stream))
|
||||
{
|
||||
if (stream.EndStreamReceived)
|
||||
{
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.5.1
|
||||
//
|
||||
// ...an endpoint that receives any frames after receiving a frame with the
|
||||
// END_STREAM flag set MUST treat that as a connection error (Section 5.4.1)
|
||||
// of type STREAM_CLOSED, unless the frame is permitted as described below.
|
||||
//
|
||||
// (The allowed frame types for this situation are WINDOW_UPDATE, RST_STREAM and PRIORITY)
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(_incomingFrame.Type, stream.StreamId), Http2ErrorCode.STREAM_CLOSED);
|
||||
}
|
||||
|
||||
return stream.OnDataAsync(_incomingFrame.DataPayload,
|
||||
endStream: (_incomingFrame.DataFlags & Http2DataFrameFlags.END_STREAM) == Http2DataFrameFlags.END_STREAM);
|
||||
}
|
||||
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.5.1
|
||||
//
|
||||
// ...an endpoint that receives any frames after receiving a frame with the
|
||||
// END_STREAM flag set MUST treat that as a connection error (Section 5.4.1)
|
||||
// of type STREAM_CLOSED, unless the frame is permitted as described below.
|
||||
//
|
||||
// (The allowed frame types for this situation are WINDOW_UPDATE, RST_STREAM and PRIORITY)
|
||||
//
|
||||
// If we couldn't find the stream, it was either alive previously but closed with
|
||||
// END_STREAM or RST_STREAM, or it was implicitly closed when the client opened
|
||||
// a new stream with a higher ID. Per the spec, we should send RST_STREAM if
|
||||
|
|
@ -316,29 +325,29 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
//
|
||||
// We choose to do that here so we don't have to keep state to track implicitly closed
|
||||
// streams vs. streams closed with END_STREAM or RST_STREAM.
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.STREAM_CLOSED);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED);
|
||||
}
|
||||
|
||||
private async Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext> application)
|
||||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId == 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.HeadersHasPadding && _incomingFrame.HeadersPadLength >= _incomingFrame.Length)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorPaddingTooLong(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.HeadersHasPriority && _incomingFrame.HeadersStreamDependency == _incomingFrame.StreamId)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamSelfDependency(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_streams.TryGetValue(_incomingFrame.StreamId, out var stream))
|
||||
|
|
@ -352,7 +361,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
// (The allowed frame types for this situation are WINDOW_UPDATE, RST_STREAM and PRIORITY)
|
||||
if (stream.EndStreamReceived)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.STREAM_CLOSED);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(_incomingFrame.Type, stream.StreamId), Http2ErrorCode.STREAM_CLOSED);
|
||||
}
|
||||
|
||||
// TODO: trailers
|
||||
|
|
@ -366,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
//
|
||||
// If we couldn't find the stream, it was previously closed (either implicitly or with
|
||||
// END_STREAM or RST_STREAM).
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.STREAM_CLOSED);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -400,22 +409,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId == 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.PriorityStreamDependency == _incomingFrame.StreamId)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamSelfDependency(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 5)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 5), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
|
@ -425,17 +434,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId == 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 4)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 4), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
ThrowIfIncomingFrameSentToIdleStream();
|
||||
|
|
@ -452,22 +461,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdNotZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if ((_incomingFrame.SettingsFlags & Http2SettingsFrameFlags.ACK) == Http2SettingsFrameFlags.ACK && _incomingFrame.Length != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorSettingsAckLengthNotZero, Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length % 6 != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorSettingsLengthNotMultipleOfSix, Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
try
|
||||
|
|
@ -477,7 +486,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
catch (Http2SettingsParameterOutOfRangeException ex)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(ex.Parameter == Http2SettingsParameter.SETTINGS_INITIAL_WINDOW_SIZE
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorSettingsParameterOutOfRange(ex.Parameter), ex.Parameter == Http2SettingsParameter.SETTINGS_INITIAL_WINDOW_SIZE
|
||||
? Http2ErrorCode.FLOW_CONTROL_ERROR
|
||||
: Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
|
@ -487,21 +496,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdNotZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 8)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 8), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
if ((_incomingFrame.PingFlags & Http2PingFrameFlags.ACK) == Http2PingFrameFlags.ACK)
|
||||
{
|
||||
// TODO: verify that payload is equal to the outgoing PING frame
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
@ -512,12 +522,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId != 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdNotZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
Stop();
|
||||
|
|
@ -528,26 +538,34 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.Length != 4)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 4), Http2ErrorCode.FRAME_SIZE_ERROR);
|
||||
}
|
||||
|
||||
ThrowIfIncomingFrameSentToIdleStream();
|
||||
|
||||
if (_incomingFrame.WindowUpdateSizeIncrement == 0)
|
||||
{
|
||||
if (_incomingFrame.StreamId == 0)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _frameWriter.WriteRstStreamAsync(_incomingFrame.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.6.9
|
||||
// A receiver MUST treat the receipt of a WINDOW_UPDATE
|
||||
// frame with an flow-control window increment of 0 as a
|
||||
// stream error (Section 5.4.2) of type PROTOCOL_ERROR;
|
||||
// errors on the connection flow-control window MUST be
|
||||
// treated as a connection error (Section 5.4.1).
|
||||
//
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.5.4.1
|
||||
// An endpoint can end a connection at any time. In
|
||||
// particular, an endpoint MAY choose to treat a stream
|
||||
// error as a connection error.
|
||||
//
|
||||
// Since server initiated stream resets are not yet properly
|
||||
// implemented and tested, we treat all zero length window
|
||||
// increments as connection errors for now.
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorWindowUpdateIncrementZero, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
|
@ -555,9 +573,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
private Task ProcessContinuationFrameAsync<TContext>(IHttpApplication<TContext> application)
|
||||
{
|
||||
if (_currentHeadersStream == null || _incomingFrame.StreamId != _currentHeadersStream.StreamId)
|
||||
if (_currentHeadersStream == null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorContinuationWithNoHeaders, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_incomingFrame.StreamId != _currentHeadersStream.StreamId)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
var endHeaders = (_incomingFrame.ContinuationFlags & Http2ContinuationFrameFlags.END_HEADERS) == Http2ContinuationFrameFlags.END_HEADERS;
|
||||
|
|
@ -569,7 +592,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (_currentHeadersStream != null)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
|
@ -589,6 +612,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
catch (Http2StreamErrorException ex)
|
||||
{
|
||||
Log.Http2StreamError(ConnectionId, ex);
|
||||
ResetRequestHeaderParsingState();
|
||||
return _frameWriter.WriteRstStreamAsync(ex.StreamId, ex.ErrorCode);
|
||||
}
|
||||
|
|
@ -603,7 +627,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
// All HTTP/2 requests MUST include exactly one valid value for the :method, :scheme, and :path pseudo-header
|
||||
// fields, unless it is a CONNECT request (Section 8.3). An HTTP request that omits mandatory pseudo-header
|
||||
// fields is malformed (Section 8.1.2.6).
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorMissingMandatoryPseudoHeaderFields, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
_streams[_incomingFrame.StreamId] = _currentHeadersStream;
|
||||
|
|
@ -638,7 +662,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
// initial state for all streams.
|
||||
if (_incomingFrame.StreamId > _highestOpenedStreamId)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdle(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -666,7 +690,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
// All pseudo-header fields MUST appear in the header block before regular header fields.
|
||||
// Any request or response that contains a pseudo-header field that appears in a header
|
||||
// block after a regular header field MUST be treated as malformed (Section 8.1.2.6).
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorPseudoHeaderFieldAfterRegularHeaders, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
_requestHeaderParsingState = RequestHeaderParsingState.PseudoHeaderFields;
|
||||
|
|
@ -675,21 +699,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
// Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header
|
||||
// fields as malformed (Section 8.1.2.6).
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorUnknownPseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (headerField == PseudoHeaderFields.Status)
|
||||
{
|
||||
// Pseudo-header fields defined for requests MUST NOT appear in responses; pseudo-header fields
|
||||
// defined for responses MUST NOT appear in requests.
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorResponsePseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if ((_parsedPseudoHeaderFields & headerField) == headerField)
|
||||
{
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.3
|
||||
// All HTTP/2 requests MUST include exactly one valid value for the :method, :scheme, and :path pseudo-header fields
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorDuplicatePseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (headerField == PseudoHeaderFields.Method)
|
||||
|
|
@ -706,7 +730,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
if (IsConnectionSpecificHeaderField(name, value))
|
||||
{
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorConnectionSpecificHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2
|
||||
|
|
@ -715,7 +739,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
if (name[i] >= 65 && name[i] <= 90)
|
||||
{
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorHeaderNameUppercase, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
public class Http2ConnectionErrorException : Exception
|
||||
{
|
||||
public Http2ConnectionErrorException(Http2ErrorCode errorCode)
|
||||
: base($"HTTP/2 connection error: {errorCode}")
|
||||
public Http2ConnectionErrorException(string message, Http2ErrorCode errorCode)
|
||||
: base($"HTTP/2 connection error ({errorCode}): {message}")
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
{
|
||||
public class Http2StreamErrorException : Exception
|
||||
{
|
||||
public Http2StreamErrorException(int streamId, Http2ErrorCode errorCode)
|
||||
: base($"HTTP/2 stream ID {streamId} error: {errorCode}")
|
||||
public Http2StreamErrorException(int streamId, string message, Http2ErrorCode errorCode)
|
||||
: base($"HTTP/2 stream ID {streamId} error ({errorCode}): {message}")
|
||||
{
|
||||
StreamId = streamId;
|
||||
ErrorCode = errorCode;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||
|
|
@ -45,5 +47,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
|||
void RequestBodyMininumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate);
|
||||
|
||||
void ResponseMininumDataRateNotSatisfied(string connectionId, string traceIdentifier);
|
||||
|
||||
void Http2ConnectionError(string connectionId, Http2ConnectionErrorException ex);
|
||||
|
||||
void Http2StreamError(string connectionId, Http2StreamErrorException ex);
|
||||
|
||||
void HPackDecodingError(string connectionId, int streamId, HPackDecodingException ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
@ -66,6 +68,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
private static readonly Action<ILogger, string, string, Exception> _responseMinimumDataRateNotSatisfied =
|
||||
LoggerMessage.Define<string, string>(LogLevel.Information, 28, @"Connection id ""{ConnectionId}"", Request id ""{TraceIdentifier}"": the connection was closed becuase the response was not read by the client at the specified minimum data rate.");
|
||||
|
||||
private static readonly Action<ILogger, string, Exception> _http2ConnectionError =
|
||||
LoggerMessage.Define<string>(LogLevel.Information, 29, @"Connection id ""{ConnectionId}"": HTTP/2 connection error.");
|
||||
|
||||
private static readonly Action<ILogger, string, Exception> _http2StreamError =
|
||||
LoggerMessage.Define<string>(LogLevel.Information, 30, @"Connection id ""{ConnectionId}"": HTTP/2 stream error.");
|
||||
|
||||
private static readonly Action<ILogger, string, int, Exception> _hpackDecodingError =
|
||||
LoggerMessage.Define<string, int>(LogLevel.Information, 31, @"Connection id ""{ConnectionId}"": HPACK decoding error while decoding headers for stream ID {StreamId}.");
|
||||
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
public KestrelTrace(ILogger logger)
|
||||
|
|
@ -168,6 +179,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
_responseMinimumDataRateNotSatisfied(_logger, connectionId, traceIdentifier, null);
|
||||
}
|
||||
|
||||
public void Http2ConnectionError(string connectionId, Http2ConnectionErrorException ex)
|
||||
{
|
||||
_http2ConnectionError(_logger, connectionId, ex);
|
||||
}
|
||||
|
||||
public void Http2StreamError(string connectionId, Http2StreamErrorException ex)
|
||||
{
|
||||
_http2StreamError(_logger, connectionId, ex);
|
||||
}
|
||||
|
||||
public void HPackDecodingError(string connectionId, int streamId, HPackDecodingException ex)
|
||||
{
|
||||
_hpackDecodingError(_logger, connectionId, streamId, ex);
|
||||
}
|
||||
|
||||
public virtual void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
=> _logger.Log(logLevel, eventId, state, exception, formatter);
|
||||
|
||||
|
|
|
|||
|
|
@ -1256,6 +1256,370 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
internal static string FormatHPackErrorIncompleteHeaderBlock()
|
||||
=> GetString("HPackErrorIncompleteHeaderBlock");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with even stream ID {streamId}.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamIdEven
|
||||
{
|
||||
get => GetString("Http2ErrorStreamIdEven");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with even stream ID {streamId}.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamIdEven(object frameType, object streamId)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamIdEven", "frameType", "streamId"), frameType, streamId);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a A PUSH_PROMISE frame.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorPushPromiseReceived
|
||||
{
|
||||
get => GetString("Http2ErrorPushPromiseReceived");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a A PUSH_PROMISE frame.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorPushPromiseReceived()
|
||||
=> GetString("Http2ErrorPushPromiseReceived");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to stream ID {streamId} before signaling of the header block for stream ID {headersStreamId}.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorHeadersInterleaved
|
||||
{
|
||||
get => GetString("Http2ErrorHeadersInterleaved");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to stream ID {streamId} before signaling of the header block for stream ID {headersStreamId}.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorHeadersInterleaved(object frameType, object streamId, object headersStreamId)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorHeadersInterleaved", "frameType", "streamId", "headersStreamId"), frameType, streamId, headersStreamId);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with stream ID 0.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamIdZero
|
||||
{
|
||||
get => GetString("Http2ErrorStreamIdZero");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with stream ID 0.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamIdZero(object frameType)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamIdZero", "frameType"), frameType);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with stream ID different than 0.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamIdNotZero
|
||||
{
|
||||
get => GetString("Http2ErrorStreamIdNotZero");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with stream ID different than 0.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamIdNotZero(object frameType)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamIdNotZero", "frameType"), frameType);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with padding longer than or with the same length as the sent data.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorPaddingTooLong
|
||||
{
|
||||
get => GetString("Http2ErrorPaddingTooLong");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with padding longer than or with the same length as the sent data.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorPaddingTooLong(object frameType)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorPaddingTooLong", "frameType"), frameType);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to closed stream ID {streamId}.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamClosed
|
||||
{
|
||||
get => GetString("Http2ErrorStreamClosed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to closed stream ID {streamId}.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamClosed(object frameType, object streamId)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamClosed", "frameType", "streamId"), frameType, streamId);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to stream ID {streamId} which is in the "half-closed (remote) state".
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamHalfClosedRemote
|
||||
{
|
||||
get => GetString("Http2ErrorStreamHalfClosedRemote");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to stream ID {streamId} which is in the "half-closed (remote) state".
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamHalfClosedRemote(object frameType, object streamId)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamHalfClosedRemote", "frameType", "streamId"), frameType, streamId);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with dependency information that would cause stream ID {streamId} to depend on itself.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamSelfDependency
|
||||
{
|
||||
get => GetString("Http2ErrorStreamSelfDependency");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with dependency information that would cause stream ID {streamId} to depend on itself.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamSelfDependency(object frameType, object streamId)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamSelfDependency", "frameType", "streamId"), frameType, streamId);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with length different than {expectedLength}.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorUnexpectedFrameLength
|
||||
{
|
||||
get => GetString("Http2ErrorUnexpectedFrameLength");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame with length different than {expectedLength}.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorUnexpectedFrameLength(object frameType, object expectedLength)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorUnexpectedFrameLength", "frameType", "expectedLength"), frameType, expectedLength);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a SETTINGS frame with a length that is not a multiple of 6.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorSettingsLengthNotMultipleOfSix
|
||||
{
|
||||
get => GetString("Http2ErrorSettingsLengthNotMultipleOfSix");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a SETTINGS frame with a length that is not a multiple of 6.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorSettingsLengthNotMultipleOfSix()
|
||||
=> GetString("Http2ErrorSettingsLengthNotMultipleOfSix");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a SETTINGS frame with ACK set and length different than 0.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorSettingsAckLengthNotZero
|
||||
{
|
||||
get => GetString("Http2ErrorSettingsAckLengthNotZero");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a SETTINGS frame with ACK set and length different than 0.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorSettingsAckLengthNotZero()
|
||||
=> GetString("Http2ErrorSettingsAckLengthNotZero");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a SETTINGS frame with a value for parameter {parameter} that is out of range.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorSettingsParameterOutOfRange
|
||||
{
|
||||
get => GetString("Http2ErrorSettingsParameterOutOfRange");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a SETTINGS frame with a value for parameter {parameter} that is out of range.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorSettingsParameterOutOfRange(object parameter)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorSettingsParameterOutOfRange", "parameter"), parameter);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a WINDOW_UPDATE frame with a window size increment of 0.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorWindowUpdateIncrementZero
|
||||
{
|
||||
get => GetString("Http2ErrorWindowUpdateIncrementZero");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a WINDOW_UPDATE frame with a window size increment of 0.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorWindowUpdateIncrementZero()
|
||||
=> GetString("Http2ErrorWindowUpdateIncrementZero");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a CONTINUATION frame not preceded by a HEADERS frame.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorContinuationWithNoHeaders
|
||||
{
|
||||
get => GetString("Http2ErrorContinuationWithNoHeaders");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a CONTINUATION frame not preceded by a HEADERS frame.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorContinuationWithNoHeaders()
|
||||
=> GetString("Http2ErrorContinuationWithNoHeaders");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to idle stream ID {streamId}.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorStreamIdle
|
||||
{
|
||||
get => GetString("Http2ErrorStreamIdle");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a {frameType} frame to idle stream ID {streamId}.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorStreamIdle(object frameType, object streamId)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Http2ErrorStreamIdle", "frameType", "streamId"), frameType, streamId);
|
||||
|
||||
/// <summary>
|
||||
/// The client sent trailers containing one or more pseudo-header fields.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorTrailersContainPseudoHeaderField
|
||||
{
|
||||
get => GetString("Http2ErrorTrailersContainPseudoHeaderField");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent trailers containing one or more pseudo-header fields.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorTrailersContainPseudoHeaderField()
|
||||
=> GetString("Http2ErrorTrailersContainPseudoHeaderField");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a header with uppercase characters in its name.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorHeaderNameUppercase
|
||||
{
|
||||
get => GetString("Http2ErrorHeaderNameUppercase");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a header with uppercase characters in its name.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorHeaderNameUppercase()
|
||||
=> GetString("Http2ErrorHeaderNameUppercase");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a trailer with uppercase characters in its name.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorTrailerNameUppercase
|
||||
{
|
||||
get => GetString("Http2ErrorTrailerNameUppercase");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a trailer with uppercase characters in its name.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorTrailerNameUppercase()
|
||||
=> GetString("Http2ErrorTrailerNameUppercase");
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a HEADERS frame containing trailers without setting the END_STREAM flag.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorHeadersWithTrailersNoEndStream
|
||||
{
|
||||
get => GetString("Http2ErrorHeadersWithTrailersNoEndStream");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client sent a HEADERS frame containing trailers without setting the END_STREAM flag.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorHeadersWithTrailersNoEndStream()
|
||||
=> GetString("Http2ErrorHeadersWithTrailersNoEndStream");
|
||||
|
||||
/// <summary>
|
||||
/// Request headers missing one or more mandatory pseudo-header fields.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorMissingMandatoryPseudoHeaderFields
|
||||
{
|
||||
get => GetString("Http2ErrorMissingMandatoryPseudoHeaderFields");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request headers missing one or more mandatory pseudo-header fields.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorMissingMandatoryPseudoHeaderFields()
|
||||
=> GetString("Http2ErrorMissingMandatoryPseudoHeaderFields");
|
||||
|
||||
/// <summary>
|
||||
/// Pseudo-header field found in request headers after regular header fields.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorPseudoHeaderFieldAfterRegularHeaders
|
||||
{
|
||||
get => GetString("Http2ErrorPseudoHeaderFieldAfterRegularHeaders");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pseudo-header field found in request headers after regular header fields.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorPseudoHeaderFieldAfterRegularHeaders()
|
||||
=> GetString("Http2ErrorPseudoHeaderFieldAfterRegularHeaders");
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain unknown pseudo-header field.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorUnknownPseudoHeaderField
|
||||
{
|
||||
get => GetString("Http2ErrorUnknownPseudoHeaderField");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain unknown pseudo-header field.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorUnknownPseudoHeaderField()
|
||||
=> GetString("Http2ErrorUnknownPseudoHeaderField");
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain response-specific pseudo-header field.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorResponsePseudoHeaderField
|
||||
{
|
||||
get => GetString("Http2ErrorResponsePseudoHeaderField");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain response-specific pseudo-header field.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorResponsePseudoHeaderField()
|
||||
=> GetString("Http2ErrorResponsePseudoHeaderField");
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain duplicate pseudo-header field.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorDuplicatePseudoHeaderField
|
||||
{
|
||||
get => GetString("Http2ErrorDuplicatePseudoHeaderField");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain duplicate pseudo-header field.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorDuplicatePseudoHeaderField()
|
||||
=> GetString("Http2ErrorDuplicatePseudoHeaderField");
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain connection-specific header field.
|
||||
/// </summary>
|
||||
internal static string Http2ErrorConnectionSpecificHeaderField
|
||||
{
|
||||
get => GetString("Http2ErrorConnectionSpecificHeaderField");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request headers contain connection-specific header field.
|
||||
/// </summary>
|
||||
internal static string FormatHttp2ErrorConnectionSpecificHeaderField()
|
||||
=> GetString("Http2ErrorConnectionSpecificHeaderField");
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Protocols;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||
|
|
@ -77,6 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
private readonly PipeFactory _pipeFactory = new PipeFactory();
|
||||
private readonly (IPipeConnection Transport, IPipeConnection Application) _pair;
|
||||
private readonly TestApplicationErrorLogger _logger;
|
||||
private readonly Http2ConnectionContext _connectionContext;
|
||||
private readonly Http2Connection _connection;
|
||||
private readonly Http2PeerSettings _clientSettings = new Http2PeerSettings();
|
||||
|
|
@ -215,9 +217,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
_hpackDecoder = new HPackDecoder((int)_clientSettings.HeaderTableSize);
|
||||
|
||||
_logger = new TestApplicationErrorLogger();
|
||||
|
||||
_connectionContext = new Http2ConnectionContext
|
||||
{
|
||||
ServiceContext = new TestServiceContext(),
|
||||
ServiceContext = new TestServiceContext()
|
||||
{
|
||||
Log = new TestKestrelTrace(_logger)
|
||||
},
|
||||
PipeFactory = _pipeFactory,
|
||||
Application = _pair.Application,
|
||||
Transport = _pair.Transport
|
||||
|
|
@ -421,7 +428,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendDataAsync(0, _noData, endStream: false);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdZero(Http2FrameType.DATA));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -431,7 +442,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendDataAsync(2, _noData, endStream: false);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdEven(Http2FrameType.DATA, streamId: 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -442,7 +457,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
|
||||
await SendInvalidDataFrameAsync(1, frameLength: 5, padLength: 5);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: true);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.DATA));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -453,7 +472,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
|
||||
await SendInvalidDataFrameAsync(1, frameLength: 5, padLength: 6);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: true);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.DATA));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -464,7 +487,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
|
||||
await SendInvalidDataFrameAsync(1, frameLength: 0, padLength: 0);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: true);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.DATA));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -475,7 +502,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendDataAsync(1, _helloWorldBytes, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.DATA, streamId: 1, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -485,7 +516,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendDataAsync(1, _helloWorldBytes, endStream: false);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdle(Http2FrameType.DATA, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -498,7 +533,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendDataAsync(1, _helloWorldBytes, endStream: false);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(Http2FrameType.DATA, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -519,7 +558,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendDataAsync(1, _helloWorldBytes, endStream: false);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.DATA, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -547,7 +590,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendDataAsync(1, _helloWorldBytes, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 3, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 3,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.DATA, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -647,7 +694,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StartStreamAsync(0, _browserRequestHeaders, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdZero(Http2FrameType.HEADERS));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -657,7 +708,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await StartStreamAsync(2, _browserRequestHeaders, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdEven(Http2FrameType.HEADERS, streamId: 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -679,7 +734,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Try to re-use the stream ID (http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1)
|
||||
await StartStreamAsync(1, _browserRequestHeaders, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -692,7 +751,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -714,7 +777,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Stream 1 was implicitly closed by opening stream 3 before (http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1)
|
||||
await StartStreamAsync(1, _browserRequestHeaders, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 3, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 3,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -727,7 +794,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendInvalidHeadersFrameAsync(1, frameLength: padLength, padLength: padLength);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.HEADERS));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -740,7 +811,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendInvalidHeadersFrameAsync(1, frameLength, padLength);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorPaddingTooLong(Http2FrameType.HEADERS));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -751,7 +826,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendHeadersAsync(3, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.HEADERS, streamId: 3, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -761,7 +840,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendHeadersWithPriorityAsync(1, _browserRequestHeaders, priority: 42, streamDependency: 1, endStream: true);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamSelfDependency(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -771,7 +854,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendIncompleteHeadersFrameAsync(streamId: 1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.COMPRESSION_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<HPackDecodingException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.COMPRESSION_ERROR,
|
||||
expectedErrorMessage: CoreStrings.HPackErrorIncompleteHeaderBlock);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -781,11 +868,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, headerBlock);
|
||||
await WaitForStreamErrorAsync(1, Http2ErrorCode.PROTOCOL_ERROR, ignoreNonRstStreamFrames: false);
|
||||
await WaitForStreamErrorAsync(
|
||||
ignoreNonRstStreamFrames: false,
|
||||
expectedStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorHeaderNameUppercase);
|
||||
|
||||
// Verify that the stream ID can't be re-used
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, _browserRequestHeaders);
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -799,7 +894,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(":unknown", "0"),
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorUnknownPseudoHeaderField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -813,21 +908,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(":status", "200"),
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorResponsePseudoHeaderField);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(DuplicatePseudoHeaderFieldData))]
|
||||
public Task HEADERS_Received_HeaderBlockContainsDuplicatePseudoHeaderField_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
{
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorDuplicatePseudoHeaderField);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MissingPseudoHeaderFieldData))]
|
||||
public Task HEADERS_Received_HeaderBlockDoesNotContainMandatoryPseudoHeaderField_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
{
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorMissingMandatoryPseudoHeaderFields);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -854,23 +949,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
[MemberData(nameof(PseudoHeaderFieldAfterRegularHeadersData))]
|
||||
public Task HEADERS_Received_HeaderBlockContainsPseudoHeaderFieldAfterRegularHeaders_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
{
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorPseudoHeaderFieldAfterRegularHeaders);
|
||||
}
|
||||
|
||||
private async Task HEADERS_Received_InvalidHeaderFields_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
private async Task HEADERS_Received_InvalidHeaderFields_StreamError(IEnumerable<KeyValuePair<string, string>> headers, string expectedErrorMessage)
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, headers);
|
||||
await WaitForStreamErrorAsync(1, Http2ErrorCode.PROTOCOL_ERROR, ignoreNonRstStreamFrames: false);
|
||||
await WaitForStreamErrorAsync(
|
||||
ignoreNonRstStreamFrames: false,
|
||||
expectedStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: expectedErrorMessage);
|
||||
|
||||
// Verify that the stream ID can't be re-used
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, _browserRequestHeaders);
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsConnectionSpecificHeader_StreamError()
|
||||
public Task HEADERS_Received_HeaderBlockContainsConnectionHeader_StreamError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
|
|
@ -880,7 +983,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>("connection", "keep-alive")
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, CoreStrings.Http2ErrorConnectionSpecificHeaderField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -894,21 +997,34 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>("te", "trailers, deflate")
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, CoreStrings.Http2ErrorConnectionSpecificHeaderField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsTEHeader_ValueIsTrailers_NoError()
|
||||
public async Task HEADERS_Received_HeaderBlockContainsTEHeader_ValueIsTrailers_NoError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>(":method", "GET"),
|
||||
new KeyValuePair<string, string>(":path", "/"),
|
||||
new KeyValuePair<string, string>(":scheme", "http"),
|
||||
new KeyValuePair<string, string>("te", "trailers, deflate")
|
||||
new KeyValuePair<string, string>("te", "trailers")
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers);
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers);
|
||||
|
||||
await ExpectAsync(Http2FrameType.HEADERS,
|
||||
withLength: 55,
|
||||
withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS,
|
||||
withStreamId: 1);
|
||||
await ExpectAsync(Http2FrameType.DATA,
|
||||
withLength: 0,
|
||||
withFlags: (byte)Http2HeadersFrameFlags.END_STREAM,
|
||||
withStreamId: 1);
|
||||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -918,7 +1034,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendPriorityAsync(0);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdZero(Http2FrameType.PRIORITY));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -928,7 +1048,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendPriorityAsync(2);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdEven(Http2FrameType.PRIORITY, streamId: 2));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -940,7 +1064,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendInvalidPriorityFrameAsync(1, length);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(Http2FrameType.PRIORITY, expectedLength: 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -951,7 +1079,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendPriorityAsync(1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.PRIORITY, streamId: 1, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -961,7 +1093,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendPriorityAsync(1, streamDependency: 1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamSelfDependency(Http2FrameType.PRIORITY, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1007,7 +1143,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendRstStreamAsync(0);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdZero(Http2FrameType.RST_STREAM));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1017,7 +1157,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendRstStreamAsync(2);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdEven(Http2FrameType.RST_STREAM, streamId: 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1027,7 +1171,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendRstStreamAsync(1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdle(Http2FrameType.RST_STREAM, streamId: 1));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1042,7 +1190,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendInvalidRstStreamFrameAsync(1, length);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, ignoreNonGoAwayFrames: true);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: true,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(Http2FrameType.RST_STREAM, expectedLength: 4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1053,7 +1205,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendRstStreamAsync(1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.RST_STREAM, streamId: 1, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1065,13 +1221,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SETTINGS_Received_StreamIdNonZero_ConnectionError()
|
||||
public async Task SETTINGS_Received_StreamIdNotZero_ConnectionError()
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendSettingsWithInvalidStreamIdAsync(1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdNotZero(Http2FrameType.SETTINGS));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1090,7 +1250,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendSettingsWithInvalidParameterValueAsync(parameter, value);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: expectedErrorCode, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: expectedErrorCode,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorSettingsParameterOutOfRange(parameter));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1101,7 +1265,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendSettingsAsync();
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.SETTINGS, streamId: 0, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1113,7 +1281,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendSettingsAckWithInvalidLengthAsync(length);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorSettingsAckLengthNotZero);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1128,7 +1300,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendSettingsWithInvalidLengthAsync(length);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorSettingsLengthNotMultipleOfSix);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1138,7 +1314,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendPushPromiseFrameAsync();
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorPushPromiseReceived);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1173,7 +1353,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendPingAsync(Http2PingFrameFlags.NONE);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.PING, streamId: 0, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1183,7 +1367,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendPingWithInvalidStreamIdAsync(streamId: 1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdNotZero(Http2FrameType.PING));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1197,7 +1385,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendPingWithInvalidLengthAsync(length);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(Http2FrameType.PING, expectedLength: 8));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1231,13 +1423,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GOAWAY_Received_StreamIdNonZero_ConnectionError()
|
||||
public async Task GOAWAY_Received_StreamIdNotZero_ConnectionError()
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendInvalidGoAwayFrameAsync();
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdNotZero(Http2FrameType.GOAWAY));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1248,7 +1444,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendGoAwayAsync();
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.GOAWAY, streamId: 0, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1258,7 +1458,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendWindowUpdateAsync(2, sizeIncrement: 42);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdEven(Http2FrameType.WINDOW_UPDATE, streamId: 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1269,7 +1473,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendWindowUpdateAsync(1, sizeIncrement: 42);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.WINDOW_UPDATE, streamId: 1, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1283,7 +1491,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendInvalidWindowUpdateAsync(streamId, sizeIncrement: 42, length: length);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.FRAME_SIZE_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(Http2FrameType.WINDOW_UPDATE, expectedLength: 4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1293,7 +1505,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendWindowUpdateAsync(0, sizeIncrement: 0);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorWindowUpdateIncrementZero);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WINDOW_UPDATE_Received_OnStream_SizeIncrementZero_ConnectionError()
|
||||
{
|
||||
await InitializeConnectionAsync(_waitForAbortApplication);
|
||||
|
||||
await StartStreamAsync(1, _browserRequestHeaders, endStream: true);
|
||||
await SendWindowUpdateAsync(1, sizeIncrement: 0);
|
||||
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorWindowUpdateIncrementZero);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1303,20 +1534,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await SendWindowUpdateAsync(1, sizeIncrement: 1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WINDOW_UPDATE_Received_OnStream_SizeIncrementZero_StreamError()
|
||||
{
|
||||
await InitializeConnectionAsync(_waitForAbortApplication);
|
||||
|
||||
await StartStreamAsync(1, _browserRequestHeaders, endStream: true);
|
||||
await SendWindowUpdateAsync(1, sizeIncrement: 0);
|
||||
|
||||
await WaitForStreamErrorAsync(expectedStreamId: 1, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonRstStreamFrames: true);
|
||||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: true);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdle(Http2FrameType.WINDOW_UPDATE, streamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1348,7 +1570,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _oneContinuationRequestHeaders);
|
||||
await SendContinuationAsync(3, Http2ContinuationFrameFlags.END_HEADERS);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(Http2FrameType.CONTINUATION, streamId: 3, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1359,7 +1585,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _postRequestHeaders);
|
||||
await SendIncompleteContinuationFrameAsync(streamId: 1);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.COMPRESSION_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<HPackDecodingException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.COMPRESSION_ERROR,
|
||||
expectedErrorMessage: CoreStrings.HPackErrorIncompleteHeaderBlock);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1371,11 +1601,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Assert.True(await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, headers));
|
||||
await SendEmptyContinuationFrameAsync(1, Http2ContinuationFrameFlags.END_HEADERS);
|
||||
|
||||
await WaitForStreamErrorAsync(1, Http2ErrorCode.PROTOCOL_ERROR, ignoreNonRstStreamFrames: false);
|
||||
await WaitForStreamErrorAsync(
|
||||
ignoreNonRstStreamFrames: false,
|
||||
expectedStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorMissingMandatoryPseudoHeaderFields);
|
||||
|
||||
// Verify that the stream ID can't be re-used
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, headers);
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 1, expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.HEADERS, streamId: 1));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1448,7 +1686,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendUnknownFrameTypeAsync(streamId: 1);
|
||||
await SendUnknownFrameTypeAsync(streamId: 1, frameType: 42);
|
||||
|
||||
// Check that the connection is still alive
|
||||
await SendPingAsync(Http2PingFrameFlags.NONE);
|
||||
|
|
@ -1466,13 +1704,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _browserRequestHeaders);
|
||||
await SendUnknownFrameTypeAsync(streamId: 1);
|
||||
await SendUnknownFrameTypeAsync(streamId: 1, frameType: 42);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 0,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorHeadersInterleaved(frameType: 42, streamId: 1, headersStreamId: 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConnectionError_AbortsAllStreams()
|
||||
public async Task ConnectionErrorAbortsAllStreams()
|
||||
{
|
||||
await InitializeConnectionAsync(_waitForAbortApplication);
|
||||
|
||||
|
|
@ -1484,7 +1726,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Cause a connection error by sending an invalid frame
|
||||
await SendDataAsync(0, _noData, endStream: false);
|
||||
|
||||
await WaitForConnectionErrorAsync(expectedLastStreamId: 5, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 5,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamIdZero(Http2FrameType.DATA));
|
||||
|
||||
await WaitForAllStreamsAsync();
|
||||
Assert.Contains(1, _abortedStreamIds);
|
||||
|
|
@ -1492,6 +1738,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Assert.Contains(5, _abortedStreamIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConnectionResetLoggedWithActiveStreams()
|
||||
{
|
||||
await InitializeConnectionAsync(_waitForAbortApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, _browserRequestHeaders);
|
||||
|
||||
_pair.Application.Output.Complete(new ConnectionResetException(string.Empty));
|
||||
|
||||
var result = await _pair.Application.Input.ReadAsync();
|
||||
Assert.True(result.IsCompleted);
|
||||
Assert.Single(_logger.Messages, m => m.Exception is ConnectionResetException);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConnectionResetNotLoggedWithNoActiveStreams()
|
||||
{
|
||||
await InitializeConnectionAsync(_waitForAbortApplication);
|
||||
|
||||
_pair.Application.Output.Complete(new ConnectionResetException(string.Empty));
|
||||
|
||||
var result = await _pair.Application.Input.ReadAsync();
|
||||
Assert.True(result.IsCompleted);
|
||||
Assert.DoesNotContain(_logger.Messages, m => m.Exception is ConnectionResetException);
|
||||
}
|
||||
|
||||
private async Task InitializeConnectionAsync(RequestDelegate application)
|
||||
{
|
||||
_connectionTask = _connection.ProcessAsync(new DummyApplication(application));
|
||||
|
|
@ -1931,11 +2203,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
||||
private Task SendUnknownFrameTypeAsync(int streamId)
|
||||
private Task SendUnknownFrameTypeAsync(int streamId, int frameType)
|
||||
{
|
||||
var frame = new Http2Frame();
|
||||
frame.StreamId = streamId;
|
||||
frame.Type = (Http2FrameType)42;
|
||||
frame.Type = (Http2FrameType)frameType;
|
||||
frame.Length = 0;
|
||||
return SendAsync(frame.Raw);
|
||||
}
|
||||
|
|
@ -1996,10 +2268,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
private Task WaitForConnectionStopAsync(int expectedLastStreamId, bool ignoreNonGoAwayFrames)
|
||||
{
|
||||
return WaitForConnectionErrorAsync(expectedLastStreamId, Http2ErrorCode.NO_ERROR, ignoreNonGoAwayFrames);
|
||||
return WaitForConnectionErrorAsync<Exception>(ignoreNonGoAwayFrames, expectedLastStreamId, Http2ErrorCode.NO_ERROR, expectedErrorMessage: null);
|
||||
}
|
||||
|
||||
private async Task WaitForConnectionErrorAsync(int expectedLastStreamId, Http2ErrorCode expectedErrorCode, bool ignoreNonGoAwayFrames)
|
||||
private async Task WaitForConnectionErrorAsync<TException>(bool ignoreNonGoAwayFrames, int expectedLastStreamId, Http2ErrorCode expectedErrorCode, string expectedErrorMessage)
|
||||
where TException : Exception
|
||||
{
|
||||
var frame = await ReceiveFrameAsync();
|
||||
|
||||
|
|
@ -2018,11 +2291,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Assert.Equal(expectedLastStreamId, frame.GoAwayLastStreamId);
|
||||
Assert.Equal(expectedErrorCode, frame.GoAwayErrorCode);
|
||||
|
||||
if (expectedErrorMessage != null)
|
||||
{
|
||||
var message = Assert.Single(_logger.Messages, m => m.Exception is TException);
|
||||
Assert.Contains(expectedErrorMessage, message.Exception.Message);
|
||||
}
|
||||
|
||||
await _connectionTask;
|
||||
_pair.Application.Output.Complete();
|
||||
}
|
||||
|
||||
private async Task WaitForStreamErrorAsync(int expectedStreamId, Http2ErrorCode expectedErrorCode, bool ignoreNonRstStreamFrames)
|
||||
private async Task WaitForStreamErrorAsync(bool ignoreNonRstStreamFrames, int expectedStreamId, Http2ErrorCode expectedErrorCode, string expectedErrorMessage)
|
||||
{
|
||||
var frame = await ReceiveFrameAsync();
|
||||
|
||||
|
|
@ -2039,6 +2318,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Assert.Equal(0, frame.Flags);
|
||||
Assert.Equal(expectedStreamId, frame.StreamId);
|
||||
Assert.Equal(expectedErrorCode, frame.RstStreamErrorCode);
|
||||
|
||||
if (expectedErrorMessage != null)
|
||||
{
|
||||
var message = Assert.Single(_logger.Messages, m => m.Exception is Http2StreamErrorException);
|
||||
Assert.Contains(expectedErrorMessage, message.Exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyDecodedRequestHeaders(IEnumerable<KeyValuePair<string, string>> expectedHeaders)
|
||||
|
|
|
|||
Loading…
Reference in New Issue