Merge branch 'release/2.2'
This commit is contained in:
commit
5295ebba0b
|
|
@ -22,8 +22,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
// Standard completed task
|
||||
private static readonly Func<object, Task> _syncTaskFunc = (obj) => Task.CompletedTask;
|
||||
// Non-standard completed task
|
||||
private static readonly Task _psuedoAsyncTask = Task.FromResult(27);
|
||||
private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask;
|
||||
private static readonly Task _pseudoAsyncTask = Task.FromResult(27);
|
||||
private static readonly Func<object, Task> _pseudoAsyncTaskFunc = (obj) => _pseudoAsyncTask;
|
||||
|
||||
private TestHttp1Connection _http1Connection;
|
||||
private DuplexPipe.DuplexPipePair _pair;
|
||||
|
|
@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
_http1Connection.OnStarting(_syncTaskFunc, null);
|
||||
break;
|
||||
case Startup.Async:
|
||||
_http1Connection.OnStarting(_psuedoAsyncTaskFunc, null);
|
||||
_http1Connection.OnStarting(_pseudoAsyncTaskFunc, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
public void RequestBodyDone(string connectionId, string traceIdentifier) { }
|
||||
public void RequestBodyNotEntirelyRead(string connectionId, string traceIdentifier) { }
|
||||
public void RequestBodyDrainTimedOut(string connectionId, string traceIdentifier) { }
|
||||
public void RequestBodyMininumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate) { }
|
||||
public void ResponseMininumDataRateNotSatisfied(string connectionId, string traceIdentifier) { }
|
||||
public void RequestBodyMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate) { }
|
||||
public void ResponseMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier) { }
|
||||
public void ApplicationAbortedConnection(string connectionId, string traceIdentifier) { }
|
||||
public void Http2ConnectionError(string connectionId, Http2ConnectionErrorException ex) { }
|
||||
public void Http2StreamError(string connectionId, Http2StreamErrorException ex) { }
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
{
|
||||
public class PipeThroughputBenchmark
|
||||
{
|
||||
private const int _writeLenght = 57;
|
||||
private const int _writeLength = 57;
|
||||
private const int InnerLoopCount = 512;
|
||||
|
||||
private Pipe _pipe;
|
||||
|
|
@ -32,15 +32,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
{
|
||||
for (int i = 0; i < InnerLoopCount; i++)
|
||||
{
|
||||
_pipe.Writer.GetMemory(_writeLenght);
|
||||
_pipe.Writer.Advance(_writeLenght);
|
||||
_pipe.Writer.GetMemory(_writeLength);
|
||||
_pipe.Writer.Advance(_writeLength);
|
||||
await _pipe.Writer.FlushAsync();
|
||||
}
|
||||
});
|
||||
|
||||
var reading = Task.Run(async () =>
|
||||
{
|
||||
long remaining = InnerLoopCount * _writeLenght;
|
||||
long remaining = InnerLoopCount * _writeLength;
|
||||
while (remaining != 0)
|
||||
{
|
||||
var result = await _pipe.Reader.ReadAsync();
|
||||
|
|
@ -57,8 +57,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
{
|
||||
for (int i = 0; i < InnerLoopCount; i++)
|
||||
{
|
||||
_pipe.Writer.GetMemory(_writeLenght);
|
||||
_pipe.Writer.Advance(_writeLenght);
|
||||
_pipe.Writer.GetMemory(_writeLength);
|
||||
_pipe.Writer.Advance(_writeLength);
|
||||
_pipe.Writer.FlushAsync().GetAwaiter().GetResult();
|
||||
var result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||
_pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace System.Buffers
|
|||
|
||||
private readonly List<Exception> _blockAccessExceptions;
|
||||
|
||||
private readonly TaskCompletionSource<object> _allBlocksRetuned;
|
||||
private readonly TaskCompletionSource<object> _allBlocksReturned;
|
||||
|
||||
private int _totalBlocks;
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ namespace System.Buffers
|
|||
_rentTracking = rentTracking;
|
||||
_blocks = new HashSet<DiagnosticPoolBlock>();
|
||||
_syncObj = new object();
|
||||
_allBlocksRetuned = new TaskCompletionSource<object>();
|
||||
_allBlocksReturned = new TaskCompletionSource<object>();
|
||||
_blockAccessExceptions = new List<Exception>();
|
||||
}
|
||||
|
||||
|
|
@ -138,11 +138,11 @@ namespace System.Buffers
|
|||
{
|
||||
if (_blockAccessExceptions.Any())
|
||||
{
|
||||
_allBlocksRetuned.SetException(CreateAccessExceptions());
|
||||
_allBlocksReturned.SetException(CreateAccessExceptions());
|
||||
}
|
||||
else
|
||||
{
|
||||
_allBlocksRetuned.SetResult(null);
|
||||
_allBlocksReturned.SetResult(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,8 +153,8 @@ namespace System.Buffers
|
|||
|
||||
public async Task WhenAllBlocksReturnedAsync(TimeSpan timeout)
|
||||
{
|
||||
var task = await Task.WhenAny(_allBlocksRetuned.Task, Task.Delay(timeout));
|
||||
if (task != _allBlocksRetuned.Task)
|
||||
var task = await Task.WhenAny(_allBlocksReturned.Task, Task.Delay(timeout));
|
||||
if (task != _allBlocksReturned.Task)
|
||||
{
|
||||
MemoryPoolThrowHelper.ThrowInvalidOperationException_BlocksWereNotReturnedInTime(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace System.Buffers
|
|||
{
|
||||
/// <summary>
|
||||
/// Slab tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The
|
||||
/// individual blocks are then treated as independant array segments.
|
||||
/// individual blocks are then treated as independent array segments.
|
||||
/// </summary>
|
||||
internal class MemoryPoolSlab : IDisposable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
else if (_requestTargetForm != HttpRequestTarget.OriginForm)
|
||||
{
|
||||
// Tail call
|
||||
ValidateNonOrginHostHeader(hostText);
|
||||
ValidateNonOriginHostHeader(hostText);
|
||||
}
|
||||
else if (!HttpUtilities.IsHostHeaderValid(hostText))
|
||||
{
|
||||
|
|
@ -364,7 +364,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
}
|
||||
|
||||
private void ValidateNonOrginHostHeader(string hostText)
|
||||
private void ValidateNonOriginHostHeader(string hostText)
|
||||
{
|
||||
if (_requestTargetForm == HttpRequestTarget.AuthorityForm)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -155,6 +155,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// TryRead can throw OperationCanceledException https://github.com/dotnet/corefx/issues/32029
|
||||
// beacuse of buggy logic, this works around that for now
|
||||
}
|
||||
catch (BadHttpRequestException ex)
|
||||
{
|
||||
// At this point, the response has already been written, so this won't result in a 4XX response;
|
||||
|
|
@ -567,8 +572,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
var extensionCursor = extensionCursorPosition.Value;
|
||||
var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;
|
||||
|
||||
var sufixBuffer = buffer.Slice(extensionCursor);
|
||||
if (sufixBuffer.Length < 2)
|
||||
var suffixBuffer = buffer.Slice(extensionCursor);
|
||||
if (suffixBuffer.Length < 2)
|
||||
{
|
||||
consumed = extensionCursor;
|
||||
examined = buffer.End;
|
||||
|
|
@ -576,16 +581,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
return;
|
||||
}
|
||||
|
||||
sufixBuffer = sufixBuffer.Slice(0, 2);
|
||||
var sufixSpan = sufixBuffer.ToSpan();
|
||||
suffixBuffer = suffixBuffer.Slice(0, 2);
|
||||
var sufixSpan = suffixBuffer.ToSpan();
|
||||
|
||||
if (sufixSpan[1] == '\n')
|
||||
{
|
||||
// We consumed the \r\n at the end of the extension, so switch modes.
|
||||
_mode = _inputLength > 0 ? Mode.Data : Mode.Trailer;
|
||||
|
||||
consumed = sufixBuffer.End;
|
||||
examined = sufixBuffer.End;
|
||||
consumed = suffixBuffer.End;
|
||||
examined = suffixBuffer.End;
|
||||
AddAndCheckConsumedBytes(charsToByteCRExclusive + 2);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -73,23 +73,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
return WriteAsync(Constants.EmptyData, cancellationToken);
|
||||
}
|
||||
|
||||
public void Write<T>(Func<PipeWriter, T, long> callback, T state)
|
||||
{
|
||||
lock (_contextLock)
|
||||
{
|
||||
if (_completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = _pipeWriter;
|
||||
var bytesCommitted = callback(buffer, state);
|
||||
_unflushedBytes += bytesCommitted;
|
||||
_totalBytesCommitted += bytesCommitted;
|
||||
}
|
||||
}
|
||||
|
||||
public Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state)
|
||||
public Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state, CancellationToken cancellationToken)
|
||||
{
|
||||
lock (_contextLock)
|
||||
{
|
||||
|
|
@ -104,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
_totalBytesCommitted += bytesCommitted;
|
||||
}
|
||||
|
||||
return FlushAsync();
|
||||
return FlushAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public void WriteResponseHeaders(int statusCode, string reasonPhrase, HttpResponseHeaders responseHeaders)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
ThrowInvalidEmtpyHeaderName();
|
||||
ThrowInvalidEmptyHeaderName();
|
||||
}
|
||||
if (value.Count == 0)
|
||||
{
|
||||
|
|
@ -177,7 +177,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
ThrowInvalidEmtpyHeaderName();
|
||||
ThrowInvalidEmptyHeaderName();
|
||||
}
|
||||
|
||||
if (value.Count > 0 && !AddValueFast(key, value))
|
||||
|
|
@ -457,7 +457,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
throw new InvalidOperationException(CoreStrings.FormatInvalidAsciiOrControlChar(string.Format("0x{0:X4}", (ushort)ch)));
|
||||
}
|
||||
|
||||
private static void ThrowInvalidEmtpyHeaderName()
|
||||
private static void ThrowInvalidEmptyHeaderName()
|
||||
{
|
||||
throw new InvalidOperationException(CoreStrings.InvalidEmptyHeaderName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -915,7 +915,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
private Task WriteChunkedAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
|
||||
{
|
||||
return Output.WriteAsync(_writeChunk, data);
|
||||
return Output.WriteAsync(_writeChunk, data, cancellationToken);
|
||||
}
|
||||
|
||||
private static long WriteChunk(PipeWriter writableBuffer, ReadOnlyMemory<byte> buffer)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
public interface IHttpOutputProducer : IDisposable
|
||||
{
|
||||
void Abort(ConnectionAbortedException abortReason);
|
||||
Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state);
|
||||
Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state, CancellationToken cancellationToken);
|
||||
Task FlushAsync(CancellationToken cancellationToken);
|
||||
Task Write100ContinueAsync();
|
||||
void WriteResponseHeaders(int statusCode, string ReasonPhrase, HttpResponseHeaders responseHeaders);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
while (true)
|
||||
{
|
||||
var result = await _context.RequestBodyPipe.Reader.ReadAsync();
|
||||
var result = await _context.RequestBodyPipe.Reader.ReadAsync(cancellationToken);
|
||||
var readableBuffer = result.Buffer;
|
||||
var consumed = readableBuffer.End;
|
||||
var actual = 0;
|
||||
|
|
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
while (true)
|
||||
{
|
||||
var result = await _context.RequestBodyPipe.Reader.ReadAsync();
|
||||
var result = await _context.RequestBodyPipe.Reader.ReadAsync(cancellationToken);
|
||||
var readableBuffer = result.Buffer;
|
||||
var consumed = readableBuffer.End;
|
||||
var bytesRead = 0;
|
||||
|
|
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
bytesRead += memory.Length;
|
||||
|
||||
#if NETCOREAPP2_1
|
||||
await destination.WriteAsync(memory);
|
||||
await destination.WriteAsync(memory, cancellationToken);
|
||||
#elif NETSTANDARD2_0
|
||||
var array = memory.GetArray();
|
||||
await destination.WriteAsync(array.Array, array.Offset, array.Count, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
const int Shift16Shift24 = (1 << 16) | (1 << 24);
|
||||
const int Shift8Identity = (1 << 8) | (1);
|
||||
|
||||
// Encode as bytes upto the first non-ASCII byte and return count encoded
|
||||
// Encode as bytes up to the first non-ASCII byte and return count encoded
|
||||
int i = 0;
|
||||
// Use Intrinsic switch
|
||||
if (IntPtr.Size == 8) // 64 bit
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
// Mimics BinaryPrimities with oddly sized units
|
||||
// Mimics BinaryPrimitives with oddly sized units
|
||||
internal class Bitshifter
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.FlowControl
|
|||
|
||||
public void Advance(int bytes)
|
||||
{
|
||||
var connectionSucess = _connectionLevelFlowControl.TryAdvance(bytes);
|
||||
var connectionSuccess = _connectionLevelFlowControl.TryAdvance(bytes);
|
||||
|
||||
Debug.Assert(connectionSucess, "Connection-level input flow control should never be aborted.");
|
||||
Debug.Assert(connectionSuccess, "Connection-level input flow control should never be aborted.");
|
||||
|
||||
if (!_streamLevelFlowControl.TryAdvance(bytes))
|
||||
{
|
||||
|
|
@ -78,9 +78,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.FlowControl
|
|||
|
||||
private void UpdateConnectionWindow(int bytes)
|
||||
{
|
||||
var connectionSucess = _connectionLevelFlowControl.TryUpdateWindow(bytes, out var connectionWindowUpdateSize);
|
||||
var connectionSuccess = _connectionLevelFlowControl.TryUpdateWindow(bytes, out var connectionWindowUpdateSize);
|
||||
|
||||
Debug.Assert(connectionSucess, "Connection-level input flow control should never be aborted.");
|
||||
Debug.Assert(connectionSuccess, "Connection-level input flow control should never be aborted.");
|
||||
|
||||
if (connectionWindowUpdateSize > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack
|
|||
|
||||
public int Length => GetLength(Name.Length, Value.Length);
|
||||
|
||||
public static int GetLength(int nameLength, int valueLenth) => nameLength + valueLenth + 32;
|
||||
public static int GetLength(int nameLength, int valueLength) => nameLength + valueLength + 32;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
private RequestHeaderParsingState _requestHeaderParsingState;
|
||||
private PseudoHeaderFields _parsedPseudoHeaderFields;
|
||||
private Http2HeadersFrameFlags _headerFlags;
|
||||
private int _totalParsedHeaderSize;
|
||||
private bool _isMethodConnect;
|
||||
private readonly object _stateLock = new object();
|
||||
private int _highestOpenedStreamId;
|
||||
|
|
@ -92,6 +93,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_serverSettings.HeaderTableSize = (uint)context.ServiceContext.ServerOptions.Limits.Http2.HeaderTableSize;
|
||||
_hpackDecoder = new HPackDecoder((int)_serverSettings.HeaderTableSize);
|
||||
_incomingFrame = new Http2Frame(_serverSettings.MaxFrameSize);
|
||||
_serverSettings.MaxHeaderListSize = (uint)context.ServiceContext.ServerOptions.Limits.MaxRequestHeadersTotalSize;
|
||||
}
|
||||
|
||||
public string ConnectionId => _context.ConnectionId;
|
||||
|
|
@ -888,6 +890,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_parsedPseudoHeaderFields = PseudoHeaderFields.None;
|
||||
_headerFlags = Http2HeadersFrameFlags.NONE;
|
||||
_isMethodConnect = false;
|
||||
_totalParsedHeaderSize = 0;
|
||||
}
|
||||
|
||||
private void ThrowIfIncomingFrameSentToIdleStream()
|
||||
|
|
@ -934,7 +937,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
Input.CancelPendingRead();
|
||||
}
|
||||
|
||||
|
||||
if (_state != Http2ConnectionState.Open)
|
||||
{
|
||||
// Complete the task waiting on all streams to finish
|
||||
|
|
@ -944,15 +946,57 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
}
|
||||
|
||||
// We can't throw a Http2StreamErrorException here, it interrupts the header decompression state and may corrupt subsequent header frames on other streams.
|
||||
// For now these either need to be connection errors or BadRequests. If we want to downgrade any of them to stream errors later then we need to
|
||||
// rework the flow so that the remaining headers are drained and the decompression state is maintained.
|
||||
public void OnHeader(Span<byte> name, Span<byte> value)
|
||||
{
|
||||
// https://tools.ietf.org/html/rfc7540#section-6.5.2
|
||||
// "The value is based on the uncompressed size of header fields, including the length of the name and value in octets plus an overhead of 32 octets for each header field.";
|
||||
_totalParsedHeaderSize += HeaderField.RfcOverhead + name.Length + value.Length;
|
||||
if (_totalParsedHeaderSize > _context.ServiceContext.ServerOptions.Limits.MaxRequestHeadersTotalSize)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
ValidateHeader(name, value);
|
||||
_currentHeadersStream.OnHeader(name, value);
|
||||
try
|
||||
{
|
||||
// Drop trailers for now. Adding them to the request headers is not thread safe.
|
||||
// https://github.com/aspnet/KestrelHttpServer/issues/2051
|
||||
if (_requestHeaderParsingState != RequestHeaderParsingState.Trailers)
|
||||
{
|
||||
// Throws BadReqeust for header count limit breaches.
|
||||
// Throws InvalidOperation for bad encoding.
|
||||
_currentHeadersStream.OnHeader(name, value);
|
||||
}
|
||||
}
|
||||
catch (BadHttpRequestException bre)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(bre.Message, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
throw new Http2ConnectionErrorException(CoreStrings.BadRequest_MalformedRequestInvalidHeaders, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateHeader(Span<byte> name, Span<byte> value)
|
||||
{
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.1
|
||||
/*
|
||||
Intermediaries that process HTTP requests or responses (i.e., any
|
||||
intermediary not acting as a tunnel) MUST NOT forward a malformed
|
||||
request or response. Malformed requests or responses that are
|
||||
detected MUST be treated as a stream error (Section 5.4.2) of type
|
||||
PROTOCOL_ERROR.
|
||||
|
||||
For malformed requests, a server MAY send an HTTP response prior to
|
||||
closing or resetting the stream. Clients MUST NOT accept a malformed
|
||||
response. Note that these requirements are intended to protect
|
||||
against several types of common attacks against HTTP; they are
|
||||
deliberately strict because being permissive can expose
|
||||
implementations to these vulnerabilities.*/
|
||||
if (IsPseudoHeaderField(name, out var headerField))
|
||||
{
|
||||
if (_requestHeaderParsingState == RequestHeaderParsingState.Headers)
|
||||
|
|
@ -960,7 +1004,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, CoreStrings.Http2ErrorPseudoHeaderFieldAfterRegularHeaders, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorPseudoHeaderFieldAfterRegularHeaders, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (_requestHeaderParsingState == RequestHeaderParsingState.Trailers)
|
||||
|
|
@ -975,21 +1019,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, CoreStrings.Http2ErrorUnknownPseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(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, CoreStrings.Http2ErrorResponsePseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(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, CoreStrings.Http2ErrorDuplicatePseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorDuplicatePseudoHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
if (headerField == PseudoHeaderFields.Method)
|
||||
|
|
@ -1006,7 +1050,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
if (IsConnectionSpecificHeaderField(name, value))
|
||||
{
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorConnectionSpecificHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorConnectionSpecificHeaderField, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
// http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2
|
||||
|
|
@ -1021,7 +1065,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorHeaderNameUppercase, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorHeaderNameUppercase, Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
*/
|
||||
public partial class Http2Frame
|
||||
{
|
||||
private const int SettingSize = 6; // 2 bytes for the id, 4 bytes for the value.
|
||||
internal const int SettingSize = 6; // 2 bytes for the id, 4 bytes for the value.
|
||||
|
||||
public Http2SettingsFrameFlags SettingsFlags
|
||||
{
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
Dispose();
|
||||
}
|
||||
|
||||
public Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state)
|
||||
public Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return true;
|
||||
}
|
||||
|
||||
// Approximate MaxRequestLineSize by totaling the required pseudo header field lengths.
|
||||
var requestLineLength = _methodText.Length + Scheme.Length + hostText.Length + path.Length;
|
||||
if (requestLineLength > ServiceContext.ServerOptions.Limits.MaxRequestLineSize)
|
||||
{
|
||||
ResetAndAbort(new ConnectionAbortedException(CoreStrings.BadRequest_RequestLineTooLong), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
var queryIndex = path.IndexOf('?');
|
||||
QueryString = queryIndex == -1 ? string.Empty : path.Substring(queryIndex);
|
||||
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
if (rate < minRequestBodyDataRate.BytesPerSecond && !Debugger.IsAttached)
|
||||
{
|
||||
Log.RequestBodyMininumDataRateNotSatisfied(_context.ConnectionId, _http1Connection.TraceIdentifier, minRequestBodyDataRate.BytesPerSecond);
|
||||
Log.RequestBodyMinimumDataRateNotSatisfied(_context.ConnectionId, _http1Connection.TraceIdentifier, minRequestBodyDataRate.BytesPerSecond);
|
||||
RequestTimedOut = true;
|
||||
_http1Connection.SendTimeoutResponse();
|
||||
}
|
||||
|
|
@ -492,7 +492,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
if (_writeTimingWrites > 0 && timestamp > _writeTimingTimeoutTimestamp && !Debugger.IsAttached)
|
||||
{
|
||||
RequestTimedOut = true;
|
||||
Log.ResponseMininumDataRateNotSatisfied(_http1Connection.ConnectionIdFeature, _http1Connection.TraceIdentifier);
|
||||
Log.ResponseMinimumDataRateNotSatisfied(_http1Connection.ConnectionIdFeature, _http1Connection.TraceIdentifier);
|
||||
Abort(new ConnectionAbortedException(CoreStrings.ConnectionTimedBecauseResponseMininumDataRateNotSatisfied));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
|||
|
||||
void RequestBodyDrainTimedOut(string connectionId, string traceIdentifier);
|
||||
|
||||
void RequestBodyMininumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate);
|
||||
void RequestBodyMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate);
|
||||
|
||||
void ResponseMininumDataRateNotSatisfied(string connectionId, string traceIdentifier);
|
||||
void ResponseMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier);
|
||||
|
||||
void ApplicationAbortedConnection(string connectionId, string traceIdentifier);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,10 +64,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
LoggerMessage.Define<string, string>(LogLevel.Debug, new EventId(26, nameof(RequestBodyDone)), @"Connection id ""{ConnectionId}"", Request id ""{TraceIdentifier}"": done reading request body.");
|
||||
|
||||
private static readonly Action<ILogger, string, string, double, Exception> _requestBodyMinimumDataRateNotSatisfied =
|
||||
LoggerMessage.Define<string, string, double>(LogLevel.Information, new EventId(27, nameof(RequestBodyMininumDataRateNotSatisfied)), @"Connection id ""{ConnectionId}"", Request id ""{TraceIdentifier}"": the request timed out because it was not sent by the client at a minimum of {Rate} bytes/second.");
|
||||
LoggerMessage.Define<string, string, double>(LogLevel.Information, new EventId(27, nameof(RequestBodyMinimumDataRateNotSatisfied)), @"Connection id ""{ConnectionId}"", Request id ""{TraceIdentifier}"": the request timed out because it was not sent by the client at a minimum of {Rate} bytes/second.");
|
||||
|
||||
private static readonly Action<ILogger, string, string, Exception> _responseMinimumDataRateNotSatisfied =
|
||||
LoggerMessage.Define<string, string>(LogLevel.Information, new EventId(28, nameof(ResponseMininumDataRateNotSatisfied)), @"Connection id ""{ConnectionId}"", Request id ""{TraceIdentifier}"": the connection was closed because the response was not read by the client at the specified minimum data rate.");
|
||||
LoggerMessage.Define<string, string>(LogLevel.Information, new EventId(28, nameof(ResponseMinimumDataRateNotSatisfied)), @"Connection id ""{ConnectionId}"", Request id ""{TraceIdentifier}"": the connection was closed because 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, new EventId(29, nameof(Http2ConnectionError)), @"Connection id ""{ConnectionId}"": HTTP/2 connection error.");
|
||||
|
|
@ -199,7 +199,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
_requestBodyDone(_logger, connectionId, traceIdentifier, null);
|
||||
}
|
||||
|
||||
public virtual void RequestBodyMininumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate)
|
||||
public virtual void RequestBodyMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate)
|
||||
{
|
||||
_requestBodyMinimumDataRateNotSatisfied(_logger, connectionId, traceIdentifier, rate, null);
|
||||
}
|
||||
|
|
@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
_requestBodyDrainTimedOut(_logger, connectionId, traceIdentifier, null);
|
||||
}
|
||||
|
||||
public virtual void ResponseMininumDataRateNotSatisfied(string connectionId, string traceIdentifier)
|
||||
public virtual void ResponseMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier)
|
||||
{
|
||||
_responseMinimumDataRateNotSatisfied(_logger, connectionId, traceIdentifier, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
/// Defaults to 8,192 bytes (8 KB).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For HTTP/2 this measures the total size of the required pseudo headers
|
||||
/// :method, :scheme, :authority, and :path.
|
||||
/// </remarks>
|
||||
public int MaxRequestLineSize
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
|||
(handle, status, state) => ReadCallback(handle, status, state);
|
||||
|
||||
private static readonly Func<UvStreamHandle, int, object, LibuvFunctions.uv_buf_t> _allocCallback =
|
||||
(handle, suggestedsize, state) => AllocCallback(handle, suggestedsize, state);
|
||||
(handle, suggestedSize, state) => AllocCallback(handle, suggestedSize, state);
|
||||
|
||||
private readonly UvStreamHandle _socket;
|
||||
private readonly CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource();
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
|||
protected virtual void DispatchConnection(UvStreamHandle socket)
|
||||
{
|
||||
// REVIEW: This task should be tracked by the server for graceful shutdown
|
||||
// Today it's handled specifically for http but not for aribitrary middleware
|
||||
// Today it's handled specifically for http but not for arbitrary middleware
|
||||
_ = HandleConnectionAsync(socket);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
|||
DispatchPipe.Accept(acceptSocket);
|
||||
|
||||
// REVIEW: This task should be tracked by the server for graceful shutdown
|
||||
// Today it's handled specifically for http but not for aribitrary middleware
|
||||
// Today it's handled specifically for http but not for arbitrary middleware
|
||||
_ = HandleConnectionAsync(acceptSocket);
|
||||
}
|
||||
catch (UvException ex) when (LibuvConstants.IsConnectionReset(ex.StatusCode))
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
|||
int family = (int)_field0;
|
||||
if (PlatformApis.IsDarwin)
|
||||
{
|
||||
// see explaination in example 4
|
||||
// see explanation in example 4
|
||||
family = family >> 8;
|
||||
}
|
||||
family = family & 0xFF;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
_httpConnection.Debugger = mockDebugger.Object;
|
||||
var bytesPerSecond = 100;
|
||||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
mockLogger.Setup(l => l.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>())).Throws(new InvalidOperationException("Should not log"));
|
||||
mockLogger.Setup(l => l.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>())).Throws(new InvalidOperationException("Should not log"));
|
||||
|
||||
TickBodyWithMinimumDataRate(mockLogger.Object, bytesPerSecond);
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Timed out
|
||||
Assert.True(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
|
||||
}
|
||||
|
||||
private void TickBodyWithMinimumDataRate(IKestrelTrace logger, int bytesPerSecond)
|
||||
|
|
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
|
||||
// Tick after grace period w/ low data rate
|
||||
now += TimeSpan.FromSeconds(2);
|
||||
|
|
@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Timed out
|
||||
Assert.True(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -202,7 +202,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
|
||||
// Data rate: 150 bytes/second
|
||||
now += TimeSpan.FromSeconds(1);
|
||||
|
|
@ -212,7 +212,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
|
||||
// Data rate: 120 bytes/second
|
||||
now += TimeSpan.FromSeconds(1);
|
||||
|
|
@ -222,7 +222,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
|
||||
// Data rate: 100 bytes/second
|
||||
now += TimeSpan.FromSeconds(1);
|
||||
|
|
@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
|
||||
|
||||
// Data rate: ~85 bytes/second
|
||||
now += TimeSpan.FromSeconds(1);
|
||||
|
|
@ -242,7 +242,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Timed out
|
||||
Assert.True(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(logger =>
|
||||
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
|
||||
logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -285,7 +285,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(
|
||||
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
logger => logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
Times.Never);
|
||||
|
||||
// Resume at 6.5s
|
||||
|
|
@ -299,7 +299,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(
|
||||
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
logger => logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
Times.Never);
|
||||
|
||||
// Tick at 10s, expected counted time is 7s, expected data rate drops below 100 bytes/second
|
||||
|
|
@ -309,7 +309,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Timed out
|
||||
Assert.True(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(
|
||||
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
logger => logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(
|
||||
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
logger => logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
Times.Never);
|
||||
|
||||
// Pause at 2.25s
|
||||
|
|
@ -360,7 +360,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Not timed out
|
||||
Assert.False(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(
|
||||
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
logger => logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
Times.Never);
|
||||
|
||||
// Tick at 4s, expected counted time is 4s, expected data rate drops below 100 bytes/second
|
||||
|
|
@ -370,7 +370,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
// Timed out
|
||||
Assert.True(_httpConnection.RequestTimedOut);
|
||||
mockLogger.Verify(
|
||||
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
logger => logger.RequestBodyMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
|
@ -539,7 +539,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteTimingAbortsConnectionWhenRepeadtedSmallWritesDoNotCompleteWithMinimumDataRate()
|
||||
public async Task WriteTimingAbortsConnectionWhenRepeatedSmallWritesDoNotCompleteWithMinimumDataRate()
|
||||
{
|
||||
var systemClock = new MockSystemClock();
|
||||
var minResponseDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(5));
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
}
|
||||
|
||||
// Doesn't put empty blocks inbetween every byte
|
||||
// Doesn't put empty blocks in between every byte
|
||||
internal class BytePerSegmentTestSequenceFactory : ReadOnlySequenceFactory
|
||||
{
|
||||
public static ReadOnlySequenceFactory Instance { get; } = new HttpParserTests.BytePerSegmentTestSequenceFactory();
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
await body.StopAsync();
|
||||
|
||||
// Add some more data. Checking for cancelation and exiting the loop
|
||||
// Add some more data. Checking for cancellation and exiting the loop
|
||||
// should take priority over reading this data.
|
||||
input.Add("b");
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Buffers;
|
||||
using System.IO.Pipelines;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||
|
|
@ -31,7 +32,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void WritesNoopAfterConnectionCloses()
|
||||
public async Task WritesNoopAfterConnectionCloses()
|
||||
{
|
||||
var pipeOptions = new PipeOptions
|
||||
(
|
||||
|
|
@ -48,12 +49,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
var called = false;
|
||||
|
||||
socketOutput.Write((buffer, state) =>
|
||||
await socketOutput.WriteAsync((buffer, state) =>
|
||||
{
|
||||
called = true;
|
||||
return 0;
|
||||
},
|
||||
0);
|
||||
0,
|
||||
default);
|
||||
|
||||
Assert.False(called);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
|
||||
new KeyValuePair<string, string>("a", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _largeHeaderValue)
|
||||
new KeyValuePair<string, string>("a", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _4kHeaderValue)
|
||||
};
|
||||
|
||||
private static readonly IEnumerable<KeyValuePair<string, string>> _twoContinuationsRequestHeaders = new[]
|
||||
|
|
@ -63,14 +63,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
|
||||
new KeyValuePair<string, string>("a", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("e", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("f", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("g", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("h", _largeHeaderValue)
|
||||
new KeyValuePair<string, string>("a", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("e", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("f", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("g", _4kHeaderValue),
|
||||
};
|
||||
|
||||
private static readonly byte[] _helloBytes = Encoding.ASCII.GetBytes("hello");
|
||||
|
|
@ -102,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
_connectionContext.ServiceContext.ServerOptions.Limits.Http2.MaxFrameSize = length;
|
||||
_connection = new Http2Connection(_connectionContext);
|
||||
|
||||
await InitializeConnectionAsync(_echoApplication, expectedSettingsLegnth: 12);
|
||||
await InitializeConnectionAsync(_echoApplication, expectedSettingsCount: 3);
|
||||
|
||||
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
|
||||
await SendDataAsync(1, new byte[length].AsSpan(), endStream: true);
|
||||
|
|
@ -1067,7 +1066,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task HEADERS_Received_WithTrailers_Decoded(bool sendData)
|
||||
public async Task HEADERS_Received_WithTrailers_Discarded(bool sendData)
|
||||
{
|
||||
await InitializeConnectionAsync(_readTrailersApplication);
|
||||
|
||||
|
|
@ -1105,7 +1104,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
withFlags: (byte)Http2DataFrameFlags.END_STREAM,
|
||||
withStreamId: 1);
|
||||
|
||||
VerifyDecodedRequestHeaders(_browserRequestHeaders.Concat(_requestTrailers));
|
||||
VerifyDecodedRequestHeaders(_browserRequestHeaders);
|
||||
|
||||
// Make sure the trailers are missing. https://github.com/aspnet/KestrelHttpServer/issues/2630
|
||||
foreach (var header in _requestTrailers)
|
||||
{
|
||||
Assert.False(_receivedHeaders.ContainsKey(header.Key));
|
||||
}
|
||||
|
||||
await StopConnectionAsync(expectedLastStreamId: 3, ignoreNonGoAwayFrames: false);
|
||||
}
|
||||
|
|
@ -1454,27 +1459,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
[Theory]
|
||||
[MemberData(nameof(UpperCaseHeaderNameData))]
|
||||
public async Task HEADERS_Received_HeaderNameContainsUpperCaseCharacter_StreamError(byte[] headerBlock)
|
||||
public async Task HEADERS_Received_HeaderNameContainsUpperCaseCharacter_ConnectionError(byte[] headerBlock)
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, headerBlock);
|
||||
await WaitForStreamErrorAsync(
|
||||
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<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.STREAM_CLOSED,
|
||||
expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.HEADERS, streamId: 1));
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: CoreStrings.Http2ErrorHeaderNameUppercase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsUnknownPseudoHeaderField_StreamError()
|
||||
public Task HEADERS_Received_HeaderBlockContainsUnknownPseudoHeaderField_ConnectionError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
|
|
@ -1484,11 +1482,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(":unknown", "0"),
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorUnknownPseudoHeaderField);
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, expectedErrorMessage: CoreStrings.Http2ErrorUnknownPseudoHeaderField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsResponsePseudoHeaderField_StreamError()
|
||||
public Task HEADERS_Received_HeaderBlockContainsResponsePseudoHeaderField_ConnectionError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
|
|
@ -1498,21 +1496,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(HeaderNames.Status, "200"),
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorResponsePseudoHeaderField);
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, expectedErrorMessage: CoreStrings.Http2ErrorResponsePseudoHeaderField);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(DuplicatePseudoHeaderFieldData))]
|
||||
public Task HEADERS_Received_HeaderBlockContainsDuplicatePseudoHeaderField_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
public Task HEADERS_Received_HeaderBlockContainsDuplicatePseudoHeaderField_ConnectionError(IEnumerable<KeyValuePair<string, string>> 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, expectedErrorMessage: CoreStrings.Http2ErrorMissingMandatoryPseudoHeaderFields);
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, expectedErrorMessage: CoreStrings.Http2ErrorDuplicatePseudoHeaderField);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1537,20 +1528,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
[Theory]
|
||||
[MemberData(nameof(PseudoHeaderFieldAfterRegularHeadersData))]
|
||||
public Task HEADERS_Received_HeaderBlockContainsPseudoHeaderFieldAfterRegularHeaders_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
public Task HEADERS_Received_HeaderBlockContainsPseudoHeaderFieldAfterRegularHeaders_ConnectionError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
{
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, expectedErrorMessage: CoreStrings.Http2ErrorPseudoHeaderFieldAfterRegularHeaders);
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, expectedErrorMessage: CoreStrings.Http2ErrorPseudoHeaderFieldAfterRegularHeaders);
|
||||
}
|
||||
|
||||
private async Task HEADERS_Received_InvalidHeaderFields_StreamError(IEnumerable<KeyValuePair<string, string>> headers, string expectedErrorMessage)
|
||||
private async Task HEADERS_Received_InvalidHeaderFields_ConnectionError(IEnumerable<KeyValuePair<string, string>> headers, string expectedErrorMessage)
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
await StartStreamAsync(1, headers, endStream: true);
|
||||
await WaitForConnectionErrorAsync<Http2ConnectionErrorException>(
|
||||
ignoreNonGoAwayFrames: false,
|
||||
expectedLastStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: expectedErrorMessage);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MissingPseudoHeaderFieldData))]
|
||||
public async Task HEADERS_Received_HeaderBlockDoesNotContainMandatoryPseudoHeaderField_StreamError(IEnumerable<KeyValuePair<string, string>> headers)
|
||||
{
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS, headers);
|
||||
await WaitForStreamErrorAsync(
|
||||
expectedStreamId: 1,
|
||||
expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR,
|
||||
expectedErrorMessage: expectedErrorMessage);
|
||||
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, _browserRequestHeaders);
|
||||
|
|
@ -1562,7 +1566,62 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsConnectionHeader_StreamError()
|
||||
public Task HEADERS_Received_HeaderBlockOverLimit_ConnectionError()
|
||||
{
|
||||
// > 32kb
|
||||
var headers = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>("a", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("e", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("f", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("g", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("h", _4kHeaderValue),
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, CoreStrings.BadRequest_HeadersExceedMaxTotalSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_TooManyHeaders_ConnectionError()
|
||||
{
|
||||
// > MaxRequestHeaderCount (100)
|
||||
var headers = new List<KeyValuePair<string, string>>();
|
||||
headers.AddRange(new []
|
||||
{
|
||||
new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
});
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
headers.Add(new KeyValuePair<string, string>(i.ToString(), i.ToString()));
|
||||
}
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, CoreStrings.BadRequest_TooManyHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_InvalidCharacters_ConnectionError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>("Custom", "val\0ue"),
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, CoreStrings.BadRequest_MalformedRequestInvalidHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsConnectionHeader_ConnectionError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
|
|
@ -1572,11 +1631,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>("connection", "keep-alive")
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, CoreStrings.Http2ErrorConnectionSpecificHeaderField);
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, CoreStrings.Http2ErrorConnectionSpecificHeaderField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task HEADERS_Received_HeaderBlockContainsTEHeader_ValueIsNotTrailers_StreamError()
|
||||
public Task HEADERS_Received_HeaderBlockContainsTEHeader_ValueIsNotTrailers_ConnectionError()
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
|
|
@ -1586,7 +1645,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>("te", "trailers, deflate")
|
||||
};
|
||||
|
||||
return HEADERS_Received_InvalidHeaderFields_StreamError(headers, CoreStrings.Http2ErrorConnectionSpecificHeaderField);
|
||||
return HEADERS_Received_InvalidHeaderFields_ConnectionError(headers, CoreStrings.Http2ErrorConnectionSpecificHeaderField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -2005,18 +2064,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendSettingsAsync();
|
||||
|
||||
var frame = await ExpectAsync(Http2FrameType.SETTINGS,
|
||||
withLength: 6,
|
||||
withLength: Http2Frame.SettingSize * 2,
|
||||
withFlags: 0,
|
||||
withStreamId: 0);
|
||||
|
||||
// Only non protocol defaults are sent
|
||||
Assert.Equal(1, frame.SettingsCount);
|
||||
Assert.Equal(2, frame.SettingsCount);
|
||||
var settings = frame.GetSettings();
|
||||
Assert.Equal(1, settings.Count);
|
||||
Assert.Equal(2, settings.Count);
|
||||
|
||||
var setting = settings[0];
|
||||
Assert.Equal(Http2SettingsParameter.SETTINGS_MAX_CONCURRENT_STREAMS, setting.Parameter);
|
||||
Assert.Equal(100u, setting.Value);
|
||||
|
||||
setting = settings[1];
|
||||
Assert.Equal(Http2SettingsParameter.SETTINGS_MAX_HEADER_LIST_SIZE, setting.Parameter);
|
||||
Assert.Equal(32 * 1024u, setting.Value);
|
||||
|
||||
await ExpectAsync(Http2FrameType.SETTINGS,
|
||||
withLength: 0,
|
||||
withFlags: (byte)Http2SettingsFrameFlags.ACK,
|
||||
|
|
@ -2029,6 +2093,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
public async Task SETTINGS_Custom_Sent()
|
||||
{
|
||||
_connection.ServerSettings.MaxConcurrentStreams = 1;
|
||||
_connection.ServerSettings.MaxHeaderListSize = 4 * 1024;
|
||||
|
||||
_connectionTask = _connection.ProcessRequestsAsync(new DummyApplication(_noopApplication));
|
||||
|
||||
|
|
@ -2036,18 +2101,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendSettingsAsync();
|
||||
|
||||
var frame = await ExpectAsync(Http2FrameType.SETTINGS,
|
||||
withLength: 6,
|
||||
withLength: 6 * 2,
|
||||
withFlags: 0,
|
||||
withStreamId: 0);
|
||||
|
||||
// Only non protocol defaults are sent
|
||||
Assert.Equal(1, frame.SettingsCount);
|
||||
Assert.Equal(2, frame.SettingsCount);
|
||||
var settings = frame.GetSettings();
|
||||
Assert.Equal(1, settings.Count);
|
||||
Assert.Equal(2, settings.Count);
|
||||
|
||||
var setting = settings[0];
|
||||
Assert.Equal(Http2SettingsParameter.SETTINGS_MAX_CONCURRENT_STREAMS, setting.Parameter);
|
||||
Assert.Equal(1u, setting.Value);
|
||||
|
||||
setting = settings[1];
|
||||
Assert.Equal(Http2SettingsParameter.SETTINGS_MAX_HEADER_LIST_SIZE, setting.Parameter);
|
||||
Assert.Equal(4 * 1024u, setting.Value);
|
||||
|
||||
await ExpectAsync(Http2FrameType.SETTINGS,
|
||||
withLength: 0,
|
||||
withFlags: (byte)Http2SettingsFrameFlags.ACK,
|
||||
|
|
@ -2945,7 +3015,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CONTINUATION_Received_WithTrailers_Decoded(bool sendData)
|
||||
public async Task CONTINUATION_Received_WithTrailers_Discarded(bool sendData)
|
||||
{
|
||||
await InitializeConnectionAsync(_readTrailersApplication);
|
||||
|
||||
|
|
@ -2994,11 +3064,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
withFlags: (byte)Http2DataFrameFlags.END_STREAM,
|
||||
withStreamId: 1);
|
||||
|
||||
VerifyDecodedRequestHeaders(_browserRequestHeaders.Concat(new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("trailer-1", "1"),
|
||||
new KeyValuePair<string, string>("trailer-2", "2")
|
||||
}));
|
||||
VerifyDecodedRequestHeaders(_browserRequestHeaders);
|
||||
|
||||
// Make sure the trailers are missing. https://github.com/aspnet/KestrelHttpServer/issues/2630
|
||||
Assert.False(_receivedHeaders.ContainsKey("trailer-1"));
|
||||
Assert.False(_receivedHeaders.ContainsKey("trailer-2"));
|
||||
|
||||
await StopConnectionAsync(expectedLastStreamId: 3, ignoreNonGoAwayFrames: false);
|
||||
}
|
||||
|
|
@ -3128,14 +3198,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Assert.Contains("date", _decodedHeaders.Keys, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.Equal("200", _decodedHeaders[HeaderNames.Status]);
|
||||
Assert.Equal("0", _decodedHeaders["content-length"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["a"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["b"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["c"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["d"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["e"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["f"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["g"]);
|
||||
Assert.Equal(_largeHeaderValue, _decodedHeaders["h"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["a"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["b"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["c"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["d"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["e"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["f"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["g"]);
|
||||
Assert.Equal(_4kHeaderValue, _decodedHeaders["h"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -569,6 +569,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HEADERS_Received_MaxRequestLineSize_Reset()
|
||||
{
|
||||
// Default 8kb limit
|
||||
// This test has to work around the HPack parser limit for incoming field sizes over 4kb. That's going to be a problem for people with long urls.
|
||||
// https://github.com/aspnet/KestrelHttpServer/issues/2872
|
||||
var headers = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>(HeaderNames.Method, "GET" + new string('a', 1024 * 3)),
|
||||
new KeyValuePair<string, string>(HeaderNames.Path, "/Hello/How/Are/You/" + new string('a', 1024 * 3)),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Authority, "localhost" + new string('a', 1024 * 3) + ":80"),
|
||||
};
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
||||
await StartStreamAsync(1, headers, endStream: true);
|
||||
|
||||
await WaitForStreamErrorAsync(expectedStreamId: 1, Http2ErrorCode.PROTOCOL_ERROR, CoreStrings.BadRequest_RequestLineTooLong);
|
||||
|
||||
await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ContentLength_Received_SingleDataFrame_Verified()
|
||||
{
|
||||
|
|
@ -623,10 +645,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>("a", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("a", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>(HeaderNames.ContentLength, "12"),
|
||||
};
|
||||
await StartStreamAsync(1, headers, endStream: false);
|
||||
|
|
@ -726,10 +748,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Path, "/"),
|
||||
new KeyValuePair<string, string>(HeaderNames.Scheme, "http"),
|
||||
new KeyValuePair<string, string>("a", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _largeHeaderValue),
|
||||
new KeyValuePair<string, string>("a", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("b", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("c", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>("d", _4kHeaderValue),
|
||||
new KeyValuePair<string, string>(HeaderNames.ContentLength, "12"),
|
||||
};
|
||||
await InitializeConnectionAsync(_noopApplication);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
public class Http2TestBase : TestApplicationErrorLoggerLoggedTest, IDisposable, IHttpHeadersHandler
|
||||
{
|
||||
protected static readonly string _largeHeaderValue = new string('a', HPackDecoder.MaxStringOctets);
|
||||
protected static readonly string _4kHeaderValue = new string('a', HPackDecoder.MaxStringOctets);
|
||||
|
||||
protected static readonly IEnumerable<KeyValuePair<string, string>> _browserRequestHeaders = new[]
|
||||
{
|
||||
|
|
@ -174,7 +174,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
foreach (var name in new[] { "a", "b", "c", "d", "e", "f", "g", "h" })
|
||||
{
|
||||
context.Response.Headers[name] = _largeHeaderValue;
|
||||
context.Response.Headers[name] = _4kHeaderValue;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
|
@ -307,7 +307,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
_decodedHeaders[name.GetAsciiStringNonNullCharacters()] = value.GetAsciiOrUTF8StringNonNullCharacters();
|
||||
}
|
||||
|
||||
protected async Task InitializeConnectionAsync(RequestDelegate application, int expectedSettingsLegnth = 6)
|
||||
protected async Task InitializeConnectionAsync(RequestDelegate application, int expectedSettingsCount = 2)
|
||||
{
|
||||
_connectionTask = _connection.ProcessRequestsAsync(new DummyApplication(application));
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
await SendSettingsAsync();
|
||||
|
||||
await ExpectAsync(Http2FrameType.SETTINGS,
|
||||
withLength: expectedSettingsLegnth,
|
||||
withLength: expectedSettingsCount * 6,
|
||||
withFlags: 0,
|
||||
withStreamId: 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,11 +35,34 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public Task Server_Http2Only_Cleartext_Success()
|
||||
public async Task Server_Http2Only_Cleartext_Success()
|
||||
{
|
||||
// Expect a SETTINGS frame (type 0x4) with default settings
|
||||
return TestSuccess(HttpProtocols.Http2, Encoding.ASCII.GetString(Http2Connection.ClientPreface),
|
||||
"\x00\x00\x06\x04\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x64");
|
||||
var expected = new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x0C, // Payload Length (6 * settings count)
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // SETTINGS frame (type 0x04)
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x64, // Connection limit
|
||||
0x00, 0x06, 0x00, 0x00, 0x80, 0x00 // Header size limit
|
||||
};
|
||||
var testContext = new TestServiceContext(LoggerFactory);
|
||||
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0))
|
||||
{
|
||||
Protocols = HttpProtocols.Http2
|
||||
};
|
||||
|
||||
using (var server = new TestServer(context => Task.CompletedTask, testContext, listenOptions))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
await connection.Send(Encoding.ASCII.GetString(Http2Connection.ClientPreface));
|
||||
// Can't use Receive when expecting binary data
|
||||
var actual = new byte[expected.Length];
|
||||
var read = await connection.Stream.ReadAsync(actual, 0, actual.Length);
|
||||
Assert.Equal(expected.Length, read);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TestSuccess(HttpProtocols serverProtocols, string request, string expectedResponse)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.IO.Pipelines;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
|
@ -55,6 +56,73 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestBodyReadAsyncCanBeCancelled()
|
||||
{
|
||||
var helloTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
using (var server = new TestServer(async context =>
|
||||
{
|
||||
var buffer = new byte[1024];
|
||||
try
|
||||
{
|
||||
|
||||
int read = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length, cts.Token);
|
||||
|
||||
Assert.Equal("Hello ", Encoding.UTF8.GetString(buffer, 0, read));
|
||||
|
||||
helloTcs.TrySetResult(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// This shouldn't fail
|
||||
helloTcs.TrySetException(ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await context.Request.Body.ReadAsync(buffer, 0, buffer.Length, cts.Token);
|
||||
|
||||
context.Response.ContentLength = 12;
|
||||
await context.Response.WriteAsync("Read success");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
context.Response.ContentLength = 14;
|
||||
await context.Response.WriteAsync("Read cancelled");
|
||||
}
|
||||
|
||||
}, new TestServiceContext(LoggerFactory)))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
await connection.Send(
|
||||
"POST / HTTP/1.1",
|
||||
"Host:",
|
||||
"Connection: keep-alive",
|
||||
"Content-Length: 11",
|
||||
"",
|
||||
"");
|
||||
|
||||
await connection.Send("Hello ");
|
||||
|
||||
await helloTcs.Task;
|
||||
|
||||
// Cancel the body after hello is read
|
||||
cts.Cancel();
|
||||
|
||||
await connection.Send("World");
|
||||
|
||||
await connection.Receive($"HTTP/1.1 200 OK",
|
||||
$"Date: {server.Context.DateHeaderValue}",
|
||||
"Content-Length: 14",
|
||||
"",
|
||||
"Read cancelled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanUpgradeRequestWithConnectionKeepAliveUpgradeHeader()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
|
@ -99,6 +100,61 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ResponseBodyWriteAsyncCanBeCancelled()
|
||||
{
|
||||
var serviceContext = new TestServiceContext(LoggerFactory);
|
||||
serviceContext.ServerOptions.Limits.MaxResponseBufferSize = 5;
|
||||
var cts = new CancellationTokenSource();
|
||||
var appTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var writeReturnedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
using (var server = new TestServer(async context =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await context.Response.WriteAsync("hello", cts.Token).DefaultTimeout();
|
||||
writeReturnedTcs.TrySetResult(null);
|
||||
|
||||
var task = context.Response.WriteAsync("world", cts.Token);
|
||||
Assert.False(task.IsCompleted);
|
||||
await task.DefaultTimeout();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
appTcs.TrySetException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
appTcs.TrySetResult(null);
|
||||
writeReturnedTcs.TrySetCanceled();
|
||||
}
|
||||
}, serviceContext))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
await connection.Send(
|
||||
"GET / HTTP/1.1",
|
||||
"Host:",
|
||||
"",
|
||||
"");
|
||||
|
||||
await connection.Receive($"HTTP/1.1 200 OK",
|
||||
$"Date: {server.Context.DateHeaderValue}",
|
||||
"Transfer-Encoding: chunked",
|
||||
"",
|
||||
"5",
|
||||
"hello");
|
||||
|
||||
await writeReturnedTcs.Task.DefaultTimeout();
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(() => appTcs.Task).DefaultTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task ResponseStatusCodeSetBeforeHttpContextDisposeAppException()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
|||
public class ConfigurationReaderTests
|
||||
{
|
||||
[Fact]
|
||||
public void ReadCertificatesWhenNoCertificatsSection_ReturnsEmptyCollection()
|
||||
public void ReadCertificatesWhenNoCertificatesSection_ReturnsEmptyCollection()
|
||||
{
|
||||
var config = new ConfigurationBuilder().AddInMemoryCollection().Build();
|
||||
var reader = new ConfigurationReader(config);
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
RunTestWithStaticPort(port => RegisterAddresses_Success($"{addressInput}:{port}", testUrls, port));
|
||||
|
||||
[Fact]
|
||||
public async Task RegisterHttpAddress_UpradedToHttpsByConfigureEndpointDefaults()
|
||||
public async Task RegisterHttpAddress_UpgradedToHttpsByConfigureEndpointDefaults()
|
||||
{
|
||||
var hostBuilder = TransportSelector.GetWebHostBuilder()
|
||||
.UseKestrel(serverOptions =>
|
||||
|
|
@ -676,14 +676,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
[Theory]
|
||||
[InlineData("ftp://localhost")]
|
||||
[InlineData("ssh://localhost")]
|
||||
public void ThrowsForUnsupportedAddressFromHosting(string addr)
|
||||
public void ThrowsForUnsupportedAddressFromHosting(string address)
|
||||
{
|
||||
TestApplicationErrorLogger.IgnoredExceptions.Add(typeof(InvalidOperationException));
|
||||
|
||||
var hostBuilder = TransportSelector.GetWebHostBuilder()
|
||||
.ConfigureServices(AddTestLogging)
|
||||
.UseKestrel()
|
||||
.UseUrls(addr)
|
||||
.UseUrls(address)
|
||||
.Configure(ConfigureEchoAddress);
|
||||
|
||||
using (var host = hostBuilder.Build())
|
||||
|
|
@ -786,7 +786,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
|
||||
using (var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
// Bind first to IPv6Any to ensure both the IPv4 and IPv6 ports are avaiable.
|
||||
// Bind first to IPv6Any to ensure both the IPv4 and IPv6 ports are available.
|
||||
socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
|
||||
socket.Listen(0);
|
||||
port = ((IPEndPoint)socket.LocalEndPoint).Port;
|
||||
|
|
|
|||
|
|
@ -658,7 +658,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
await Assert.ThrowsAsync<TaskCanceledException>(async () => await readTcs.Task);
|
||||
|
||||
// The cancellation token for only the last request should be triggered.
|
||||
var abortedRequestId = await registrationTcs.Task;
|
||||
var abortedRequestId = await registrationTcs.Task.DefaultTimeout();
|
||||
Assert.Equal(2, abortedRequestId);
|
||||
|
||||
Assert.Single(TestSink.Writes.Where(w => w.LoggerName == "Microsoft.AspNetCore.Server.Kestrel" &&
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
|
||||
var mockKestrelTrace = new Mock<IKestrelTrace>();
|
||||
mockKestrelTrace
|
||||
.Setup(trace => trace.ResponseMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Setup(trace => trace.ResponseMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Callback(() => responseRateTimeoutMessageLogged.SetResult(null));
|
||||
mockKestrelTrace
|
||||
.Setup(trace => trace.ConnectionStop(It.IsAny<string>()))
|
||||
|
|
@ -560,7 +560,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
|
||||
var mockKestrelTrace = new Mock<IKestrelTrace>();
|
||||
mockKestrelTrace
|
||||
.Setup(trace => trace.ResponseMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Setup(trace => trace.ResponseMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Callback(() => responseRateTimeoutMessageLogged.SetResult(null));
|
||||
mockKestrelTrace
|
||||
.Setup(trace => trace.ConnectionStop(It.IsAny<string>()))
|
||||
|
|
@ -645,7 +645,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
|
||||
var mockKestrelTrace = new Mock<IKestrelTrace>();
|
||||
mockKestrelTrace
|
||||
.Setup(trace => trace.ResponseMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Setup(trace => trace.ResponseMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Callback(() => responseRateTimeoutMessageLogged.SetResult(null));
|
||||
mockKestrelTrace
|
||||
.Setup(trace => trace.ConnectionStop(It.IsAny<string>()))
|
||||
|
|
@ -779,7 +779,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
await AssertStreamCompleted(connection.Stream, minTotalOutputSize, targetBytesPerSecond);
|
||||
await appFuncCompleted.Task.DefaultTimeout();
|
||||
|
||||
mockKestrelTrace.Verify(t => t.ResponseMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
mockKestrelTrace.Verify(t => t.ResponseMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
mockKestrelTrace.Verify(t => t.ConnectionStop(It.IsAny<string>()), Times.Once());
|
||||
Assert.False(requestAborted);
|
||||
}
|
||||
|
|
@ -854,7 +854,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
var targetBytesPerSecond = responseSize / 4;
|
||||
await AssertStreamCompleted(connection.Stream, minTotalOutputSize, targetBytesPerSecond);
|
||||
|
||||
mockKestrelTrace.Verify(t => t.ResponseMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
mockKestrelTrace.Verify(t => t.ResponseMinimumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
mockKestrelTrace.Verify(t => t.ConnectionStop(It.IsAny<string>()), Times.Once());
|
||||
Assert.False(requestAborted);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,12 +303,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
|||
Assert.NotEmpty(completeQueue);
|
||||
|
||||
// Add more bytes to the write-behind buffer to prevent the next write from
|
||||
outputProducer.Write((writableBuffer, state) =>
|
||||
_ = outputProducer.WriteAsync((writableBuffer, state) =>
|
||||
{
|
||||
writableBuffer.Write(state);
|
||||
return state.Count;
|
||||
},
|
||||
halfWriteBehindBuffer);
|
||||
halfWriteBehindBuffer,
|
||||
default);
|
||||
|
||||
// Act
|
||||
var writeTask2 = outputProducer.WriteDataAsync(halfWriteBehindBuffer);
|
||||
|
|
|
|||
|
|
@ -153,16 +153,16 @@ namespace Microsoft.AspNetCore.Testing
|
|||
_trace2.RequestBodyDrainTimedOut(connectionId, traceIdentifier);
|
||||
}
|
||||
|
||||
public void RequestBodyMininumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate)
|
||||
public void RequestBodyMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier, double rate)
|
||||
{
|
||||
_trace1.RequestBodyMininumDataRateNotSatisfied(connectionId, traceIdentifier, rate);
|
||||
_trace2.RequestBodyMininumDataRateNotSatisfied(connectionId, traceIdentifier, rate);
|
||||
_trace1.RequestBodyMinimumDataRateNotSatisfied(connectionId, traceIdentifier, rate);
|
||||
_trace2.RequestBodyMinimumDataRateNotSatisfied(connectionId, traceIdentifier, rate);
|
||||
}
|
||||
|
||||
public void ResponseMininumDataRateNotSatisfied(string connectionId, string traceIdentifier)
|
||||
public void ResponseMinimumDataRateNotSatisfied(string connectionId, string traceIdentifier)
|
||||
{
|
||||
_trace1.ResponseMininumDataRateNotSatisfied(connectionId, traceIdentifier);
|
||||
_trace2.ResponseMininumDataRateNotSatisfied(connectionId, traceIdentifier);
|
||||
_trace1.ResponseMinimumDataRateNotSatisfied(connectionId, traceIdentifier);
|
||||
_trace2.ResponseMinimumDataRateNotSatisfied(connectionId, traceIdentifier);
|
||||
}
|
||||
|
||||
public void ApplicationAbortedConnection(string connectionId, string traceIdentifier)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
return NetworkInterface.GetAllNetworkInterfaces()
|
||||
.Where(iface => iface.OperationalStatus == OperationalStatus.Up)
|
||||
.SelectMany(iface => iface.GetIPProperties().UnicastAddresses)
|
||||
.Any(addrInfo => addrInfo.Address.AddressFamily == AddressFamily.InterNetworkV6 && addrInfo.Address.ScopeId != 0);
|
||||
.Any(addressInfo => addressInfo.Address.AddressFamily == AddressFamily.InterNetworkV6 && addressInfo.Address.ScopeId != 0);
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ namespace CodeGenerator
|
|||
PrimaryHeader = responsePrimaryHeaders.Contains("Content-Length")
|
||||
}})
|
||||
.ToArray();
|
||||
// 63 for reponseHeaders as it steals one bit for Content-Length in CopyTo(ref MemoryPoolIterator output)
|
||||
// 63 for responseHeaders as it steals one bit for Content-Length in CopyTo(ref MemoryPoolIterator output)
|
||||
Debug.Assert(responseHeaders.Length <= 63);
|
||||
Debug.Assert(responseHeaders.Max(x => x.Index) <= 62);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue